ddc-core-flow 0.3.2.1 → 0.4.3.1
raw patch · 73 files changed
Files
- DDC/Core/Flow.hs +17/−0
- DDC/Core/Flow/Compounds.hs +43/−14
- DDC/Core/Flow/Context.hs +4/−18
- DDC/Core/Flow/Context/Base.hs +44/−0
- DDC/Core/Flow/Context/FillPath.hs +148/−0
- DDC/Core/Flow/Convert.hs +190/−0
- DDC/Core/Flow/Convert/Base.hs +88/−0
- DDC/Core/Flow/Convert/Exp.hs +465/−0
- DDC/Core/Flow/Convert/Type.hs +209/−0
- DDC/Core/Flow/Env.hs +39/−30
- DDC/Core/Flow/Exp.hs +6/−3
- DDC/Core/Flow/Exp/Simple/Collect.hs +77/−0
- DDC/Core/Flow/Exp/Simple/Compounds.hs +287/−0
- DDC/Core/Flow/Exp/Simple/Exp.hs +196/−0
- DDC/Core/Flow/Lower.hs +367/−0
- DDC/Core/Flow/Prim.hs +102/−41
- DDC/Core/Flow/Prim/Base.hs +211/−52
- DDC/Core/Flow/Prim/DaConFlow.hs +6/−4
- DDC/Core/Flow/Prim/DaConPrim.hs +16/−16
- DDC/Core/Flow/Prim/KiConFlow.hs +11/−5
- DDC/Core/Flow/Prim/OpConcrete.hs +194/−0
- DDC/Core/Flow/Prim/OpControl.hs +131/−0
- DDC/Core/Flow/Prim/OpFlow.hs +0/−252
- DDC/Core/Flow/Prim/OpLoop.hs +0/−84
- DDC/Core/Flow/Prim/OpPrim.hs +76/−3
- DDC/Core/Flow/Prim/OpSeries.hs +471/−0
- DDC/Core/Flow/Prim/OpStore.hs +136/−56
- DDC/Core/Flow/Prim/OpVector.hs +135/−0
- DDC/Core/Flow/Prim/TyConFlow.hs +159/−18
- DDC/Core/Flow/Prim/TyConPrim.hs +28/−7
- DDC/Core/Flow/Procedure.hs +28/−20
- DDC/Core/Flow/Process.hs +1/−0
- DDC/Core/Flow/Process/Operator.hs +214/−44
- DDC/Core/Flow/Process/Pretty.hs +117/−21
- DDC/Core/Flow/Process/Process.hs +13/−33
- DDC/Core/Flow/Profile.hs +33/−15
- DDC/Core/Flow/Transform/Annotate.hs +88/−0
- DDC/Core/Flow/Transform/Concretize.hs +76/−34
- DDC/Core/Flow/Transform/Deannotate.hs +74/−0
- DDC/Core/Flow/Transform/Extract.hs +73/−41
- DDC/Core/Flow/Transform/Extract/Intersperse.hs +0/−53
- DDC/Core/Flow/Transform/Forward.hs +68/−0
- DDC/Core/Flow/Transform/Melt.hs +171/−0
- DDC/Core/Flow/Transform/Prep.hs +0/−169
- DDC/Core/Flow/Transform/Rates/Clusters.hs +17/−0
- DDC/Core/Flow/Transform/Rates/Clusters/Base.hs +37/−0
- DDC/Core/Flow/Transform/Rates/Clusters/Greedy.hs +126/−0
- DDC/Core/Flow/Transform/Rates/Clusters/Linear.hs +322/−0
- DDC/Core/Flow/Transform/Rates/CnfFromExp.hs +206/−0
- DDC/Core/Flow/Transform/Rates/Combinators.hs +304/−0
- DDC/Core/Flow/Transform/Rates/Fail.hs +59/−0
- DDC/Core/Flow/Transform/Rates/Graph.hs +229/−0
- DDC/Core/Flow/Transform/Rates/SeriesOfVector.hs +532/−0
- DDC/Core/Flow/Transform/Rates/SizeInference.hs +485/−0
- DDC/Core/Flow/Transform/Schedule.hs +8/−247
- DDC/Core/Flow/Transform/Schedule/Base.hs +108/−0
- DDC/Core/Flow/Transform/Schedule/Error.hs +75/−0
- DDC/Core/Flow/Transform/Schedule/Kernel.hs +320/−0
- DDC/Core/Flow/Transform/Schedule/Lifting.hs +130/−0
- DDC/Core/Flow/Transform/Schedule/Nest.hs +141/−135
- DDC/Core/Flow/Transform/Schedule/Scalar.hs +330/−0
- DDC/Core/Flow/Transform/Schedule/SeriesEnv.hs +0/−157
- DDC/Core/Flow/Transform/Slurp.hs +325/−123
- DDC/Core/Flow/Transform/Slurp/Alloc.hs +0/−41
- DDC/Core/Flow/Transform/Slurp/Context.hs +287/−0
- DDC/Core/Flow/Transform/Slurp/Error.hs +74/−0
- DDC/Core/Flow/Transform/Slurp/Operator.hs +153/−58
- DDC/Core/Flow/Transform/Slurp/Resize.hs +120/−0
- DDC/Core/Flow/Transform/Thread.hs +77/−74
- DDC/Core/Flow/Transform/TransformUpX.hs +85/−0
- DDC/Core/Flow/Transform/Wind.hs +87/−75
- LICENSE +1/−15
- ddc-core-flow.cabal +82/−41
DDC/Core/Flow.hs view
@@ -6,11 +6,27 @@ ( -- * Language profile profile + -- * Driver+ , Lifting (..)+ , Config (..)+ , defaultConfigVector+ , defaultConfigKernel+ , defaultConfigScalar+ , Method (..)+ , lowerModule+ -- * Names , Name (..)+ , KiConFlow (..) , TyConFlow (..)+ , DaConFlow (..)+ , OpControl (..)+ , OpSeries (..)+ , OpStore (..)+ , OpVector (..) , PrimTyCon (..) , PrimArith (..)+ , PrimVec (..) , PrimCast (..) -- * Name Parsing@@ -23,3 +39,4 @@ where import DDC.Core.Flow.Prim import DDC.Core.Flow.Profile+import DDC.Core.Flow.Lower
DDC/Core/Flow/Compounds.hs view
@@ -1,18 +1,30 @@ -- | Short-hands for constructing compound expressions. module DDC.Core.Flow.Compounds- ( module DDC.Core.Compounds.Simple+ ( module DDC.Core.Flow.Exp.Simple.Compounds -- * Fragment specific kinds , kRate+ , kProc -- * Fragment specific types+ , isRateNatType+ , isSeriesType+ , isRateVecType+ , isRefType+ , isVectorType+ , isProcessType , tTuple1, tTuple2, tTupleN- , tVector, tSeries, tSegd, tSel1, tSel2, tRef, tWorld+ , tVector, tBuffer, tSeries, tRateVec, tSegd, tSel1, tSel2, tRef, tWorld , tRateNat+ , tDown+ , tTail+ , tRateAppend, tRateCross+ , tProcess+ , tResize -- * Primtiive types- , tVoid, tBool, tNat, tInt, tWord+ , tVoid, tBool, tNat, tInt, tWord, tFloat, tVec -- * Primitive literals and data constructors , xBool, dcBool@@ -21,25 +33,42 @@ , xTuple2, dcTuple2 , dcTupleN - -- * Flow operators+ -- * Primitive Vec operators+ , xvRep+ , xvProj+ , xvGather+ , xvScatter++ -- * Series operators+ , xProj , xRateOfSeries , xNatOfRateNat+ , xNext, xNextC+ , xDown+ , xTail+ , xSeriesOfRateVec - -- * Loop operators- , xLoopLoopN- , xLoopGuard+ -- * Control operators+ , xLoopN+ , xGuard+ , xSegment+ , xSplit -- * Store operators- , xNew, xRead, xWrite- , xNewVector, xReadVector, xWriteVector, xNewVectorR, xNewVectorN- , xSliceVector- , xNext)+ , xNew, xRead, xWrite+ , xNewVector, xNewVectorR, xNewVectorN+ , xReadVector, xReadVectorC+ , xWriteVector, xWriteVectorC+ , xTailVector+ , xTruncVector) where import DDC.Core.Flow.Prim.KiConFlow import DDC.Core.Flow.Prim.TyConFlow import DDC.Core.Flow.Prim.TyConPrim import DDC.Core.Flow.Prim.DaConPrim-import DDC.Core.Flow.Prim.OpFlow-import DDC.Core.Flow.Prim.OpLoop+import DDC.Core.Flow.Prim.OpControl+import DDC.Core.Flow.Prim.OpConcrete+import DDC.Core.Flow.Prim.OpSeries import DDC.Core.Flow.Prim.OpStore-import DDC.Core.Compounds.Simple+import DDC.Core.Flow.Prim.OpPrim+import DDC.Core.Flow.Exp.Simple.Compounds
DDC/Core/Flow/Context.hs view
@@ -1,21 +1,7 @@ module DDC.Core.Flow.Context- (Context (..))+ ( module DDC.Core.Flow.Context.Base+ , module DDC.Core.Flow.Context.FillPath ) where-import DDC.Type.Exp-import DDC.Core.Flow.Prim--data Context- -- | A top-level context associated with a rate that is a parameter- -- of the process. This context isn't created by the process itself.- = ContextRate- { contextRate :: Type Name }-- -- | A nested context created by a mkSel function.- | ContextSelect- { contextOuterRate :: Type Name- , contextInnerRate :: Type Name- , contextFlags :: Bound Name- , contextSelector :: Bind Name }- deriving (Show, Eq)-+import DDC.Core.Flow.Context.Base+import DDC.Core.Flow.Context.FillPath
+ DDC/Core/Flow/Context/Base.hs view
@@ -0,0 +1,44 @@++module DDC.Core.Flow.Context.Base+ (Context (..))+where+import DDC.Type.Exp+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Process.Operator+++data Context+ -- | A top-level context associated with a rate that is a parameter+ -- of the process. This context isn't created by the process itself.+ = ContextRate+ { contextRate :: Type Name+ , contextOps :: [Operator]+ , contextInner :: [Context] }++ -- | A nested context created by a mkSel1# function.+ | ContextSelect+ { contextOuterRate :: Type Name+ , contextInnerRate :: Type Name+ , contextFlags :: Bound Name+ , contextSelector :: Bind Name+ , contextOps :: [Operator]+ , contextInner :: [Context] }+++ -- | A nested context created by a mkSegd# function.+ | ContextSegment+ { contextOuterRate :: Type Name+ , contextInnerRate :: Type Name+ , contextLens :: Bound Name+ , contextSegd :: Bind Name+ , contextOps :: [Operator]+ , contextInner :: [Context] }++ | ContextAppend+ { contextRate1 :: Type Name+ , contextInner1 :: Context+ , contextRate2 :: Type Name+ , contextInner2 :: Context }+ deriving Show++
+ DDC/Core/Flow/Context/FillPath.hs view
@@ -0,0 +1,148 @@++module DDC.Core.Flow.Context.FillPath+ ( FillMap, FillPath+ , pathsOfFills+ , getAccForPath+ , getAcc+ , isSimple+ , isNone )+where+import DDC.Type.Exp+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Process.Operator+import DDC.Core.Flow.Context.Base++import qualified Data.Map as Map+import Control.Monad+++type FillMap = Map.Map Name (FillPath, Type Name)++data FillPath+ = PathNone+ | PathRate (Type Name)+ | PathSelect (Bound Name)+ | PathSegment (Bound Name)+ | PathAppend FillPath FillPath+ deriving (Eq, Show)+++pathsOfFills :: Context -> Maybe FillMap+pathsOfFills ctx+ = go ctx Map.empty+ where+ go c@ContextAppend{} _+ = do m1 <- go (contextInner1 c) Map.empty+ m2 <- go (contextInner2 c) Map.empty+ return $ Map.unionWith merge+ (Map.map appl m1)+ (Map.map appr m2)++ go c m+ = do m' <- insertFillsNoDupes (contextOps c) (path c) m+ foldM (flip go) m' (contextInner c)++ appl (p,t)+ = (PathAppend p PathNone, t)+ appr (p,t)+ = (PathAppend PathNone p, t)++ merge (PathAppend PathNone _, t) (PathAppend _ PathNone, _)+ = (PathNone, t)+ merge (PathAppend l _, t) (PathAppend _ r, _)+ = (PathAppend l r, t)+ merge _ _+ = error "ddc-core-flow.pathsOfFills: impossible!"++ path c@ContextRate{} + = PathRate $ contextRate c+ path c@ContextSelect{} + = PathSelect $ contextFlags c+ path c@ContextSegment{} + = PathSegment $ contextLens c+ path ContextAppend{} + = PathAppend PathNone PathNone+++ insertFillsNoDupes ops p m+ = foldM (insert1 p) m ops++ insert1 p m OpFill{ opTargetVector = UName n+ , opElemType = ty }+ = case Map.lookup n m of+ Nothing+ -> Just (Map.insert n (p,ty) m)+ Just _+ -> Nothing+ insert1 _ m _+ = Just m+++isPrefixOf :: FillPath -> FillPath -> Bool+isPrefixOf PathNone _+ = True+isPrefixOf (PathAppend h i) (PathAppend j k)+ = h == j && isPrefixOf i k+ || i == PathNone && k == PathNone && isPrefixOf h j+isPrefixOf a b+ = a == b++isNone :: FillPath -> Bool+isNone PathNone+ = True+isNone (PathAppend i j)+ = isNone i && isNone j+isNone _+ = False++-- A simple fill path has only one place it's filling, and it's just a rate with no select or segment+isSimple :: FillPath -> Bool+isSimple (PathAppend i j)+ = isSimple i && isNone j+ || isSimple j && isNone i+isSimple (PathRate _)+ = True+isSimple _+ = False++++getAccForPath :: FillMap -> FillPath -> Maybe Name+getAccForPath m fp+ = case Map.minViewWithKey $ Map.filter search m of+ Nothing -> Nothing+ Just ((k,_),_) -> Just k+ where+ search (fp', _)+ = isPrefixOf fp fp'++-- If acc is Nothing, you can just use the current index ^0+getAcc :: FillMap -> Name -> Maybe Name+getAcc m n+ = case Map.lookup n m of+ Nothing+ -> Nothing -- ???+ Just (fp, _)+ -> if isSimple fp+ then Nothing+ else getAccForPath m fp++-- I don't think this actually gives us the fewest number of accumulators.+-- Depending on the ordering of the map, maybe we'd have+--+-- [ h = App a None;+-- i = App a None;+-- j = App a b;+-- k = App a c ]+-- +-- here, @h@ and @i@ will be given the same accumulator, but @j@ and @k@ need separate+-- accumulators: three accumulators in total.+--+-- If the order were different, such as+-- [ j = App a b;+-- h = App a None;+-- i = App a None;+-- k = App a c ]+-- then searching for @h@ or @i@ would find @j@, and we would end up with only two accumulators, @j@ and @k@.+-- +
+ DDC/Core/Flow/Convert.hs view
@@ -0,0 +1,190 @@++-- | Conversion of Flow to Tetra+--+module DDC.Core.Flow.Convert+ ( tetraOfFlowModule )+where++import DDC.Core.Flow.Convert.Base+import DDC.Core.Flow.Convert.Type+import DDC.Core.Flow.Convert.Exp+import DDC.Core.Exp.Annot+import DDC.Core.Module+import DDC.Control.Check++import qualified DDC.Core.Flow.Prim as F+import qualified DDC.Core.Salt.Name as T+import qualified DDC.Core.Salt.Compounds as T++import DDC.Core.Salt.Convert (initRuntime)+import DDC.Core.Salt.Runtime (Config(..))++import qualified Data.Set as S+++tetraOfFlowModule :: Module a F.Name -> Either Error (Module a T.Name)+tetraOfFlowModule mm+ = evalCheck (S.empty, S.empty)+ $ convertM mm++convertM :: Module a F.Name -> ConvertM (Module a T.Name)+convertM mm+ = do + -- Convert signatures of imported functions.+ tsImportT' <- mapM convertImportNameTypeM $ moduleImportTypes mm+ tsImportV' <- mapM convertImportNameValueM $ moduleImportValues mm++ let tsImportV'rest =+ [ ( T.NameVar "getFieldOfBoxed"+ , ImportValueSea "getFieldOfBoxed" + $ tForalls [kRegion, kData] + $ \[r,d] -> T.tPtr r T.tObj `tFun` T.tNat `tFun` d)++ , ( T.NameVar "setFieldOfBoxed"+ , ImportValueSea "setFieldOfBoxed" + $ tForalls [kRegion, kData] + $ \[r,d] -> T.tPtr r T.tObj `tFun` T.tNat `tFun` d `tFun` T.tVoid)++ , ( T.NameVar "allocBoxed"+ , ImportValueSea "allocBoxed" + $ tForalls [kRegion ] + $ \[r ] -> T.tTag `tFun` T.tNat `tFun` T.tPtr r T.tObj)+ ]++ -- Convert signatures of exported functions.+ tsExportT' <- mapM convertExportM+ $ moduleExportTypes mm++ tsExportV' <- mapM convertExportM+ $ moduleExportValues mm++ -- Convert the body of the module+ body' <- convertX $ moduleBody mm++ -- Build the output module.+ let mm_tetra + = ModuleCore+ { moduleName = moduleName mm+ , moduleIsHeader = moduleIsHeader mm++ , moduleExportTypes = tsExportT'+ , moduleExportValues = tsExportV'++ , moduleImportTypes = tsImportT'+ , moduleImportCaps = []+ , moduleImportValues = tsImportV' ++ tsImportV'rest++ -- We're only using whole module compilation for+ -- flow programs, so there aren't any imports.+ , moduleImportDataDefs = []+ , moduleImportTypeDefs = []++ , moduleDataDefsLocal = []+ , moduleTypeDefsLocal = []++ , moduleBody = body' }++ -- Initialise the salt heap.+ -- Hardcode this for now, because eventually this will target tetra.+ mm_init <- case initRuntime (Config 10000) mm_tetra of+ Nothing -> return mm_tetra+ Just mm' -> return mm'++ return $ mm_init+++---------------------------------------------------------------------------------------------------+-- | Convert an export spec.+convertExportM+ :: (F.Name, ExportSource F.Name (Type F.Name))+ -> ConvertM (T.Name, ExportSource T.Name (Type T.Name))++convertExportM (n, esrc)+ = do n' <- convertName n+ esrc' <- convertExportSourceM esrc+ return (n', esrc')+++-- Convert an export source.+convertExportSourceM + :: ExportSource F.Name (Type F.Name)+ -> ConvertM (ExportSource T.Name (Type T.Name))++convertExportSourceM esrc+ = case esrc of+ ExportSourceLocal n t+ -> do n' <- convertName n+ t' <- convertType t+ return $ ExportSourceLocal n' t'++ ExportSourceLocalNoType n+ -> do n' <- convertName n+ return $ ExportSourceLocalNoType n'+++---------------------------------------------------------------------------------------------------+-- | Convert an import spec.+convertImportNameTypeM+ :: (F.Name, ImportType F.Name (Type F.Name))+ -> ConvertM (T.Name, ImportType T.Name (Type T.Name))++convertImportNameTypeM (n, isrc)+ = do n' <- convertImportNameM n+ isrc' <- convertImportTypeM isrc+ return (n', isrc')+++-- | Convert an import spec.+convertImportNameValueM+ :: (F.Name, ImportValue F.Name (Type F.Name))+ -> ConvertM (T.Name, ImportValue T.Name (Type T.Name))++convertImportNameValueM (n, isrc)+ = do n' <- convertImportNameM n+ isrc' <- convertImportValueM isrc+ return (n', isrc')+++-- | Convert an imported name.+-- These can be variable names for values, +-- or variable or constructor names for type imports.+convertImportNameM :: F.Name -> ConvertM T.Name+convertImportNameM n+ = case n of+ F.NameVar str -> return $ T.NameVar str+ F.NameCon str -> return $ T.NameCon str+ _ -> throw $ ErrorInvalidBinder n+++-- | Convert an import source.+convertImportTypeM + :: ImportType F.Name (Type F.Name)+ -> ConvertM (ImportType T.Name (Type T.Name))++convertImportTypeM isrc+ = case isrc of+ ImportTypeAbstract t+ -> do t' <- convertType t+ return $ ImportTypeAbstract t'++ ImportTypeBoxed t+ -> do t' <- convertType t+ return $ ImportTypeBoxed t'+++-- | Convert an import value spec.+convertImportValueM + :: ImportValue F.Name (Type F.Name)+ -> ConvertM (ImportValue T.Name (Type T.Name))++convertImportValueM isrc+ = case isrc of+ ImportValueModule mn n t _+ -> do n' <- convertName n+ t' <- convertType t+ return $ ImportValueModule mn n' t' Nothing++ ImportValueSea str t+ -> do t' <- convertType t + return $ ImportValueSea str t'+
+ DDC/Core/Flow/Convert/Base.hs view
@@ -0,0 +1,88 @@++module DDC.Core.Flow.Convert.Base+ ( ConvertM+ , Error (..)+ , withRateXLAM, isRateXLAM+ , withSuspFns, isSuspFn)+where+import DDC.Data.Pretty+import DDC.Core.Exp.Annot+import DDC.Core.Flow.Prim as F+import qualified DDC.Control.Check as G++import qualified Data.Set as S+import Data.Maybe++-- | Conversion Monad+-- State contains+-- * names of function that have been converted to Suspended computations.+-- whenever these are called, we need to add a "run" cast.+-- * names of rate XLAMs that have been removed.+-- any reference to these must also be removed.+type ConvertM x = G.CheckM (S.Set F.Name, S.Set F.Name) Error x+++withRateXLAM :: Bind F.Name -> ConvertM a -> ConvertM a+withRateXLAM r c+ | Just r' <- takeNameOfBind r+ = do (fs,rs) <- G.get+ G.put (fs, S.insert r' rs)+ val <- c+ G.put (fs, rs)+ return $ val+ | otherwise+ = c+++isRateXLAM :: F.Name -> ConvertM Bool+isRateXLAM r+ = do (_,rs) <- G.get+ return $ S.member r rs+++withSuspFns :: [Bind F.Name] -> ConvertM a -> ConvertM a+withSuspFns bs c+ = do (fs,rs) <- G.get+ let ns = catMaybes $ map takeNameOfBind bs+ G.put (S.union (S.fromList ns) fs, rs)+ val <- c+ G.put (fs, rs)+ return $ val++isSuspFn :: F.Name -> ConvertM Bool+isSuspFn f+ = do (fs,_) <- G.get+ return $ S.member f fs+++-- | Things that can go wrong during the conversion.+data Error+ -- | An invalid name used in a binding position+ = ErrorInvalidBinder F.Name++ -- | A partially applied primitive, such as "Series"+ | ErrorPartialPrimitive F.Name++ -- | Something we can't convert, like "runKernel0#",+ -- but that shouldn't be created+ | ErrorNotSupported F.Name++ -- | Found an unexpected type sum.+ | ErrorUnexpectedSum+++instance Pretty Error where+ ppr err+ = case err of+ ErrorInvalidBinder n+ -> vcat [ text "Invalid name used in binder '" <> ppr n <> text "'."]++ ErrorPartialPrimitive n+ -> vcat [ text "Cannot convert primitive " <> ppr n <> text "." ]++ ErrorNotSupported n+ -> vcat [ text "Cannot convert " <> ppr n <> text ", as it shouldn't be generated by flow transforms." ]++ ErrorUnexpectedSum+ -> vcat [ text "Unexpected type sum."]+
+ DDC/Core/Flow/Convert/Exp.hs view
@@ -0,0 +1,465 @@++-- | Conversion of Flow expressions to Tetra expressions+-- This only handles the subset of flow that occurs after lowering.+module DDC.Core.Flow.Convert.Exp+ ( convertX )+where++import DDC.Core.Flow.Convert.Base+import DDC.Core.Flow.Convert.Type+import DDC.Core.Exp.Annot+import DDC.Type.Transform.BoundT++import qualified DDC.Core.Flow.Prim as F+import qualified DDC.Core.Flow.Compounds as F++import qualified DDC.Core.Salt.Name as T+import qualified DDC.Core.Salt.Compounds as T+import qualified DDC.Core.Salt.Env as T++import Control.Monad+++convertX :: Exp a F.Name -> ConvertM (Exp a T.Name)+convertX xx+ -- Remove any /\(k : Rate). They are not needed any more.+ | XLAM _ b x <- xx+ , typeOfBind b == F.kRate+ = withRateXLAM b $ removeXLAM b <$> convertX x++ -- Operators that just need a region added as first argument+ | Just (op, xs@(_:_)) <- takeXPrimApps xx+ = case op of+ F.NameOpStore F.OpStoreNew+ | [ ty, val ] <- xs+ , Just tY <- takeXType ty+ -> do tY' <- convertType tY+ val' <- convertX val+ return $ allocRef anno tY' val'++ F.NameOpStore F.OpStoreRead+ | [ ty, ref ] <- xs+ -> do ty' <- convertX ty+ ref' <- convertX ref++ return $ mk (T.PrimStore T.PrimStorePeek)+ [ xRTop anno, ty', ref', T.xNat anno 0 ]++ F.NameOpStore F.OpStoreWrite+ | [ ty, ref, val ] <- xs+ -> do ty' <- convertX ty+ ref' <- convertX ref+ val' <- convertX val++ return+ $ XLet anno+ (LLet (BNone T.tVoid)+ $ mk (T.PrimStore T.PrimStorePoke)+ [ xRTop anno, ty', ref', T.xNat anno 0, val' ])+ (XCon anno $ DaConUnit)+++ -- natOfRateNat becomes a noop, as RateNats become Nats.+ F.NameOpConcrete F.OpConcreteNatOfRateNat+ | [ _r, n ] <- xs+ -> convertX n++ F.NameOpConcrete (F.OpConcreteNext 1)+ | [t, _r, v, i] <- xs+ -> do v' <- convertX v+ i' <- convertX i+ t' <- convertX t+ return $ mk (T.PrimStore T.PrimStorePeek)+ [ xRTop anno, t', v'+ , mk (T.PrimArith T.PrimArithMul)+ [ XType anno T.tNat, i'+ , mk (T.PrimStore T.PrimStoreSize) [t'] ] ]++ -- vlength# [t] vec+ -- becomes a projection+ F.NameOpVector F.OpVectorLength+ | [xt, v] <- xs+ , Just t <- takeXType xt+ -> do t' <- convertType t+ v' <- convertX v+ return $ xVecLen t' v'++ -- vwrite# [t] buf ix val+ F.NameOpStore (F.OpStoreWriteVector 1)+ | [xt, buf, ix, val] <- xs+ , Just t <- takeXType xt+ -> do t' <- convertType t+ buf' <- convertX buf+ ix' <- convertX ix+ val' <- convertX val++ return+ $ XLet anno+ (LLet (BNone T.tVoid)+ $ mk (T.PrimStore T.PrimStorePoke)+ [ xRTop anno+ , XType anno t'+ , buf'+ , mk (T.PrimArith T.PrimArithMul)+ [ XType anno T.tNat, ix'+ , mk (T.PrimStore T.PrimStoreSize) [XType anno t'] ]+ , val' ])+ (XCon anno DaConUnit)++ -- vbuf# [t] vec+ F.NameOpStore F.OpStoreBufOfVector+ | [xt, vec] <- xs+ , Just t <- takeXType xt+ -> do t' <- convertType t+ vec' <- convertX vec++ return+ $ xVecPtr t' vec'+++ -- vnew# [t] len+ F.NameOpStore F.OpStoreNewVector+ | [xt, sz] <- xs+ , Just t <- takeXType xt+ -> do t' <- convertType t+ sz' <- convertX sz++ let lenR = allocRef anno T.tNat sz'+ datR = allocPtr anno t' sz'+ tup = allocTupleN anno [(tRef rTop T.tNat, lenR), (T.tPtr rTop t', datR)]+ return tup++ -- vtrunc# [t] len vec+ F.NameOpStore F.OpStoreTruncVector+ | [xt, sz, v] <- xs+ , Just t <- takeXType xt+ -> do _t' <- convertType t+ sz' <- convertX sz+ v' <- convertX v++ return+ $ XLet anno+ (LLet (BNone T.tVoid)+ $ mk (T.PrimStore T.PrimStorePoke)+ [ xRTop anno+ , XType anno T.tNat+ , projTuple anno v' 0 (T.tPtr rTop T.tNat)+ , T.xNat anno 0+ , sz' ])+ (XCon anno $ DaConUnit)++ F.NameOpSeries F.OpSeriesRunProcess+ | [proc] <- xs+ -> do proc' <- convertX proc+ return+ $ XApp anno proc' $ XCon anno $ DaConUnit++{-+ -- runKernelN# [ty1]...[tyN] v1...vN proc+ -- becomes+ -- proc (length v1) (ptrOfVec v1) ... (ptrOfVec vN)+ F.NameOpConcrete (F.OpConcreteRunKernel n)+ | (xts, xs') <- splitAt n xs+ , Just ts <- mapM takeXType xts+ , (vs, [proc]) <- splitAt n xs'+ -> do vs' <- mapM convertX vs+ ts' <- mapM convertType ts++ proc' <- convertX proc++ case (vs',ts') of+ ((v':_), (t':_))+ -> return+ $ XLet anno (LLet (BNone tUnit)+ ( xApps anno proc'+ (xVecLen t' v' : zipWith xVecPtr ts' vs')))+ true+ (_, _)+ -> throw $ ErrorNotSupported op+-}++ _+ -> case takeXApps xx of+ Just (f,args) -> convertApp f args+ Nothing -> error "ddc-core-flow.convertX: impossible!"++ | Just+ (DaConPrim (F.NameDaConFlow (F.DaConFlowTuple n)) _+ , args) <- takeXConApps xx+ , length args == n * 2+ , (xts, xs) <- splitAt n args+ , Just ts <- mapM takeXType xts+ = do ts' <- mapM convertType ts+ xs' <- mapM convertX xs+ return+ $ allocTupleN anno (ts' `zip` xs')++ | Just (f, args@(_:_)) <- takeXApps xx+ = convertApp f args++ | XCase _ x+ [AAlt (PData (DaConPrim (F.NameDaConFlow (F.DaConFlowTuple n)) _) bs) x1]+ <- xx+ , length bs == n + = do x' <- convertX x+ bs' <- mapM convertBind bs+ x1' <- convertX x1+ return+ $ xLets anno+ [ LLet b (projTuple anno x' i $ typeOfBind b)+ | (b,i) <- bs' `zip` [0..] ]+ x1'++ -- otherwise just boilerplate recursion+ | otherwise+ = case xx of+ XVar a b+ -> XVar a <$> convertBound b+ XCon a c+ -> XCon a <$> convertDaCon c+ XLAM a b x+ -> XLAM a <$> convertBind b <*> convertX x+ XLam a b x+ -> XLam a <$> convertBind b <*> convertX x+ XApp a p q+ -> XApp a <$> convertX p <*> convertX q+ XLet a ls x+ -> let bs = valwitBindsOfLets ls+ in withSuspFns bs $ XLet a <$> convertLets ls <*> convertX x+ XCase a x as+ -> XCase a<$> convertX x <*> mapM convertAlt as+ XCast a c x+ -> XCast a<$> convertCast c <*> convertX x+ XType a t+ -> XType a<$> convertType t+ XWitness a w+ -> XWitness a <$> convertWit w+ where+ anno = annotOfExp xx++ mk = prim anno++prim anno n args+ = let t = T.typeOfPrimOp n+ in xApps anno (XVar anno (UPrim (T.NamePrimOp n) t)) args+++convertApp :: Exp a F.Name -> [Exp a F.Name] -> ConvertM (Exp a T.Name)+convertApp f args+ = do f' <- convertX f+ -- filter out any type args that reference deleted XLAMs+ let checkT arg+ | XType _ (TVar (UName n)) <- arg+ = not <$> isRateXLAM n+ | otherwise+ = return True+ args' <- filterM checkT args+ >>= mapM convertX++ let checkF+ | XVar _ (UName n) <- f+ = isSuspFn n+ | otherwise+ = return False++ isSusp <- checkF+ if isSusp+ then return $ xApps anno f' args'+ else return $ xApps anno f' args'+ where+ anno = annotOfExp f++convertDaCon + :: DaCon F.Name (Type F.Name)+ -> ConvertM (DaCon T.Name (Type T.Name))+convertDaCon dd+ = case dd of+ DaConUnit+ -> return DaConUnit+ DaConPrim n t+ -> DaConPrim <$> convertName n <*> convertType t+ DaConBound n+ -> DaConBound <$> convertName n++convertLets :: Lets a F.Name -> ConvertM (Lets a T.Name)+convertLets ll+ = case ll of++ LLet b x+ -> LLet <$> convertBind b <*> convertX x++ LRec bxs+ -> LRec <$> mapM (both convertBind convertX) bxs++ LPrivate rs t ws+ -> LPrivate <$> mapM convertBind rs+ <*> liftMaybe convertType t -- ??+ <*> mapM convertBind ws++ where+ liftMaybe f m+ = case m of+ Just a -> Just <$> f a+ Nothing -> return Nothing++ both f g+ = \(a,b) -> (,) <$> f a <*> g b++convertAlt :: Alt a F.Name -> ConvertM (Alt a T.Name)+convertAlt aa+ = case aa of+ AAlt p x+ -> AAlt <$> convertPat p <*> convertX x++convertPat :: Pat F.Name -> ConvertM (Pat T.Name)+convertPat pp+ = case pp of+ PDefault+ -> return $ PDefault+ PData dc bs+ -> PData <$> convertDaCon dc <*> mapM convertBind bs++convertCast :: Cast a F.Name -> ConvertM (Cast a T.Name)+convertCast cc+ = case cc of+ CastWeakenEffect et+ -> CastWeakenEffect <$> convertType et++ CastPurify w+ -> CastPurify <$> convertWit w++ CastBox+ -> return $ CastBox++ CastRun+ -> return $ CastRun+++convertWit :: Witness a F.Name -> ConvertM (Witness a T.Name)+convertWit = error "ddc-core-flow.convertWit: cannot convert witness from core flow program"+++-- | When replacing @/\(b : Rate). x@ with @x@, if @b@ is a de bruijn index then any type vars in @x@ must be lowered.+-- @b@ must not be mentioned in @x@.+removeXLAM :: Bind F.Name -> Exp a T.Name -> Exp a T.Name+removeXLAM b t+ = case b of+ BAnon _+ -> lowerT 1 t+ _+ -> t+++-- | Type of the top-level region.+xRTop :: a -> Exp a T.Name+xRTop a = XType a rTop++-- | Get the Nat# of length from a Vector+xVecLen :: Type T.Name -> Exp a T.Name -> Exp a T.Name+xVecLen _t x+ = prim anno (T.PrimStore T.PrimStorePeek)+ [ xRTop anno, XType anno T.tNat+ , projTuple anno x 0 (T.tPtr rTop T.tNat)+ , T.xNat anno 0 ]+ where+ anno = annotOfExp x++-- | Get the pointer to the data from a Vector+xVecPtr :: Type T.Name -> Exp a T.Name -> Exp a T.Name+xVecPtr t x+ = projTuple anno x 1 (T.tPtr rTop t)+ where+ anno = annotOfExp x++allocRef :: a -> Type T.Name -> Exp a T.Name -> Exp a T.Name+allocRef anno tY val+ = let ty = XType anno tY++ sz = prim anno (T.PrimStore T.PrimStoreSize) [ty]+ addr = prim anno (T.PrimStore T.PrimStoreAlloc) [sz]+ ptr = prim anno (T.PrimStore T.PrimStoreMakePtr)+ [ xRTop anno, ty, addr ]+ + ll = LLet (BAnon $ T.tPtr rTop tY)+ ptr++ ptr' = XVar anno $ UIx 0+ poke = prim anno (T.PrimStore T.PrimStorePoke)+ [ xRTop anno, ty, ptr', T.xNat anno 0, val ]+ in XLet anno ll+ $ XLet anno (LLet (BNone T.tVoid) poke) + ptr'++allocPtr :: a -> Type T.Name -> Exp a T.Name -> Exp a T.Name+allocPtr anno tY elts+ = let ty = XType anno tY++ sz = prim anno (T.PrimStore T.PrimStoreSize) [ty]+ addr = prim anno (T.PrimStore T.PrimStoreAlloc)+ [ prim anno (T.PrimArith T.PrimArithMul)+ [ XType anno T.tNat, elts, sz] ]+ ptr = prim anno (T.PrimStore T.PrimStoreMakePtr)+ [ xRTop anno, ty, addr ]+ + in ptr+++unptr :: Type T.Name -> Type T.Name+unptr t+ | Just (_,t') <- T.takeTPtr t+ = t'+ | otherwise+ = t++trybox :: a -> Type T.Name -> Exp a T.Name -> Exp a T.Name+trybox anno t x+ -- Already a pointer, don't bother+ | Just (_,_) <- T.takeTPtr t+ = x+ | otherwise+ = allocRef anno t x++tryunbox :: a -> Type T.Name -> Exp a T.Name -> Exp a T.Name+tryunbox anno t x+ -- Already a pointer, don't bother+ | Just (_,_) <- T.takeTPtr t+ = x+ | otherwise+ = prim anno (T.PrimStore T.PrimStorePeek)+ [ xRTop anno, XType anno t+ , x, T.xNat anno 0 ]++projTuple :: a -> Exp a T.Name -> Integer -> Type T.Name -> Exp a T.Name+projTuple anno x i t+ = let t' = unptr t+ in tryunbox anno t+ $ castPtr anno t' T.tObj+ $ xApps anno (XVar anno $ UName $ T.NameVar "getFieldOfBoxed")+ [ xRTop anno, XType anno $ T.tPtr rTop T.tObj, x, T.xNat anno i ]+++allocTupleN :: a -> [(Type T.Name, Exp a T.Name)] -> Exp a T.Name+allocTupleN anno txs+ = let tup = xApps anno (XVar anno $ UName $ T.NameVar "allocBoxed")+ [ xRTop anno, T.xTag anno 0, T.xNat anno (fromIntegral $ length txs) ]++ tup' = XVar anno $ UIx 0+ + set i t x+ = let t' = unptr t+ x' = trybox anno t x+ in xApps anno (XVar anno $ UName $ T.NameVar "setFieldOfBoxed")+ [ xRTop anno, XType anno (T.tPtr rTop T.tObj), tup', T.xNat anno i+ , castPtr anno T.tObj t' x' ]+ + in XLet anno (LLet (BAnon $ T.tPtr rTop T.tObj) tup)+ $ xLets anno+ [LLet (BNone T.tVoid) (set i t x) | ((t,x), i) <- txs `zip` [0..]]+ tup'+++castPtr :: a -> Type T.Name -> Type T.Name -> Exp a T.Name -> Exp a T.Name+castPtr anno to from x+ = prim anno (T.PrimStore T.PrimStoreCastPtr)+ [ xRTop anno, XType anno to, XType anno from, x ]+
+ DDC/Core/Flow/Convert/Type.hs view
@@ -0,0 +1,209 @@++-- | Conversion of Flow types to Tetra types+-- This only handles the subset of flow that occurs after lowering.+module DDC.Core.Flow.Convert.Type+ ( convertType+ , convertBind+ , convertBound+ , convertName+ , rTop+ , tVec+ , tRef )+where+import DDC.Core.Flow.Convert.Base+import DDC.Core.Exp.Annot+import DDC.Control.Check (throw)+import DDC.Type.Transform.BoundT++import qualified DDC.Core.Flow.Prim as F+import qualified DDC.Core.Flow.Compounds as F++import qualified DDC.Core.Salt.Name as T+import qualified DDC.Core.Salt.Compounds as T++++tRef :: Type T.Name -> Type T.Name -> Type T.Name+tRef = T.tPtr ++tVec :: Type T.Name+tVec = T.tPtr rTop T.tObj+++-- | Convert types from Flow to Tetra.+--+-- The majority of type conversions are just replacing one name with another,+-- so these are performed in @convertName@.+--+-- Others require removing arguments or adding regions are performed here, before name conversion:+-- * Rate foralls are removed+-- * @Series k a@ becomes @Ptr# rTop a@+-- * @RateNat k@ becomes @Nat#@+-- * @Ref a@ becomes @Ref# rTop a@+-- * @a->b->c@ becomes @a -> b -> S (Read rT + Write rT + Alloc rT) c@+--+convertType :: Type F.Name -> ConvertM (Type T.Name)+convertType tt+ -- Remove [k : Rate] foralls.+ | TForall b t <- tt+ , typeOfBind b == F.kRate+ = removeForall b <$> convertType t++ -- Convert @Vector a@ to @Tuple2# (Ptr# a) (Ref# Nat#)@+ | Just (F.NameTyConFlow F.TyConFlowVector, [tA]) <- takePrimTyConApps tt+ = do _tA' <- convertType tA+ return $ tVec -- T.tTupleN [T.tPtr rTop tA', T.tRef rTop T.tNat]++ -- Convert @Buffer a@ to @Ptr# a@+ | Just (F.NameTyConFlow F.TyConFlowBuffer, [tA]) <- takePrimTyConApps tt+ = do tA' <- convertType tA+ return $ T.tPtr rTop tA'++ -- Convert @TupleN#@ to @Ptr# rTop Obj@+ | Just (F.NameTyConFlow (F.TyConFlowTuple _), ts) <- takePrimTyConApps tt+ = do -- Might as well attempt to convert the types, just so we know they're valid+ mapM_ convertType ts+ return $ tVec++ -- Convert @Series k a@ to just @Ptr# a@+ | Just (F.NameTyConFlow F.TyConFlowSeries, [_K, tA]) <- takePrimTyConApps tt+ = T.tPtr rTop <$> convertType tA++ -- Convert @RateNat k@ to @Nat#@+ | Just (F.NameTyConFlow F.TyConFlowRateNat, [_K]) <- takePrimTyConApps tt+ = return $ T.tNat++ -- Convert Refs+ | Just (F.NameTyConFlow F.TyConFlowRef, [tA]) <- takePrimTyConApps tt+ = tRef rTop <$> convertType tA++ -- Convert normal TFuns to TFunECs with pure and empty. why?+ | (args@(_:_), res) <- takeTFunArgResult tt+ = do args' <- mapM convertType args+ res' <- convertType res++ return $ foldr tFun res' args'+ ++ -- For other primitives, convertName will handle convert them+ | otherwise+ = case tt of+ TVar b+ -> TVar <$> convertBound b+ TCon c+ -> TCon <$> convertTyCon c++ TAbs b t+ -> TAbs <$> convertBind b <*> convertType t++ TApp p q+ -> TApp <$> convertType p <*> convertType q++ TForall b t+ -> TForall <$> convertBind b <*> convertType t++ TSum _t+ -> return $ TSum $ TypeSumBot $ kData -- throw $ ErrorUnexpectedSum+++convertBind :: Bind F.Name -> ConvertM (Bind T.Name)+convertBind b+ = case b of+ BNone t -> BNone <$> convertType t+ BAnon t -> BAnon <$> convertType t+ BName n t -> BName <$> convertName n <*> convertType t+++convertBound :: Bound F.Name -> ConvertM (Bound T.Name)+convertBound b+ = case b of+ UIx i -> return $ UIx i+ UName n -> UName <$> convertName n+ UPrim n t -> UPrim <$> convertName n <*> convertType t+++++convertName :: F.Name -> ConvertM T.Name+convertName nn+ = case nn of+ F.NameVar n+ -> return $ T.NameVar n+ F.NameVarMod n x+ -> flip T.NameExt x <$> convertName n+ F.NameCon n+ -> return $ T.NameCon n++ F.NameKiConFlow _+ -> throw $ ErrorPartialPrimitive nn++ F.NameTyConFlow tf+ -> case tf of+ -- F.TyConFlowTuple n+ -- -> return $ T.NameTyConTetra $ T.TyConTetraTuple n++ -- Vector, Series, RateNat and Ref are handled elsewhere as arguments must be changed+ _+ -> throw $ ErrorPartialPrimitive nn++ -- Machine primitives ------------------+ -- F.NamePrimTyCon T.PrimTyConBool+ -- -> return $ T.NamePrimTyCon T.PrimTyConNat++ F.NamePrimTyCon p+ -> return $ T.NamePrimTyCon p++ F.NamePrimArith p+ -> return $ T.NamePrimOp $ T.PrimArith p++ F.NamePrimCast p+ -> return $ T.NamePrimOp $ T.PrimCast p++ -- Literals -----------------------------+ F.NameLitBool b+ -> return $ T.NamePrimLit (T.PrimLitBool b)++ F.NameLitNat l+ -> return $ T.NamePrimLit (T.PrimLitNat l)++ F.NameLitInt l+ -> return $ T.NamePrimLit (T.PrimLitInt l)++ F.NameLitWord l k+ -> return $ T.NamePrimLit (T.PrimLitWord l k)++ _ -> throw $ ErrorInvalidBinder nn+++convertTyCon :: TyCon F.Name -> ConvertM (TyCon T.Name)+convertTyCon tc+ = case tc of+ TyConSort s+ -> return $ TyConSort s+ TyConKind k+ -> return $ TyConKind k+ TyConWitness w+ -> return $ TyConWitness w+ TyConSpec s+ -> return $ TyConSpec s+ TyConBound b k+ -> TyConBound <$> convertBound b <*> convertType k+ TyConExists i k+ -> TyConExists i <$> convertType k+++-- | When replacing @Forall b t@ with @t@, if @b@ is a de bruijn+-- index then @t@ must be lowered. @b@ must not be mentioned in @t@.+removeForall :: Bind F.Name -> Type T.Name -> Type T.Name+removeForall b t+ = case b of+ BAnon _+ -> lowerT 1 t+ _+ -> t+++-- | Top region+rTop :: Type T.Name+rTop = TVar $ UName $ T.NameVar "rT"+
DDC/Core/Flow/Env.hs view
@@ -32,52 +32,57 @@ primDataDefs :: DataDefs Name primDataDefs = fromListDataDefs- -- Primitive ------------------------------------------------ $ -- Bool#- [ DataDef (NamePrimTyCon PrimTyConBool) + $ -- Primitive -----------------------------------------------+ -- Bool#+ [ makeDataDefAlg (NamePrimTyCon PrimTyConBool) [] (Just [ (NameLitBool True, []) , (NameLitBool False, []) ]) -- Nat#- , DataDef (NamePrimTyCon PrimTyConNat) [] Nothing+ , makeDataDefAlg (NamePrimTyCon PrimTyConNat) [] Nothing -- Int#- , DataDef (NamePrimTyCon PrimTyConInt) [] Nothing+ , makeDataDefAlg (NamePrimTyCon PrimTyConInt) [] Nothing + -- Float32#+ , makeDataDefAlg (NamePrimTyCon (PrimTyConFloat 32)) [] Nothing++ -- Float64#+ , makeDataDefAlg (NamePrimTyCon (PrimTyConFloat 64)) [] Nothing+ -- WordN#- , DataDef (NamePrimTyCon (PrimTyConWord 64)) [] Nothing- , DataDef (NamePrimTyCon (PrimTyConWord 32)) [] Nothing- , DataDef (NamePrimTyCon (PrimTyConWord 16)) [] Nothing- , DataDef (NamePrimTyCon (PrimTyConWord 8)) [] Nothing+ , makeDataDefAlg (NamePrimTyCon (PrimTyConWord 64)) [] Nothing+ , makeDataDefAlg (NamePrimTyCon (PrimTyConWord 32)) [] Nothing+ , makeDataDefAlg (NamePrimTyCon (PrimTyConWord 16)) [] Nothing+ , makeDataDefAlg (NamePrimTyCon (PrimTyConWord 8)) [] Nothing -- Flow ------------------------------------------------------ -- Vector- , DataDef+ , makeDataDefAbs (NameTyConFlow TyConFlowVector)- [kRate, kData]- (Just [])+ [BAnon kRate, BAnon kData] -- Series- , DataDef+ , makeDataDefAbs (NameTyConFlow TyConFlowSeries)- [kRate, kData]- (Just [])+ [BAnon kRate, BAnon kData] ] -- Tuple -- Hard-code maximum tuple arity to 32.- ++ [ makeTupleDataDef arity | arity <- [2..32] ]+ -- We don't have a way of avoiding the upper bound.+ ++ [ makeTupleDataDef arity+ | arity <- [2..32] ] -- | Make a tuple data def for the given tuple arity. makeTupleDataDef :: Int -> DataDef Name makeTupleDataDef n- = DataDef+ = makeDataDefAlg (NameTyConFlow (TyConFlowTuple n))- (replicate n kData)+ (replicate n (BAnon kData)) (Just [ ( NameDaConFlow (DaConFlowTuple n) , (reverse [tIx kData i | i <- [0..n - 1]]))]) @@ -106,7 +111,7 @@ kindOfPrimName :: Name -> Maybe (Kind Name) kindOfPrimName nn = case nn of- NameKiConFlow KiConFlowRate -> Just sProp+ NameKiConFlow _ -> Just sProp NameTyConFlow tc -> Just $ kindTyConFlow tc NamePrimTyCon tc -> Just $ kindPrimTyCon tc _ -> Nothing@@ -123,18 +128,22 @@ typeOfPrimName :: Name -> Maybe (Type Name) typeOfPrimName dc = case dc of- NameOpFlow p -> Just $ typeOpFlow p- NameOpLoop p -> Just $ typeOpLoop p- NameOpStore p -> Just $ typeOpStore p- NameDaConFlow p -> Just $ typeDaConFlow p+ NameOpConcrete p -> Just $ typeOpConcrete p+ NameOpSeries p -> Just $ typeOpSeries p+ NameOpStore p -> Just $ typeOpStore p+ NameOpControl p -> Just $ typeOpControl p+ NameOpVector p -> Just $ typeOpVector p+ NameDaConFlow p -> Just $ typeDaConFlow p - NamePrimCast p -> Just $ typePrimCast p- NamePrimArith p -> Just $ typePrimArith p+ NamePrimCast p -> Just $ typePrimCast p + NamePrimArith p -> Just $ typePrimArith p+ NamePrimVec p -> Just $ typePrimVec p - NameLitBool _ -> Just $ tBool- NameLitNat _ -> Just $ tNat- NameLitInt _ -> Just $ tInt- NameLitWord _ bits -> Just $ tWord bits+ NameLitBool _ -> Just $ tBool+ NameLitNat _ -> Just $ tNat+ NameLitInt _ -> Just $ tInt+ NameLitWord _ bits -> Just $ tWord bits+ NameLitFloat _ bits -> Just $ tFloat bits _ -> Nothing
DDC/Core/Flow/Exp.hs view
@@ -1,6 +1,6 @@ module DDC.Core.Flow.Exp- ( module DDC.Core.Exp.Simple + ( module DDC.Core.Flow.Exp.Simple.Exp , KindEnvF, TypeEnvF , TypeF , ModuleF@@ -15,8 +15,9 @@ where import DDC.Core.Module import DDC.Core.Flow.Prim-import DDC.Core.Exp.Simple-import DDC.Type.Env (Env)+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Core.Flow.Exp.Simple.Collect ()+import DDC.Type.Env (Env) type KindEnvF = Env Name type TypeEnvF = Env Name@@ -33,3 +34,5 @@ type BoundF = Bound Name type BindF = Bind Name++
+ DDC/Core/Flow/Exp/Simple/Collect.hs view
@@ -0,0 +1,77 @@+-- | Collecting sets of variables and constructors.+module DDC.Core.Flow.Exp.Simple.Collect+ ()+where+import DDC.Core.Collect.BindStruct+import DDC.Core.Collect.FreeX+import DDC.Core.Flow.Exp.Simple.Exp+++-- Exp ------------------------------------------------------------------------+instance BindStruct (Exp a n) n where+ slurpBindTree xx+ = case xx of+ XAnnot _ x+ -> slurpBindTree x+ XVar u+ -> [BindUse BoundExp u]++ XCon dc+ -> case dc of+ DaConBound n -> [BindCon BoundExp (UName n) Nothing]+ _ -> []++ XApp x1 x2 -> slurpBindTree x1 ++ slurpBindTree x2+ XLAM b x -> [bindDefT BindLAM [b] [x]]+ XLam b x -> [bindDefX BindLam [b] [x]] ++ XLet (LLet b x1) x2+ -> slurpBindTree x1+ ++ [bindDefX BindLet [b] [x2]]++ XLet (LRec bxs) x2+ -> [bindDefX BindLetRec + (map fst bxs) + (map snd bxs ++ [x2])]+ + XLet (LPrivate bsR mtExtend bs) x2 + -> (case mtExtend of+ Nothing -> []+ Just tR -> slurpBindTree tR)+ ++ [ BindDef BindLetRegions bsR+ [bindDefX BindLetRegionWith bs [x2]] ]++ XCase x alts -> slurpBindTree x ++ concatMap slurpBindTree alts+ XCast c x -> slurpBindTree c ++ slurpBindTree x+ XType t -> slurpBindTree t+ XWitness w -> slurpBindTree w+++instance BindStruct (Cast a n) n where+ slurpBindTree cc+ = case cc of+ CastWeakenEffect eff -> slurpBindTree eff+ CastPurify w -> slurpBindTree w+ CastBox -> []+ CastRun -> []+++instance BindStruct (Alt a n) n where+ slurpBindTree alt+ = case alt of+ AAlt PDefault x+ -> slurpBindTree x++ AAlt (PData _ bs) x+ -> [bindDefX BindCasePat bs [x]]+++instance BindStruct (Witness a n) n where+ slurpBindTree ww+ = case ww of+ WVar u -> [BindUse BoundWit u]+ WCon{} -> []+ WApp w1 w2 -> slurpBindTree w1 ++ slurpBindTree w2+ WType t -> slurpBindTree t+ WAnnot _ w -> slurpBindTree w+
+ DDC/Core/Flow/Exp/Simple/Compounds.hs view
@@ -0,0 +1,287 @@++-- | Utilities for constructing and destructing compound expressions.+--+-- For the Simple version of the AST.+module DDC.Core.Flow.Exp.Simple.Compounds+ ( module DDC.Type.Exp.Simple.Compounds++ -- * Lambdas+ , xLAMs+ , xLams+ , makeXLamFlags+ , takeXLAMs+ , takeXLams+ , takeXLamFlags++ -- * Applications+ , xApps+ , takeXApps+ , takeXApps1+ , takeXAppsAsList+ , takeXConApps+ , takeXPrimApps++ -- * Lets+ , xLets+ , splitXLets + , bindsOfLets+ , specBindsOfLets+ , valwitBindsOfLets++ -- * Patterns+ , bindsOfPat++ -- * Alternatives+ , takeCtorNameOfAlt++ -- * Witnesses+ , wApp+ , wApps+ , takeXWitness+ , takeWAppsAsList+ , takePrimWiConApps++ -- * Types+ , takeXType++ -- * Data Constructors+ , xUnit, C.dcUnit+ , C.takeNameOfDaCon+ , C.takeTypeOfDaCon)+where+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Type.Exp.Simple.Compounds+import qualified DDC.Core.Exp.Annot as C+++-- Lambdas ---------------------------------------------------------------------+-- | Make some nested type lambdas.+xLAMs :: [Bind n] -> Exp a n -> Exp a n+xLAMs bs x+ = foldr XLAM x bs+++-- | Make some nested value or witness lambdas.+xLams :: [Bind n] -> Exp a n -> Exp a n+xLams bs x+ = foldr XLam x bs+++-- | Split type lambdas from the front of an expression,+-- or `Nothing` if there aren't any.+takeXLAMs :: Exp a n -> Maybe ([Bind n], Exp a n)+takeXLAMs xx+ = let go bs (XLAM b x) = go (b:bs) x+ go bs x = (reverse bs, x)+ in case go [] xx of+ ([], _) -> Nothing+ (bs, body) -> Just (bs, body)+++-- | Split nested value or witness lambdas from the front of an expression,+-- or `Nothing` if there aren't any.+takeXLams :: Exp a n -> Maybe ([Bind n], Exp a n)+takeXLams xx+ = let go bs (XLam b x) = go (b:bs) x+ go bs x = (reverse bs, x)+ in case go [] xx of+ ([], _) -> Nothing+ (bs, body) -> Just (bs, body)+++-- | Make some nested lambda abstractions,+-- using a flag to indicate whether the lambda is a+-- level-1 (True), or level-0 (False) binder.+makeXLamFlags :: [(Bool, Bind n)] -> Exp a n -> Exp a n+makeXLamFlags fbs x+ = foldr (\(f, b) x'+ -> if f then XLAM b x'+ else XLam b x')+ x fbs+++-- | Split nested lambdas from the front of an expression, +-- with a flag indicating whether the lambda was a level-1 (True), +-- or level-0 (False) binder.+takeXLamFlags :: Exp a n -> Maybe ([(Bool, Bind n)], Exp a n)+takeXLamFlags xx+ = let go bs (XLAM b x) = go ((True, b):bs) x+ go bs (XLam b x) = go ((False, b):bs) x+ go bs x = (reverse bs, x)+ in case go [] xx of+ ([], _) -> Nothing+ (bs, body) -> Just (bs, body)+++-- Applications ---------------------------------------------------------------+-- | Build sequence of value applications.+xApps :: Exp a n -> [Exp a n] -> Exp a n+xApps t1 ts = foldl XApp t1 ts+++-- | Flatten an application into the function part and its arguments.+--+-- Returns `Nothing` if there is no outer application.+takeXApps :: Exp a n -> Maybe (Exp a n, [Exp a n])+takeXApps xx+ = case takeXAppsAsList xx of+ (x1 : xsArgs) -> Just (x1, xsArgs)+ _ -> Nothing+++-- | Flatten an application into the function part and its arguments.+--+-- This is like `takeXApps` above, except we know there is at least one argument.+takeXApps1 :: Exp a n -> Exp a n -> (Exp a n, [Exp a n])+takeXApps1 x1 x2+ = case takeXApps x1 of+ Nothing -> (x1, [x2])+ Just (x11, x12s) -> (x11, x12s ++ [x2])+++-- | Flatten an application into the function parts and arguments, if any.+takeXAppsAsList :: Exp a n -> [Exp a n]+takeXAppsAsList xx+ = case xx of+ XApp x1 x2 -> takeXAppsAsList x1 ++ [x2]+ _ -> [xx]+++-- | Flatten an application of a primop into the variable+-- and its arguments.+-- +-- Returns `Nothing` if the expression isn't a primop application.+takeXPrimApps :: Exp a n -> Maybe (n, [Exp a n])+takeXPrimApps xx+ = case takeXAppsAsList xx of+ XVar (UPrim p _) : xs -> Just (p, xs)+ _ -> Nothing++-- | Flatten an application of a data constructor into the constructor+-- and its arguments. +--+-- Returns `Nothing` if the expression isn't a constructor application.+takeXConApps :: Exp a n -> Maybe (DaCon n (Type n), [Exp a n])+takeXConApps xx+ = case takeXAppsAsList xx of+ XCon dc : xs -> Just (dc, xs)+ _ -> Nothing+++-- Lets -----------------------------------------------------------------------+-- | Wrap some let-bindings around an expression.+xLets :: [Lets a n] -> Exp a n -> Exp a n+xLets lts x+ = foldr XLet x lts+++-- | Split let-bindings from the front of an expression, if any.+splitXLets :: Exp a n -> ([Lets a n], Exp a n)+splitXLets xx+ = case xx of+ XLet lts x + -> let (lts', x') = splitXLets x+ in (lts : lts', x')++ _ -> ([], xx)+++-- | Take the binds of a `Lets`.+--+-- The level-1 and level-0 binders are returned separately.+bindsOfLets :: Lets a n -> ([Bind n], [Bind n])+bindsOfLets ll+ = case ll of+ LLet b _ -> ([], [b])+ LRec bxs -> ([], map fst bxs)+ LPrivate bs _ bbs -> (bs, bbs)+++-- | Like `bindsOfLets` but only take the spec (level-1) binders.+specBindsOfLets :: Lets a n -> [Bind n]+specBindsOfLets ll+ = case ll of+ LLet _ _ -> []+ LRec _ -> []+ LPrivate bs _ _ -> bs+++-- | Like `bindsOfLets` but only take the value and witness (level-0) binders.+valwitBindsOfLets :: Lets a n -> [Bind n]+valwitBindsOfLets ll+ = case ll of+ LLet b _ -> [b]+ LRec bxs -> map fst bxs+ LPrivate _ _ bs -> bs+++-- Alternatives ---------------------------------------------------------------+-- | Take the constructor name of an alternative, if there is one.+takeCtorNameOfAlt :: Alt a n -> Maybe n+takeCtorNameOfAlt aa+ = case aa of+ AAlt (PData dc _) _ -> C.takeNameOfDaCon dc+ _ -> Nothing+++-- Patterns -------------------------------------------------------------------+-- | Take the binds of a `Pat`.+bindsOfPat :: Pat n -> [Bind n]+bindsOfPat pp+ = case pp of+ PDefault -> []+ PData _ bs -> bs+++-- Witnesses ------------------------------------------------------------------+-- | Construct a witness application+wApp :: Witness a n -> Witness a n -> Witness a n+wApp = WApp+++-- | Construct a sequence of witness applications+wApps :: Witness a n -> [Witness a n] -> Witness a n+wApps = foldl wApp+++-- | Take the witness from an `XWitness` argument, if any.+takeXWitness :: Exp a n -> Maybe (Witness a n)+takeXWitness xx+ = case xx of+ XWitness t -> Just t+ _ -> Nothing+++-- | Flatten an application into the function parts and arguments, if any.+takeWAppsAsList :: Witness a n -> [Witness a n]+takeWAppsAsList ww+ = case ww of+ WApp w1 w2 -> takeWAppsAsList w1 ++ [w2]+ _ -> [ww]+++-- | Flatten an application of a witness into the witness constructor+-- name and its arguments.+--+-- Returns nothing if there is no witness constructor in head position.+takePrimWiConApps :: Witness a n -> Maybe (n, [Witness a n])+takePrimWiConApps ww+ = case takeWAppsAsList ww of+ WCon wc : args | WiConBound (UPrim n _) _ <- wc+ -> Just (n, args)+ _ -> Nothing+++-- Types ----------------------------------------------------------------------+-- | Take the type from an `XType` argument, if any.+takeXType :: Exp a n -> Maybe (Type n)+takeXType xx+ = case xx of+ XType t -> Just t+ _ -> Nothing+++-- Units -----------------------------------------------------------------------+-- | Construct a value of unit type.+xUnit :: Exp a n+xUnit = XCon C.dcUnit
+ DDC/Core/Flow/Exp/Simple/Exp.hs view
@@ -0,0 +1,196 @@++-- | Core language AST with a separate node to hold annotations.+--+-- This version of the AST is used when generating code where most or all+-- of the annotations would be empty. General purpose transformations should+-- deal with the fully annotated version of the AST instead.+--+module DDC.Core.Flow.Exp.Simple.Exp + ( module DDC.Type.Exp++ -- * Expressions+ , Exp (..)+ , Cast (..)+ , Lets (..)+ , Alt (..)+ , Pat (..)++ -- * Witnesses+ , Witness (..)++ -- * Data Constructors+ , DaCon (..)++ -- * Witness Constructors+ , WiCon (..))+where+import DDC.Core.Exp (WiCon (..))+import DDC.Core.Exp (DaCon (..))+import DDC.Type.Exp+import DDC.Type.Sum ()+import Control.DeepSeq+++-- Values ---------------------------------------------------------------------+-- | Well-typed expressions have types of kind `Data`.+data Exp a n+ -- | Annotation.+ = XAnnot a (Exp a n)++ -- | Value variable or primitive operation.+ | XVar !(Bound n)++ -- | Data constructor or literal.+ | XCon !(DaCon n (Type n))++ -- | Type abstraction (level-1).+ | XLAM !(Bind n) !(Exp a n)++ -- | Value and Witness abstraction (level-0).+ | XLam !(Bind n) !(Exp a n)++ -- | Application.+ | XApp !(Exp a n) !(Exp a n)++ -- | Possibly recursive bindings.+ | XLet !(Lets a n) !(Exp a n)++ -- | Case branching.+ | XCase !(Exp a n) ![Alt a n]++ -- | Type cast.+ | XCast !(Cast a n) !(Exp a n)++ -- | Type can appear as the argument of an application.+ | XType !(Type n)++ -- | Witness can appear as the argument of an application.+ | XWitness !(Witness a n)+ deriving (Show, Eq)+++-- | Possibly recursive bindings.+data Lets a n+ -- | Non-recursive expression binding.+ = LLet !(Bind n) !(Exp a n)++ -- | Recursive binding of lambda abstractions.+ | LRec ![(Bind n, Exp a n)]++ -- | Bind a local region variable,+ -- and witnesses to its properties.+ | LPrivate ![Bind n] !(Maybe (Type n)) ![Bind n]+ deriving (Show, Eq)+++-- | Case alternatives.+data Alt a n+ = AAlt !(Pat n) !(Exp a n)+ deriving (Show, Eq)+++-- | Pattern matching.+data Pat n+ -- | The default pattern always succeeds.+ = PDefault+ + -- | Match a data constructor and bind its arguments.+ | PData !(DaCon n (Type n)) ![Bind n]+ deriving (Show, Eq)+++-- | When a witness exists in the program it guarantees that a+-- certain property of the program is true.+data Witness a n+ = WAnnot a (Witness a n)++ -- | Witness variable.+ | WVar !(Bound n)+ + -- | Witness constructor.+ | WCon !(WiCon n)+ + -- | Witness application.+ | WApp !(Witness a n) !(Witness a n)++ -- | Type can appear as the argument of an application.+ | WType !(Type n)+ deriving (Show, Eq)+++-- | Type casts.+data Cast a n+ -- | Weaken the effect of an expression.+ -- The given effect is added to the effect+ -- of the body.+ = CastWeakenEffect !(Effect n)+ + -- | Purify the effect (action) of an expression.+ | CastPurify !(Witness a n)++ -- | Box up a computation, + -- capturing its effects in the S computation type.+ | CastBox ++ -- | Run a computation,+ -- releasing its effects into the environment.+ | CastRun+ deriving (Show, Eq)+++-- NFData ---------------------------------------------------------------------+instance (NFData a, NFData n) => NFData (Exp a n) where+ rnf xx+ = case xx of+ XAnnot a x -> rnf a `seq` rnf x+ XVar u -> rnf u+ XCon dc -> rnf dc+ XLAM b x -> rnf b `seq` rnf x+ XLam b x -> rnf b `seq` rnf x+ XApp x1 x2 -> rnf x1 `seq` rnf x2+ XLet lts x -> rnf lts `seq` rnf x+ XCase x alts -> rnf x `seq` rnf alts+ XCast c x -> rnf c `seq` rnf x+ XType t -> rnf t+ XWitness w -> rnf w+++instance (NFData a, NFData n) => NFData (Cast a n) where+ rnf cc+ = case cc of+ CastWeakenEffect e -> rnf e+ CastPurify w -> rnf w+ CastBox -> ()+ CastRun -> ()+++instance (NFData a, NFData n) => NFData (Lets a n) where+ rnf lts+ = case lts of+ LLet b x -> rnf b `seq` rnf x+ LRec bxs -> rnf bxs+ LPrivate bs1 t2 bs3 -> rnf bs1 `seq` rnf t2 `seq` rnf bs3+++instance (NFData a, NFData n) => NFData (Alt a n) where+ rnf aa+ = case aa of+ AAlt w x -> rnf w `seq` rnf x+++instance NFData n => NFData (Pat n) where+ rnf pp+ = case pp of+ PDefault -> ()+ PData dc bs -> rnf dc `seq` rnf bs+++instance (NFData a, NFData n) => NFData (Witness a n) where+ rnf ww+ = case ww of+ WAnnot a w -> rnf a `seq` rnf w+ WVar u -> rnf u+ WCon c -> rnf c+ WApp w1 w2 -> rnf w1 `seq` rnf w2+ WType t -> rnf t+
+ DDC/Core/Flow/Lower.hs view
@@ -0,0 +1,367 @@+++module DDC.Core.Flow.Lower+ ( Config (..)+ , defaultConfigScalar+ , defaultConfigKernel+ , defaultConfigVector+ , Method (..)+ , Lifting (..)+ , lowerModule)+where+import DDC.Core.Transform.TransformUpX ()+import DDC.Core.Flow.Transform.Slurp+import DDC.Core.Flow.Transform.Schedule+import DDC.Core.Flow.Transform.Schedule.Base+import DDC.Core.Flow.Transform.Extract+import DDC.Core.Flow.Transform.TransformUpX+import DDC.Core.Flow.Transform.Annotate+import DDC.Core.Flow.Transform.Deannotate+import DDC.Core.Flow.Process+import DDC.Core.Flow.Procedure+import DDC.Core.Flow.Compounds+import DDC.Core.Flow.Profile+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Exp+import DDC.Core.Module+++import qualified DDC.Core.Simplifier as C+import qualified DDC.Core.Simplifier.Recipe as C+import qualified DDC.Core.Transform.Namify as C+import qualified DDC.Core.Transform.Snip as Snip+import qualified DDC.Type.Env as Env+import qualified Control.Monad.State.Strict as S+import qualified Data.Monoid as M+import Control.Monad+++-- | Configuration for the lower transform.+data Config+ = Config+ { configMethod :: Method }+ deriving (Eq, Show)+++-- | What lowering method to use.+data Method+ -- | Produce sequential scalar code with nested loops.+ = MethodScalar++ -- | Produce vector kernel code that only processes an even multiple+ -- of the vector width.+ | MethodKernel+ { methodLifting :: Lifting }++ -- | Try to produce sequential vector code,+ -- falling back to scalar code if this is not possible.+ | MethodVector+ { methodLifting :: Lifting }+ deriving (Eq, Show)+++-- | Config for producing code with just scalar operations.+defaultConfigScalar :: Config+defaultConfigScalar+ = Config+ { configMethod = MethodScalar }+++-- | Config for producing code with vector operations, +-- where the loops just handle a size of data which is an even multiple+-- of the vector width.+defaultConfigKernel :: Config+defaultConfigKernel+ = Config+ { configMethod = MethodKernel (Lifting 8)}+++-- | Config for producing code with vector operations, +-- where the loops handle arbitrary data sizes, of any number of elements.+defaultConfigVector :: Config+defaultConfigVector+ = Config+ { configMethod = MethodVector (Lifting 8)}+++-- Lower ----------------------------------------------------------------------+-- | Take a module that contains some well formed series processes defined+-- at top-level, and lower them into procedures. +lowerModule :: Config -> ModuleF -> Either Error ModuleF+lowerModule config mm+ = case slurpProcesses mm of+ -- Can't slurp a process definition from one of the top level series+ -- processes. + Left err + -> Left (ErrorSlurpError err)++ -- We've got a process definition for all of then.+ Right procs+ -> do + -- Find names of all process bindings+ let procname (Left p) = [processName p]+ procname (Right _) = []++ procnames = concatMap procname procs++ -- Schedule the processeses into procedures.+ lets <- mapM (lowerEither config procnames) procs++ -- Wrap all the procedures into a new module.+ let mm_lowered = mm+ { moduleBody = annotate ()+ $ XLet (LRec lets) xUnit }++ -- Clean up extracted code+ let mm_clean = cleanModule mm_lowered+ return mm_clean+++-- | Look at slurped result, and if it's a process lower it, otherwise remove any runProcess# inside expressions+lowerEither :: Config -> [Name] -> (Either Process (Bind Name, Exp () Name)) -> Either Error (BindF, ExpF)+lowerEither config _ (Left process)+ = lowerProcess config process++lowerEither _config _procnames (Right (b,xx))+ = let xx' = deannotate (const Nothing)+ $ transformSimpleUpX' replaceRunProc+ $ annotate () xx+ in return (b, xx')+ where++ -- Replace all calls to runProcess# with runProcessUnit#+ replaceRunProc (XVar (UPrim (NameOpSeries OpSeriesRunProcess) _))+ = Just+ $ XVar+ $ UPrim (NameOpSeries OpSeriesRunProcessUnit)+ (typeOpSeries OpSeriesRunProcessUnit)+ -- Also replace any Process# types with Units+ replaceRunProc (XType t)+ = Just+ $ XType (replaceProcTy t)+ replaceRunProc (XLet (LLet bind x) e)+ = Just+ $ XLet (LLet (replaceProcTyB bind) x) e+ replaceRunProc (XLet (LRec bxs) e)+ | (bs,xs) <- unzip bxs+ , bs' <- map replaceProcTyB bs+ = Just+ $ XLet (LRec (zip bs' xs)) e++ replaceRunProc _+ = Nothing++ replaceProcTyB (BName n t) = BName n $ replaceProcTy t+ replaceProcTyB (BAnon t) = BAnon $ replaceProcTy t+ replaceProcTyB (BNone t) = BNone $ replaceProcTy t++ -- Replace Process# a b with Unit+ replaceProcTy tt+ = case tt of+ TVar{} -> tt+ TCon{} -> tt++ TAbs bind tt'+ -> TAbs bind (replaceProcTy tt')++ TApp l r+ | Just (NameTyConFlow TyConFlowProcess, [_,_]) <- takePrimTyConApps tt+ -> tUnit+ | otherwise+ -> TApp (replaceProcTy l) (replaceProcTy r)++ TForall bind tt'+ -> TForall bind (replaceProcTy tt')++ TSum ts+ -> TSum ts+ ++-- | Lower a single series process into fused code.+lowerProcess :: Config -> Process -> Either Error (BindF, ExpF)+lowerProcess config process+ + -- Scalar lowering ------------------------------+ | MethodScalar <- configMethod config+ = do + -- Schedule process into scalar code.+ proc <- scheduleScalar process++ -- Extract code for the kernel+ let (bProc, xProc) = extractProcedure proc++ return (bProc, xProc)+++ -- Vector lowering -----------------------------+ -- To use the vector method, + -- the type of the source function needs to have a quantifier for+ -- the rate variable (k), as well as a (RateNat k) witness.+ --+ | MethodVector lifting <- configMethod config+ , [nRN] <- [ nRN | (flag, BName nRN tRN) <- processParamFlags process+ , not flag+ , isRateNatType tRN ]+ , tK <- processLoopRate process+ = do let c = liftingFactor lifting++ -- The RateNat witness+ let xRN = XVar (UName nRN)++ let tProc = processProcType process+ let _tLoopRate = processLoopRate process++ -----------------------------------------+ -- Create the vector version of the kernel.+ -- Vector code processes several elements per loop iteration.+ procVec <- scheduleKernel lifting process+ let (_, xProcVec) = extractProcedure procVec+ + + let bxsDownSeries + = [ ( bS+ , ( BName (NameVarMod n "down")+ (tSeries tProc (tDown c tK) tE)+ , xDown c tProc tK tE (XVar (UIx 0)) xS))+ | (flag, bS@(BName n tS)) <- processParamFlags process+ , not flag+ , let Just tE = elemTypeOfSeriesType tS+ , let Just uS = takeSubstBoundOfBind bS+ , let xS = XVar uS+ , isSeriesType tS ]++ -- Get a value arg to give to the vector procedure.+ let getDownValArg b+ | Just (b', _) <- lookup b bxsDownSeries+ = liftM XVar $ takeSubstBoundOfBind b'++ | otherwise+ = liftM XVar $ takeSubstBoundOfBind b++ let Just xsVecValArgs + = sequence + $ map getDownValArg + $ map snd+ $ filter (not.fst)+ $ processParamFlags process++ let bRateDown+ = BAnon (tRateNat (tDown c tK))++ let xProcVec' + = XLam bRateDown+ $ xLets [LLet b x | (_, (b, x)) <- bxsDownSeries]+ $ xApps xProcVec+ $ [XType tProc, XType tK] ++ xsVecValArgs+++ -----------------------------------------+ -- Create tail version.+ -- Scalar code processes the final elements of the loop.+ procTail <- scheduleScalar process+ let (bProcTail, xProcTail) = extractProcedure procTail++ -- Window the input series to select the tails.+ let bxsTailSeries+ = [ ( bS, ( BName (NameVarMod n "tail") (tSeries tProc (tTail c tK) tE)+ , xTail c tProc tK tE (XVar (UIx 0)) xS))+ | (flag, bS@(BName n tS)) <- processParamFlags process+ , not flag+ , let Just tE = elemTypeOfSeriesType tS+ , let Just uS = takeSubstBoundOfBind bS+ , let xS = XVar uS+ , isSeriesType tS ]++ -- Window the output vectors to select the tails.+ let bxsTailVector+ = [ ( bV, ( BName (NameVarMod n "tail") (tVector tE)+ , xTailVector c tK tE (XVar (UIx 0)) xV))+ | (flag, bV@(BName n tV)) <- processParamFlags process+ , not flag+ , let Just tE = elemTypeOfVectorType tV+ , let Just uV = takeSubstBoundOfBind bV+ , let xV = XVar uV+ , isVectorType tV ]++ -- Get a value arg to give to the scalar procedure.+ let getTailValArg b+ | Just (b', _) <- lookup b bxsTailSeries+ = liftM XVar $ takeSubstBoundOfBind b'++ | Just (b', _) <- lookup b bxsTailVector+ = liftM XVar $ takeSubstBoundOfBind b'++ | otherwise+ = liftM XVar $ takeSubstBoundOfBind b++ let Just xsTailValArgs+ = sequence + $ map getTailValArg (map snd $ filter (not.fst) $ procedureParamFlags procTail)++ let bRateTail+ = BAnon (tRateNat (tTail c tK))++ let xProcTail'+ = XLam bRateTail+ $ xLets [LLet b x | (_, (b, x)) <- bxsTailSeries]+ $ xLets [LLet b x | (_, (b, x)) <- bxsTailVector]+ $ xApps xProcTail+ $ [XType tProc, XType (tTail c tK)] ++ xsTailValArgs++ ------------------------------------------+ -- Stich the vector and scalar versions together.+ let xProc+ = makeXLamFlags (processParamFlags process)+ xBody++ xBody+ = XLet (LLet (BNone tUnit) + (xSplit c tK xRN xProcVec' xProcTail'))+ xUnit+ + -- Reconstruct a binder for the whole procedure / process.+ let bProc+ = BName (processName process)+ (typeOfBind bProcTail)++ return (bProc, xProc)++ -- Kernel lowering -----------------------------+ | MethodKernel lifting <- configMethod config+ = do+ -- Schedule process into + proc <- scheduleKernel lifting process++ -- Extract code for the kernel+ let (bProc, xProc) = extractProcedure proc++ return (bProc, xProc)++ | otherwise+ = error $ "ddc-core-flow.lowerProcess: invalid lowering method"+ +++-- Clean ----------------------------------------------------------------------+-- | Do some beta-reductions to ensure that arguments to worker functions+-- are inlined, then normalize nested applications. +-- When snipping, leave lambda abstractions in place so the worker functions+-- applied to our loop combinators aren't moved.+cleanModule :: ModuleF -> ModuleF+cleanModule mm+ = let+ clean + = C.Trans (C.Namify (C.makeNamifier freshT)+ (C.makeNamifier freshX))+ M.<> C.Trans C.Forward+ M.<> C.beta+ M.<> C.Trans (C.Snip (Snip.configZero { Snip.configPreserveLambdas = True }))+ M.<> C.Trans C.Flatten++ mm_cleaned + = C.result $ S.evalState+ (C.applySimplifier profile Env.empty Env.empty+ (C.Fix 4 clean) mm)+ 0+ in mm_cleaned+
DDC/Core/Flow/Prim.hs view
@@ -18,21 +18,31 @@ , readDaConFlow , typeDaConFlow - -- * Flow operators- , OpFlow (..)- , readOpFlow- , typeOpFlow+ -- * Fusable Flow operators+ , OpConcrete (..)+ , readOpConcrete+ , typeOpConcrete - -- * Loop operators- , OpLoop (..)- , readOpLoop- , typeOpLoop+ -- * Series operators+ , OpSeries (..)+ , readOpSeries+ , typeOpSeries + -- * Control operators+ , OpControl (..)+ , readOpControl+ , typeOpControl+ -- * Store operators , OpStore (..) , readOpStore , typeOpStore + -- * Store operators+ , OpVector (..)+ , readOpVector+ , typeOpVector+ -- * Primitive type constructors , PrimTyCon (..) , kindPrimTyCon@@ -41,6 +51,13 @@ , PrimArith (..) , typePrimArith + -- * Primitive vector operators+ , PrimVec (..)+ , typePrimVec+ , multiOfPrimVec+ , liftPrimArithToVec+ , lowerPrimVecToArith+ -- * Casting between primitive types , PrimCast (..) , typePrimCast)@@ -51,20 +68,34 @@ import DDC.Core.Flow.Prim.TyConPrim import DDC.Core.Flow.Prim.DaConFlow import DDC.Core.Flow.Prim.DaConPrim ()-import DDC.Core.Flow.Prim.OpFlow-import DDC.Core.Flow.Prim.OpLoop+import DDC.Core.Flow.Prim.OpConcrete+import DDC.Core.Flow.Prim.OpControl+import DDC.Core.Flow.Prim.OpSeries import DDC.Core.Flow.Prim.OpStore+import DDC.Core.Flow.Prim.OpVector import DDC.Core.Flow.Prim.OpPrim -import DDC.Core.Salt.Name +import DDC.Core.Lexer.Tokens (isVarStart)++import DDC.Core.Salt.Name ( readPrimTyCon- , readPrimCast+ , readPrimArith- , readLitPrimNat- , readLitPrimInt- , readLitPrimWordOfBits)--import DDC.Base.Pretty+ + , readPrimVec+ , multiOfPrimVec+ , liftPrimArithToVec+ , lowerPrimVecToArith+ + , readPrimCast+ , readLitNat+ , readLitInt+ , readLitWordOfBits+ , readLitFloatOfBits)+ +import DDC.Data.Name+import DDC.Data.Pretty+import DDC.Data.ListUtils import Control.DeepSeq import Data.Char @@ -79,18 +110,22 @@ NameKiConFlow con -> rnf con NameTyConFlow con -> rnf con NameDaConFlow con -> rnf con- NameOpFlow op -> rnf op- NameOpLoop op -> rnf op+ NameOpConcrete op -> rnf op+ NameOpControl op -> rnf op+ NameOpSeries op -> rnf op NameOpStore op -> rnf op+ NameOpVector op -> rnf op - NamePrimTyCon con -> rnf con- NamePrimArith con -> rnf con- NamePrimCast c -> rnf c+ NamePrimTyCon op -> rnf op+ NamePrimArith op -> rnf op+ NamePrimVec op -> rnf op+ NamePrimCast op -> rnf op NameLitBool b -> rnf b NameLitNat n -> rnf n NameLitInt i -> rnf i NameLitWord i bits -> rnf i `seq` rnf bits+ NameLitFloat r bits -> rnf r `seq` rnf bits instance Pretty Name where@@ -103,63 +138,89 @@ NameKiConFlow con -> ppr con NameTyConFlow con -> ppr con NameDaConFlow con -> ppr con- NameOpFlow op -> ppr op- NameOpLoop op -> ppr op+ NameOpConcrete op -> ppr op+ NameOpControl op -> ppr op+ NameOpSeries op -> ppr op NameOpStore op -> ppr op+ NameOpVector op -> ppr op NamePrimTyCon tc -> ppr tc NamePrimArith op -> ppr op+ NamePrimVec op -> ppr op NamePrimCast op -> ppr op NameLitBool True -> text "True#" NameLitBool False -> text "False#"- NameLitNat i -> integer i <> text "#"- NameLitInt i -> integer i <> text "i" <> text "#"- NameLitWord i bits -> integer i <> text "w" <> int bits <> text "#"+ NameLitNat i -> integer i <> text "#"+ NameLitInt i -> integer i <> text "i" <> text "#"+ NameLitWord i bits -> integer i <> text "w" <> int bits <> text "#"+ NameLitFloat r bits -> double (fromRational r) <> text "f" <> int bits <> text "#" +instance CompoundName Name where+ extendName n str + = NameVarMod n str+ + splitName nn+ = case nn of+ NameVarMod n str -> Just (n, str)+ _ -> Nothing++ -- | Read the name of a variable, constructor or literal. readName :: String -> Maybe Name readName str -- Flow fragment specific names.- | Just p <- readKiConFlow str = Just $ NameKiConFlow p- | Just p <- readTyConFlow str = Just $ NameTyConFlow p- | Just p <- readDaConFlow str = Just $ NameDaConFlow p- | Just p <- readOpFlow str = Just $ NameOpFlow p- | Just p <- readOpLoop str = Just $ NameOpLoop p- | Just p <- readOpStore str = Just $ NameOpStore p+ | Just p <- readKiConFlow str = Just $ NameKiConFlow p+ | Just p <- readTyConFlow str = Just $ NameTyConFlow p+ | Just p <- readDaConFlow str = Just $ NameDaConFlow p+ | Just p <- readOpConcrete str = Just $ NameOpConcrete p+ | Just p <- readOpControl str = Just $ NameOpControl p+ | Just p <- readOpSeries str = Just $ NameOpSeries p + | Just p <- readOpStore str = Just $ NameOpStore p+ | Just p <- readOpVector str = Just $ NameOpVector p -- Primitive names.- | Just p <- readPrimTyCon str = Just $ NamePrimTyCon p- | Just p <- readPrimArith str = Just $ NamePrimArith p- | Just p <- readPrimCast str = Just $ NamePrimCast p+ | Just p <- readPrimTyCon str = Just $ NamePrimTyCon p+ | Just p <- readPrimArith str = Just $ NamePrimArith p+ | Just p <- readPrimVec str = Just $ NamePrimVec p+ | Just p <- readPrimCast str = Just $ NamePrimCast p -- Literal Bools | str == "True#" = Just $ NameLitBool True | str == "False#" = Just $ NameLitBool False -- Literal Nat- | Just val <- readLitPrimNat str+ | Just str' <- stripSuffix "#" str+ , Just val <- readLitNat str' = Just $ NameLitNat val -- Literal Ints- | Just val <- readLitPrimInt str+ | Just str' <- stripSuffix "#" str+ , Just val <- readLitInt str' = Just $ NameLitInt val -- Literal Words- | Just (val, bits) <- readLitPrimWordOfBits str+ | Just str' <- stripSuffix "#" str+ , Just (val, bits) <- readLitWordOfBits str' , elem bits [8, 16, 32, 64] = Just $ NameLitWord val bits + -- Literal Floats+ | Just str' <- stripSuffix "#" str+ , Just (val, bits) <- readLitFloatOfBits str'+ , elem bits [32, 64]+ = Just $ NameLitFloat (toRational val) bits+ -- Variables. | c : _ <- str- , isLower c+ , isVarStart c , Just (str1, strMod) <- splitModString str , Just n <- readName str1 = Just $ NameVarMod n strMod | c : _ <- str- , isLower c + , isVarStart c = Just $ NameVar str -- Constructors.
DDC/Core/Flow/Prim/Base.hs view
@@ -4,17 +4,21 @@ , KiConFlow (..) , TyConFlow (..) , DaConFlow (..)- , OpFlow (..)- , OpLoop (..)+ , OpConcrete (..)+ , OpControl (..)+ , OpSeries (..) , OpStore (..)+ , OpVector (..) , PrimTyCon (..) , PrimArith (..)+ , PrimVec (..) , PrimCast (..)) where import Data.Typeable-import DDC.Core.Salt.Name +import DDC.Core.Salt.Name ( PrimTyCon (..) , PrimArith (..)+ , PrimVec (..) , PrimCast (..)) @@ -39,16 +43,22 @@ -- | Fragment specific data constructors. | NameDaConFlow DaConFlow - -- | Flow operators.- | NameOpFlow OpFlow+ -- | Concrete series operators.+ | NameOpConcrete OpConcrete - -- | Loop operators.- | NameOpLoop OpLoop+ -- | Control operators.+ | NameOpControl OpControl + -- | Series operators.+ | NameOpSeries OpSeries+ -- | Store operators. | NameOpStore OpStore + -- | Vector operators.+ | NameOpVector OpVector + -- Machine primitives ------------------ -- | A primitive type constructor. | NamePrimTyCon PrimTyCon@@ -59,7 +69,10 @@ -- | Primitive casting between numeric types. | NamePrimCast PrimCast + -- | Primitive vector operators.+ | NamePrimVec PrimVec + -- Literals ----------------------------- -- | A boolean literal. | NameLitBool Bool@@ -70,14 +83,18 @@ -- | An integer literal. | NameLitInt Integer - -- | A word literal.- | NameLitWord Integer Int+ -- | A word literal, with the given number of bits precision.+ | NameLitWord Integer Int++ -- | A float literal, with the given number of bits precision.+ | NameLitFloat Rational Int deriving (Eq, Ord, Show, Typeable) -- | Fragment specific kind constructors. data KiConFlow = KiConFlowRate+ | KiConFlowProc deriving (Eq, Ord, Show) @@ -86,9 +103,15 @@ -- | @TupleN#@ constructor. Tuples. = TyConFlowTuple Int - -- | @Vector#@ constructor. Vectors. + -- | @Vector#@ constructor. Vector is a pair of mutable length and mutable data | TyConFlowVector + -- | @Buffer#@ constructor. Mutable Buffer with no associated length+ | TyConFlowBuffer++ -- | @RateVec#@ constructor. Vector is a pair of mutable length and mutable data+ | TyConFlowRateVec+ -- | @Series#@ constructor. Series types. | TyConFlowSeries @@ -98,14 +121,31 @@ -- | @SelN#@ constructor. Selectors. | TyConFlowSel Int - -- | @Ref#@ constructor. References.+ -- | @Ref#@ constructor. References. | TyConFlowRef - -- | @World#@ constructor. State token used when converting to GHC core.+ -- | @World#@ constructor. State token used when converting to GHC core. | TyConFlowWorld -- | @RateNat#@ constructor. Naturals witnessing a type-level Rate. | TyConFlowRateNat++ -- | Multiply two @Rate@s together+ | TyConFlowRateCross+ -- | Add two @Rate@s together+ | TyConFlowRateAppend++ -- | @DownN#@ constructor. Rate decimation. + | TyConFlowDown Int++ -- | @TailN#@ constructor. Rate tail after decimation.+ | TyConFlowTail Int++ -- | @Process@ constructor.+ | TyConFlowProcess++ -- | @Resize p j k@ is a witness that @Process p j@ can be resized to @Process p k@+ | TyConFlowResize deriving (Eq, Ord, Show) @@ -116,49 +156,140 @@ deriving (Eq, Ord, Show) --- | Flow operators.-data OpFlow- -- series conversions.- = OpFlowVectorOfSeries- | OpFlowRateOfSeries- | OpFlowNatOfRateNat+-- | Fusable Flow operators that work on Series.+data OpSeries+ -- | Replicate a single element into a series.+ = OpSeriesRep - -- selectors- | OpFlowMkSel Int+ -- | Segmented replicate.+ | OpSeriesReps - -- maps- | OpFlowMap Int+ -- | Segmented indices+ | OpSeriesIndices - -- replicates- | OpFlowRep- | OpFlowReps+ -- | Fill an existing vector from a series.+ | OpSeriesFill - -- folds- | OpFlowFold- | OpFlowFoldIndex- | OpFlowFolds+ -- | Gather (read) elements from a vector.+ | OpSeriesGather - -- unfolds- | OpFlowUnfold- | OpFlowUnfolds+ -- | Scatter (write) elements into a vector.+ | OpSeriesScatter - -- split/combine- | OpFlowSplit Int- | OpFlowCombine Int+ -- | Make a selector.+ | OpSeriesMkSel Int - -- packing- | OpFlowPack+ -- | Make a segment descriptor.+ | OpSeriesMkSegd++ -- | Apply a worker to corresponding elements of some series.+ | OpSeriesMap Int++ -- | Pack a series according to a flags vector.+ | OpSeriesPack++ -- | Generate a new series with size based on klok/rate+ | OpSeriesGenerate++ -- | Reduce a series with an associative operator,+ -- updating an existing accumulator.+ | OpSeriesReduce++ -- | Segmented fold.+ | OpSeriesFolds++ -- | Execute a process+ | OpSeriesRunProcess++ -- | Introduce a Proc type, but argument returns unit instead of process+ -- Has exact same type as RunProcess except for that,+ -- so that they can easily be swapped during lowering+ | OpSeriesRunProcessUnit++ -- | Convert vector(s) into manifests, all with same length with runtime check.+ | OpSeriesRateVecsOfVectors Int++ -- | Convert manifest into series+ | OpSeriesSeriesOfRateVec++ -- | Append two series+ | OpSeriesAppend++ -- | Cross a series and a vector+ | OpSeriesCross+++ -- | Resize a process+ | OpSeriesResizeProc++ -- | Resize a process+ | OpSeriesResizeId++ -- | Inject a series into the left side of an append+ | OpSeriesResizeAppL+ -- | Inject a series into the right side of an append+ | OpSeriesResizeAppR++ -- | Map over the contents of an append+ | OpSeriesResizeApp++ -- | Move from filtered to filtee+ | OpSeriesResizeSel1+ -- | Move from segment data to segment lens+ | OpSeriesResizeSegd+ -- | Move from (cross a b) to a+ | OpSeriesResizeCross+++ -- | Join two series processes.+ | OpSeriesJoin deriving (Eq, Ord, Show) --- | Loop operators.-data OpLoop- = OpLoopLoop- | OpLoopLoopN- | OpLoopGuard+-- | Series related operators.+-- These operators work on series after the code has been fused.+-- They do not appear in the source program.+data OpConcrete+ -- | Project out a component of a tuple,+ -- given the tuple arity and index of the desired component.+ = OpConcreteProj Int Int++ -- | Take the rate of a series.+ | OpConcreteRateOfSeries++ -- | Take the underlying @Nat@ of a @RateNat@.+ | OpConcreteNatOfRateNat++ -- | Take some elements from a series.+ | OpConcreteNext Int++ -- | Decimate the rate of a series.+ | OpConcreteDown Int++ -- | Take the tail rate of a decimated series.+ | OpConcreteTail Int deriving (Eq, Ord, Show) +-- | Control operators.+data OpControl+ -- Top level loop, indexed by a rate type.+ = OpControlLoop++ -- Top level loop, taking a RateNat.+ | OpControlLoopN++ -- Evaluate some function when a flag is true.+ | OpControlGuard++ -- Evaluate some function a given number of times.+ | OpControlSegment++ -- Used for producing SIMD code.+ | OpControlSplit Int+ deriving (Eq, Ord, Show)++ -- | Store operators. data OpStore -- Assignables ----------------@@ -171,7 +302,6 @@ -- | Write to a reference. | OpStoreWrite - -- Vectors -------------------- -- | Allocate a new vector (taking a @Nat@ for the length) | OpStoreNewVector@@ -182,18 +312,47 @@ -- | Allocate a new vector (taking a @RateNat@ for the length) | OpStoreNewVectorN - -- | Read from a vector.- | OpStoreReadVector + -- | Read a packed Vec of values from a Vector buffer.+ | OpStoreReadVector Int - -- | Write to a vector.- | OpStoreWriteVector+ -- | Write a packed Vec of values to a Vector buffer.+ | OpStoreWriteVector Int - -- | Slice after a pack/filter (taking a @Nat@ for new length)- | OpStoreSliceVector + -- | Window a target vector to the tail of some rate.+ | OpStoreTailVector Int + -- | Truncate a vector to a smaller length.+ | OpStoreTruncVector - -- Streams --------------------- -- | Take the next element from a series.- | OpStoreNext+ -- | Get a vector's data buffer+ | OpStoreBufOfVector++ -- | Get a vector's data buffer+ | OpStoreBufOfRateVec+ deriving (Eq, Ord, Show)+++-- | Fusable flow operators that work on Vectors.+data OpVector+ -- | Apply worker function to @n@ vectors zipped.+ = OpVectorMap Int++ -- | Filter a vector according to a predicate.+ | OpVectorFilter++ -- | Associative fold.+ | OpVectorReduce++ -- | Create a new vector from an index function.+ | OpVectorGenerate++ -- | Get a vector's length.+ | OpVectorLength++ -- | Gather (read) elements from a vector:+ --+ -- > gather v ix = map (v!) ix+ --+ | OpVectorGather deriving (Eq, Ord, Show)
DDC/Core/Flow/Prim/DaConFlow.hs view
@@ -5,15 +5,17 @@ where import DDC.Core.Flow.Prim.TyConFlow import DDC.Core.Flow.Prim.Base-import DDC.Core.Exp.Simple-import DDC.Core.Compounds.Simple-import DDC.Base.Pretty+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Data.Pretty import Data.List import Data.Char import Control.DeepSeq -instance NFData DaConFlow+instance NFData DaConFlow where+ rnf !_ = ()+ instance Pretty DaConFlow where ppr dc
DDC/Core/Flow/Prim/DaConPrim.hs view
@@ -9,18 +9,18 @@ import DDC.Core.Flow.Prim.TyConPrim import DDC.Core.Flow.Prim.DaConFlow import DDC.Core.Flow.Prim.Base-import DDC.Core.Compounds.Simple-import DDC.Core.Exp.Simple+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp -- | A literal @Bool#@ xBool :: Bool -> Exp a Name-xBool b = XCon (mkDaConAlg (NameLitBool b) tBool)+xBool b = XCon (dcBool b) -- | A literal @Bool#@ data constructor.-dcBool :: Bool -> DaCon Name-dcBool b = mkDaConAlg (NameLitBool b) tBool+dcBool :: Bool -> DaCon Name (Type Name)+dcBool b = DaConPrim (NameLitBool b) tBool -- | A literal @Nat#@@@ -29,14 +29,14 @@ -- | A Literal @Nat#@ data constructor.-dcNat :: Integer -> DaCon Name-dcNat i = mkDaConAlg (NameLitInt i) tNat+dcNat :: Integer -> DaCon Name (Type Name)+dcNat i = DaConPrim (NameLitNat i) tNat -- | Data constructor for @Tuple1#@-dcTuple1 :: DaCon Name-dcTuple1 = mkDaConAlg (NameDaConFlow (DaConFlowTuple 1))- $ typeDaConFlow (DaConFlowTuple 1)+dcTuple1 :: DaCon Name (Type Name)+dcTuple1 = DaConPrim (NameDaConFlow (DaConFlowTuple 1))+ (typeDaConFlow (DaConFlowTuple 1)) -- | Construct a @Tuple2#@@@ -50,14 +50,14 @@ -- | Data constructor for @Tuple2#@-dcTuple2 :: DaCon Name-dcTuple2 = mkDaConAlg (NameDaConFlow (DaConFlowTuple 2))- $ typeDaConFlow (DaConFlowTuple 2)+dcTuple2 :: DaCon Name (Type Name)+dcTuple2 = DaConPrim (NameDaConFlow (DaConFlowTuple 2))+ (typeDaConFlow (DaConFlowTuple 2)) -- | Data constructor for n-tuples-dcTupleN :: Int -> DaCon Name+dcTupleN :: Int -> DaCon Name (Type Name) dcTupleN n- = mkDaConAlg (NameDaConFlow (DaConFlowTuple n))- $ typeDaConFlow (DaConFlowTuple n)+ = DaConPrim (NameDaConFlow (DaConFlowTuple n))+ (typeDaConFlow (DaConFlowTuple n))
DDC/Core/Flow/Prim/KiConFlow.hs view
@@ -1,22 +1,25 @@ module DDC.Core.Flow.Prim.KiConFlow ( readKiConFlow- , kRate)+ , kRate+ , kProc ) where import DDC.Core.Flow.Prim.Base-import DDC.Core.Compounds-import DDC.Core.Exp.Simple-import DDC.Base.Pretty+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Type.Exp.Simple.Compounds+import DDC.Data.Pretty import Control.DeepSeq -instance NFData KiConFlow+instance NFData KiConFlow where+ rnf !_ = () instance Pretty KiConFlow where ppr con = case con of KiConFlowRate -> text "Rate"+ KiConFlowProc -> text "Proc" -- | Read a kind constructor name.@@ -24,8 +27,11 @@ readKiConFlow str = case str of "Rate" -> Just $ KiConFlowRate+ "Proc" -> Just $ KiConFlowProc _ -> Nothing -- Compounds ------------------------------------------------------------------ kRate = TCon (TyConBound (UPrim (NameKiConFlow KiConFlowRate) sProp) sProp)++kProc = TCon (TyConBound (UPrim (NameKiConFlow KiConFlowProc) sProp) sProp)
+ DDC/Core/Flow/Prim/OpConcrete.hs view
@@ -0,0 +1,194 @@++module DDC.Core.Flow.Prim.OpConcrete+ ( readOpConcrete+ , typeOpConcrete++ -- * Compounds+ , xProj+ , xRateOfSeries+ , xNatOfRateNat+ , xNext+ , xNextC++ , xDown+ , xTail )+where+import DDC.Core.Flow.Prim.KiConFlow+import DDC.Core.Flow.Prim.TyConFlow+import DDC.Core.Flow.Prim.TyConPrim+import DDC.Core.Flow.Prim.Base+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Data.Pretty+import Control.DeepSeq+import Data.List+import Data.Char+++instance NFData OpConcrete where+ rnf !_ = ()+++instance Pretty OpConcrete where+ ppr pf+ = case pf of+ OpConcreteProj arity ix -> text "proj" + <> int arity <> text "_" <> int ix+ <> text "#"++ OpConcreteRateOfSeries -> text "rateOfSeries" <> text "#"+ OpConcreteNatOfRateNat -> text "natOfRateNat" <> text "#"++ OpConcreteNext 1 -> text "next#"+ OpConcreteNext n -> text "next$" <> int n <> text "#"++ OpConcreteDown n -> text "down$" <> int n <> text "#"+ OpConcreteTail n -> text "tail$" <> int n <> text "#"+++-- | Read a series operator name.+readOpConcrete :: String -> Maybe OpConcrete+readOpConcrete str+ | Just rest <- stripPrefix "proj" str+ , (ds, '_' : rest2) <- span isDigit rest+ , not $ null ds+ , arity <- read ds+ , arity >= 1+ , (ds2, "#") <- span isDigit rest2+ , not $ null ds2+ , ix <- read ds2+ , ix >= 1+ , ix <= arity+ = Just $ OpConcreteProj arity ix+++ | Just rest <- stripPrefix "next$" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , n <- read ds+ , n >= 1+ = Just $ OpConcreteNext n++ | Just rest <- stripPrefix "down$" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , n <- read ds+ , n >= 1+ = Just $ OpConcreteDown n++ | Just rest <- stripPrefix "tail$" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , n <- read ds+ , n >= 1+ = Just $ OpConcreteTail n++ | otherwise+ = case str of+ "rateOfSeries#" -> Just $ OpConcreteRateOfSeries+ "natOfRateNat#" -> Just $ OpConcreteNatOfRateNat+ "next#" -> Just $ OpConcreteNext 1+ _ -> Nothing+++-- | Yield the type of a series operator.+typeOpConcrete :: OpConcrete -> Type Name+typeOpConcrete op+ = case op of+ -- Tuple projections --------------------+ OpConcreteProj a ix+ -> tForalls (replicate a kData) + $ \_ -> tFun (tTupleN [TVar (UIx i) | i <- reverse [0..a-1]])+ (TVar (UIx (a - ix)))+++ -- rateOfSeries# :: [p : Proc]. [k : Rate]. [a : Data]+ -- . Series p k a -> RateNat k+ OpConcreteRateOfSeries + -> tForalls [kProc, kRate, kData] $ \[tP, tKR, tA]+ -> tSeries tP tKR tA `tFun` tRateNat tKR++ -- natOfRateNat# :: [k : Rate]. RateNat k -> Nat#+ OpConcreteNatOfRateNat + -> tForall kRate $ \tK + -> tRateNat tK `tFun` tNat++ -- next# :: [a : Data]. [k : Rate]. Series# k a -> Nat# -> a+ OpConcreteNext 1+ -> tForalls [kData, kProc, kRate]+ $ \[tA, tP, tK] -> tSeries tP tK tA `tFun` tNat `tFun` tA++ -- next$N# :: [a : Data]. [k : Rate]+ -- . Series# (DownN# k) a -> Nat# -> VecN# a+ OpConcreteNext n+ -> tForalls [kData, kProc, kRate]+ $ \[tA, tP, tK] -> tSeries tP (tDown n tK) tA `tFun` tNat `tFun` tVec n tA++ -- down$N# :: [k : Rate]. [a : Data].+ -- . RateNat (DownN# k) -> Series# k a -> Series# (DownN# k) a+ OpConcreteDown n+ -> tForalls [kProc, kRate, kData]+ $ \[tP, tK, tA] -> tRateNat (tDown n tK) + `tFun` tSeries tP tK tA `tFun` tSeries tP (tDown n tK) tA++ -- tail$N# :: [k : Rate]. [a : Data].+ -- . RateNat (TailN# k) -> Series# k a -> Series# (TailN# k) a+ OpConcreteTail n+ -> tForalls [kProc, kRate, kData]+ $ \[tP, tK, tA] -> tRateNat (tTail n tK)+ `tFun` tSeries tP tK tA `tFun` tSeries tP (tTail n tK) tA++++-- Compounds ------------------------------------------------------------------+type TypeF = Type Name+type ExpF = Exp () Name++xProj :: [Type Name] -> Int -> Exp () Name -> Exp () Name+xProj ts ix x+ = xApps (xVarOpConcrete (OpConcreteProj (length ts) ix))+ ([XType t | t <- ts] ++ [x])+++xRateOfSeries :: TypeF -> TypeF -> TypeF -> ExpF -> ExpF+xRateOfSeries tP tK tA xS + = xApps (xVarOpConcrete OpConcreteRateOfSeries) + [XType tP, XType tK, XType tA, xS]+++xNatOfRateNat :: TypeF -> ExpF -> ExpF+xNatOfRateNat tK xR+ = xApps (xVarOpConcrete OpConcreteNatOfRateNat)+ [XType tK, xR]+++xNext :: TypeF -> TypeF -> TypeF -> ExpF -> ExpF -> ExpF+xNext tProc tRate tElem xStream xIndex+ = xApps (xVarOpConcrete (OpConcreteNext 1))+ [XType tElem, XType tProc, XType tRate, xStream, xIndex]+++xNextC :: Int -> TypeF -> TypeF -> TypeF -> ExpF -> ExpF -> ExpF+xNextC c tProc tRate tElem xStream xIndex+ = xApps (xVarOpConcrete (OpConcreteNext c))+ [XType tElem, XType tProc, XType tRate, xStream, xIndex]+++xDown :: Int -> TypeF -> TypeF -> TypeF -> ExpF -> ExpF -> ExpF+xDown n tP tK tE xRN xS+ = xApps (xVarOpConcrete (OpConcreteDown n))+ [XType tP, XType tK, XType tE, xRN, xS]+++xTail :: Int -> TypeF -> TypeF -> TypeF -> ExpF -> ExpF -> ExpF+xTail n tP tK tE xRN xS+ = xApps (xVarOpConcrete (OpConcreteTail n))+ [XType tP, XType tK, XType tE, xRN, xS]++++-- Utils -----------------------------------------------------------------------+xVarOpConcrete :: OpConcrete -> Exp () Name+xVarOpConcrete op+ = XVar (UPrim (NameOpConcrete op) (typeOpConcrete op))+
+ DDC/Core/Flow/Prim/OpControl.hs view
@@ -0,0 +1,131 @@++-- | Control constructs used in lowered code.+module DDC.Core.Flow.Prim.OpControl+ ( readOpControl+ , typeOpControl+ , xLoopN+ , xGuard+ , xSegment+ , xSplit)+where+import DDC.Core.Flow.Prim.KiConFlow+import DDC.Core.Flow.Prim.TyConPrim+import DDC.Core.Flow.Prim.TyConFlow+import DDC.Core.Flow.Prim.Base+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Data.Pretty+import Control.DeepSeq+import Data.Char+import Data.List+++instance NFData OpControl where+ rnf !_ = ()+++instance Pretty OpControl where+ ppr fo+ = case fo of+ OpControlLoop -> text "loop#"+ OpControlLoopN -> text "loopn#"+ OpControlGuard -> text "guard#"+ OpControlSegment -> text "segment#"+ OpControlSplit n -> text "split$" <> int n <> text "#"+++-- | Read a control operator name.+readOpControl :: String -> Maybe OpControl+readOpControl str+ | Just rest <- stripPrefix "split$" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , arity <- read ds+ = Just $ OpControlSplit arity++ | otherwise+ = case str of+ "loop#" -> Just $ OpControlLoop+ "loopn#" -> Just $ OpControlLoopN+ "guard#" -> Just $ OpControlGuard+ "segment#" -> Just $ OpControlSegment+ _ -> Nothing+++-- Types ----------------------------------------------------------------------+-- | Yield the type of a control operator.+typeOpControl :: OpControl -> Type Name+typeOpControl op+ = case op of+ -- loop# :: [k : Rate]. (Nat# -> Unit) -> Unit+ OpControlLoop+ -> tForall kRate + $ \_ -> (tNat `tFun` tUnit) `tFun` tUnit++ -- loopn# :: [k : Rate]. RateNat# k -> (Nat# -> Unit) -> Unit+ OpControlLoopN+ -> tForall kRate + $ \kR -> tRateNat kR `tFun` (tNat `tFun` tUnit) `tFun` tUnit++ -- guard# :: Ref# Nat# -> Bool# -> (Nat# -> Unit) -> Unit+ OpControlGuard + -> tBool+ `tFun` (tUnit `tFun` tUnit)+ `tFun` tUnit++ -- segment# :: Ref Nat# -> Nat# -> (Nat# -> Nat# -> Unit) -> Unit+ -- In the worker the first parameter is the index of the current+ -- element in the segment, and the second is the index into the + -- overall series.+ OpControlSegment+ -> tNat+ `tFun` (tNat `tFun` tUnit)+ `tFun` tUnit++ -- split# :: [k : Rate]. RateNat# k+ -- -> (RateNat# (Down8# k) -> Unit)+ -- -> (RateNat# (Tail8# k) -> Unit)+ -- -> Unit+ OpControlSplit n+ -> tForall kRate+ $ \tK -> tRateNat tK+ `tFun` (tRateNat (tDown n tK) `tFun` tUnit)+ `tFun` (tRateNat (tTail n tK) `tFun` tUnit)+ `tFun` tUnit+++-- Compounds ------------------------------------------------------------------+type TypeF = Type Name+type ExpF = Exp () Name+++xLoopN :: TypeF -> ExpF -> ExpF -> ExpF+xLoopN tR xRN xF + = xApps (xVarOpControl OpControlLoopN) + [XType tR, xRN, xF]+++xGuard :: ExpF -> ExpF -> ExpF+xGuard xFlag xFun+ = xApps (xVarOpControl OpControlGuard) + [xFlag, xFun]+++xSegment :: ExpF -> ExpF -> ExpF+xSegment xIters xFun+ = xApps (xVarOpControl OpControlSegment)+ [xIters, xFun]+++xSplit :: Int -> TypeF -> ExpF+ -> ExpF -> ExpF -> ExpF+xSplit n tK xRN xDownFn xTailFn + = xApps (xVarOpControl $ OpControlSplit n)+ [ XType tK, xRN, xDownFn, xTailFn ]+++-- Utils -----------------------------------------------------------------------+xVarOpControl :: OpControl -> ExpF+xVarOpControl op+ = XVar (UPrim (NameOpControl op) (typeOpControl op))+
− DDC/Core/Flow/Prim/OpFlow.hs
@@ -1,252 +0,0 @@--module DDC.Core.Flow.Prim.OpFlow- ( readOpFlow- , typeOpFlow- , xRateOfSeries- , xNatOfRateNat)-where-import DDC.Core.Flow.Prim.KiConFlow-import DDC.Core.Flow.Prim.TyConFlow-import DDC.Core.Flow.Prim.TyConPrim-import DDC.Core.Flow.Prim.Base-import DDC.Core.Transform.LiftT-import DDC.Core.Compounds.Simple-import DDC.Core.Exp.Simple-import DDC.Base.Pretty-import Control.DeepSeq-import Data.List-import Data.Char ---instance NFData OpFlow---instance Pretty OpFlow where- ppr pf- = case pf of- OpFlowVectorOfSeries -> text "vectorOfSeries" <> text "#"- OpFlowRateOfSeries -> text "rateOfSeries" <> text "#"- OpFlowNatOfRateNat -> text "natOfRateNat" <> text "#"-- OpFlowMkSel 1 -> text "mkSel" <> text "#"- OpFlowMkSel n -> text "mkSel" <> int n <> text "#"-- OpFlowMap 1 -> text "map" <> text "#"- OpFlowMap i -> text "map" <> int i <> text "#"-- OpFlowRep -> text "rep" <> text "#"- OpFlowReps -> text "reps" <> text "#"-- OpFlowFold -> text "fold" <> text "#"- OpFlowFoldIndex -> text "foldIndex" <> text "#"- OpFlowFolds -> text "folds" <> text "#"-- OpFlowUnfold -> text "unfold" <> text "#"- OpFlowUnfolds -> text "unfolds" <> text "#"-- OpFlowSplit i -> text "split" <> int i <> text "#"- OpFlowCombine i -> text "combine" <> int i <> text "#"-- OpFlowPack -> text "pack" <> text "#"----- | Read a data flow operator name.-readOpFlow :: String -> Maybe OpFlow-readOpFlow str- | Just rest <- stripPrefix "mkSel" str- , (ds, "#") <- span isDigit rest- , not $ null ds- , arity <- read ds- , arity == 1- = Just $ OpFlowMkSel arity-- | Just rest <- stripPrefix "map" str- , (ds, "#") <- span isDigit rest- , not $ null ds- , arity <- read ds- = Just $ OpFlowMap arity-- | Just rest <- stripPrefix "split" str- , (ds, "#") <- span isDigit rest- , not $ null ds- , arity <- read ds- = Just $ OpFlowSplit arity-- | Just rest <- stripPrefix "combine" str- , (ds, "#") <- span isDigit rest- , not $ null ds- , arity <- read ds- = Just $ OpFlowCombine arity-- | otherwise- = case str of- "vectorOfSeries#" -> Just $ OpFlowVectorOfSeries- "rateOfSeries#" -> Just $ OpFlowRateOfSeries- "natOfRateNat#" -> Just $ OpFlowNatOfRateNat- "mkSel#" -> Just $ OpFlowMkSel 1- "map#" -> Just $ OpFlowMap 1- "rep#" -> Just $ OpFlowRep- "reps#" -> Just $ OpFlowReps- "fold#" -> Just $ OpFlowFold- "foldIndex#" -> Just $ OpFlowFoldIndex- "folds#" -> Just $ OpFlowFolds- "unfold#" -> Just $ OpFlowUnfold- "unfolds#" -> Just $ OpFlowUnfolds- "pack#" -> Just $ OpFlowPack- _ -> Nothing----- Types -------------------------------------------------------------------------- | Yield the type of a data flow operator, --- or `error` if there isn't one.-typeOpFlow :: OpFlow -> Type Name-typeOpFlow op- = case takeTypeOpFlow op of- Just t -> t- Nothing -> error $ "ddc-core-flow.typeOpFlow: invalid op " ++ show op----- | Yield the type of a data flow operator.-takeTypeOpFlow :: OpFlow -> Maybe (Type Name)-takeTypeOpFlow op- = case op of- -- Series Conversions -------------------- -- vectorOfSeries# :: [k : Rate]. [a : Data]- -- . Series k a -> Vector a- OpFlowVectorOfSeries- -> Just $ tForalls [kRate, kData] $ \[tK, tA] - -> tSeries tK tA `tFun` tVector tA-- -- rateOfSeries# :: [k : Rate]. [a : Data]- -- . Series k a -> RateNat k- OpFlowRateOfSeries - -> Just $ tForalls [kRate, kData] $ \[tK, tA]- -> tSeries tK tA `tFun` tRateNat tK-- -- natOfRateNat# :: [k : Rate]. RateNat k -> Nat#- OpFlowNatOfRateNat - -> Just $ tForall kRate $ \tK - -> tRateNat tK `tFun` tNat--- -- Selectors ----------------------------- -- mkSel1# :: [k1 : Rate]. [a : Data]- -- . Series k1 Bool#- -- -> ([k2 : Rate]. Sel1 k1 k2 -> a)- -- -> a- OpFlowMkSel 1- -> Just $ tForalls [kRate, kData] $ \[tK1, tA]- -> tSeries tK1 tBool- `tFun` (tForall kRate $ \tK2 - -> tSel1 (liftT 1 tK1) tK2 `tFun` (liftT 1 tA))- `tFun` tA-- - -- Maps ---------------------------------- -- map :: [k : Rate] [a b : Data]- -- . (a -> b) -> Series k a -> Series k b- OpFlowMap 1- -> Just $ tForalls [kRate, kData, kData] $ \[tK, tA, tB]- -> (tA `tFun` tB)- `tFun` tSeries tK tA- `tFun` tSeries tK tB-- -- mapN :: [k : Rate] [a0..aN : Data]- -- . (a0 -> .. aN) -> Series k a0 -> .. Series k aN- OpFlowMap n- | n >= 2- , Just tWork <- tFunOfList - [ TVar (UIx i) - | i <- reverse [0..n] ]-- , Just tBody <- tFunOfList- (tWork : [tSeries (TVar (UIx (n + 1))) (TVar (UIx i)) - | i <- reverse [0..n] ])-- -> Just $ foldr TForall tBody- [ BAnon k | k <- kRate : replicate (n + 1) kData ]--- -- Replicates -------------------------- -- rep :: [a : Data] [k : Rate]- -- . a -> Series k a- OpFlowRep - -> Just $ tForalls [kData, kRate] $ \[tA, tR]- -> tA `tFun` tSeries tR tA-- -- reps :: [k1 k2 : Rate]. [a : Data]- -- . Segd k1 k2 - -- -> Series k1 a- -- -> Series k2 a- OpFlowReps - -> Just $ tForalls [kRate, kRate, kData] $ \[tK1, tK2, tA]- -> tSegd tK1 tK2- `tFun` tSeries tK1 tA- `tFun` tSeries tK2 tA--- -- Folds --------------------------------- -- fold :: [k : Rate]. [a b: Data]- -- . (a -> b -> a) -> a -> Series k b -> a- OpFlowFold - -> Just $ tForalls [kRate, kData, kData] $ \[tK, tA, tB]- -> (tA `tFun` tB `tFun` tA)- `tFun` tA- `tFun` tSeries tK tB- `tFun` tA-- -- foldIndex :: [k : Rate]. [a b: Data]- -- . (Int# -> a -> b -> a) -> a -> Series k b -> a- OpFlowFoldIndex- -> Just $ tForalls [kRate, kData, kData] $ \[tK, tA, tB]- -> (tInt `tFun` tA `tFun` tB `tFun` tA)- `tFun` tA- `tFun` tSeries tK tB- `tFun` tA-- -- folds :: [k1 k2 : Rate]. [a b: Data]- -- . Segd k1 k2 - -- -> (a -> b -> a) -- fold operator- -- -> Series k1 a -- start values- -- -> Series k2 b -- source elements- -- -> Series k1 a -- result values- OpFlowFolds- -> Just $ tForalls [kRate, kRate, kData, kData] $ \[tK1, tK2, tA, tB]- -> tSegd tK1 tK2- `tFun` (tInt `tFun` tA `tFun` tB `tFun` tA)- `tFun` tSeries tK1 tA- `tFun` tSeries tK2 tB- `tFun` tSeries tK1 tA--- -- Packs --------------------------------- -- pack :: [k1 k2 : Rate]. [a : Data]- -- . Sel2 k1 k2- -- -> Series k1 a -> Series k2 a- OpFlowPack- -> Just $ tForalls [kRate, kRate, kData] $ \[tK1, tK2, tA]- -> tSel1 tK1 tK2 - `tFun` tSeries tK1 tA- `tFun` tSeries tK2 tA-- _ -> Nothing----- Compounds -------------------------------------------------------------------xRateOfSeries :: Type Name -> Type Name -> Exp () Name -> Exp () Name-xRateOfSeries tK tA xS - = xApps (xVarOpFlow OpFlowRateOfSeries) - [XType tK, XType tA, xS]---xNatOfRateNat :: Type Name -> Exp () Name -> Exp () Name-xNatOfRateNat tK xR- = xApps (xVarOpFlow OpFlowNatOfRateNat)- [XType tK, xR]----- Utils ------------------------------------------------------------------------xVarOpFlow :: OpFlow -> Exp () Name-xVarOpFlow op- = XVar (UPrim (NameOpFlow op) (typeOpFlow op))-
− DDC/Core/Flow/Prim/OpLoop.hs
@@ -1,84 +0,0 @@---- | Loop related names.-module DDC.Core.Flow.Prim.OpLoop- ( readOpLoop- , typeOpLoop- , xLoopLoopN- , xLoopGuard)-where-import DDC.Core.Flow.Prim.KiConFlow-import DDC.Core.Flow.Prim.TyConPrim-import DDC.Core.Flow.Prim.TyConFlow-import DDC.Core.Flow.Prim.Base-import DDC.Core.Compounds.Simple-import DDC.Core.Exp.Simple-import DDC.Base.Pretty-import Control.DeepSeq---instance NFData OpLoop---instance Pretty OpLoop where- ppr fo- = case fo of- OpLoopLoop -> text "loop#"- OpLoopLoopN -> text "loopn#"-- OpLoopGuard -> text "guard#"----- | Read a loop operator name.-readOpLoop :: String -> Maybe OpLoop-readOpLoop str- = case str of- "loop#" -> Just $ OpLoopLoop- "loopn#" -> Just $ OpLoopLoopN- "guard#" -> Just $ OpLoopGuard- _ -> Nothing----- Types ------------------------------------------------------------------------- | Yield the type of a loop operator.-typeOpLoop :: OpLoop -> Type Name-typeOpLoop op- = case op of- -- loop# :: [k : Rate]. (Nat# -> Unit) -> Unit- OpLoopLoop- -> tForall kRate - $ \_ -> (tNat `tFun` tUnit) `tFun` tUnit-- -- loopn# :: [k : Rate]. RateNat k -> (Nat# -> Unit) -> Unit- OpLoopLoopN- -> tForall kRate - $ \kR -> tRateNat kR `tFun` (tNat `tFun` tUnit) `tFun` tUnit-- -- guard# :: Ref# Nat# -> Bool# - -- -> (Nat# -> Unit) -> Unit- OpLoopGuard - -> tRef tNat- `tFun` tBool- `tFun` (tNat `tFun` tUnit)- `tFun` tUnit----- Compounds -------------------------------------------------------------------xLoopLoopN :: Type Name -> Exp () Name -> Exp () Name -> Exp () Name-xLoopLoopN tR xRN xF - = xApps (xVarOpLoop OpLoopLoopN) [XType tR, xRN, xF]---xLoopGuard - :: Exp () Name -- ^ Reference to guard counter.- -> Exp () Name -- ^ Boolean flag to test.- -> Exp () Name -- ^ Body of guard.- -> Exp () Name--xLoopGuard xB xCount xF- = xApps (xVarOpLoop OpLoopGuard) [xCount, xB, xF]----- Utils ------------------------------------------------------------------------xVarOpLoop :: OpLoop -> Exp () Name-xVarOpLoop op- = XVar (UPrim (NameOpLoop op) (typeOpLoop op))
DDC/Core/Flow/Prim/OpPrim.hs view
@@ -1,18 +1,30 @@ module DDC.Core.Flow.Prim.OpPrim ( typePrimCast- , typePrimArith)+ , typePrimArith+ , typePrimVec++ -- * Compounds+ , xvRep+ , xvProj+ , xvGather+ , xvScatter) where import DDC.Core.Flow.Prim.TyConPrim+import DDC.Core.Flow.Prim.TyConFlow+import DDC.Core.Flow.Prim.KiConFlow import DDC.Core.Flow.Prim.Base-import DDC.Core.Compounds.Simple-import DDC.Core.Exp.Simple+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp -- | Take the type of a primitive cast. typePrimCast :: PrimCast -> Type Name typePrimCast cc = case cc of+ PrimCastConvert+ -> tForalls [kData, kData] $ \[t1, t2] -> t2 `tFun` t1+ PrimCastPromote -> tForalls [kData, kData] $ \[t1, t2] -> t2 `tFun` t1 @@ -51,3 +63,64 @@ PrimArithBAnd -> tForall kData $ \t -> t `tFun` t `tFun` t PrimArithBOr -> tForall kData $ \t -> t `tFun` t `tFun` t PrimArithBXOr -> tForall kData $ \t -> t `tFun` t `tFun` t+++-- | Take the type of a primitive vector operator.+typePrimVec :: PrimVec -> Type Name+typePrimVec op+ = case op of+ PrimVecNeg n -> tForall kData $ \t -> tVec n t `tFun` tVec n t+ PrimVecAdd n -> tForall kData $ \t -> tVec n t `tFun` tVec n t `tFun` tVec n t+ PrimVecSub n -> tForall kData $ \t -> tVec n t `tFun` tVec n t `tFun` tVec n t+ PrimVecMul n -> tForall kData $ \t -> tVec n t `tFun` tVec n t `tFun` tVec n t+ PrimVecDiv n -> tForall kData $ \t -> tVec n t `tFun` tVec n t `tFun` tVec n t++ PrimVecRep n + -> tForall kData $ \t -> t `tFun` tVec n t++ PrimVecPack n+ -> tForall kData + $ \t -> let Just t' = tFunOfList (replicate n t ++ [tVec n t]) + in t'++ PrimVecProj n _+ -> tForall kData+ $ \t -> tVec n t `tFun` t++ PrimVecGather n+ -> tForalls [kRate, kData]+ $ \[k, t] -> tRateVec k t `tFun` tVec n tNat `tFun` tVec n t++ PrimVecScatter n+ -> tForall kData+ $ \t -> tVector t `tFun` tVec n tNat `tFun` tVec n t `tFun` tUnit+++-- Compounds ------------------------------------------------------------------+xvRep :: Int -> Type Name -> Exp () Name -> Exp () Name+xvRep c tA xZ+ = xApps (xVarPrimVec (PrimVecRep c)) + [XType tA, xZ]++xvProj :: Int -> Int -> Type Name -> Exp () Name -> Exp () Name+xvProj n i tA xV+ = xApps (xVarPrimVec (PrimVecProj n i))+ [XType tA, xV]++xvGather :: Int -> Type Name -> Type Name -> Exp () Name -> Exp () Name -> Exp () Name+xvGather c tK tA xVec xIxs+ = xApps (xVarPrimVec (PrimVecGather c))+ [XType tK, XType tA, xVec, xIxs]+++xvScatter :: Int -> Type Name -> Exp () Name -> Exp () Name -> Exp () Name -> Exp () Name+xvScatter c tA xVec xIxs xElems+ = xApps (xVarPrimVec (PrimVecScatter c))+ [XType tA, xVec, xIxs, xElems]+++-- Utils -----------------------------------------------------------------------+xVarPrimVec :: PrimVec -> Exp () Name+xVarPrimVec op+ = XVar (UPrim (NamePrimVec op) (typePrimVec op))+
+ DDC/Core/Flow/Prim/OpSeries.hs view
@@ -0,0 +1,471 @@++module DDC.Core.Flow.Prim.OpSeries+ ( readOpSeries+ , typeOpSeries+ + -- Compounds+ , xSeriesOfRateVec)+where+import DDC.Core.Flow.Prim.KiConFlow+import DDC.Core.Flow.Prim.TyConFlow+import DDC.Core.Flow.Prim.TyConPrim+import DDC.Core.Flow.Prim.Base+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Core.Transform.BoundT+import DDC.Data.Pretty+import Control.DeepSeq+import Data.List+import Data.Char +++instance NFData OpSeries where+ rnf !_ = ()+++instance Pretty OpSeries where+ ppr pf+ = case pf of+ OpSeriesRep -> text "srep" <> text "#"+ OpSeriesReps -> text "sreps" <> text "#"++ OpSeriesIndices -> text "sindices" <> text "#"++ OpSeriesFill -> text "sfill" <> text "#"++ OpSeriesGather -> text "sgather" <> text "#"+ OpSeriesScatter -> text "sscatter" <> text "#"++ OpSeriesMkSel 1 -> text "smkSel" <> text "#"+ OpSeriesMkSel n -> text "smkSel" <> int n <> text "#"++ OpSeriesMkSegd -> text "smkSegd" <> text "#"++ OpSeriesMap 1 -> text "smap" <> text "#"+ OpSeriesMap i -> text "smap" <> int i <> text "#"++ OpSeriesPack -> text "spack" <> text "#"++ OpSeriesGenerate -> text "sgenerate" <> text "#"++ OpSeriesReduce -> text "sreduce" <> text "#"+ OpSeriesFolds -> text "sfolds" <> text "#"++ OpSeriesJoin -> text "pjoin" <> text "#"++ OpSeriesRunProcess -> text "runProcess" <> text "#"+ OpSeriesRunProcessUnit -> text "runProcessUnit" <> text "#"++ OpSeriesRateVecsOfVectors n -> text "ratify" <> int n <> text "#"++ OpSeriesSeriesOfRateVec -> text "series" <> text "#"+ OpSeriesAppend -> text "sappend" <> text "#"+ OpSeriesCross -> text "scross" <> text "#"++ OpSeriesResizeProc -> text "presize" <> text "#"+ OpSeriesResizeId -> text "rid" <> text "#"+ OpSeriesResizeAppL -> text "rappl" <> text "#"+ OpSeriesResizeAppR -> text "rappr" <> text "#"+ OpSeriesResizeApp -> text "rapp" <> text "#"+ OpSeriesResizeSel1 -> text "rsel1" <> text "#"+ OpSeriesResizeSegd -> text "rsegd" <> text "#"+ OpSeriesResizeCross -> text "rcross" <> text "#"+++-- | Read a data flow operator name.+readOpSeries :: String -> Maybe OpSeries+readOpSeries str+ | Just rest <- stripPrefix "smap" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , arity <- read ds+ = Just $ OpSeriesMap arity++ | Just rest <- stripPrefix "smkSel" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , arity <- read ds+ , arity == 1+ = Just $ OpSeriesMkSel arity++ | Just rest <- stripPrefix "ratify" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , arity <- read ds+ = Just $ OpSeriesRateVecsOfVectors arity+++ | otherwise+ = case str of+ "srep#" -> Just $ OpSeriesRep+ "sreps#" -> Just $ OpSeriesReps+ "sindices#" -> Just $ OpSeriesIndices+ "sgather#" -> Just $ OpSeriesGather+ "smkSel#" -> Just $ OpSeriesMkSel 1+ "smkSegd#" -> Just $ OpSeriesMkSegd+ "smap#" -> Just $ OpSeriesMap 1+ "spack#" -> Just $ OpSeriesPack+ "sgenerate#" -> Just $ OpSeriesGenerate+ "sreduce#" -> Just $ OpSeriesReduce+ "sfolds#" -> Just $ OpSeriesFolds+ "sfill#" -> Just $ OpSeriesFill+ "sscatter#" -> Just $ OpSeriesScatter+ "pjoin#" -> Just $ OpSeriesJoin+ "runProcess#" -> Just $ OpSeriesRunProcess+ "runProcessUnit#"->Just $ OpSeriesRunProcessUnit+ "series#" -> Just $ OpSeriesSeriesOfRateVec+ "sappend#" -> Just $ OpSeriesAppend+ "scross#" -> Just $ OpSeriesCross++ "presize#" -> Just $ OpSeriesResizeProc+ "rid#" -> Just $ OpSeriesResizeId+ "rappl#" -> Just $ OpSeriesResizeAppL+ "rappr#" -> Just $ OpSeriesResizeAppR+ "rapp#" -> Just $ OpSeriesResizeApp+ "rsel1#" -> Just $ OpSeriesResizeSel1+ "rsegd#" -> Just $ OpSeriesResizeSegd+ "rcross#" -> Just $ OpSeriesResizeCross++ _ -> Nothing+++-- Types -----------------------------------------------------------------------+-- | Yield the type of a data flow operator, +-- or `error` if there isn't one.+typeOpSeries :: OpSeries -> Type Name+typeOpSeries op+ = case takeTypeOpSeries op of+ Just t -> t+ Nothing -> error $ "ddc-core-flow.typeOpSeries: invalid op " ++ show op+++-- | Yield the type of a data flow operator.+takeTypeOpSeries :: OpSeries -> Maybe (Type Name)+takeTypeOpSeries op+ = case op of+ -- Replicates -------------------------+ -- rep :: [p : Proc] [k : Rate] [a : Data] + -- . a -> Series p k a+ OpSeriesRep + -> Just $ tForalls [kProc, kRate, kData] $ \[tP, tR, tA]+ -> tA `tFun` tSeries tP tR tA++ -- reps :: [p : Proc]. [k1 k2 : Rate]. [a : Data]+ -- . Segd k1 k2 -> Series p k1 a -> Series p k2 a+ OpSeriesReps + -> Just $ tForalls [kProc, kRate, kRate, kData] $ \[tP, tK1, tK2, tA]+ -> tSegd tK1 tK2 `tFun` tSeries tP tK1 tA `tFun` tSeries tP tK2 tA+++ -- Indices ------------------------------+ -- indices :: [p : Proc]. [k1 k2 : Rate]. + -- . Segd k1 k2 -> Series p k2 k1 Nat+ OpSeriesIndices+ -> Just $ tForalls [kProc, kRate, kRate] $ \[tP, tK1, tK2]+ -> tSegd tK1 tK2 `tFun` tSeries tP tK2 tNat+++ -- Maps ---------------------------------+ -- map :: [p : Proc]. [kR kL : Rate] [a b : Data]+ -- . (a -> b) -> Series p kR kL a -> Series p kR kL b+ OpSeriesMap 1+ -> Just $ tForalls [kProc, kRate, kData, kData] $ \[tP, tKR, tA, tB]+ -> (tA `tFun` tB)+ `tFun` tSeries tP tKR tA+ `tFun` tSeries tP tKR tB++ -- mapN :: [p : Proc] [kR kL : Rate] [a0..aN : Data]+ -- . (a0 -> .. aN) -> Series p kR kL a0 -> .. Series p kR kL aN+ OpSeriesMap n+ | n >= 2+ , Just tWork <- tFunOfList + [ TVar (UIx i) + | i <- reverse [0..n] ]++ , Just tBody <- tFunOfList+ (tWork : [tSeries (TVar $ UIx $ n + 2) (TVar $ UIx $ n + 1)+ (TVar $ UIx i) + | i <- reverse [0..n] ])++ -> Just $ foldr TForall tBody+ [ BAnon k | k <- kProc : kRate : replicate (n + 1) kData ]+++ -- Packs --------------------------------+ -- pack :: [p : Proc]. [k1 k2 kL : Rate]. [a : Data]+ -- . Sel2 k1 k2+ -- -> Series p k1 kL a -> Series p k2 kL a+ OpSeriesPack+ -> Just $ tForalls [kProc, kRate, kRate, kData] $ \[tP, tK1, tK2, tA]+ -> tSel1 tP tK1 tK2 + `tFun` tSeries tP tK1 tA+ `tFun` tSeries tP tK2 tA+++ -- Processes ----------------------------+ -- join# :: [p : Proc]. [k : Rate]. [a b : Data].+ -- . Process p k a+ -- -> Process p k b+ -- -> Process p k (a,b)+ OpSeriesJoin+ -> Just $ tForalls [kProc, kRate] $+ \[tP, tK]+ -> tProcess tP tK+ `tFun` tProcess tP tK+ `tFun` tProcess tP tK+++ -- mkSel1# :: [p : Proc]. [k1 kL : Rate]+ -- . Series p k1 kL Bool#+ -- -> ([k2 : Rate]. Sel1 p k1 k2 -> Process# p kL)+ -- -> Process# p kL+ OpSeriesMkSel 1+ -> Just $ tForalls [kProc, kRate, kRate] $ \[tP, tK1, tKL]+ -> tSeries tP tK1 tBool+ `tFun` (tForall kRate $ \tK2 + -> tSel1 (liftT 1 tP) (liftT 1 tK1) tK2 `tFun` tProcess (liftT 1 tP) (liftT 1 tKL))+ `tFun` tProcess tP tKL+++ -- mkSegd# :: [p : Proc]. [k1 kL : Rate]+ -- . Series# p k1 kL Nat#+ -- -> ([k2 : Rate]. Segd# k1 k2 -> Process# p kL)+ -- -> Process# p kL+ OpSeriesMkSegd+ -> Just $ tForalls [kProc, kRate] $ \[tP, tK1]+ -> tSeries tP tK1 tNat+ `tFun` (tForall kRate $ \tK2+ -> tSegd (liftT 1 tK1) tK2 `tFun` tProcess (liftT 1 tP) (liftT 1 tK1))+ `tFun` tProcess tP tK1+++ -- runProcess# :: [k : Rate]+ -- . + -- ([p : Proc]. Unit -> Process p k)+ -- -> Unit+ OpSeriesRunProcess+ -> Just $ tForalls [kRate] $ \[tK]+ -> (tForall kProc $ \tP+ -> tUnit `tFun` tProcess tP (liftT 1 tK))+ `tFun` tUnit++ -- runProcessUnit# :: [k : Rate]+ -- . + -- ([p : Proc]. Unit -> Unit)+ -- -> Unit+ OpSeriesRunProcessUnit+ -> Just $ tForalls [kRate] $ \[_]+ -> (tForall kProc $ \_+ -> tUnit `tFun` tUnit)+ `tFun` tUnit+++ -- ratify0# :: [z : Data]+ -- . Nat+ -- -> ([k : Rate]. z)+ -- -> z+ OpSeriesRateVecsOfVectors 0+ -> Just $ tForall kData $ \tA+ -> tNat+ `tFun` (tForall kRate $ \_ -> liftT 1 tA)+ `tFun` tA++ -- ratifyN# :: [a0..aN z : Data]+ -- . Vector a0 .. Vector aN + -- -> ([k : Rate]. RateVec k a0 .. RateVec k aN -> z)+ -- -> z+ OpSeriesRateVecsOfVectors n+ | tK <- TVar (UIx 0)++ , Just tWork <- tFunOfList + $ [ tRateVec tK (TVar (UIx i))+ | i <- reverse [2..n+1] ]+ ++[ TVar (UIx 1) ]++ , tWork' <- TForall (BAnon kRate) tWork++ , Just tBody <- tFunOfList+ $ [ tVector (TVar (UIx i)) | i <- reverse [1..n] ]+ ++[ tWork', TVar (UIx 0) ]++ -> Just $ foldr TForall tBody+ [ BAnon k | k <- replicate (n+1) kData ]++ -- series# :: [p : Proc]. [k : Rate]. [a : Data]+ -- . RateVec k a -> Series p k a+ OpSeriesSeriesOfRateVec+ -> Just $ tForalls [kProc, kRate, kData] $ \[tP, tK, tA]+ -> tRateVec tK tA `tFun` tSeries tP tK tA++ -- sappend# :: [p : Proc]. [k1R k2R : Rate]. [a : Data]+ -- . Series p k1R a -> Series p k2R a+ -- -> Series p (k1R + k2R) a+ OpSeriesAppend+ -> Just $ tForalls [kProc, kRate, kRate, kData] $+ \[tP, tK1, tK2, tA]+ -> tSeries tP tK1 tA+ `tFun` tSeries tP tK2 tA+ `tFun` tSeries tP (tRateAppend tK1 tK2) tA++ -- scross# :: [p : Proc]. [kR kO : Rate]. [a b : Data]+ -- . Series p kR a+ -- -> RateVec kO b+ -- -> Series p (kR * kO) (a,b)+ OpSeriesCross+ -> Just $ tForalls [kProc, kRate, kRate, kData, kData] $+ \[tP, tKR, tKO, tA, tB]+ -> tSeries tP tKR tA+ `tFun` tRateVec tKO tB+ `tFun` tSeries tP (tRateCross tKR tKO) (tTuple2 tA tB)+++ -- generate# :: [p : Proc]. [k : Rate]. [a : Data]+ -- . (Nat# -> a) -> Series p k a+ OpSeriesGenerate+ -> Just $ tForalls [kProc, kRate, kData] $ \[tP, tK, tA]+ -> (tNat `tFun` tA)+ `tFun` tSeries tP tK tA++ -- Reductions -------------------------------+ -- reduce# :: [p : Proc]. [k : Rate]. [a : Data]+ -- . Ref a -> (a -> a -> a) -> a -> Series p k a -> Process p k+ OpSeriesReduce+ -> Just $ tForalls [kProc, kRate, kData] $ \[tP, tK, tA]+ -> tRef tA+ `tFun` (tA `tFun` tA `tFun` tA)+ `tFun` tA+ `tFun` tSeries tP tK tA+ `tFun` tProcess tP tK+++ -- folds# :: [p : Proc]. [k1 k2 : Rate]. [a : Data]+ -- . Segd# k1 k2 -> Series p k1 a -> Series k2 b+ OpSeriesFolds+ -> Just $ tForalls [kProc, kRate, kRate, kData] $ \[tP, tK1, tK2, tA]+ -> tSegd tK1 tK2+ `tFun` tSeries tP tK1 tA+ `tFun` tSeries tP tK2 tA+++ -- Store operators ---------------------------+ -- scatter# :: [p : Proc]. [k : Rate]. [a : Data]+ -- . Vector a -> Series p k Nat# -> Series p k a -> Process p k+ OpSeriesScatter+ -> Just $ tForalls [kProc, kRate, kData] $ \[tP, tK, tA]+ -> tVector tA+ `tFun` tSeries tP tK tNat+ `tFun` tSeries tP tK tA+ `tFun` tProcess tP tK+++ -- gather# :: [p : Proc]. [k1 k2 : Rate]. [a : Data]+ -- . RateVec k1 a -> Series p k2 Nat# -> Series p k2 a+ OpSeriesGather+ -> Just $ tForalls [kProc, kRate, kRate, kData] $ \[tP, tK1, tK2, tA]+ -> tRateVec tK1 tA + `tFun` tSeries tP tK2 tNat+ `tFun` tSeries tP tK2 tA+++ -- fill# :: [p : Proc]. [k : Rate]. [a : Data]. Vector a -> Series p k a -> Process p k+ OpSeriesFill+ -> Just $ tForalls [kProc, kRate, kData] $ \[tP, tK, tA] + -> tVector tA+ `tFun` tSeries tP tK tA+ `tFun` tProcess tP tK+++ -- Resizing -----------------------++ -- presize# :: [p : Proc]. [j k : Rate]+ -- . Resize p j k+ -- -> Process p j+ -- -> Process p k+ OpSeriesResizeProc+ -> Just $ tForalls [kProc, kRate, kRate] $+ \[tP, tJ, tK]+ -> tResize tP tJ tK+ `tFun` tProcess tP tJ+ `tFun` tProcess tP tK++ -- rid# :: [p : Proc]. [k : Rate]+ -- . Resize p k k+ OpSeriesResizeId+ -> Just $ tForalls [kProc, kRate] $+ \[tP, tK]+ -> tResize tP tK tK++ -- rappl# :: [p : Proc]. [k l : Rate]+ -- . Resize p k (Append k l)+ OpSeriesResizeAppL+ -> Just $ tForalls [kProc, kRate, kRate] $+ \[tP, tK, tL]+ -> tResize tP tK (tRateAppend tK tL)++ -- rappr# :: [p : Proc]. [k l : Rate]+ -- . Resize p l (Append k l)+ OpSeriesResizeAppR+ -> Just $ tForalls [kProc, kRate, kRate] $+ \[tP, tK, tL]+ -> tResize tP tL (tRateAppend tK tL)+++ -- rapp# :: [p : Proc]. [k k' l l' : Rate]+ -- . Resize k k'+ -- -> Resize l l'+ -- -> Resize (Append k l) (Append k' l')+ OpSeriesResizeApp+ -> Just $ tForalls [kProc, kRate, kRate, kRate, kRate] $+ \[tP, tK, tK', tL, tL']+ -> tResize tP tK tK'+ `tFun` tResize tP tL tL'+ `tFun` tResize tP (tRateAppend tK tL) (tRateAppend tK' tL')++ -- rsel1# :: [p : Proc]. [j k l : Rate]+ -- . Sel1 p k l+ -- -> Resize p j l+ -- -> Resize p j k+ OpSeriesResizeSel1+ -> Just $ tForalls [kProc, kRate, kRate, kRate] $+ \[tP, tJ, tK, tL]+ -> tSel1 tP tK tL+ `tFun` tResize tP tJ tL+ `tFun` tResize tP tJ tK++ -- rsegd# :: [p : Proc]. [j k l : Rate]+ -- . Segd k l+ -- -> Resize p j l+ -- -> Resize p j k+ OpSeriesResizeSegd+ -> Just $ tForalls [kProc, kRate, kRate, kRate] $+ \[tP, tJ, tK, tL]+ -> tSegd tK tL+ `tFun` tResize tP tJ tL+ `tFun` tResize tP tJ tK++ -- rcross# :: [p : Proc]. [j k l : Rate]+ -- . Resize p j (Cross k l)+ -- -> Resize p j k+ OpSeriesResizeCross+ -> Just $ tForalls [kProc, kRate, kRate, kRate] $+ \[tP, tJ, tK, tL]+ -> tResize tP tJ (tRateCross tK tL)+ `tFun` tResize tP tJ tK++++ _ -> Nothing+++-- Compounds ------------------------------------------------------------------+xSeriesOfRateVec :: Type Name -> Type Name -> Type Name -> Exp () Name -> Exp () Name+xSeriesOfRateVec tP tK tA xV + = xApps (xVarOpSeries OpSeriesSeriesOfRateVec) + [XType tP, XType tK, XType tA, xV]+++-- Utils -----------------------------------------------------------------------+xVarOpSeries :: OpSeries -> Exp () Name+xVarOpSeries op+ = XVar (UPrim (NameOpSeries op) (typeOpSeries op))+
DDC/Core/Flow/Prim/OpStore.hs view
@@ -3,22 +3,27 @@ ( OpStore (..) , readOpStore , typeOpStore- , xNew, xRead, xWrite- , xNewVector, xReadVector, xWriteVector, xNewVectorR, xNewVectorN- , xSliceVector- , xNext)+ , xNew, xRead, xWrite+ , xNewVector, xNewVectorR, xNewVectorN+ , xReadVector, xReadVectorC+ , xWriteVector, xWriteVectorC+ , xTailVector+ , xTruncVector+ , xBufOfVector, xBufOfRateVec) where import DDC.Core.Flow.Prim.KiConFlow import DDC.Core.Flow.Prim.TyConFlow import DDC.Core.Flow.Prim.TyConPrim import DDC.Core.Flow.Prim.Base-import DDC.Core.Compounds.Simple-import DDC.Core.Exp.Simple-import DDC.Base.Pretty+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Data.Pretty import Control.DeepSeq-+import Data.List+import Data.Char -instance NFData OpStore+instance NFData OpStore where+ rnf !_ = () instance Pretty OpStore where@@ -30,43 +35,74 @@ OpStoreWrite -> text "write#" -- Vectors.- OpStoreNewVector -> text "newVector#"- OpStoreNewVectorR -> text "newVectorR#"- OpStoreNewVectorN -> text "newVectorN#"- OpStoreReadVector -> text "readVector#"- OpStoreWriteVector -> text "writeVector#"- OpStoreSliceVector -> text "sliceVector#"+ OpStoreNewVector -> text "vnew#"+ OpStoreNewVectorR -> text "vnewR#"+ OpStoreNewVectorN -> text "vnewN#" - -- Streams.- OpStoreNext -> text "next#"+ OpStoreReadVector 1 -> text "vread#"+ OpStoreReadVector n -> text "vread$" <> int n <> text "#" + OpStoreWriteVector 1 -> text "vwrite#"+ OpStoreWriteVector n -> text "vwrite$" <> int n <> text "#" + OpStoreTailVector 1 -> text "vtail#"+ OpStoreTailVector n -> text "vtail" <> int n <> text "#"++ OpStoreTruncVector -> text "vtrunc#"+ OpStoreBufOfVector -> text "vbuf#"+ OpStoreBufOfRateVec -> text "vbufofratevec#"++ -- | Read a store operator name. readOpStore :: String -> Maybe OpStore readOpStore str- = case str of- "new#" -> Just OpStoreNew- "read#" -> Just OpStoreRead- "write#" -> Just OpStoreWrite+ | Just rest <- stripPrefix "vread$" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , n <- read ds+ , n >= 1+ = Just $ OpStoreReadVector n - "newVector#" -> Just OpStoreNewVector- "newVectorR#" -> Just OpStoreNewVectorR- "newVectorN#" -> Just OpStoreNewVectorN- "readVector#" -> Just OpStoreReadVector- "writeVector#" -> Just OpStoreWriteVector- "sliceVector#" -> Just OpStoreSliceVector+ | Just rest <- stripPrefix "vwrite$" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , n <- read ds+ , n >= 1+ = Just $ OpStoreWriteVector n - "next#" -> Just OpStoreNext- _ -> Nothing+ | Just rest <- stripPrefix "vtail$" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , n <- read ds+ , n >= 1+ = Just $ OpStoreTailVector n + | otherwise+ = case str of+ "new#" -> Just OpStoreNew+ "read#" -> Just OpStoreRead+ "write#" -> Just OpStoreWrite+ + "vnew#" -> Just OpStoreNewVector+ "vnewR#" -> Just OpStoreNewVectorR+ "vnewN#" -> Just OpStoreNewVectorN+ "vread#" -> Just (OpStoreReadVector 1)+ "vwrite#" -> Just (OpStoreWriteVector 1)+ "vtail#" -> Just (OpStoreTailVector 1)+ "vtrunc#" -> Just OpStoreTruncVector+ "vbuf#" -> Just OpStoreBufOfVector+ "vbufofratevec#"-> Just OpStoreBufOfRateVec + _ -> Nothing++ -- Types ---------------------------------------------------------------------- -- | Yield the type of a store operator. typeOpStore :: OpStore -> Type Name typeOpStore op = case op of -- Assignables ----------------- -- new# :: [a : Data]. a -> Array# a+ -- new# :: [a : Data]. a -> Ref# a OpStoreNew -> tForall kData $ \tA -> tA `tFun` tRef tA @@ -79,43 +115,62 @@ -> tForall kData $ \tA -> tRef tA `tFun` tA `tFun` tUnit -- Arrays ---------------------- -- newVector# :: [a : Data]. Nat -> Vector# a+ -- vnew# :: [a : Data]. Nat -> Vector# a OpStoreNewVector -> tForall kData $ \tA -> tNat `tFun` tVector tA - -- newVectorR# :: [a : Data]. [k : Rate]. Vector# a+ -- vnew# :: [a : Data]. [k : Rate]. Vector# a OpStoreNewVectorR -> tForalls [kData, kRate] $ \[tA, _] -> tVector tA - -- newVectorN# :: [a : Data]. [k : Rate]. RateNat k -> Vector a+ -- vnew# :: [a : Data]. [k : Rate]. RateNat k -> Vector a OpStoreNewVectorN -> tForalls [kData, kRate] $ \[tA, tK] -> tRateNat tK `tFun` tVector tA - -- readVector# :: [a : Data]. Vector# a -> Nat# -> a- OpStoreReadVector+ -- vread# :: [a : Data]. Vector# a -> Nat# -> a+ OpStoreReadVector 1 -> tForall kData - $ \tA -> tVector tA `tFun` tNat `tFun` tA+ $ \tA -> tBuffer tA `tFun` tNat `tFun` tA - -- writeVector# :: [a : Data]. Vector# a -> Nat# -> a -> Unit- OpStoreWriteVector+ -- vreadN# :: [a : Data]. Vector# a -> Nat# -> VecN# a+ OpStoreReadVector n -> tForall kData - $ \tA -> tVector tA `tFun` tNat `tFun` tA `tFun` tUnit+ $ \tA -> tBuffer tA `tFun` tNat `tFun` tVec n tA - -- sliceVector# :: [a : Data]. Nat# -> Vector# a -> Vector# a- OpStoreSliceVector+ -- vwrite# :: [a : Data]. Vector# a -> Nat# -> a -> Unit+ OpStoreWriteVector 1 -> tForall kData - $ \tA -> tNat `tFun` tVector tA `tFun` tVector tA+ $ \tA -> tBuffer tA `tFun` tNat `tFun` tA `tFun` tUnit + -- vwriteN# :: [a : Data]. Vector# a -> Nat# -> VecN# a -> Unit+ OpStoreWriteVector n+ -> tForall kData + $ \tA -> tBuffer tA `tFun` tNat `tFun` tVec n tA `tFun` tUnit - -- Streams --------------------- -- next# :: [a : Data]. [k : Rate]. Series# k a -> Nat# -> a- OpStoreNext- -> tForalls [kData, kRate]- $ \[tA, tK] -> tSeries tK tA `tFun` tNat `tFun` tA+ -- vtail$N# :: [k : Rate]. [a : Data]. RateNat (TailN k) -> Vector# a -> Vector# a+ OpStoreTailVector n+ -> tForalls [kRate, kData]+ $ \[tK, tA] -> tRateNat (tTail n tK) `tFun` tVector tA `tFun` tVector tA + -- vtrunc# :: [a : Data]. Nat# -> Vector# a -> Unit+ OpStoreTruncVector+ -> tForall kData + $ \tA -> tNat `tFun` tVector tA `tFun` tUnit + -- vbuf# :: [a : Data]. Vector# a -> Buffer# a+ OpStoreBufOfVector+ -> tForall kData + $ \tA -> tVector tA `tFun` tBuffer tA++ -- vbufofratevec# :: [k : Rate]. [a : Data]. RateVec# k a -> Buffer# a+ OpStoreBufOfRateVec+ -> tForalls [kRate, kData]+ $ \[tK, tA] -> tRateVec tK tA `tFun` tBuffer tA+++ -- Compounds ------------------------------------------------------------------ xNew :: Type Name -> Exp () Name -> Exp () Name xNew t xV@@ -155,25 +210,50 @@ xReadVector :: Type Name -> Exp () Name -> Exp () Name -> Exp () Name xReadVector t xArr xIx- = xApps (xVarOpStore OpStoreReadVector)+ = xApps (xVarOpStore (OpStoreReadVector 1)) [XType t, xArr, xIx] +xReadVectorC :: Int -> Type Name -> Exp () Name -> Exp () Name -> Exp () Name+xReadVectorC c t xArr xIx+ = xApps (xVarOpStore (OpStoreReadVector c))+ [XType t, xArr, xIx]++ xWriteVector :: Type Name -> Exp () Name -> Exp () Name -> Exp () Name -> Exp () Name xWriteVector t xArr xIx xElem- = xApps (xVarOpStore OpStoreWriteVector)+ = xApps (xVarOpStore (OpStoreWriteVector 1)) [XType t, xArr, xIx, xElem] -xSliceVector :: Type Name -> Exp () Name -> Exp () Name -> Exp () Name-xSliceVector tElem xLen xArr- = xApps (xVarOpStore OpStoreSliceVector)++xWriteVectorC :: Int -> Type Name -> Exp () Name -> Exp () Name -> Exp () Name -> Exp () Name+xWriteVectorC c t xArr xIx xElem+ = xApps (xVarOpStore (OpStoreWriteVector c))+ [XType t, xArr, xIx, xElem]+++xTailVector :: Int -> Type Name -> Type Name -> Exp () Name -> Exp () Name -> Exp () Name+xTailVector n tK tA xRN xVec+ = xApps (xVarOpStore (OpStoreTailVector n))+ [XType tK, XType tA, xRN, xVec]+++xTruncVector :: Type Name -> Exp () Name -> Exp () Name -> Exp () Name+xTruncVector tElem xLen xArr+ = xApps (xVarOpStore OpStoreTruncVector) [XType tElem, xLen, xArr] +xBufOfVector :: Type Name -> Exp () Name -> Exp () Name+xBufOfVector tElem xArr+ = xApps (xVarOpStore OpStoreBufOfVector)+ [XType tElem, xArr] -xNext :: Type Name -> Type Name -> Exp () Name -> Exp () Name -> Exp () Name-xNext tRate tElem xStream xIndex- = xApps (xVarOpStore OpStoreNext)- [XType tElem, XType tRate, xStream, xIndex]+xBufOfRateVec :: Type Name -> Type Name -> Exp () Name -> Exp () Name+xBufOfRateVec tRate tElem xArr+ = xApps (xVarOpStore OpStoreBufOfRateVec)+ [XType tRate, XType tElem, xArr]++ -- Utils ----------------------------------------------------------------------
+ DDC/Core/Flow/Prim/OpVector.hs view
@@ -0,0 +1,135 @@+module DDC.Core.Flow.Prim.OpVector+ ( readOpVector+ , typeOpVector)+where+import DDC.Core.Flow.Prim.TyConFlow+import DDC.Core.Flow.Prim.TyConPrim+import DDC.Core.Flow.Prim.Base+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Data.Pretty+import Control.DeepSeq+import Data.List+import Data.Char +++instance NFData OpVector where+ rnf !_ = ()+++instance Pretty OpVector where+ ppr pf+ = case pf of+ OpVectorMap 1 -> text "vmap" <> text "#"+ OpVectorMap i -> text "vmap" <> int i <> text "#"++ OpVectorFilter -> text "vfilter" <> text "#"++ OpVectorReduce -> text "vreduce" <> text "#"++ OpVectorGenerate -> text "vgenerate" <> text "#"+ OpVectorLength -> text "vlength" <> text "#"++ OpVectorGather -> text "vgather" <> text "#"+++-- | Read a data flow operator name.+readOpVector :: String -> Maybe OpVector+readOpVector str+ | Just rest <- stripPrefix "vmap" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , arity <- read ds+ = Just $ OpVectorMap arity++ | otherwise+ = case str of+ "vmap#" -> Just $ OpVectorMap 1+ "vfilter#" -> Just $ OpVectorFilter+ "vreduce#" -> Just $ OpVectorReduce+ "vgenerate#" -> Just $ OpVectorGenerate+ "vlength#" -> Just $ OpVectorLength+ "vgather#" -> Just $ OpVectorGather+ _ -> Nothing+++-- Types -----------------------------------------------------------------------+-- | Yield the type of a data flow operator, +-- or `error` if there isn't one.+typeOpVector :: OpVector -> Type Name+typeOpVector op+ = case takeTypeOpVector op of+ Just t -> t+ Nothing -> error $ "ddc-core-flow.typeOpVector: invalid op " ++ show op+++-- | Yield the type of a data flow operator.+takeTypeOpVector :: OpVector -> Maybe (Type Name)+takeTypeOpVector op+ = case op of+ -- Maps ---------------------------------+ -- map :: [a b : Data]+ -- . (a -> b) -> Vector a -> Vector b+ OpVectorMap 1+ -> Just $ tForalls [kData, kData] $ \[tA, tB]+ -> (tA `tFun` tB)+ `tFun` tVector tA+ `tFun` tVector tB++ -- mapN :: [a0..aN : Data]+ -- . (a0 -> .. aN) -> Vector a0 -> .. Vector aN+ OpVectorMap n+ | n >= 2+ , Just tWork <- tFunOfList + [ TVar (UIx i) + | i <- reverse [0..n] ]++ , Just tBody <- tFunOfList+ (tWork : [tVector (TVar (UIx i)) + | i <- reverse [0..n] ])++ -> Just $ foldr TForall tBody+ [ BAnon k | k <- replicate (n + 1) kData ]++ -- Selectors ----------------------------+ -- filter# :: [a : Data]+ -- . Vector a+ -- -> (a -> Bool#)+ -- -> Vector a+ OpVectorFilter+ -> Just $ tForalls [kData] $ \[tA]+ -> (tA `tFun` tBool)+ `tFun` tVector tA+ `tFun` tVector tA++ -- reduce# :: [a: Data]+ -- . (a -> a -> a) -> a -> Vector a -> a+ OpVectorReduce+ -> Just $ tForalls [kData] $ \[tA]+ -> (tA `tFun` tA `tFun` tA)+ `tFun` tA+ `tFun` tVector tA+ `tFun` tA++ -- Vector creation and filling ----------+ -- generate :: [a : Data]. Nat# -> (Nat# -> a) -> Vector a+ OpVectorGenerate+ -> Just $ tForalls [kData] $ \[tA] + -> tNat+ `tFun` (tNat `tFun` tA)+ `tFun` tVector tA++ -- length :: [a : Data]. Vector a -> Nat#+ OpVectorLength+ -> Just $ tForalls [kData] $ \[tA] + -> tVector tA `tFun` tNat++ -- gather :: [a : Data]. Vector a -> Vector Nat# -> Vector a+ OpVectorGather+ -> Just $ tForalls [kData] $ \[tA] + -> tVector tA+ `tFun` tVector tNat+ `tFun` tVector tA++ _ -> Nothing+
DDC/Core/Flow/Prim/TyConFlow.hs view
@@ -3,42 +3,70 @@ ( TyConFlow (..) , readTyConFlow , kindTyConFlow++ -- * Predicates+ , isRateNatType+ , isSeriesType+ , isRefType+ , isVectorType+ , isRateVecType+ , isBufferType+ , isProcessType++ -- * Compounds , tTuple1 , tTuple2 , tTupleN , tVector+ , tBuffer+ , tRateVec , tSeries , tSegd , tSel1 , tSel2 , tRef , tWorld- , tRateNat)+ , tRateNat+ , tRateAppend+ , tRateCross+ , tDown+ , tTail+ , tProcess+ , tResize) where import DDC.Core.Flow.Prim.KiConFlow import DDC.Core.Flow.Prim.Base-import DDC.Core.Compounds.Simple-import DDC.Core.Exp.Simple-import DDC.Base.Pretty+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp+import DDC.Data.Pretty import Control.DeepSeq import Data.Char import Data.List -instance NFData TyConFlow+instance NFData TyConFlow where+ rnf !_ = () instance Pretty TyConFlow where ppr dc = case dc of- TyConFlowTuple n -> text "Tuple" <> int n <> text "#"+ TyConFlowTuple n -> text "Tuple" <> int n <> text "#"+ TyConFlowBuffer -> text "Buffer#" TyConFlowVector -> text "Vector#"+ TyConFlowRateVec -> text "RateVec#" TyConFlowSeries -> text "Series#" TyConFlowSegd -> text "Segd#"- TyConFlowSel n -> text "Sel" <> int n <> text "#"+ TyConFlowSel n -> text "Sel" <> int n <> text "#" TyConFlowRef -> text "Ref#" TyConFlowWorld -> text "World#" TyConFlowRateNat -> text "RateNat#"+ TyConFlowRateCross -> text "RateCross#"+ TyConFlowRateAppend -> text "RateAppend#"+ TyConFlowDown n -> text "Down" <> int n <> text "#"+ TyConFlowTail n -> text "Tail" <> int n <> text "#"+ TyConFlowProcess -> text "Process#"+ TyConFlowResize -> text "Resize#" -- | Read a type constructor name.@@ -50,15 +78,33 @@ , arity <- read ds = Just $ TyConFlowTuple arity + | Just rest <- stripPrefix "Down" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , n <- read ds+ = Just $ TyConFlowDown n++ | Just rest <- stripPrefix "Tail" str+ , (ds, "#") <- span isDigit rest+ , not $ null ds+ , n <- read ds+ = Just $ TyConFlowTail n+ | otherwise = case str of+ "Buffer#" -> Just $ TyConFlowBuffer "Vector#" -> Just $ TyConFlowVector+ "RateVec#" -> Just $ TyConFlowRateVec "Series#" -> Just $ TyConFlowSeries "Segd#" -> Just $ TyConFlowSegd "Sel1#" -> Just $ TyConFlowSel 1 "Ref#" -> Just $ TyConFlowRef "World#" -> Just $ TyConFlowWorld "RateNat#" -> Just $ TyConFlowRateNat+ "RateCross#" -> Just $ TyConFlowRateCross+ "RateAppend#" -> Just $ TyConFlowRateAppend+ "Process#" -> Just $ TyConFlowProcess+ "Resize#" -> Just $ TyConFlowResize _ -> Nothing @@ -68,15 +114,79 @@ kindTyConFlow tc = case tc of TyConFlowTuple n -> foldr kFun kData (replicate n kData)- TyConFlowVector -> kData `kFun` kData- TyConFlowSeries -> kRate `kFun` kData `kFun` kData+ TyConFlowBuffer -> kData `kFun` kData+ TyConFlowVector -> kData `kFun` kData+ TyConFlowRateVec -> kRate `kFun` kData `kFun` kData+ TyConFlowSeries -> kProc `kFun` kRate `kFun` kData `kFun` kData TyConFlowSegd -> kRate `kFun` kRate `kFun` kData- TyConFlowSel n -> foldr kFun kData (replicate (n + 1) kRate)+ TyConFlowSel n -> kProc `kFun` foldr kFun kData (replicate (n + 1) kRate) TyConFlowRef -> kData `kFun` kData TyConFlowWorld -> kData TyConFlowRateNat -> kRate `kFun` kData+ TyConFlowRateCross -> kRate `kFun` kRate `kFun` kRate+ TyConFlowRateAppend -> kRate `kFun` kRate `kFun` kRate+ TyConFlowDown{} -> kRate `kFun` kRate+ TyConFlowTail{} -> kRate `kFun` kRate+ TyConFlowProcess -> kProc `kFun` kRate `kFun` kData+ TyConFlowResize -> kProc `kFun` kRate `kFun` kRate `kFun` kData +-- Predicates -----------------------------------------------------------------+-- | Check if some type is a fully applied type of a RateNat+isRateNatType :: Type Name -> Bool+isRateNatType tt+ = case takePrimTyConApps tt of+ Just (NameTyConFlow TyConFlowRateNat, [_]) -> True+ _ -> False+++-- | Check if some type is a fully applied type of a Series.+isSeriesType :: Type Name -> Bool+isSeriesType tt+ = case takePrimTyConApps tt of+ Just (NameTyConFlow TyConFlowSeries, [_, _, _]) -> True+ _ -> False+++-- | Check if some type is a fully applied type of a Ref.+isRefType :: Type Name -> Bool+isRefType tt+ = case takePrimTyConApps tt of+ Just (NameTyConFlow TyConFlowRef, [_]) -> True+ _ -> False+++-- | Check if some type is a fully applied type of a Vector.+isVectorType :: Type Name -> Bool+isVectorType tt+ = case takePrimTyConApps tt of+ Just (NameTyConFlow TyConFlowVector, [_]) -> True+ _ -> False+++-- | Check if some type is a fully applied type of a Buffer.+isBufferType :: Type Name -> Bool+isBufferType tt+ = case takePrimTyConApps tt of+ Just (NameTyConFlow TyConFlowBuffer, [_]) -> True+ _ -> False++-- | Check if some type is a fully applied type of a RateVec.+isRateVecType :: Type Name -> Bool+isRateVecType tt+ = case takePrimTyConApps tt of+ Just (NameTyConFlow TyConFlowRateVec, [_, _])-> True+ _ -> False++-- | Check if some type is a fully applied Process.+isProcessType :: Type Name -> Bool+isProcessType tt+ = case takePrimTyConApps tt of+ Just (NameTyConFlow TyConFlowProcess, [_, _]) -> True+ _ -> False+++ -- Compounds ------------------------------------------------------------------ tTuple1 :: Type Name -> Type Name tTuple1 tA = tApps (tConTyConFlow (TyConFlowTuple 1)) [tA]@@ -90,24 +200,31 @@ tTupleN tys = tApps (tConTyConFlow (TyConFlowTuple (length tys))) tys -tVector :: Type Name -> Type Name+tBuffer :: Type Name -> Type Name+tBuffer tA = tApps (tConTyConFlow TyConFlowBuffer) [tA]+++tVector :: Type Name -> Type Name tVector tA = tApps (tConTyConFlow TyConFlowVector) [tA] +tRateVec :: Type Name -> Type Name -> Type Name+tRateVec tK tA = tApps (tConTyConFlow TyConFlowRateVec) [tK, tA] -tSeries :: Type Name -> Type Name -> Type Name-tSeries tK tA = tApps (tConTyConFlow TyConFlowSeries) [tK, tA] +tSeries :: Type Name -> Type Name -> Type Name -> Type Name+tSeries tP tK tA = tApps (tConTyConFlow TyConFlowSeries) [tP, tK, tA] + tSegd :: Type Name -> Type Name -> Type Name tSegd tK1 tK2 = tApps (tConTyConFlow TyConFlowSegd) [tK1, tK2] -tSel1 :: Type Name -> Type Name -> Type Name-tSel1 tK1 tK2 = tApps (tConTyConFlow $ TyConFlowSel 1) [tK1, tK2]+tSel1 :: Type Name -> Type Name -> Type Name -> Type Name+tSel1 tP tK1 tK2 = tApps (tConTyConFlow $ TyConFlowSel 1) [tP, tK1, tK2] -tSel2 :: Type Name -> Type Name -> Type Name -> Type Name-tSel2 tK1 tK2 tK3 = tApps (tConTyConFlow $ TyConFlowSel 2) [tK1, tK2, tK3]+tSel2 :: Type Name -> Type Name -> Type Name -> Type Name -> Type Name+tSel2 tP tK1 tK2 tK3 = tApps (tConTyConFlow $ TyConFlowSel 2) [tP, tK1, tK2, tK3] tRef :: Type Name -> Type Name@@ -119,7 +236,31 @@ tRateNat :: Type Name -> Type Name-tRateNat tK = tApps (tConTyConFlow TyConFlowRateNat) [tK]+tRateNat tK = tApp (tConTyConFlow TyConFlowRateNat) tK++tRateCross :: Type Name -> Type Name -> Type Name+tRateCross tKa tKb = tConTyConFlow TyConFlowRateCross `tApps` [tKa, tKb]++tRateAppend :: Type Name -> Type Name -> Type Name+tRateAppend tKa tKb = tConTyConFlow TyConFlowRateAppend `tApps` [tKa, tKb]++++tDown :: Int -> Type Name -> Type Name +tDown n tK = tApp (tConTyConFlow $ TyConFlowDown n) tK+++tTail :: Int -> Type Name -> Type Name +tTail n tK = tApp (tConTyConFlow $ TyConFlowTail n) tK+++tProcess :: Type Name -> Type Name -> Type Name +tProcess tP tK = (tConTyConFlow TyConFlowProcess) `tApps` [tP, tK]++tResize :: Type Name -> Type Name -> Type Name -> Type Name +tResize tP tJ tK = (tConTyConFlow TyConFlowResize) `tApps` [tP, tJ, tK]++ -- Utils ----------------------------------------------------------------------
DDC/Core/Flow/Prim/TyConPrim.hs view
@@ -5,11 +5,13 @@ , tBool , tNat , tInt- , tWord)+ , tFloat+ , tWord+ , tVec) where import DDC.Core.Flow.Prim.Base-import DDC.Core.Compounds.Simple-import DDC.Core.Exp.Simple+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp -- | Yield the kind of a type constructor.@@ -17,15 +19,17 @@ kindPrimTyCon tc = case tc of PrimTyConVoid -> kData- PrimTyConPtr -> (kRegion `kFun` kData `kFun` kData)+ PrimTyConPtr -> kRegion `kFun` kData `kFun` kData PrimTyConAddr -> kData PrimTyConBool -> kData PrimTyConNat -> kData PrimTyConInt -> kData+ PrimTyConSize -> kData PrimTyConWord _ -> kData PrimTyConFloat _ -> kData PrimTyConTag -> kData- PrimTyConString -> kData+ PrimTyConTextLit -> kData+ PrimTyConVec _ -> kData `kFun` kData -- Compounds ------------------------------------------------------------------@@ -40,18 +44,35 @@ -- | Primitive Nat# type. tNat :: Type Name-tNat = TCon (TyConBound (UPrim (NamePrimTyCon PrimTyConInt) kData) kData)+tNat = TCon (TyConBound (UPrim (NamePrimTyCon PrimTyConNat) kData) kData) -- | Primitive `Int#` type. tInt :: Type Name-tInt = TCon (TyConBound (UPrim (NamePrimTyCon PrimTyConInt) kData) kData)+tInt = TCon (TyConBound (UPrim (NamePrimTyCon PrimTyConInt) kData) kData) +-- | Primitive `FloatN#` type of the given width.+tFloat :: Int -> Type Name+tFloat bits+ = TCon (TyConBound (UPrim (NamePrimTyCon (PrimTyConFloat bits)) kData) kData)++ -- | Primitive `WordN#` type of the given width. tWord :: Int -> Type Name tWord bits = TCon (TyConBound (UPrim (NamePrimTyCon (PrimTyConWord bits)) kData) kData) +-- | Primitive @VecN# a@.+tVec :: Int -> Type Name -> Type Name+tVec n tA = TApp (tConPrimTyCon (PrimTyConVec n)) tA ++-- Utils ----------------------------------------------------------------------+tConPrimTyCon :: PrimTyCon -> Type Name+tConPrimTyCon tcp+ = let k = kindPrimTyCon tcp+ u = UPrim (NamePrimTyCon tcp) k+ tc = TyConBound u k+ in TCon tc
DDC/Core/Flow/Procedure.hs view
@@ -15,20 +15,14 @@ import DDC.Core.Flow.Exp import DDC.Core.Flow.Prim import DDC.Core.Flow.Context-import Data.Monoid -- | An imperative procedure made up of some loops. data Procedure = Procedure { procedureName :: Name- , procedureParamTypes :: [BindF]- , procedureParamValues :: [BindF]- , procedureNest :: Nest- , procedureStmts :: [LetsF]- , procedureResult :: ExpF- , procedureResultType :: TypeF }-+ , procedureParamFlags :: [(Bool,BindF)]+ , procedureNest :: Nest } -- | A loop nest. data Nest@@ -37,20 +31,31 @@ | NestList { nestList :: [Nest]} + -- Used to define the outer loop of a process. | NestLoop { nestRate :: Type Name , nestStart :: [StmtStart] , nestBody :: [StmtBody] , nestInner :: Nest- , nestEnd :: [StmtEnd] - , nestResult :: Exp () Name }+ , nestEnd :: [StmtEnd] } - | NestIf+ -- Guarded context, + -- used when lowering pack-like operations.+ | NestGuard { nestOuterRate :: Type Name , nestInnerRate :: Type Name , nestFlags :: Bound Name , nestBody :: [StmtBody] , nestInner :: Nest }++ -- Segmented context,+ -- used when lowering segmented operations.+ | NestSegment+ { nestOuterRate :: Type Name+ , nestInnerRate :: Type Name+ , nestLength :: Bound Name+ , nestBody :: [StmtBody]+ , nestInner :: Nest } deriving Show @@ -70,13 +75,18 @@ -- | Statements that can appear at the start of a loop. -- These initialise accumulators. data StmtStart- -- Allocate a new vector.- = StartVecNew+ -- | Evaluate a pure expression+ = StartStmt+ { startResultBind :: Bind Name+ , startExpression :: Exp () Name }++ -- | Allocate a new vector.+ | StartVecNew { startVecNewName :: Name , startVecNewElemType :: Type Name , startVecNewRate :: Type Name } - -- Inititlise a new accumulator.+ -- | Inititlise a new accumulator. | StartAcc { startAccName :: Name , startAccType :: Type Name@@ -140,8 +150,7 @@ -- | Statements that appear after a loop to cleanup. data StmtEnd- -- | Pure ending statements to produce the result of - -- the overall process.+ -- | Generic ending statements. = EndStmt { endBind :: Bind Name , endExp :: Exp () Name }@@ -152,10 +161,9 @@ , endType :: Type Name , endAccName :: Name } - -- | Destructively slice down a vector to its final size.- | EndVecSlice+ -- | Destructively truncate a vector to its final size.+ | EndVecTrunc { endVecName :: Name , endVecType :: Type Name- , endVecRate :: Type Name }+ , endVecAcc :: Bound Name } deriving Show-
DDC/Core/Flow/Process.hs view
@@ -1,6 +1,7 @@ module DDC.Core.Flow.Process ( Process (..)+ , Operator (..)) where import DDC.Core.Flow.Process.Process
DDC/Core/Flow/Process/Operator.hs view
@@ -1,6 +1,7 @@ module DDC.Core.Flow.Process.Operator- (Operator (..))+ ( Operator (..)+ , bindOfOp) where import DDC.Core.Flow.Exp @@ -29,95 +30,264 @@ } ------------------------------------------ -- | Convert a series to a manifest vector.- | OpCreate- { -- | Binder for result vector- opResultVector :: BindF+ -- | Flat replicate.+ | OpRep+ { -- Binder for result series.+ opResultSeries :: BindF - -- | Rate of input series- , opInputRate :: TypeF+ -- Rate of output series.+ , opOutputRate :: TypeF - -- | Bound of input series.- , opInputSeries :: BoundF+ -- Type of the elements.+ , opElemType :: TypeF - -- | Rate that should be used when allocating the vector.- -- This is filled in by `patchAllocRates`.- , opAllocRate :: Maybe TypeF+ -- Exp to compute the element to be replicated.+ , opInputExp :: ExpF } - -- | Type of the elements.+ -----------------------------------------+ -- | Segmented replicate.+ | OpReps+ { -- Binder for result series.+ opResultSeries :: BindF++ -- Rate of input series.+ , opInputRate :: TypeF++ -- Rate of output series.+ , opOutputRate :: TypeF++ -- Type of the elements. , opElemType :: TypeF++ -- Bound for the segment descriptor.+ , opSegdBound :: BoundF++ -- Bound for the input series.+ , opInputSeries :: BoundF }++ -----------------------------------------+ -- | Segmented indices.+ | OpIndices+ { -- Binder for result series.+ opResultSeries :: BindF++ -- Rate of input series.+ , opInputRate :: TypeF++ -- Rate of output series.+ , opOutputRate :: TypeF++ -- Bound for the segment descriptor.+ , opSegdBound :: BoundF }++ -----------------------------------------+ -- | Fill a vector with elements from a series.+ | OpFill+ { -- Binder for result value (a Unit)+ opResultBind :: BindF++ -- Bound of target vector.+ , opTargetVector :: BoundF++ -- Rate of input series.+ , opInputRate :: TypeF++ -- Bound of input series.+ , opInputSeries :: BoundF ++ -- Type of the elements.+ , opElemType :: TypeF }++ -----------------------------------------+ -- | Gather elements from a vector into a series.+ | OpGather+ { -- Binder for result series.+ opResultBind :: BindF++ -- Bound of source elem vector.+ , opSourceVector :: BoundF++ -- Bound of source index series.+ , opSourceIndices :: BoundF++ -- Rate of input and output series.+ , opInputRate :: TypeF++ -- Rate of input vector series.+ , opVectorRate :: TypeF++ -- Type of gathered elements.+ , opElemType :: TypeF } + -----------------------------------------+ -- | Scatter elements from a series into a vector.+ | OpScatter+ { -- Binder for result value (a Unit)+ opResultBind :: BindF + -- Bound of target vector.+ , opTargetVector :: BoundF++ -- Bound of source index series.+ , opSourceIndices :: BoundF++ -- Bound of source element series.+ , opSourceElems :: BoundF++ -- Rate of input serieses.+ , opInputRate :: TypeF++ -- Type of elements.+ , opElemType :: TypeF+ }+ ----------------------------------------- -- | Apply a function to corresponding elements in several input series -- of the same rate, producing a new series. This subsumes the regular -- 'map' operator as well as 'zipWith' like operators where the input -- lengths are identical. | OpMap- { -- | Arity of map, number of input streams.+ { -- Arity of map, number of input streams. opArity :: Int - -- | Binder for result series.+ -- Binder for result series. , opResultSeries :: BindF - -- | Rate of all input series.+ -- Rate of all input series. , opInputRate :: TypeF - -- | Names for input series.+ -- Names for input series. , opInputSeriess :: [BoundF] - -- | Worker input parameters+ -- Worker input parameters , opWorkerParams :: [BindF] - -- | Worker body+ -- Worker body , opWorkerBody :: ExpF } ------------------------------------------ -- | Fold all the elements of a series.- | OpFold- { -- | Binder for result value.- opResultValue :: BindF+ -- | Pack a series according to a selector.+ | OpPack+ { -- Binder for result series.+ opResultSeries :: BindF - -- | Rate of input series.+ -- Rate of input series. , opInputRate :: TypeF - -- | Bound of input series.+ -- Bound of input series. , opInputSeries :: BoundF - -- | Starting accumulator value.- , opZero :: ExpF+ -- Rate of output series.+ , opOutputRate :: TypeF - -- | Worker parameter for index input.- -- Should be BNone for OpFlowFold, but something for OpFlowFoldIndex+ -- Type of a series element.+ , opElemType :: TypeF }++ -----------------------------------------+ -- | Generate a new Series, with elements based on index+ | OpGenerate+ { -- Binder for result series.+ opResultSeries :: BindF++ -- Rate of output series.+ , opOutputRate :: TypeF++ -- Worker parameter for function index input. , opWorkerParamIndex :: BindF - -- | Worker parameter for accumulator input.+ -- Worker body.+ , opWorkerBody :: ExpF+ }++ -----------------------------------------+ -- | Reduce the elements of a series into a reference.+ | OpReduce+ { -- Binder for result value (a Unit)+ opResultBind :: BindF++ -- Bound of target Ref.+ , opTargetRef :: BoundF++ -- Rate of input series.+ , opInputRate :: TypeF++ -- Bound of input series.+ , opInputSeries :: BoundF++ -- Neutral element.+ , opZero :: ExpF++ -- Worker parameter for accumulator input. , opWorkerParamAcc :: BindF - -- | Worker parameter for element input.+ -- Worker parameter for element input. , opWorkerParamElem :: BindF - -- | Worker body.- , opWorkerBody :: ExpF }+ -- Worker body.+ , opWorkerBody :: ExpF+ } ------------------------------------------ -- | Pack a series according to a selector.- | OpPack- { -- | Binder for result series.+ -- | Convert a series from a vector+ | OpSeriesOfRateVec+ { -- Binder for result series. opResultSeries :: BindF - -- | Rate of input series.+ -- Rate of the input series. , opInputRate :: TypeF - -- | Bound of input series.- , opInputSeries :: BoundF+ -- Bound of the input vector+ , opInputRateVec :: BoundF - -- | Rate of output series.- , opOutputRate :: TypeF+ -- Type of the elements.+ , opElemType :: TypeF+ } - -- | Type of a series element.- , opElemType :: TypeF }- deriving Show+ -----------------------------------------+ -- | Use an existing series passed in as argument+ | OpSeriesOfArgument+ { -- Binder for result series.+ opResultSeries :: BindF + -- Rate of the input series.+ , opInputRate :: TypeF++ -- Type of the elements.+ , opElemType :: TypeF+ }+++ deriving (Show, Eq)++bindOfOp :: Operator -> BindF+bindOfOp o+ = case o of+ OpId{}+ -> opResultSeries o+ OpRep{}+ -> opResultSeries o+ OpReps{}+ -> opResultSeries o+ OpIndices{}+ -> opResultSeries o+ OpMap{}+ -> opResultSeries o+ OpPack{}+ -> opResultSeries o+ OpGenerate{}+ -> opResultSeries o+ OpSeriesOfRateVec{}+ -> opResultSeries o+ OpSeriesOfArgument{}+ -> opResultSeries o++ OpFill{}+ -> opResultBind o+ OpGather{}+ -> opResultBind o+ OpScatter{}+ -> opResultBind o+ OpReduce{}+ -> opResultBind o
DDC/Core/Flow/Process/Pretty.hs view
@@ -2,46 +2,142 @@ module DDC.Core.Flow.Process.Pretty where import DDC.Core.Flow.Process.Process import DDC.Core.Flow.Process.Operator-import DDC.Base.Pretty-import DDC.Type.Pretty ()+import DDC.Core.Flow.Context+import DDC.Core.Pretty ()+import DDC.Data.Pretty instance Pretty Process where ppr p = vcat $ [ ppr (processName p)- , text " result type: " <> ppr (processResultType p)- , text " parameters: " <> ppr (processParamValues p) ]- ++ map (indent 2 . ppr) (processOperators p)+ , text " parameters: " <> ppr (processParamFlags p) + , indent 2 $ ppr $ processContext p ] +instance Pretty Context where+ ppr cc+ = case cc of+ ContextRate{}+ -> vcat+ $ [ text "Rate " <> ppr (contextRate cc) ]+ ++ ops+ ++ inner+ ContextSelect{}+ -> vcat+ $ [ text "Select " <> ppr (contextInnerRate cc) <> text " <= " <> ppr (contextOuterRate cc)+ , text " flags: " <> ppr (contextFlags cc) + , text " sel: " <> ppr (contextSelector cc) ]+ ++ ops+ ++ inner+ ContextSegment{}+ -> vcat+ $ [ text "Segment " <> ppr (contextInnerRate cc) <> text " <= " <> ppr (contextOuterRate cc)+ , text " lens: " <> ppr (contextLens cc) + , text " segd: " <> ppr (contextSegd cc) ]+ ++ ops+ ++ inner+ ContextAppend{}+ -> vcat+ $ [ text "Append " <> ppr (contextRate1 cc) <> text " " <> ppr (contextRate2 cc)+ , indent 2 $ ppr $ contextInner1 cc+ , indent 2 $ ppr $ contextInner2 cc ]++ where+ ops = map (indent 2 . ppr) (contextOps cc)+ inner = map (indent 2 . ppr) (contextInner cc)++ instance Pretty Operator where ppr op@OpId{} = vcat [ text "Id"- , text " rate: " <> ppr (opInputRate op)- , text " input: " <> ppr (opInputSeries op)- , text " result: " <> ppr (opResultSeries op) ]+ , text " rate: " <> ppr (opInputRate op)+ , text " input: " <> ppr (opInputSeries op)+ , text " result: " <> ppr (opResultSeries op) ] - ppr op@OpCreate{}+ ppr op@OpRep{} = vcat- [ text "Create"- , text " rate: " <> ppr (opInputRate op)- , text " input: " <> ppr (opInputSeries op) - , text " result: " <> ppr (opResultVector op) ]+ [ text "Rep"+ , text " result: " <> ppr (opResultSeries op)+ , text " output rate: " <> ppr (opOutputRate op)+ , text " type: " <> ppr (opElemType op) ] - ppr op@OpMap{}+ ppr op@OpReps{} = vcat- [ text "Map"- , text " rate: " <> ppr (opInputRate op) ]+ [ text "Reps"+ , text " result: " <> ppr (opResultSeries op)+ , text " input rate: " <> ppr (opInputRate op)+ , text " output rate: " <> ppr (opOutputRate op)+ , text " type: " <> ppr (opElemType op)+ , text " segd: " <> ppr (opSegdBound op)+ , text " input: " <> ppr (opInputSeries op) ]+ + ppr op@OpIndices{}+ = vcat+ [ text "Indices"+ , text " result: " <> ppr (opResultSeries op)+ , text " input rate: " <> ppr (opInputRate op)+ , text " output rate: " <> ppr (opOutputRate op) ] - ppr op@OpFold{}+ ppr op@OpFill{} = vcat- [ text "Fold"- , text " rate: " <> ppr (opInputRate op) ]+ [ text "Fill"+ , text " target: " <> ppr (opTargetVector op)+ , text " input: " <> ppr (opInputSeries op) ] + ppr op@OpGather{}+ = vcat+ [ text "Gather"+ , text " result: " <> ppr (opResultBind op)+ , text " vector: " <> ppr (opSourceVector op)+ , text " indices: " <> ppr (opSourceIndices op)+ , text " rate: " <> ppr (opInputRate op)+ , text " type: " <> ppr (opElemType op) ]++ ppr op@OpScatter{}+ = vcat+ [ text "Scatter"+ , text " vector: " <> ppr (opTargetVector op)+ , text " indices: " <> ppr (opSourceIndices op)+ , text " elems: " <> ppr (opSourceElems op)+ , text " rate: " <> ppr (opInputRate op)+ , text " type: " <> ppr (opElemType op) ]++ ppr op@OpGenerate{}+ = vcat+ [ text "Generate"+ , text " rate: " <> ppr (opOutputRate op) ]++ ppr op@OpReduce{}+ = vcat+ [ text "Reduce"+ , text " rate: " <> ppr (opInputRate op)+ , text " input: " <> ppr (opInputSeries op) ]++ ppr op@OpMap{}+ = vcat+ [ text "Map"+ , text " rate: " <> ppr (opInputRate op)+ , text " result: " <> ppr (opResultSeries op) ]+ ppr op@OpPack{} = vcat [ text "Pack"- , text " input rate: " <> ppr (opInputRate op) - , text " output rate: " <> ppr (opOutputRate op) ]+ , text " input rate: " <> ppr (opInputRate op) + , text " output rate: " <> ppr (opOutputRate op) ]++ ppr op@OpSeriesOfRateVec{}+ = vcat+ [ text "SeriesOfRateVec"+ , text " rate: " <> ppr (opInputRate op)+ , text " input: " <> ppr (opInputRateVec op)+ , text " result: " <> ppr (opResultSeries op) ]++ ppr op@OpSeriesOfArgument{}+ = vcat+ [ text "SeriesOfArgument"+ , text " rate: " <> ppr (opInputRate op)+ , text " result: " <> ppr (opResultSeries op) ]++
DDC/Core/Flow/Process/Process.hs view
@@ -1,18 +1,14 @@ module DDC.Core.Flow.Process.Process- (Process (..))+ ( Process (..)) where-import DDC.Core.Flow.Process.Operator import DDC.Core.Flow.Context import DDC.Core.Flow.Prim import DDC.Core.Flow.Exp --- | A process applies some series operators and produces some non-series--- result.------ We get one of these for each top-level series function in the--- original program.+-- | A process is a graph of series operators that read from some parameter+-- series and write to some accumulators. data Process = Process { -- | Name of whole process.@@ -20,36 +16,20 @@ -- source code. processName :: Name - -- | Type parameters to process.- -- These are the type parameters of the original function.- , processParamTypes :: [BindF]+ -- | Proc type+ , processProcType :: TypeF - -- | Value parameters to process.- -- These are the value parameters of the original function.- , processParamValues :: [BindF]+ -- | Rate of process loop+ , processLoopRate :: TypeF - -- | Flow contexts in this process.+ -- | Parameters to process.+ -- These are the parameters of the original function, with flag being true for types.+ , processParamFlags :: [(Bool, BindF)]++ -- | Flow context in this process. -- This contains a ContextRate entry for all the Rate variables -- in the parameters, along with an entry for all the nested -- contexts introduced by the process itself.- , processContexts :: [Context]-- -- | Flow operators in this process.- , processOperators :: [Operator] -- -- | Top-level statements that don't invoke stream operators.- -- These are typically statements that combine reduction results, - -- like the addition in (fold (+) 0 s1 + fold (*) 1 s1).- -- - -- INVARIANT: - -- The worker functions for stream operators do not mention- -- any of the bound variables. - , processStmts :: [LetsF]-- -- Type of process result- , processResultType :: TypeF-- -- Final result of process.- , processResult :: ExpF+ , processContext :: Context }
DDC/Core/Flow/Profile.hs view
@@ -12,7 +12,7 @@ import DDC.Core.Fragment import DDC.Core.Lexer import DDC.Type.Exp-import DDC.Data.Token+import DDC.Data.SourcePos import Control.Monad.State.Strict import DDC.Type.Env (Env) import qualified DDC.Type.Env as Env@@ -25,15 +25,27 @@ { profileName = "Flow" , profileFeatures = features , profilePrimDataDefs = primDataDefs- , profilePrimSupers = primSortEnv , profilePrimKinds = primKindEnv , profilePrimTypes = primTypeEnv+ , profileTypeIsUnboxed = const False + , profileNameIsHole = Nothing + , profileMakeLiteralName = Just makeLiteralName } - -- We don't need to distinguish been boxed and unboxed- -- because we allow unboxed instantiation.- , profileTypeIsUnboxed = const False } +-- | Convert a literal to a Salt name.+makeLiteralName :: SourcePos -> Literal -> Bool -> Maybe Name+makeLiteralName _ lit True+ = case lit of+ LNat n -> Just $ NameLitNat n+ LInt i -> Just $ NameLitInt i+ LWord i b -> Just $ NameLitWord i b+ LFloat f b -> Just $ NameLitFloat (toRational f) b+ _ -> Nothing +makeLiteralName _ _ _+ = Nothing++ features :: Features features = Features@@ -41,10 +53,14 @@ , featuresTrackedClosures = False , featuresFunctionalEffects = False , featuresFunctionalClosures = False+ , featuresEffectCapabilities = False+ , featuresImplicitRun = False+ , featuresImplicitBox = False , featuresPartialPrims = True , featuresPartialApplication = True , featuresGeneralApplication = True , featuresNestedFunctions = True+ , featuresGeneralLetRec = False , featuresDebruijnBinders = True , featuresUnboundLevel0Vars = False , featuresUnboxedInstantiation = True@@ -56,25 +72,27 @@ -- | Lex a string to tokens, using primitive names. -- -- The first argument gives the starting source line number.-lexModuleString :: String -> Int -> String -> [Token (Tok Name)]+lexModuleString :: String -> Int -> String -> [Located (Token Name)] lexModuleString sourceName lineStart str = map rn $ lexModuleWithOffside sourceName lineStart str- where rn (Token strTok sp) - = case renameTok readName strTok of- Just t' -> Token t' sp- Nothing -> Token (KJunk "lexical error") sp+ where + rn (Located sp strTok) + = case renameToken readName strTok of+ Just t' -> Located sp t'+ Nothing -> Located sp (KErrorJunk "lexical error") -- | Lex a string to tokens, using primitive names. -- -- The first argument gives the starting source line number.-lexExpString :: String -> Int -> String -> [Token (Tok Name)]+lexExpString :: String -> Int -> String -> [Located (Token Name)] lexExpString sourceName lineStart str = map rn $ lexExp sourceName lineStart str- where rn (Token strTok sp) - = case renameTok readName strTok of- Just t' -> Token t' sp- Nothing -> Token (KJunk "lexical error") sp+ where+ rn (Located sp strTok) + = case renameToken readName strTok of+ Just t' -> Located sp t'+ Nothing -> Located sp (KErrorJunk "lexical error") -- | Create a new type variable name that is not in the given environment.
+ DDC/Core/Flow/Transform/Annotate.hs view
@@ -0,0 +1,88 @@++module DDC.Core.Flow.Transform.Annotate+ (Annotate (..))+where+import qualified DDC.Core.Exp.Annot as A+import qualified DDC.Core.Flow.Exp.Simple.Exp as S+++-- | Convert the `Simple` version of the AST to the `Annot` version,+-- using a the provided default annotation value.+class Annotate + (c1 :: * -> * -> *) + (c2 :: * -> * -> *) | c1 -> c2 + where+ annotate :: a -> c1 a n -> c2 a n+++instance Annotate S.Exp A.Exp where+ annotate def xx+ = let down = annotate def+ in case xx of+ S.XAnnot _ (S.XAnnot a x) -> down (S.XAnnot a x)+ S.XAnnot a (S.XVar u) -> A.XVar a u+ S.XAnnot a (S.XCon dc) -> A.XCon a dc+ S.XAnnot a (S.XLAM b x) -> A.XLAM a b (down x)+ S.XAnnot a (S.XLam b x) -> A.XLam a b (down x)+ S.XAnnot a (S.XApp x1 x2) -> A.XApp a (down x1) (down x2)+ S.XAnnot a (S.XLet lts x) -> A.XLet a (down lts) (down x)+ S.XAnnot a (S.XCase x alts) -> A.XCase a (down x) (map down alts)+ S.XAnnot a (S.XCast c x) -> A.XCast a (down c) (down x)+ S.XAnnot a (S.XType t) -> A.XType a t+ S.XAnnot a (S.XWitness w) -> A.XWitness a (down w)++ S.XVar u -> A.XVar def u+ S.XCon dc -> A.XCon def dc+ S.XLAM b x -> A.XLAM def b (down x)+ S.XLam b x -> A.XLam def b (down x)+ S.XApp x1 x2 -> A.XApp def (down x1) (down x2)+ S.XLet lts x -> A.XLet def (down lts) (down x)+ S.XCase x alts -> A.XCase def (down x) (map down alts)+ S.XCast c x -> A.XCast def (down c) (down x)+ S.XType t -> A.XType def t+ S.XWitness w -> A.XWitness def (down w)+++instance Annotate S.Cast A.Cast where+ annotate def cc+ = let down = annotate def+ in case cc of+ S.CastWeakenEffect eff -> A.CastWeakenEffect eff+ S.CastPurify w -> A.CastPurify (down w)+ S.CastBox -> A.CastBox+ S.CastRun -> A.CastRun+++instance Annotate S.Lets A.Lets where+ annotate def lts+ = let down = annotate def+ in case lts of+ S.LLet b x -> A.LLet b (down x)+ S.LRec bxs -> A.LRec [(b, down x) | (b, x) <- bxs]+ S.LPrivate bks mT bts -> A.LPrivate bks mT bts+++instance Annotate S.Alt A.Alt where+ annotate def alt+ = let down = annotate def+ in case alt of+ S.AAlt S.PDefault x -> A.AAlt A.PDefault (down x)+ S.AAlt (S.PData dc bs) x -> A.AAlt (A.PData dc bs) (down x)+++instance Annotate S.Witness A.Witness where+ annotate def wit+ = let down = annotate def+ in case wit of+ S.WAnnot _ (S.WAnnot a x) -> down (S.WAnnot a x)+ S.WAnnot a (S.WVar u) -> A.WVar a u+ S.WAnnot a (S.WCon wc) -> A.WCon a wc+ S.WAnnot a (S.WApp w1 w2) -> A.WApp a (down w1) (down w2)+ S.WAnnot a (S.WType t) -> A.WType a t++ S.WVar u -> A.WVar def u+ S.WCon dc -> A.WCon def dc + S.WApp x1 x2 -> A.WApp def (down x1) (down x2)+ S.WType t -> A.WType def t++
DDC/Core/Flow/Transform/Concretize.hs view
@@ -6,8 +6,9 @@ import DDC.Core.Flow.Compounds import DDC.Core.Flow.Prim import DDC.Core.Flow.Exp-import DDC.Core.Transform.TransformUpX-import qualified DDC.Type.Env as Env+import DDC.Core.Flow.Transform.TransformUpX+import DDC.Core.Env.EnvX (EnvX)+import qualified DDC.Core.Env.EnvX as EnvX import qualified Data.Map as Map @@ -15,70 +16,111 @@ -- use value level ones. concretizeModule :: Module () Name -> Module () Name concretizeModule mm- = transformSimpleUpX concretizeX Env.empty Env.empty mm+ = transformSimpleUpX concretizeX EnvX.empty mm -- | Rewrite an expression to use concrete operators. concretizeX - :: KindEnvF -> TypeEnvF+ :: EnvX Name -> ExpF -> Maybe ExpF -concretizeX _kenv tenv xx+concretizeX env xx -- loop# -> loopn#- | Just ( NameOpLoop OpLoopLoop+ -- using an existing RateNat in the environment.+ | Just ( NameOpControl OpControlLoop , [XType tK, xF]) <- takeXPrimApps xx- , Just (nS, _, tA) <- findSeriesWithRate tenv tK- , xS <- XVar (UName nS)+ , Just nRN <- findRateNatWithRate env tK+ , xRN <- XVar (UName nRN)+ = Just+ $ xLoopN tK xRN xF++ -- loop# -> loopn#+ -- using the length of a series to get the rate.+ | Just ( NameOpControl OpControlLoop+ , [XType tK, xF]) <- takeXPrimApps xx+ , Just (nS, tP, _, tA) <- findSeriesWithRate env tK+ , xS <- XVar (UName nS) = Just - $ xLoopLoopN + $ xLoopN tK -- type level rate- (xRateOfSeries tK tA xS) -- + (xRateOfSeries tP tK tA xS) -- xF -- loop body - -- newVectorR# -> newVectorN#+ -- newVectorR# -> newVector# | Just ( NameOpStore OpStoreNewVectorR , [XType tA, XType tK]) <- takeXPrimApps xx- , Just (nS, _, tS) <- findSeriesWithRate tenv tK- , xS <- XVar (UName nS)+ , Just (nS, tP, _, tS) <- findSeriesWithRate env tK+ , xS <- XVar (UName nS) = Just- $ xNewVectorN- tA tK- (xRateOfSeries tK tS xS)+ $ xNewVector+ tA+ (xNatOfRateNat tK $ xRateOfSeries tP tK tS xS) | otherwise = Nothing --- | Search the given environment for the name of a series with the+-------------------------------------------------------------------------------+-- | Search the given environment for the name of a RateNat with the -- given rate parameter. We only look at named binders.+findRateNatWithRate + :: EnvX Name -- ^ Type Environment.+ -> Type Name -- ^ Rate type.+ -> Maybe Name+ -- ^ RateNat name+findRateNatWithRate env tR+ = go (Map.toList (EnvX.envxMap env))+ where go [] = Nothing+ go ((n, tRN) : moar)+ | isRateNatTypeOfRate tR tRN = Just n+ | otherwise = go moar+++-- | Check whether some type is a RateNat type of the given rate.+isRateNatTypeOfRate + :: Type Name -> Type Name + -> Bool++isRateNatTypeOfRate tR tRN+ | Just ( NameTyConFlow TyConFlowRateNat+ , [tR']) <- takePrimTyConApps tRN+ , tR == tR'+ = True++ | otherwise+ = False+++-------------------------------------------------------------------------------+-- | Search the given environment for the name of a series with the+-- given result rate parameter. We only look at named binders. findSeriesWithRate - :: TypeEnvF -- ^ Type Environment.+ :: EnvX Name -- ^ Type Environment. -> Type Name -- ^ Rate type.- -> Maybe (Name, Type Name, Type Name)- -- ^ Series name, rate type, element type.-findSeriesWithRate tenv tR- = go (Map.toList (Env.envMap tenv))- where - go [] = Nothing+ -> Maybe (Name, Type Name, Type Name, Type Name)+ -- ^ Series name, process, result rate, element type.+findSeriesWithRate env tK+ = go (Map.toList (EnvX.envxMap env))+ where go [] = Nothing go ((n, tS) : moar)- = case isSeriesTypeOfRate tR tS of- Nothing -> go moar- Just (_, tA) -> Just (n, tR, tA)+ = case isSeriesTypeOfRate tK tS of+ Nothing -> go moar+ Just (tP, _, tA) -> Just (n, tP, tK, tA) -- | Given a rate type and a stream type, check whether the stream--- is of the given rate. If it is then return the rate and element--- types, otherwise `Nothing`.+-- is of the given result rate. If it is then return the process, result rate,+-- loop rate and element types, otherwise `Nothing`. isSeriesTypeOfRate :: Type Name -> Type Name - -> Maybe (Type Name, Type Name)+ -> Maybe (Type Name, Type Name, Type Name) -isSeriesTypeOfRate tR tS+isSeriesTypeOfRate tK tS | Just ( NameTyConFlow TyConFlowSeries- , [tR', tA]) <- takePrimTyConApps tS- , tR == tR'- = Just (tR, tA)+ , [tP, tK', tA]) <- takePrimTyConApps tS+ , tK == tK'+ = Just (tP, tK, tA) | otherwise = Nothing
+ DDC/Core/Flow/Transform/Deannotate.hs view
@@ -0,0 +1,74 @@++module DDC.Core.Flow.Transform.Deannotate+ (Deannotate(..))+where+import qualified DDC.Core.Exp.Annot as A+import qualified DDC.Core.Flow.Exp.Simple.Exp as S+++-- | Convert the `Annot` version of the AST to the `Simple` version,+-- using the provided function to decide when to keep the annotation.+class Deannotate + (c1 :: * -> * -> *)+ (c2 :: * -> * -> *) | c1 -> c2+ where + deannotate :: (a -> Maybe a) -> c1 a n -> c2 a n+++instance Deannotate A.Exp S.Exp where+ deannotate f xx+ = let down = deannotate f + wrap a x = case f a of+ Nothing -> x+ Just a' -> S.XAnnot a' x+ in case xx of+ A.XVar a u -> wrap a (S.XVar u)+ A.XCon a dc -> wrap a (S.XCon dc)+ A.XLAM a b x -> wrap a (S.XLAM b (down x))+ A.XLam a b x -> wrap a (S.XLam b (down x))+ A.XApp a x1 x2 -> wrap a (S.XApp (down x1) (down x2))+ A.XLet a lts x2 -> wrap a (S.XLet (down lts) (down x2))+ A.XCase a x alts -> wrap a (S.XCase (down x) (map down alts))+ A.XCast a cc x -> wrap a (S.XCast (down cc) (down x))+ A.XType a t -> wrap a (S.XType t)+ A.XWitness a w -> wrap a (S.XWitness (down w))+++instance Deannotate A.Lets S.Lets where+ deannotate f lts+ = let down = deannotate f+ in case lts of+ A.LLet b x -> S.LLet b (down x)+ A.LRec bxs -> S.LRec [(b, down x) | (b, x) <- bxs]+ A.LPrivate bks mt bts -> S.LPrivate bks mt bts+++instance Deannotate A.Alt S.Alt where+ deannotate f aa+ = case aa of+ A.AAlt A.PDefault x -> S.AAlt S.PDefault (deannotate f x)+ A.AAlt (A.PData dc bs) x -> S.AAlt (S.PData dc bs) (deannotate f x)+++instance Deannotate A.Witness S.Witness where+ deannotate f ww+ = let down = deannotate f+ wrap a x = case f a of+ Nothing -> x+ Just a' -> S.WAnnot a' x+ in case ww of+ A.WVar a u -> wrap a (S.WVar u)+ A.WCon a wc -> wrap a (S.WCon wc)+ A.WApp a w1 w2 -> wrap a (S.WApp (down w1) (down w2))+ A.WType a t -> wrap a (S.WType t)+++instance Deannotate A.Cast S.Cast where+ deannotate f cc+ = let down = deannotate f+ in case cc of+ A.CastWeakenEffect e -> S.CastWeakenEffect e+ A.CastPurify w -> S.CastPurify (down w)+ A.CastBox -> S.CastBox+ A.CastRun -> S.CastRun+
DDC/Core/Flow/Transform/Extract.hs view
@@ -1,13 +1,14 @@ module DDC.Core.Flow.Transform.Extract- (extractModule)+ ( extractModule+ , extractProcedure) where-import DDC.Core.Flow.Transform.Extract.Intersperse import DDC.Core.Flow.Compounds import DDC.Core.Flow.Procedure import DDC.Core.Flow.Prim+import DDC.Core.Flow.Prim.OpStore import DDC.Core.Flow.Exp-import DDC.Core.Transform.Annotate+import DDC.Core.Flow.Transform.Annotate import DDC.Core.Module @@ -27,43 +28,56 @@ -- | Extract code for a whole procedure. extractProcedure :: Procedure -> (Bind Name, ExpF)-extractProcedure (Procedure n bsParam xsParam nest stmts xResult tResult)- = let tBody = foldr tFun tResult $ map typeOfBind xsParam- tQuant = foldr TForall tBody $ bsParam- in ( BName n tQuant- , xLAMs bsParam- $ xLams xsParam- $ extractNest nest stmts xResult )+extractProcedure (Procedure n params nest)+ = let + tyOfFlags (True, b) rest+ = TForall b rest+ tyOfFlags (False, b) rest+ = tFun (typeOfBind b) rest + tBody = foldr tyOfFlags tUnit $ params+ in ( BName n tBody+ , makeXLamFlags params+ $ xLets (concatMap vecBuffers $ map snd $ filter (not.fst) params)+ $ extractNest nest xUnit ) +vecBuffers+ :: BindF+ -> [LetsF]+vecBuffers (BName n t)+ | isVectorType t+ , Just (_, [t']) <- takePrimTyConApps t+ = [ LLet (BName (NameVarMod n "buf") (tBuffer t'))+ (xBufOfVector t' $ XVar $ UName n) ]++vecBuffers _+ = []+ ------------------------------------------------------------------------------- -- | Extract code for a loop nest. extractNest :: Nest -- ^ Loops to run in sequence.- -> [LetsF] -- ^ Baseband statements from the source program- -- that run after the loop operators. -> ExpF -- ^ Final result of procedure. -> ExpF -extractNest nest stmts xResult- = let stmts' = intersperseStmts (extractLoop nest) stmts- in xLets stmts' xResult+extractNest nest xResult+ = xLets (extractLoop nest) xResult ------------------------------------------------------------------------------- -- | Extract code for a possibly nested loop. extractLoop :: Nest -> [LetsF] --- Code in a loop context.-extractLoop (NestLoop tRate starts bodys inner ends _result)+-- Code in the top-level loop context.+extractLoop (NestLoop tRate starts bodys inner ends) = let -- Starting statements. lsStart = concatMap extractStmtStart starts -- The loop itself. lLoop = LLet (BNone tUnit)- (xApps (XVar (UPrim (NameOpLoop OpLoopLoop) - (typeOpLoop OpLoopLoop)))+ (xApps (XVar (UPrim (NameOpControl OpControlLoop) + (typeOpControl OpControlLoop))) [ XType tRate -- loop rate , xBody ]) -- loop body @@ -83,31 +97,47 @@ in lsStart ++ [lLoop] ++ lsEnd --- Code in a select / if context.-extractLoop (NestIf _tRateOuter tRateInner uFlags stmtsBody nested)+-- Code in a guard context.+extractLoop (NestGuard _tRateOuter _tRateInner uFlags stmtsBody nested) = let -- Get the name of a single flag from the series of flags. UName nFlags = uFlags nFlag = NameVarMod nFlags "elem" xFlag = XVar (UName nFlag) - -- Make a name for the counter.- TVar (UName nK) = tRateInner- uCounter = UName (NameVarMod nK "count")-- xGuard = xLoopGuard xFlag (XVar uCounter)- ( XLam (BAnon tNat)+ xBody = xGuard xFlag + ( XLam (BNone tUnit) $ xLets (lsBody ++ lsNested) xUnit) - -- Selector context.- lsBody = concatMap extractStmtBody stmtsBody+ -- Statements in the guard context.+ lsBody = concatMap extractStmtBody stmtsBody -- Nested contexts.- lsNested = extractLoop nested+ lsNested = extractLoop nested - in [LLet (BNone tUnit) xGuard]+ in [LLet (BNone tUnit) xBody] +-- Code in a segment context.+extractLoop (NestSegment _tRateOuter _tRateInner uLengths stmtsBody nested)+ = let+ -- Get the name of a single segment length from the series of lengths.+ UName nLengths = uLengths+ nLength = NameVarMod nLengths "elem"+ xLength = XVar (UName nLength) + xBody = xSegment xLength + ( XLam (BAnon tNat) -- Index into current segment.+ $ xLets (lsBody ++ lsNested) xUnit)++ -- Statements in the segment context.+ lsBody = concatMap extractStmtBody stmtsBody ++ -- Nested contexts.+ lsNested = extractLoop nested++ in [LLet (BNone tUnit) xBody]++ extractLoop NestEmpty = [] @@ -121,7 +151,11 @@ extractStmtStart :: StmtStart -> [LetsF] extractStmtStart ss = case ss of- -- Allocate a new vector+ -- Evaluate a pure expression.+ StartStmt b x+ -> [LLet b x]++ -- Allocate a new vector. StartVecNew nVec tElem tRate' -> [LLet (BName nVec (tVector tElem)) (xNewVectorR tElem tRate') ]@@ -144,7 +178,7 @@ -- Write to a vector. BodyVecWrite nVec tElem xIx xVal -> [ LLet (BNone tUnit)- (xWriteVector tElem (XVar (UName nVec)) xIx xVal)]+ (xWriteVector tElem (XVar (UName $ NameVarMod nVec "buf")) xIx xVal)] -- Read from an accumulator. BodyAccRead n t bVar@@ -171,19 +205,17 @@ -> [LLet (BName n t) (xRead t (XVar (UName nAcc))) ] - -- Slice.- EndVecSlice nVec tElem tRate + -- Truncate a vector down to its final size.+ EndVecTrunc nVec tElem uCounter -> let -- Get the name of the counter.- TVar (UName nK) = tRate- uCounter = UName (NameVarMod nK "count")- xCounter = xRead tInt (XVar uCounter)+ xCounter = xRead tNat (XVar uCounter) xVec = XVar (UName nVec) -- Read the counter in a let since it will need to be threaded- in [ LLet (BAnon tInt)+ in [ LLet (BAnon tNat) xCounter - , LLet (BName nVec (tVector tElem)) - (xSliceVector tElem (XVar (UIx 0)) xVec) ]+ , LLet (BNone tUnit) + (xTruncVector tElem (XVar (UIx 0)) xVec) ]
− DDC/Core/Flow/Transform/Extract/Intersperse.hs
@@ -1,53 +0,0 @@--module DDC.Core.Flow.Transform.Extract.Intersperse- (intersperseStmts)-where-import DDC.Core.Flow.Compounds-import DDC.Core.Flow.Prim-import DDC.Core.Flow.Exp-import DDC.Core.Collect-import DDC.Core.Transform.Annotate-import DDC.Type.Env-import Data.List (partition, (\\))-import qualified Data.Set as Set----- | Given two lists of lets, order them so that any variables are bound before use.-intersperseStmts :: [LetsF] -> [LetsF] -> [LetsF]-intersperseStmts ls rs- = let bls = nubbish $ map takeSubstBoundsOfBinds $ map valwitBindsOfLets ls- brs = nubbish $ map takeSubstBoundsOfBinds $ map valwitBindsOfLets rs- in intersperse' (ls `zip` bls ++ rs `zip` brs)----- Because a name might be bound a couple of times --- (see extractStmtEnd:EndVecSlice)-nubbish :: [[Bound Name]] -> [[Bound Name]]-nubbish bs' = go bs' []- where go [] _ = []- go (b:bs) accs = (b \\ accs) : go bs (accs ++ b)---intersperse' - :: [(Lets () Name, [Bound Name])]- -> [Lets () Name]--intersperse' [] = []--intersperse' ((x,b):bxs)- -- Check if any of the free variables in x are bound later on.- -- If so, defer this binding...- | f <- freeXLets x- , (r:rs,os) <- partition (any (flip Set.member f) . snd) bxs- , (x', _) <- r- = x' : intersperse' (rs ++ (x, b) : os)-- -- Otherwise it's a valid binding- | otherwise- = x : intersperse' bxs---freeXLets :: LetsF -> Set.Set (Bound Name)-freeXLets ll- = freeX empty $ annotate () (XLet ll (XCon (dcBool True)))-
+ DDC/Core/Flow/Transform/Forward.hs view
@@ -0,0 +1,68 @@+module DDC.Core.Flow.Transform.Forward+ ( forwardProcesses )+where+import DDC.Core.Flow.Profile+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Prim.KiConFlow+import DDC.Core.Flow.Prim.TyConFlow+import DDC.Core.Exp.Annot+import DDC.Core.Module+import qualified DDC.Core.Simplifier as C++import qualified DDC.Core.Transform.Forward as Forward+import qualified DDC.Core.Transform.TransformModX as T++-- | Find all top-level Process bindings, and forward all non-series operators.+-- This is a bit of a hack, because lower doesn't accept any non-series bindings.+forwardProcesses :: Module () Name -> Module () Name+forwardProcesses mm+ = T.transformModLet forwardBind mm+++-- | Forward a single process binding+forwardBind :: Bind Name -> Exp () Name -> Exp () Name+forwardBind b xx++ -- If the result type of a top-level binding is a Process,+ -- we must prepare it for the lowering transform.+ -- Forward everything we can, while leaving series operators at the top.+ | isProcessType $ snd $ takeTFunAllArgResult $ typeOfBind b+ = C.result $ Forward.forwardX profile conf_process xx++ -- Otherwise do minimal forwarding, except for pushing any rate-valued functions+ -- into their runKernel#.+ | otherwise+ = C.result $ Forward.forwardX profile conf_nonproc xx+ where+ conf_process = Forward.Config isFloatable_process False+ conf_nonproc = Forward.Config isFloatable_nonproc False++ -- Deny forwarding of flow primitives.+ -- Force anything else that's used only once.+ --+ -- For lower to work, we need to forward everything except primitives,+ -- but that duplicates work. Lower should probably be changed.+ isFloatable_process lts+ = case lts of+ LLet (BName _ _) x+ | Just (n,_) <- takeXPrimApps x+ -> case n of+ NameOpConcrete _ -> Forward.FloatDeny+ NameOpControl _ -> Forward.FloatDeny+ NameOpSeries _ -> Forward.FloatDeny+ NameOpStore _ -> Forward.FloatDeny+ NameOpVector _ -> Forward.FloatDeny++ _ -> Forward.FloatForceUsedOnce+ _ -> Forward.FloatForceUsedOnce+++ -- Forward any Process functions - they will have Rate foralls inside them.+ isFloatable_nonproc lts+ = case lts of+ LLet _ x+ | Just (lams,_) <- takeXLamFlags x+ , any (\(_,bo) -> typeOfBind bo == kRate) lams+ -> Forward.FloatForce+ _ -> Forward.FloatAllow+
+ DDC/Core/Flow/Transform/Melt.hs view
@@ -0,0 +1,171 @@++module DDC.Core.Flow.Transform.Melt+ ( Info (..)+ , meltModule )+where+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Exp+import DDC.Core.Flow.Compounds+import DDC.Core.Module+import DDC.Core.Flow.Transform.Annotate+import DDC.Core.Flow.Transform.Deannotate+import Control.Monad.Writer.Strict hiding (Alt(..))+import qualified Data.Set as Set+import Data.Set (Set)++-------------------------------------------------------------------------------+-- | Contains binders of variables that have been melted.+data Info+ = Info (Set Name)++instance Monoid Info where+ mempty = Info (Set.empty)+ mappend (Info s1) (Info s2) = Info (Set.union s1 s2)+++-------------------------------------------------------------------------------+-- | Melt compound data structures in a module.+meltModule :: Module () Name -> (Module () Name, Info)+meltModule mm+ = let (xBody', info) + = runWriter + $ melt + $ deannotate (const Nothing) $ moduleBody mm++ in (mm { moduleBody = annotate () xBody' }, info)+++-------------------------------------------------------------------------------+class Melt c where+ melt :: c -> Writer Info c+++-- Exp ------------------------------------------------------------------------+instance Melt (Exp () Name) where++ -- Melt allocations of tuple references.+ --+ -- let b = new [TupleN# tA1 tA2] xInit in ...+ --+ -- => let b$1 = new [tA1] (projN_1 xInit) in+ -- let b$2 = new [tA2] (projN_2 xInit) in ...+ --+ melt (XLet (LLet b x1) x2)+ | BName nBind _t <- b+ , Just ( NameOpStore OpStoreNew+ , [XType tElem, xInit]) <- takeXPrimApps x1+ , Just ( NameTyConFlow (TyConFlowTuple n)+ , tAs) <- takePrimTyConApps tElem+ , length tAs == n+ = do + let ltsNew + = [ LLet (BName (NameVarMod nBind (show i)) (tRef tA))+ $ xNew tA (xProj tAs i xInit)+ | i <- [1..n]+ | tA <- tAs ]++ x2' <- melt x2+ return $ xLets ltsNew x2' +++ -- Melt reads from tuple references.+ --+ -- let b = read# [TupleN# tA1 tA2] xR in ...+ --+ -- => let b.1 = read# [tA1] xRef$1 in+ -- let b.2 = read# [tA2] xRef$2 in+ -- let b = TN# [tA1] [tA2] b$1 b$2 in ...+ --+ melt (XLet (LLet b x1) x2)+ | BName nBind _t <- b+ , Just ( NameOpStore OpStoreRead+ , [XType tElem, XVar (UName nRef)]) <- takeXPrimApps x1+ , Just ( NameTyConFlow (TyConFlowTuple n)+ , tsA) <- takePrimTyConApps tElem+ , length tsA == n+ = do + -- read all the components+ let ltsRead + = [LLet (BName (NameVarMod nBind (show i)) tA)+ $ xRead tA+ (XVar (UName (NameVarMod nRef (show i))))+ | i <- [1..n]+ | tA <- tsA ]++ -- build the result tuple+ let ltOrig + = LLet b + $ xApps (XCon (dcTupleN n))+ ( [XType t | t <- tsA] + ++ [XVar (UName (NameVarMod nBind (show i)))+ | i <- [1..n]])++ -- melt the body+ x2' <- melt x2++ return $ xLets (ltsRead ++ [ltOrig]) x2'+++ -- Melt writes to tuple references.+ --+ -- let _ = write# [TupleN# tA1 tA2] xR xV in ...+ --+ -- => let _ = write# [tA1] xR$1 (projN_1 xV) + -- let _ = write# [tA2] xR$2 (projN_2 xV) in ...+ --+ melt (XLet (LLet b x1) x2)+ | BNone tB <- b+ , Just ( NameOpStore OpStoreWrite + , [XType tElem, XVar (UName nRef), xV]) <- takeXPrimApps x1+ , Just ( NameTyConFlow (TyConFlowTuple n)+ , tsA) <- takePrimTyConApps tElem+ , length tsA == n+ = do + let ltsWrite+ = [ LLet (BNone tB)+ $ xWrite tA+ (XVar (UName (NameVarMod nRef (show i))))+ (xProj tsA i xV)+ | i <- [1..n]+ | tA <- tsA ]++ x2' <- melt x2+ return $ xLets ltsWrite x2'+++ -- Boilerplate+ melt xx+ = case xx of+ XAnnot a x -> liftM (XAnnot a) (melt x)+ XLet lts x -> liftM2 XLet (melt lts) (melt x)+ XApp x1 x2 -> liftM2 XApp (melt x1) (melt x2)+ XVar u -> return $ XVar u+ XCon dc -> return $ XCon dc+ XLAM b x -> liftM (XLAM b) (melt x)+ XLam b x -> liftM (XLam b) (melt x)+ XCase x alts -> liftM2 XCase (melt x) (mapM melt alts)+ XCast c x -> liftM (XCast c) (melt x)+ XType t -> return $ XType t+ XWitness w -> return $ XWitness w+++-- Lets -----------------------------------------------------------------------+instance Melt (Lets () Name) where+ melt lts+ = case lts of+ LLet b x+ -> liftM (LLet b) (melt x)++ LRec bxs + -> do let (bs, xs) = unzip bxs+ xs' <- mapM melt xs+ return $ LRec $ zip bs xs'++ LPrivate{}+ -> return lts+++-- Alt ------------------------------------------------------------------------+instance Melt (Alt () Name) where+ melt (AAlt w x) = liftM (AAlt w) (melt x)+
− DDC/Core/Flow/Transform/Prep.hs
@@ -1,169 +0,0 @@--module DDC.Core.Flow.Transform.Prep- (prepModule)-where-import DDC.Core.Flow.Prim-import DDC.Core.Flow.Prim.TyConPrim-import DDC.Core.Compounds-import DDC.Core.Module-import DDC.Core.Exp-import Control.Monad.State.Strict-import Data.Map (Map)-import qualified Data.Map as Map-import DDC.Type.Env (TypeEnv)-import qualified DDC.Type.Env as Env----- | Prepare a module for lowering.--- We need all worker functions passed to flow operators to be eta-expanded--- and for their parameters to have real names.-prepModule - :: Module a Name - -> (Module a Name, Map Name [Type Name])--prepModule mm- = do runState (prepModuleM mm) Map.empty---prepModuleM :: Module a Name -> PrepM (Module a Name)-prepModuleM mm- = do xBody' <- prepX Env.empty $ moduleBody mm- return $ mm { moduleBody = xBody' }----- Do a bottom-up rewrite,--- on the way up remember names of variables that are passed as workers --- to flow operators, then eta-expand bindings with those names.--- Record the environment of let-bound expressions, to know whether to --- eta-expand in their definition or at the callsite.-prepX :: TypeEnv Name -> Exp a Name -> PrepM (Exp a Name)-prepX tenv xx- = let down = prepX tenv- in case xx of- -- MapN- XApp{}- | Just (XVar _ u, xsArgs) <- takeXApps xx- , UPrim (NameOpFlow (OpFlowMap n)) _ <- u- , _xTR : xsArgs2 <- xsArgs- , (xsA, xsArgs3) <- splitAt (n + 1) xsArgs2- , tsA <- [t | XType t <- xsA]- , XVar _ (UName nWorker) : _ <- xsArgs3- , Env.member (UName nWorker) tenv- -> do addWorkerArgs nWorker (take n tsA)- return xx-- -- Worker passed to map, but not let-bound.- -- Eta-expand in-place.- XApp{}- | Just (xmap@(XVar _ u), args@[_, XType tA, XType _tB, f@(XVar a _), _])- <- takeXApps xx- , UPrim (NameOpFlow (OpFlowMap 1)) _ <- u- -> do let f' = xEtaExpand a f [tA]- args' = take 3 args ++ [f'] ++ [last args]- return $ xApps a xmap args'-- -- Detect workers passed to folds.- XApp{}- | Just (XVar _ u, [_, XType tA, XType tB, XVar _ (UName n), _, _])- <- takeXApps xx- , UPrim (NameOpFlow OpFlowFold) _ <- u- -> do addWorkerArgs n [tA, tB]- return xx-- -- FoldIndex- XApp{}- | Just (XVar _ u, [_, XType tA, XType tB, XVar _ (UName n), _, _])- <- takeXApps xx- , UPrim (NameOpFlow OpFlowFoldIndex) _ <- u- -> do addWorkerArgs n [tInt, tA, tB]- return xx-- -- Detect workers passed to mkSels- XApp{}- | Just (XVar _ u, [XType _tK1, XType _tA, _, XVar _ (UName n)])- <- takeXApps xx- , UPrim (NameOpFlow (OpFlowMkSel _)) _ <- u- -> do addWorkerArgs n []- return xx-- -- Bottom-up transform boilerplate.- XVar{} -> return xx- XCon{} -> return xx- XLAM a b x -> liftM3 XLAM (return a) (return b) (down x)- XLam a b x -> liftM3 XLam (return a) (return b) (down x)- XApp a x1 x2 -> liftM3 XApp (return a) (down x1) (down x2)-- XLet a lts x - -> do -- Slurp binds from lets, add to tenv- let tenv' = Env.extends (valwitBindsOfLets lts) tenv- x' <- prepX tenv' x-- -- Use old tenv for the binders- lts' <- prepLts tenv a lts- return $ XLet a lts' x'-- XCase a x alts -> liftM3 XCase (return a) (down x) (mapM (prepAlt tenv) alts)- XCast a c x -> liftM3 XCast (return a) (return c) (down x)- XType{} -> return xx- XWitness{} -> return xx----- Prepare let bindings for lowering.-prepLts :: TypeEnv Name -> a -> Lets a Name -> PrepM (Lets a Name)-prepLts tenv a lts- = case lts of- LLet b@(BName n _) x- -> do x' <- prepX tenv x-- mArgs <- lookupWorkerArgs n- case mArgs of- Just tsArgs- | length tsArgs > 0- -> return $ LLet b $ xEtaExpand a x' tsArgs-- _ -> return $ LLet b x'-- LLet b x- -> do x' <- prepX tenv x- return $ LLet b x'-- LRec bxs- -> do let (bs, xs) = unzip bxs- let tenv' = Env.extends bs tenv- xs' <- mapM (prepX tenv') xs- return $ LRec $ zip bs xs'-- LLetRegions{} -> return lts- LWithRegion{} -> return lts----- Prepare case alternative for lowering.-prepAlt :: TypeEnv Name -> Alt a Name -> PrepM (Alt a Name)-prepAlt tenv (AAlt w x)- = liftM (AAlt w) (prepX tenv x)---xEtaExpand :: a -> Exp a Name -> [Type Name] -> Exp a Name-xEtaExpand a x tys- = xLams a (map BAnon tys)- $ xApps a x [ XVar a (UIx (length tys - 1 - ix))- | ix <- [0 .. length tys - 1] ]----- State -----------------------------------------------------------------------type PrepS = Map Name [Type Name]-type PrepM = State PrepS----- | Record this name as being of a worker function.-addWorkerArgs :: Name -> [Type Name] -> PrepM ()-addWorkerArgs name tsParam- = modify $ Map.insert name tsParam----- | Check whether this name corresponds to a worker function.-lookupWorkerArgs :: Name -> PrepM (Maybe [Type Name])-lookupWorkerArgs name- = do names <- get- return $ Map.lookup name names-
+ DDC/Core/Flow/Transform/Rates/Clusters.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE CPP #-}+module DDC.Core.Flow.Transform.Rates.Clusters+ (cluster)+ where++#if DDC_FLOW_HAVE_LINEAR_SOLVER+import DDC.Core.Flow.Transform.Rates.Clusters.Linear++cluster = solve_linear++#else+import DDC.Core.Flow.Transform.Rates.Clusters.Greedy++cluster = cluster_greedy++#endif+
+ DDC/Core/Flow/Transform/Rates/Clusters/Base.hs view
@@ -0,0 +1,37 @@+module DDC.Core.Flow.Transform.Rates.Clusters.Base where+import DDC.Core.Flow.Transform.Rates.Graph++type TransducerMap n = n -> n -> Maybe (n,n)++-- \forall paths p from u to v, fusion preventing \not\in p+noFusionPreventingPath :: (Ord n) => [((n,n),Bool)] -> n -> n -> Bool+noFusionPreventingPath arcs u v+ -- for all paths, for all nodes in path, is fusible+ = all (all snd) (paths u v)+ && all (all snd) (paths v u)+ where+ -- list of all paths from w to x+ paths w x+ | w == x+ = [[]]+ | otherwise+ = let outs = filter (\((i,_j),_f) -> i == w) arcs+ in concatMap (\((w',j),f) -> map (((w',j),f):) (paths j x)) outs+ ++-- | Check if two nodes may be fused based on type.+-- If they have the same type, it's fine.+-- If they have a different type, we must look for any common type transducer parents.+typeComparable :: (Ord n, Eq t) => Graph n t -> TransducerMap n -> n -> n -> Bool+typeComparable g trans a b+ = case (nodeType g a, nodeType g b) of+ (Just a', Just b')+ -> if a' == b'+ then True+ else case trans a b of+ Just _ -> True+ Nothing -> False+ _+ -> False++
+ DDC/Core/Flow/Transform/Rates/Clusters/Greedy.hs view
@@ -0,0 +1,126 @@+module DDC.Core.Flow.Transform.Rates.Clusters.Greedy+ (cluster_greedy)+where+import DDC.Core.Flow.Transform.Rates.Graph+import DDC.Core.Flow.Transform.Rates.Clusters.Base++cluster_greedy + :: (Ord n, Eq t) + => Graph n t -> TransducerMap n -> [[n]]+cluster_greedy g trans+ -- First find a greedy vertical clustering, then merge any leftover horizontal opportunities+ --+ -- The clusters are built in reverse order, so fix them up.+ = reverse+ $ map reverse+ $ fuse_rest vertical+ where+ -- Vertical fusion.+ -- Go through the graph in topo order, inserting each node into a cluster+ vertical+ = foldl go_vertical []+ $ graphTopoOrder g++ -- Insert node n into the clusters ns+ go_vertical ns n+ -- Find the parent we'd like to fuse n into. It has to be a fusible edge.+ = let parent = [ n' | (n',fusible) <- nodeInEdges g n, fusible]+ -- The default unfused clustering to use if we can't merge n into parent+ unfused = [n] : ns+ in case parent of+ -- There is no parent (that is fusible)+ []+ -> unfused+ -- Check that n and n' are the same type (can be fused).+ (n':_)+ | tcmp n n'+ -> case insert n n' ns of+ Just ns' -> ns'+ Nothing -> unfused+ | otherwise+ -> unfused++ -- Try to insert n into the same cluster as n'.+ -- If n relies on output of clusters after n' (before in cs - list is reversed), we cannot put+ -- n in the n' cluster.+ -- Also check that there are no fusion-preventing paths between cluster and n.++ -- We haven't seen n' yet and we're at the end, so can't put n into same cluster as n'+ insert _n _n' []+ = Nothing++ insert n n' (c:cs) + -- We've reached n' cluster.+ -- If there are no fusion-preventing edges between n and these nodes, we can fuse.+ | n' `elem` c+ = if any (not . checkPath n) c+ then Nothing+ else Just ((n:c) : cs)++ -- If n relies on any of these nodes and we haven't reached n',+ -- we won't be able to merge n with n'+ -- (because it would not be able to execute without result of these nodes)+ | any (edge n) c+ = Nothing++ | otherwise+ = do cs' <- insert n n' cs+ return (c : cs')+++ -- Do any leftover horizontal fusion that we can+ fuse_rest [] = []+ fuse_rest (c:cs)+ = case try_merge c cs of+ Nothing+ -> c : fuse_rest cs+ Just cs'+ -> fuse_rest cs'++ -- Nothing to merge s with+ try_merge _ []+ = Nothing++ try_merge s (c:cs)+ -- Can s and c be merged together?+ | miscible s c+ = if all (\a -> all (checkPath a) s) c+ then Just ((s ++ c) : cs)+ else Nothing++ -- s and c can't be merged together, but we can't move s any further back+ | any (\a -> any (edge a) s) c+ = Nothing++ | otherwise+ = do cs' <- try_merge s cs+ return (c : cs')+++ -- Helper functions+ edge a b = hasEdge g (a,b) || hasEdge g (b,a)++ checkPath = noFusionPreventingPath arcs+ arcs = snd $ listOfGraph g++ tcmp = typeComparable g trans++ -- Check if two clusters can be merged together+ miscible s c+ = let sc = s ++ c+ -- For each a in c and b in s+ in all (\a -> all (\b ->+ -- If a and b have same type, they can be merged fine+ case (nodeType g a, nodeType g b) of+ (Just ta, Just tb)+ -> if ta == tb+ then True+ -- If they have different types, but share parent transducers,+ -- they can only be merged if they are merged with both parents.+ else case trans a b of+ Just (a',b') -> a' `elem` sc && b' `elem` sc+ Nothing -> False+ _+ -> False+ ) s) c+
+ DDC/Core/Flow/Transform/Rates/Clusters/Linear.hs view
@@ -0,0 +1,322 @@+{-# LANGUAGE DataKinds #-}+module DDC.Core.Flow.Transform.Rates.Clusters.Linear+ (solve_linear)+ where++import DDC.Data.Pretty+import DDC.Core.Flow.Transform.Rates.Graph+import DDC.Core.Flow.Transform.Rates.Clusters.Base++import qualified Data.Map as Map++import Numeric.Limp.Program.ResultKind+import Numeric.Limp.Program+import Numeric.Limp.Rep+import Numeric.Limp.Solvers.Cbc.Solve++import qualified Numeric.Limp.Canon.Convert as Conv+import qualified Numeric.Limp.Canon.Simplify as CSimp+++-- | Get parent transducers of two nodes, if exists.+-- | Integer-valued variable type for linear program+--+-- SameCluster i j - {0,1} 0 if i and j are fused together+--+-- C n - 0 if node is fused with all its users. Minimising this is good for array contraction.+--+data ZVar n+ = SameCluster n n+ | C n+ deriving (Eq, Show, Ord)++instance Pretty n => Pretty (ZVar n) where+ ppr (SameCluster a b) = text "SC" <+> ppr a <+> ppr b+ ppr (C a) = text "C" <+> ppr a+++-- | Variable type for linear program+-- Pi i - {0..} used to show the resulting partition is acyclic:+--+-- A graph is acyclic iff there is a mapping+-- pi : Node -> Int+-- such that \forall (i,j) \in Edge+-- pi(j) > pi(i)+--+data RVar n+ = Pi n+ deriving (Eq, Show, Ord)++instance Pretty n => Pretty (RVar n) where+ ppr (Pi a) = text "O" <+> ppr a++-- | Canonical form of SameCluster variables.+-- Since we only want to generate one SameCluster variable for each pair, we generate the+-- variable with min variable then max.+mkSameCluster :: Ord n => n -> n -> ZVar n+mkSameCluster m n+ = SameCluster (min m n) (max m n)++-- | Minimise objective:+-- \Sigma_i,j Weight(i,j) * SameCluster(i,j)+gobjective :: Ord n => [n] -> [(Int,n,n)] -> Linear (ZVar n) (RVar n) IntDouble 'KZ+gobjective ns ws+ = foldl (.+.) c0+ ( map (\(w,i,j) -> z (mkSameCluster i j) (Z w)) ws+ ++ map (\n -> z (C n) (Z $ length ns)) ns)+++-- | Get variable bounds - Pi are unbounded, SameCluster and C are "bools" (0 or 1)+getBounds :: Ord n => [n] -> [(Int,n,n)] -> [Bounds (ZVar n) (RVar n) IntDouble]+getBounds ns ws+ = map boundC ns+ ++ map boundSC ws+ where+ boundC n+ = binary (C n)+ boundSC (_,i,j)+ = binary (mkSameCluster i j)+++-- | Create constraints for edges and weights+getConstraints + :: (Ord n, Eq t)+ => Int -> Graph n t+ -> [((n,n),Bool)]+ -> [(Int,n,n)]+ -> TransducerMap n+ -> Constraint (ZVar n) (RVar n) IntDouble++getConstraints bigN g arcs ws trans+ = mconcat $ map edgeConstraint arcs+ ++ map weightConstraint ws+ where+ piDiff u v = r1 (Pi v) .-. r1 (Pi u)+ sc u v = z1 (mkSameCluster u v)++ -- Edge constraints:+ --+ -- For nonfusible edges (u,v), add a constraint+ -- pi(v) - pi(u) >= 1+ -- which is equivalent to+ -- pi(v) > pi(u)+ -- or "v must be scheduled after u"+ -- This will disallow u and v from being in the same cluster, as other+ -- constraints require x(u,v) = 0 can only be true if pi(u) = pi(v).+ --+ -- For fusible edges (u,v)+ -- if they are merged together, x(u,v) = 0 and pi(v) = pi(u)+ -- otherwise, x(u,v) = 1 and pi(v) > pi(u)+ -- This is achieved with the constraint+ -- x(u,v) <= pi(v) - pi(u) <= n * x(u,v)+ --+ --+ -- Note that arcs are reversed in graph, so (v,u) below is actually an edge from u to v.+ edgeConstraint ((v,u), fusible)+ -- The edge must be fusible, the two nodes must have a similar size,+ -- and there can be no other paths between u and v that aren't fusible.+ | fusible && typeComparable g trans u v && noFusionPreventingPath arcs u v+ -- We may want to remove the 'typeComparable' restriction later, and just check+ -- that they have some iteration size, but not necessarily similar.+ -- This would allow fusing @a@ into @c@ in @a = map...; c = cross a b@.+ = let x = sc u v+ in Between x (piDiff u v) (Z bigN *. x)+ :&& x :<= z1 (C u)++ -- Non-fusible edge, or nodes are different types+ | otherwise+ -- pi(v) - pi(u) >= 1+ = piDiff u v :>= c1+ :&& z1 (C u) :== c1+++ -- Weights between other nodes:+ --+ -- For any two nodes that may be scheduled together,+ -- we must make sure that if they are together, their pis *must* be the same.+ -- If they are not together, their pis are unconstrained.+ --+ -- -n * x(u,v) <= pi(v) - pi(u) <= n * x(u,v)+ --+ -- That is, if u and v are in the same cluster (x(u,v)=0)+ -- then pi(v) - pi(u) = 0, or pi(v) = pi(u)+ --+ -- Otherwise, pi(v) - pi(u) has a large enough range to be practically unbounded.+ -- + -- This constraint is not necessary if there is a fusible edge between the two,+ -- as a more restrictive constraint will be added by edgeConstraint.+ --+ weightConstraint (_,u,v)+ -- If there's an edge between the two, don't bother adding this constraint+ | not $ any (\((i,j),_) -> (u,v) == (i,j) || (v,u) == (i,j)) arcs+ = let x = sc u v+ in Between (Z (-bigN) *. x) (piDiff u v) (Z bigN *. x) + :&& checkTypes u v++ | otherwise+ = CTrue+++ -- If two nodes have different types, but parent transducers with same type,+ -- we may still fuse them together if their parent transducers are fused together+ checkTypes u v+ | Just uT <- nodeType g u+ , Just vT <- nodeType g v+ , uT /= vT+ , Just (u',v') <- trans u v+ = filtConstraint v' v u v+ :&& filtConstraint u' u u v+ :&& filtConstraint u' v' u v++ | otherwise+ = CTrue++ -- c and d can only be fused if a and b are fused+ filtConstraint a b c d+ -- If a and b are the same node, they're already fused!+ | a == b+ = CTrue++ -- Check if it's even possible for a and b to be fused.+ -- There might be a fusion-preventing edge between them.+ | checkFusible a b+ -- If it's possible, constrain (SC a b) <= (SC c d).+ -- This means that if (SC a b) is 1 (unfused), it forces (SC c d) = 1 too.+ = sc a b :<= sc c d++ -- There's a fusion-preventing path between a and b, so they can't possibly be fused.+ -- So c and d won't be fused - let's just set it to 1.+ | otherwise+ = sc c d :== c1++ checkFusible a b+ = any (\(_, i,j) -> (i,j) == (a,b) || (i,j) == (b,a)) ws+++++-- | Get list of all nodes that might be clustered together,+-- and the weighted benefit of doing so.+clusterings :: (Ord n, Eq t) => [((n,n),Bool)] -> [n] -> Int -> Graph n t -> TransducerMap n -> [(Int, n,n)]+clusterings arcs ns bigN g trans+ = go ns+ where+ -- For some node, find all later nodes of same or similar type, and calculate benefit+ go (u:rest)+ = [ (w,u,v)+ | v <- rest+ , noFusionPreventingPath arcs u v+ , cmp u v+ , let w = weight u v+ , w > 0]+ ++ go rest+ go []+ = []++ cmp = typeComparable g trans++ -- Simple trick:+ -- if there is an edge between the two,+ -- there will be some cache locality benefit from merging+ -- otherwise, + -- the only benefit is reducing loop overhead+ --+ -- Another heuristic would be to count nodes with shared parents as having a locality benefit+ weight u v+ -- An edge between them+ | (_:_) <- filter (\((i,j),_) -> (u,v) == (i,j) || (v,u) == (i,j)) arcs+ = bigN * bigN++ -- Share a parent+ | ius <- map (fst.fst) $ filter (\((_,j),_) -> j == u) arcs+ , ivs <- map (fst.fst) $ filter (\((_,j),_) -> j == v) arcs+ , _:_ <- filter (flip elem ius) ivs++ -- Assume that this is for an array.+ = bigN * bigN+ | otherwise+ = 1+++-- | Create linear program for graph, and put all the pieces together.+lp :: (Ord n, Eq t) => Graph n t -> TransducerMap n -> Program (ZVar n) (RVar n) IntDouble+lp g trans+ = minimise (gobjective names weights)+ (getConstraints nNodes g arcs weights trans)+ (getBounds names weights)+ where+ g' = listOfGraph g+ names = map fst $ fst g'+ arcs = snd g'++ weights = clusterings arcs names nNodes g trans++ nNodes+ = numNodes g+++-- | Find a good clustering for some graph.+-- The output is:+-- (Pi, Type number) -> list of nodes+solve_linear :: (Ord n, Eq t, Show n, Pretty n) => Graph n t -> TransducerMap n -> [[n]]+solve_linear g trans+ = case solve lp's of+ Left e -> error (show e)+ Right ass -> Map.elems+ $ fixMap (sub `mappend` ass)+ where+ lp' = lp g trans+ {- show_lp = CPr.ppr (show.ppr) (show.ppr) -}++ lp'c = Conv.program lp'+ -- Simplify can return a (Left InfeasibleError) if the program can't be solved,+ -- but we luckily have a proof that the programs we generate will always be feasible.+ Right (sub, lp's) = CSimp.simplify lp'c+++ fixMap ass@(Assignment mz _r)+ = reorder ass $ snd $ fillMap $ Map.foldWithKey go (0 :: Int, Map.empty) mz++ go k v (n, m)+ -- SameCluster i j = 0 --> i and j must be fused together+ | SameCluster i j <- k+ , v == 0+ = case (Map.lookup i m, Map.lookup j m) of+ (Just iC, Just jC)+ -> if iC == jC+ then (n, m)+ else (n, Map.map (\x -> if x == iC then jC else x) m)+ (Just iC, Nothing)+ -> (n, Map.insert j iC m)+ (Nothing, Just jC)+ -> (n, Map.insert i jC m)+ (Nothing, Nothing)+ -> ( n + 1+ , Map.insert i n + $ Map.insert j n m)++ | otherwise+ = (n, m)++ fillMap (n, m)+ = foldr goFill (n, m) (fst $ listOfGraph g)++ goFill (k,_ty) (n, m)+ | Map.member k m+ = (n, m)+ | otherwise+ = ( n + 1+ , Map.insert k n m)+++ reorder ass m+ = Map.fromList+ $ map (reorder' ass)+ $ Map.toList $ invertMap m++ reorder' ass (k,v:vs)+ = let k' = rOf ass (Pi v)+ in ((truncate k' :: Int, k), v:vs)+ reorder' _ (_, [])+ = error "ddc-core-flow:DDC.Core.Flow.Transform.Rates.Linear: impossible, empty list in inverted map"+
+ DDC/Core/Flow/Transform/Rates/CnfFromExp.hs view
@@ -0,0 +1,206 @@+module DDC.Core.Flow.Transform.Rates.CnfFromExp+ (cnfOfExp, takeXLamFlags_safe) where+import DDC.Core.Collect+import DDC.Core.Flow.Exp.Simple.Collect ()+import DDC.Core.Flow.Compounds+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Exp+import DDC.Core.Flow.Transform.Rates.Fail+import DDC.Core.Flow.Transform.Rates.Combinators as CNF+import qualified DDC.Type.Env as Env++import Control.Monad+import Data.List (intersect, nub)+import Data.Maybe (catMaybes)+import Data.Monoid+import qualified Data.Set as Set+++-----------------------------------+-- = Conversion from ExpF to CNF.+--+-- | Convert a given expression function to CNF.+-- For this to succeed, the function must:+-- - be in A-normal form, *except* worker functions should also be inlined+-- - all bindings are named, not de Bruijn indices+-- - names must be unique+-- - no recursive bindings+-- - no @letregion@s+--+-- If it succeeds, it should be true that+-- >>> expOfCnf . right . cnfOfExp = id+-- at least semantically, if not syntactically+-- +cnfOfExp :: ExpF -> Either ConversionError (Program Name Name)+cnfOfExp fun+ = do -- Peel off the lambdas+ let (lams, body) = takeXLamFlags_safe fun+ -- Assuming the body is already in a-normal form.+ (lets, xx) = splitXLets body++ -- Split into name and values and warn for recursive bindings+ binds <- takeLets lets++ let lam_names = catMaybes $ map (takeNameOfBind . snd) lams+ let names = lam_names ++ map fst binds+ -- Make sure names are unique+ when (length names /= length (nub names)) $+ Left FailNamesNotUnique++ -- For each value-level lambda binder, decide whether it's scalar or vector based on type+ let inputs = mconcat $ map getInput lams+ getInput (False, BName n ty)+ -- Vectors on the right, scalars on the left+ | isTypeArray ty+ = ([],[n])+ | otherwise+ = ([n],[])+ getInput (_,_) = ([],[])++ -- For each binding, classify it as either array, scalar or external.+ --+ -- We must be careful about creating externals, though: if a binding is just a+ -- worker function, we don't really need that as an external.+ -- However, if we assume that all scalars will be fusion-preventing (they currently are),+ -- then creating externals for these will not affect scheduling.+ -- But what of worker functions referencing vectors? It becomes harder to outlaw if the+ -- worker function is not inlined into the combinator binding.+ -- Tuples are another potential problem here: looking at the tuple's type, it would not be+ -- an array binding.+ let (binds', env') = getBinds binds inputs + let outs = localEnv env' xx++ return (Program inputs binds' outs)++-- | Check if type is an array type, so we know whether variables are scalar or array.+-- This is perhaps a crude way to test, as what if the result of a fold is actually a vector?+-- Well, let's not worry about that right now.+isTypeArray :: TypeF -> Bool+isTypeArray = isVectorType+++getBinds :: [(Name,(TypeF,ExpF))] -> ([Name],[Name]) -> ([CNF.Bind Name Name], ([Name],[Name]))+getBinds bs env+ = go bs env+ where+ go [] e = ([], e)+ go (b:rest) e+ = let b' = getBind b e+ e' = envOfBind b' <> e+ (rest',e'') = go rest e'+ in (b' : rest', e'')+++-- | Convert an epression to a CNF binding.+-- Assuming the incoming expression is well typed, this should never fail:+-- if we can't convert it to a "real" combinator, it will just be converted to an external.+--+-- Perhaps this is the wrong approach, and if a vector operator cannot be converted,+-- it should be an error or warning.+getBind :: (Name,(TypeF,ExpF)) -> ([Name], [Name]) -> CNF.Bind Name Name+getBind (nm,(t,x)) env+ -- Try to match against a known vector combinator.+ | Just (f, args) <- takeXApps x+ , XVar (UPrim (NameOpVector ov) _) <- f+ -- throw away that pesky type information+ , args' <- filter ((==Nothing) . takeXType) args+ = case (ov, args') of+ (OpVectorReduce, [worker, seed, arr])+ | Just fun <- getFun worker+ , snm <- name seed+ , Just a <- name arr+ -> SBind nm (Fold fun (Scalar seed snm) a)++ (OpVectorMap n, worker : arrs)+ | Just fun <- getFun worker+ , Just as <- names arrs+ , length arrs == n+ -> ABind nm (MapN fun as)++ (OpVectorFilter, [worker, arr])+ | Just fun <- getFun worker+ , Just a <- name arr+ -> ABind nm (Filter fun a)++ (OpVectorGenerate, [sz, worker])+ | Just fun <- getFun worker+ , snm <- name sz+ -> ABind nm (Generate (Scalar sz snm) fun)++ (OpVectorGather, [v, ix])+ | Just v' <- name v+ , Just ix' <- name ix+ -> ABind nm (Gather v' ix')++ _ | otherwise+ -> external++ -- It's not a vector combinator, so we'll have to create an external binding for it.+ | otherwise+ = external+ where+ external+ = let ins = localEnv env x+ out | isTypeArray t = NameArray nm+ | otherwise = NameScalar nm+ in Ext out x ins++ names as+ | xs <- catMaybes $ map name as+ , length xs == length as+ = Just xs+ | otherwise+ = Nothing++ name xx+ | XVar (UName n) <- xx+ = Just n+ | otherwise+ = Nothing++ -- Try to extract a worker function from an expression.+ -- This fails if the worker function mentions any local arrays.+ -- I'm not sure if failing in this case is strictly necessary; it should just be nonfusible edges.+ getFun xx+ = let (ss, as) = localEnv env xx+ -- Check that no local arrays are referenced+ in if null as+ then Just $ Fun xx ss+ else Nothing+++-- | Find local variables that are mentioned in expression, sorted into scalar and array+localEnv :: ([Name],[Name]) -> ExpF -> ([Name],[Name])+localEnv env xx+ -- Get all the free variables mentioned in exp+ = let free = catMaybes+ $ map takeNameOfBound+ $ Set.toList+ $ freeX Env.empty xx+ -- Limit to just the scalar references+ ss = free `intersect` fst env+ -- and array refs+ as = free `intersect` snd env+ -- Check that no local arrays are referenced+ in (ss, as)+++-- | Peel the lambdas off, or leave it alone if there are none+takeXLamFlags_safe x+ | Just (binds, body) <- takeXLamFlags x+ = (binds, body)+ | otherwise+ = ([], x)+++-- | Split into name and values and error for outlawed bindings+takeLets :: [LetsF] -> Either ConversionError [(Name, (TypeF, ExpF))]+takeLets lets+ = mapM get lets+ where+ get (LLet (BName n t) x) = return (n,(t,x))+ get (LLet (BNone _) _) = Left FailNoAnonAllowed+ get (LLet (BAnon _) _) = Left FailNoDeBruijnAllowed+ get (LRec _ ) = Left FailRecursiveBindings+ get (LPrivate _ _ _) = Left FailLetRegionNotHandled+
+ DDC/Core/Flow/Transform/Rates/Combinators.hs view
@@ -0,0 +1,304 @@+-- | Converting DDC expressions to and from Combinator Normal Form.+module DDC.Core.Flow.Transform.Rates.Combinators+ ( Fun(..), Bind(..), ABind(..), SBind(..), Scalar(..)+ , Program(..)+ , CName(..)+ , lookupA, lookupS, lookupB+ , envOfBind+ , freeOfBind, cnameOfBind+ , outputsOfCluster, inputsOfCluster+ , seriesInputsOfCluster+ ) +where+import DDC.Data.Pretty+import DDC.Core.Flow.Exp (ExpF)+import Data.Maybe (catMaybes)+import Data.List (nub)+import Prelude hiding ((<$>))++-----------------------------------+-- = Combinator normal form.+++-- | Worker function. May only reference scalars in the environment, not arrays.+-- Takes the expression of the function, and a list of the free scalars that are referenced inside it.+-- The expression must be a function from scalar to scalar.+data Fun s a+ = Fun ExpF [s]+ deriving Show++-- | Array, scalar and external bindings.+-- Array bindings are those whose value is an array, such as map, filter.+-- Scalar bindings have scalar values, currently only fold.+-- External expressions are those that cannot be converted to primitive combinators.+-- The they take a single expression that computes all outputs, with the list of free scalar and array inputs.+data Bind s a+ = ABind a (ABind s a)+ | SBind s (SBind s a)+ | Ext+ { _beOut :: CName s a+ , _beExp :: ExpF+ , _beIns :: ([s], [a])+ }+ deriving Show++-- | An array-valued binding.+data ABind s a+ -- | map_n :: (a_1 ... a_n -> b) -> Array a_1 ... Array a_n -> Array b+ = MapN (Fun s a) [a]+ -- | filter :: (a -> Bool) -> Array a -> Array a+ | Filter (Fun s a) a+ -- | generate :: Nat -> (Nat -> a) -> Array a+ | Generate (Scalar s a) (Fun s a) + -- | gather :: Array a -> Array Nat -> Array a+ | Gather a a+ -- | cross :: Array a -> Array b -> Array (a, b)+ | Cross a a+ deriving Show++-- | Scalars can either be a literal such as "0", or a named scalar reference.+-- If it's not a named scalar reference, we need to keep the expression so we can reconstruct it later.+-- (We do not have array literals, so this is only necessary for scalars)+data Scalar s a+ = Scalar ExpF (Maybe s)+ deriving Show++-- | A scalar-valued binding+data SBind s a+ -- | fold :: (a -> a -> a) -> a -> Array a -> a+ = Fold (Fun s a) (Scalar s a) a+ deriving Show++-- | An entire program/function to find a fusion clustering for+data Program s a+ = Program+ { _ins :: ([s], [a])+ , _binds :: [Bind s a]+ , _outs :: ([s], [a])+ }+ deriving Show++-- | Name of a combinator.+-- This will also be the name of the corresponding node of the graph.+data CName s a+ = NameScalar s+ | NameArray a+ deriving (Eq, Ord, Show)+++lookupA :: Eq a => Program s a -> a -> Maybe (ABind s a)+lookupA p a+ = go $ _binds p+ where+ go [] = Nothing+ go (ABind a' b : _)+ | a == a'+ = Just b+ go (_ : bs)+ = go bs++lookupS :: Eq s => Program s a -> s -> Maybe (SBind s a)+lookupS p s+ = go $ _binds p+ where+ go [] = Nothing+ go (SBind s' b : _)+ | s == s'+ = Just b+ go (_ : bs)+ = go bs+++lookupB :: (Eq s, Eq a) => Program s a -> CName s a -> Maybe (Bind s a)+lookupB p nm = go (_binds p)+ where+ go [] = Nothing+ go (b@(ABind a _) : _)+ | NameArray a' <- nm+ , a == a'+ = Just b+ go (b@(SBind s _) : _)+ | NameScalar s' <- nm+ , s == s'+ = Just b+ go (b@(Ext nm' _ _) : _)+ | nm == nm'+ = Just $ b+ go (_ : bs)+ = go bs++++envOfBind :: Bind s a -> ([s], [a])+envOfBind (SBind s _) = ([s], [])+envOfBind (ABind a _) = ([], [a])+envOfBind (Ext (NameScalar s) _ _) = ([s], [])+envOfBind (Ext (NameArray a) _ _) = ([], [a])+++cnameOfBind :: Bind s a -> CName s a+cnameOfBind (SBind s _) = NameScalar s+cnameOfBind (ABind a _) = NameArray a+cnameOfBind (Ext n _ _) = n++freeOfBind :: Bind s a -> [CName s a]+freeOfBind b+ = case b of+ SBind _ (Fold fun i a)+ -> ffun fun ++ fscalar i ++ [fa a]+ ABind _ (MapN fun as)+ -> ffun fun ++ map fa as+ ABind _ (Filter fun a)+ -> ffun fun ++ [fa a]+ ABind _ (Generate s fun)+ -> ffun fun ++ fscalar s+ ABind _ (Gather x y)+ -> [fa x, fa y]+ ABind _ (Cross x y)+ -> [fa x, fa y]+ Ext _ _ (inS,inA)+ -> map fs inS ++ map fa inA+ where+ ffun (Fun _ f) = map fs f+ fscalar (Scalar _ Nothing) = []+ fscalar (Scalar _ (Just s)) = [NameScalar s]+ fs = NameScalar+ fa = NameArray++-- | Get inputs that must be converted to series or rate vectors+seriesInputOfBind :: Bind s a -> [a]+seriesInputOfBind b+ = case b of+ SBind _ (Fold _fun _i a)+ -> [a]+ ABind _ (MapN _fun as)+ -> as+ ABind _ (Filter _fun a)+ -> [a]+ ABind _ (Generate _s _fun)+ -> []+ ABind _ (Gather v ix)+ -- Only the indices array is consumed series-wise.+ -- The vector is random access.+ -> [v, ix]+ -- Cross product's first is consumed in series, but second is consumed multiple times+ ABind _ (Cross x y)+ -> [x, y]+ -- Externals do not require series inputs.+ Ext _ _ (_inS,_inA)+ -> []++++-- | For a given program and list of nodes that will be clustered together,+-- find a list of the nodes that are used afterwards.+-- Only these nodes must be made manifest.+-- The output nodes is a subset of the input cluster nodes.+outputsOfCluster :: (Eq s, Eq a) => Program s a -> [CName s a] -> [CName s a]+outputsOfCluster prog cluster+ -- Get all bindings in the program that aren't in this cluster+ = let notin = filter (not . flip elem cluster . cnameOfBind) (_binds prog)+ -- And find their free variables+ frees = concatMap freeOfBind notin++ -- Convert the returns of the program to CNames+ (ss,as) = _outs prog+ pouts = map NameScalar ss ++ map NameArray as++ -- We want to look in both returns and free variables of bindings+ alls = frees ++ pouts+ -- Now search through and find those in the cluster+ found = filter (flip elem cluster) alls+ in nub $ found+++-- | For a given program and list of nodes that will be clustered together,+-- find a list of the nodes that are used as inputs.+-- The input nodes will not mention any of the cluster nodes.+inputsOfCluster :: (Eq s, Eq a) => Program s a -> [CName s a] -> [CName s a]+inputsOfCluster prog cluster+ -- Get bindings of clusters+ = let binds = catMaybes+ $ map (lookupB prog) cluster+ -- And find the free variables+ frees = concatMap freeOfBind binds++ -- Ignore the ones in the cluster+ found = filter (not . flip elem cluster) frees+ in nub $ found++-- | For a given program and list of nodes that will be clustered together,+-- find a list of the inputs that need to be converted to series.+-- If the cluster is correct, these should all be the same size.+seriesInputsOfCluster :: (Eq s, Eq a) => Program s a -> [CName s a] -> [a]+seriesInputsOfCluster prog cluster+ -- Get bindings of clusters+ = let binds = catMaybes+ $ map (lookupB prog) cluster+ -- And find the free variables+ frees = concatMap seriesInputOfBind binds++ -- Ignore the ones in the cluster+ found = filter (not . flip elem cluster . NameArray) frees+ in nub $ found+++-----------------------------------+-- == Pretty printing+-- This is just the notation I used in the prototype.++instance Pretty s => Pretty (Fun s a) where+ ppr (Fun _ ss)+ = encloseSep lbrace rbrace space+ $ map ppr ss++instance Pretty s => Pretty (Scalar s a) where+ ppr (Scalar _ Nothing)+ = text "-"+ ppr (Scalar _ (Just s))+ = ppr s++instance (Pretty s, Pretty a) => Pretty (Bind s a) where+ ppr (SBind n (Fold f i a))+ = bind (ppr n) "reduce" (ppr f <+> ppr i <+> ppr a)++ ppr (ABind n (MapN f as))+ = bind (ppr n) "mapN" (ppr f <+> hsep (map ppr as))++ ppr (ABind n (Filter f a))+ = bind (ppr n) "filter" (ppr f <+> ppr a)++ ppr (ABind n (Gather a b))+ = bind (ppr n) "gather" (ppr a <+> ppr b)++ ppr (ABind n (Generate sz f))+ = bind (ppr n) "generate" (ppr sz <+> ppr f)++ ppr (ABind n (Cross a b))+ = bind (ppr n) "cross" (ppr a <+> ppr b)++ ppr (Ext out _ ins)+ = bind (ppr out) "external" (binds ins)+ where+ binds (ss,as)+ = encloseSep lbrace rbrace space (map ppr ss) <+> hcat (map ppr as)++bind :: Doc -> String -> Doc -> Doc+bind nm com args+ = nm <+> nest 4 (equals <+> text com <+> args)++instance (Pretty s, Pretty a) => Pretty (Program s a) where+ ppr (Program ins binds outs)+ = params <$> vcat (map ppr binds) <$> returns+ where+ params+ = vcat (map (\i -> text "param scalar" <+> ppr i) (fst ins))+ <$> vcat (map (\i -> text "param array" <+> ppr i) (snd ins))++ returns+ = vcat (map (\i -> text "return" <+> ppr i) (fst outs))+ <$> vcat (map (\i -> text "return" <+> ppr i) (snd outs))++instance (Pretty s, Pretty a) => Pretty (CName s a) where+ ppr (NameScalar s) = text "{" <> ppr s <> text "}"+ ppr (NameArray a) = ppr a
+ DDC/Core/Flow/Transform/Rates/Fail.hs view
@@ -0,0 +1,59 @@+module DDC.Core.Flow.Transform.Rates.Fail+ ( Fail (..)+ , ConversionError (..)+ , LogFailures+ , warn, run)+where+import DDC.Core.Flow.Prim+import DDC.Data.Pretty+import Control.Monad.Writer+import Data.List++-- | Why couldn't it be converted to CNF?+data ConversionError+ -- | Function is not in a-normal form+ = FailNotANormalForm++ -- | Bindings must be unique+ | FailNamesNotUnique++ -- | Bindings must be named+ | FailNoDeBruijnAllowed++ -- | Bindings cannot be anonymous _.+ | FailNoAnonAllowed++ -- | Function contains letrec+ | FailRecursiveBindings++ -- | Function contains letregion+ | FailLetRegionNotHandled+ deriving (Show, Eq)+++-- | Why can't rates be inferred?+data Fail+ -- | The function couldn't be converted to combinator form+ = FailCannotConvert ConversionError+ -- | The constraint would require a buffer. User must expicitly buffer.+ | FailConstraintFilteredLessFiltered Name Name++ -- | The constraint would require a buffer. User must expicitly buffer.+ | FailConstraintFilteredNotUnique Name Name+ deriving (Show, Eq)+++instance Pretty Fail where+ ppr fails = text (show fails)+++type LogFailures a = Writer [Fail] a++warn :: Fail -> LogFailures ()+warn w = tell [w]++run :: LogFailures a -> (a, [Fail])+run comp+ = case runWriter comp of+ (a, warns) -> (a, nub warns)+
+ DDC/Core/Flow/Transform/Rates/Graph.hs view
@@ -0,0 +1,229 @@+module DDC.Core.Flow.Transform.Rates.Graph+ ( Graph(..)+ , Edge+ , graphOfBinds+ , graphTopoOrder + , mergeWeights+ , invertMap+ , numNodes, numEdges+ , hasNode, hasEdge+ , nodeInputs, nodeInEdges+ , nodeType+ , listOfGraph, graphOfList )+where+import DDC.Core.Flow.Transform.Rates.Combinators+import DDC.Core.Flow.Transform.Rates.SizeInference++import Data.List (nub)+import qualified Data.Map as Map+import qualified Data.Set as Set+++-- | Graph for function+-- Each node is a binding, edges are dependencies, and the bool is whether the node's output+-- can be fused or contracted.+-- For example, filter and map dependencies can be contracted,+-- but a fold cannot as it must consume the entire stream before producing output.+--++type Edge n = (n, Bool)+data Graph n t = Graph (Map.Map n (Maybe t, [Edge n]))+++graphOfBinds :: (Ord s, Ord a) => Program s a -> Env a -> Graph (CName s a) (Type a)+graphOfBinds prog env+ = Graph $ graph+ where+ graph+ = Map.fromList+ $ map gen+ $ _binds prog++ gen b+ = let n = cnameOfBind b+ ty = iter prog env n+ es = edges n b+ in (n, (ty, es))++ edges n (ABind _ (Gather a b))+ = let a' = mkedgeA (const False) a+ b' = mkedgeA (inedge n) b+ in [a', b']++ edges n (ABind _ (Cross a b))+ = let a' = mkedgeA (inedge n) a+ b' = mkedgeA (const False) b+ in [a', b']++ edges n b+ = let fs = freeOfBind b+ fs' = map (pairon (inedge n)) fs+ in fs'++ mkedgeA f a+ = (pairon f (NameArray a))++ pairon f x+ = (x, f x)++ inedge to from+ -- scalar output:+ | NameScalar _ <- from+ = False+ | Just (Ext{}) <- lookupB prog from+ = False+ | Just (Ext{}) <- lookupB prog to+ = False+ | otherwise+ = True+++++-- | Find topological ordering of DAG+-- Does not check for cycles - really must be a DAG!+graphTopoOrder :: Ord n => Graph n t -> [n]+graphTopoOrder (Graph graph)+ = reverse $ go ([], Map.keysSet graph)+ where+ go (l, s)+ = case Set.minView s of+ Nothing+ -> l+ Just (m, _)+ -> go (visit (l,s) m)++ visit (l,s) m+ | Set.member m s+ , (_ty, edges) <- graph Map.! m+ = let pres = map fst edges+ s' = Set.delete m s+ (l',s'') = foldl visit (l,s') pres+ in (m : l', s'')++ | otherwise+ = (l,s)++++-- | Merge nodes together with same value in weight map.+-- Type information of each node is thrown away.+-- It is, perhaps surprisingly, legal to merge nodes of different types (eg filtered data),+-- so the only sensible thing is to choose () for all new types.+mergeWeights :: Ord n => Graph n t -> Map.Map n Int -> Graph n ()+mergeWeights g@(Graph graph) weights+ = Graph+ $ foldl go Map.empty+ $ graphTopoOrder g+ where+ go m node+ -- Merge if it's a weighted one+ | Just k <- name_maybe node+ = merge node k m+ | otherwise+ = merge node node m++ merge node k m+ | Just (_ty,edges) <- Map.lookup node graph+ = let edges' = nub $ map (\(n,f) -> (name n, f)) edges+ in Map.insertWith ins k (Nothing,edges') m+ | otherwise+ = m++ ins (_, e1) (_, e2)+ = (Nothing, nub $ e1 ++ e2)++ weights' = invertMap weights++ name n+ = maybe n id (name_maybe n)++ -- If this node is mentioned in the weights map, then find some canonical name for it.+ name_maybe n+ | Just i <- Map.lookup n weights+ , Just (v:_) <- Map.lookup i weights'+ = Just v+ | otherwise+ = Nothing+++invertMap :: Ord v => Map.Map k v -> Map.Map v [k]+invertMap m+ = Map.foldWithKey go Map.empty m+ where+ go k v m' = Map.insertWith (++) v [k] m'+++-- | Number of nodes in graph+numNodes :: Graph n t -> Int+numNodes (Graph g)+ = Map.size g++-- | Total number of edges in graph+numEdges :: Graph n t -> Int+numEdges (Graph g)+ = Map.fold (+) 0+ $ Map.map (length . snd) g+++hasNode :: Ord n => Graph n t -> n -> Bool+hasNode (Graph gmap) k+ = k `Map.member` gmap++hasEdge :: Ord n => Graph n t -> (n,n) -> Bool+hasEdge g (i,j)+ = i `elem` nodeInputs g j++nodeInputs :: Ord n => Graph n t -> n -> [n]+nodeInputs g k+ = map fst+ $ nodeInEdges g k++nodeInEdges :: Ord n => Graph n t -> n -> [(n,Bool)]+nodeInEdges (Graph gmap) k+ | Just (_,es) <- Map.lookup k gmap+ = es+ | otherwise+ = []+++-- | Find type, or iteration size, of node, if it has one.+-- An external can't be represented as a loop, so it will be Nothing.+-- Similarly with input nodes.+nodeType :: Ord n => Graph n t -> n -> Maybe t+nodeType (Graph gmap) k+ | Just (Just na,_) <- Map.lookup k gmap+ = Just na+ | otherwise+ = Nothing+++-- | Convert @Graph@ to a lists of nodes and a list of edges+listOfGraph :: Graph n t -> ([(n,Maybe t)], [((n,n),Bool)])+listOfGraph (Graph g)+ = (nodes, edges)+ where+ gl = Map.toList g++ nodes = map (\(k,(na,_)) -> (k,na)) gl+ edges = concatMap (\(k,(_,es)) -> map (\(k',ea) -> ((k,k'),ea)) es) gl+++-- | Convert lists of nodes and list of edges to a @Graph@+graphOfList :: Ord n => ([(n,Maybe t)], [((n,n),Bool)]) -> Graph n t+graphOfList (nodes, edges)+ = Graph+ $ addEdges nodeMap+ where+ nodeMap+ = Map.fromList+ $ map (\(k,na) -> (k,(na,[])))+ $ nodes++ addEdges g+ = foldl insE g edges++ insE g ((k,k'),ea)+ = Map.adjust (\(na,es) -> (na, (k',ea):es))+ k g+
+ DDC/Core/Flow/Transform/Rates/SeriesOfVector.hs view
@@ -0,0 +1,532 @@++module DDC.Core.Flow.Transform.Rates.SeriesOfVector+ (seriesOfVectorModule+ ,seriesOfVectorFunction)+where+import DDC.Core.Flow.Compounds+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Exp as DDC+import DDC.Core.Flow.Transform.Rates.Combinators as Com+import DDC.Core.Flow.Transform.Rates.CnfFromExp+import DDC.Core.Flow.Transform.Rates.Fail+import DDC.Core.Flow.Transform.Rates.Graph+import DDC.Core.Flow.Transform.Rates.Clusters+import DDC.Core.Flow.Transform.Annotate+import DDC.Core.Flow.Transform.Deannotate+import DDC.Core.Module+import DDC.Core.Collect+import qualified DDC.Core.Flow.Transform.Rates.SizeInference as SI+import qualified DDC.Type.Env as Env++import qualified Data.Map as Map+import Data.Map (Map)+import qualified Data.Set as Set+import Data.List (partition)+++seriesOfVectorModule :: ModuleF -> (ModuleF, [(Name,Fail)])+seriesOfVectorModule mm+ = let body = deannotate (const Nothing)+ $ moduleBody mm++ (lets, xx) = splitXLets body+ letsErrs = map seriesOfVectorLets lets++ lets' = concatMap fst letsErrs+ errs = concatMap snd letsErrs++ body' = annotate ()+ $ xLets lets' xx+++ in (mm { moduleBody = body' }, errs)+ +++seriesOfVectorLets :: LetsF -> ([LetsF], [(Name,Fail)])+seriesOfVectorLets ll+ | LLet b@(BName n _) x <- ll+ , (x',ls',errs) <- seriesOfVectorFunction x+ = ( map (uncurry LLet) ls' ++ [LLet b x']+ , map (\f -> (n,f)) errs)++ | LRec bxs <- ll+ , (bs,xs) <- unzip bxs+ , (xs',ls', _errs) <- unzip3 $ map seriesOfVectorFunction xs+ = ( [LRec (concat ls' ++ (bs `zip` xs'))]+ , []) + -- We still need to produce errors if this doesn't work.++ | otherwise+ = ([ll], [])+++-- | Takes a single function body. Function body must be in a-normal form.+seriesOfVectorFunction :: ExpF -> (ExpF, [(BindF,ExpF)], [Fail])+seriesOfVectorFunction fun+ = case cnfOfExp fun of+ Left err+ -> (fun, [], [FailCannotConvert err])+ Right prog+ -> case SI.generate prog of+ Nothing+ -> (fun, [], [])++ Just (env,_s)+ -> let g = graphOfBinds prog env+ tmap a b = SI.parents prog env a b+ clusters = cluster g tmap+ (re, ls) = reconstruct fun prog env clusters+ in (re, ls, [])+++reconstruct+ :: ExpF+ -> Program Name Name+ -> SI.Env Name+ -> [[CName Name Name]]+ -> (ExpF, [(BindF, ExpF)])+reconstruct fun prog env clusters+ = (makeXLamFlags lams+ $ xLets lets' xx+ , procs)+ where++ (lams, body) = takeXLamFlags_safe fun+ (olds, xx) = splitXLets body++ types = takeTypes (concatMap valwitBindsOfLets olds ++ map snd lams)++ lets = concatMap convert clusters+ (lets', procs) = extractProcs lets lams++ convert c+ = let outputs = outputsOfCluster prog c++ arrIns = seriesInputsOfCluster prog c++ -- Map over the list of all binds and find only those that we want.+ -- This way is better than mapping lookup over c, as we get them in program order.+ binds = filter (flip elem c . cnameOfBind) (_binds prog)+ binds' = map (\a -> (a, cnameOfBind a `elem` outputs)) binds+ in mkLets types env arrIns binds'+++-- | Extract processes out so they can be made into separate bindings+extractProcs :: [LetsF] -> [(Bool, DDC.Bind Name)] -> ([LetsF], [(BindF,ExpF)])+extractProcs lets env+ = go lets $ env+ where+ go [] _+ = ([], [])++ go (l:ls) e+ -- Actually, we know they're all LLets. Maybe it should just be (Name,ExpF)+ | LLet b x <- l+ , BName nm _ <- b+ = let this = go1 b nm x e+ rest = go ls ((False,b) : e)+ in this `mappend` rest++ | otherwise+ = ([l],[]) `mappend` go ls e++ go1 b nm x e+ | Just (op, args) <- takeXApps x+ , XVar (UPrim (NameOpSeries (OpSeriesRateVecsOfVectors n)) _) <- op+ , (xs, [lam]) <- splitAt (length args - 1) args+ , (lams,body) <- takeXLamFlags_safe lam+ , ([LLet n' x'], binds) <- go1 b nm body (lams ++ e)+ = ([LLet n'+ (xApps (xVarOpSeries (OpSeriesRateVecsOfVectors n))+ (xs ++ [makeXLamFlags lams x']))]+ , binds)++ | Just (op, args) <- takeXApps x+ , XVar (UPrim (NameOpSeries OpSeriesRunProcess) _) <- op+ , (xs, [lam]) <- splitAt (length args - 1) args++ = let fsX = freeX Env.empty lam+ fsT = freeT Env.empty lam++ isMentioned (ty,bo)+ | Just bo' <- takeSubstBoundOfBind bo+ = if ty+ then Set.member bo' fsT+ else Set.member bo' fsX+ | otherwise+ = False++ os = filter isMentioned e++ ss = takeSubstBoundsOfBinds . map snd+ osT = filter (fst) os+ osX = filter (not.fst) os++ nm' = NameVarMod nm "process"++ x' = xApps op (xs +++ [xApps (XVar $ UName nm')+ ( map (XType . TVar) (ss osT)+ ++ map XVar (ss osX))])++ p' = makeXLamFlags (osT ++ osX) lam+ in ([LLet b x'], [(BName nm' (tBot kData), p')])++ | otherwise+ = ([LLet b x], [])++-- | Make "lets" for a cluster.+-- If it's external, this is trivial.+-- If not, make a runProcess# etc+mkLets :: Map Name TypeF -> SI.Env Name -> [Name] -> [(Com.Bind Name Name, Bool)] -> [LetsF]+mkLets types env arrIns bs+ | any isExt (map fst bs)+ = case bs of+ [(Ext (NameArray b) xx _, _)] -> [LLet (BName b (types Map.! b)) xx]+ [(Ext (NameScalar b) xx _, _)] -> [LLet (BName b (types Map.! b)) xx]++ _ -> error ("ddc-core-flow:DDC.Core.Flow.Transform.Rates.SeriesOfVector impossible\n" +++ "an external node has been clustered with another node.\n" +++ "this means there must be a bug in the clustering algorithm.\n" +++ show bs)++ -- We *could* just return an empty list in this case, but I don't think that's a good idea.+ | [] <- bs+ = error ("ddc-core-flow:DDC.Core.Flow.Transform.Rates.SeriesOfVector impossible\n" +++ "a cluster was created with no bindings.\n" +++ "this means there must be a bug in the clustering algorithm.\n" +++ show bs)++ | otherwise+ = process types env arrIns+ $ map toEither bs++ where+ isExt (Ext{}) = True+ isExt _ = False++ toEither (SBind s b, out) = ((s, Left b), out)+ toEither (ABind a b, out) = ((a, Right b), out)+ toEither (Ext{}, _) = error "ddc-core-flow.mkLets: impossible!"+++-- | Create a process for a cluster of array and scalar bindings.+-- No externals.+-- List of bindings cannot be empty+process :: Map Name TypeF+ -> SI.Env Name+ -> [Name]+ -> [((Name, Either (SBind Name Name) (ABind Name Name)), Bool)]+ -> [LetsF]+process types env arrIns bs+ = let pres = concatMap getPre bs+ mid = getRateVecs arrIns+ $ getGenerates bs+ $ runProcs + $ xLets (map getInSeries arrIns)+ $ mkProcs bs+ posts = concatMap getPost bs+ in pres ++ [LLet (BName (NameVarMod outname "runproc") tUnit) mid] ++ posts+ where+ getPre b+ -- There is no point of having a reduce that isn't returned.+ | ((s, Left (Fold _ (Scalar z _) _)), _) <- b+ = [LLet (BName (NameVarMod s "ref") $ tRef $ tyOf s) (xNew (tyOf s) z)]++ -- Returned vectors+ | ((v, Right _), True) <- b+ = [LLet (BName v $ tVector $ sctyOf v) (xNewVector (sctyOf v) allocSize)]++ -- Otherwise, it's not returned or we needn't allocate anything+ | _ <- b+ = []+++ getGenerates [] innerX+ = innerX+ getGenerates (b:rest) innerX+ | ((n, Right (Generate (Scalar sz _) _)), _) <- b+ , rest' <- getGenerates rest innerX+ = xApps (xVarOpSeries (OpSeriesRateVecsOfVectors 0))+ [ XType tUnit+ , sz+ , XLAM (BName (klokV n) kRate) rest' ]+ | otherwise+ = getGenerates rest innerX++ getRateVecs [] innerX+ = innerX++ getRateVecs (a:as) innerX+ | Just t <- SI.lookupV env a+ , (same,others) <- partition ((==Just t) . SI.lookupV env) as+ , rest' <- getRateVecs others innerX++ , these <- (a : same)+ , nums <- length these++ , op <- OpSeriesRateVecsOfVectors nums++ , flags <- map (\n -> (False, BName (NameVarMod n "rv") (tRateVec (klokT a) (sctyOf n)))) these+ = xApps (xVarOpSeries op)+ ( map xsctyOf these ++ [XType tUnit]+ ++ map var these+ ++[ makeXLamFlags ((True, BName (klokV a) kRate) : flags)+ rest' ]+ )++ -- Input array doesn't have a type..+ | otherwise+ = getRateVecs as innerX++ getInSeries n+ = LLet (BName (NameVarMod n "s") (tSeries procT (klokT n) (sctyOf n)))+ (xApps (xVarOpSeries OpSeriesSeriesOfRateVec)+ [ procX, klokX n, xsctyOf n, var $ NameVarMod n "rv" ] )++++ getPost b+ | ((s, Left (Fold _ (Scalar _ _) _)), _) <- b+ = [ LLet (BName s $ sctyOf s) (xRead (tyOf s) (var $ NameVarMod s "ref")) ]++ -- Ignore anything else+ | _ <- b+ = []++ runProcs body+ = let flags = [ (True, BName procName kProc)+ , (False, BNone tUnit) ]+ in xApps (xVarOpSeries OpSeriesRunProcess)+ ([XType processRate, makeXLamFlags flags body])+++ mkProcs (b:rs)+ | ((s, Left (Fold (Fun xf _) (Scalar xs _) ain)), _) <- b+ = let rest = mkProcs rs+ in XLet (LLet (BName (NameVarMod s "proc") $ tProcess procT $ klokT ain)+ $ xApps (xVarOpSeries OpSeriesReduce)+ [ procX, klokX ain, xtyOf s, var (NameVarMod s "ref")+ , xf, xs, var (NameVarMod ain "s")])+ rest++ | ((n, Right abind), out) <- b+ = let rest = mkProcs rs+ n'proc = NameVarMod n "proc"+ n's = NameVarMod n "s"+ n'flag = NameVarMod n "flags"+ n'sel = NameVarMod n "sel"++ llet nm t x1+ = XLet (LLet (BName nm t) x1)++ go | out+ = llet n'proc (tProcess procT $ klokT n)+ ( xApps (xVarOpSeries OpSeriesFill) [procX, klokX n, xsctyOf n, var $ n, var $ n's] )+ rest+ | otherwise+ = rest++ in case abind of+ MapN (Fun xf _) ains+ -> llet n's (tSeries procT (klokT n) $ sctyOf n)+ ( xApps (xVarOpSeries (OpSeriesMap (length ains)))+ ([procX, klokX n] ++ (map xsctyOf ains) ++ [xsctyOf n, xf] + ++ map (var . flip NameVarMod "s") ains) )+ go++ Filter (Fun xf _) ain+ -> llet n'flag (tSeries procT (klokT ain) tBool)+ ( xApps (xVarOpSeries (OpSeriesMap 1))+ [ procX, klokX ain, xsctyOf n, XType tBool, xf, var $ NameVarMod ain "s"] )+ $ xApps (xVarOpSeries $ OpSeriesMkSel 1)+ [ procX, klokX ain, XType processRate, var n'flag+ , XLAM (BName (klokV n) kRate)+ $ XLam (BName n'sel (tSel1 procT (klokT ain) (klokT n)))+ $ llet n's (tSeries procT (klokT n) $ sctyOf n)+ ( xApps (xVarOpSeries OpSeriesPack)+ [ procX, klokX ain, klokX n, xsctyOf n+ , var n'sel, var $ NameVarMod ain "s"] )+ go ]++ Generate _sz (Fun xf _)+ -> llet n's (tSeries procT (klokT n) $ sctyOf n)+ ( xApps (xVarOpSeries OpSeriesGenerate)+ [ procX, klokX n, xsctyOf n, xf ])+ go++ Gather v ix+ -> llet n's (tSeries procT (klokT n) $ sctyOf n)+ ( xApps (xVarOpSeries OpSeriesGather)+ ([ procX, klokX v, klokX ix, xsctyOf v+ , var $ NameVarMod v "rv", var $ NameVarMod ix "s"]) )+ go+ Cross _a _b+ -> error "ddc-core-flow.process: Cross combinator not implemented yet"++ -- All cases are handled above+ | otherwise+ = error "ddc-core-flow.process: impossible!"++++ mkProcs []+ -- bs cannot be empty: there's no point of an empty cluster.+ = let procs = concatMap getProc bs+ in case procs of+ (_:_) -> foldl1 mkJoin $ concatMap getProc bs+ [] -> error "ddc-core-flow.process: cluster with no outputs?"++ mkJoin p q+ = xApps (xVarOpSeries OpSeriesJoin) [p, q]++ getProc b@((s, Left _), _)+ = [resizeProc b $ var $ NameVarMod s "proc"]+ getProc b@((a, _), True)+ = [resizeProc b $ var $ NameVarMod a "proc"]+ getProc _+ = []++ resizeProc b v+ = goResize (fst $ fst b) v (reverse bs)++ goResize _ v []+ = v+ goResize n v (((n',b),_):rest)+ | n == n'+ = case b of+ Left (Fold _ _ ain)+ -> goResize ain v rest+ Right (MapN _ (i:_))+ -> goResize i v rest+ Right (MapN _ [])+ -> error "ddc-core-flow.process: Map with no inputs."++ Right (Filter _ ain)+ -> goResize ain+ ( xApps (xVarOpSeries OpSeriesResizeProc)+ [ procX, klokX n, klokX ain+ , xApps (xVarOpSeries OpSeriesResizeSel1)+ [ procX, klokX n, klokX ain, klokX n+ , var $ NameVarMod n "sel"+ , xApps (xVarOpSeries OpSeriesResizeId)+ [ procX, klokX n ]+ ]+ , v ]) rest++ Right (Generate _ _)+ -> v++ Right (Gather _ ain)+ -> goResize ain v rest++ Right (Cross a _b)+ -> goResize a v rest++ | otherwise+ = goResize n v rest++ + allocSize+ -- If there are any inputs, use the size of one of those+ | (i:_) <- arrIns+ = xApps (xVarOpVector OpVectorLength) [xsctyOf i, var i]+ -- Or if it's a generate, find the size of the generate expression.+ | (Scalar sz _:_) <- concatMap findGenerateSize bs+ = sz+ -- XXX Otherwise it must be an external, and this won't be called...+ | otherwise+ = error ("ddc-core-flow: allocSize, but no size known" ++ show arrIns ++ "\n" ++ show bs)++ -- Find the loop rate of the process.+ -- Since we don't have appends, it's just the rate of the first binding+ processRate+ = bindRate (head bs)++ bindRate b+ = let k = klokT (fst $ fst b)+ in case snd $ fst b of+ Left (Fold _ _ ain)+ -> klokT ain+ Right (MapN _ _)+ -> k+ Right (Filter _ ain)+ -> klokT ain+ Right (Generate _ _)+ -> k+ Right (Gather _ _)+ -> k+ Right (Cross ain _)+ -> klokT ain++ -- We just need a name for the Proc type+ procName = NameVarMod outname "PROC"+ procT = TVar $ UName $ procName+ procX = XType $ procT++ klokV = getKlok env+ klokT = TVar . UName . klokV+ klokX = XType . klokT++ findGenerateSize ((_, Right (Generate sz _)), _)+ = [sz]+ findGenerateSize _+ = []+++ -- We just need to find the name of any binding+ -- This head is safe because @mkLets@ will not call @process@ with an empty cluster.+ outname+ = fst $ fst $ head bs++ tyOf n = types Map.! n+ sctyOf = getScalarType . tyOf+ xtyOf = XType . tyOf+ xsctyOf = XType . sctyOf++ var n = XVar $ UName n+++xVarOpSeries n = XVar (UPrim (NameOpSeries n) (typeOpSeries n))+xVarOpVector n = XVar (UPrim (NameOpVector n) (typeOpVector n))+++-- | Get underlying scalar of a vector type - or just return original type if it's not a vector.+getScalarType :: TypeF -> TypeF+getScalarType tt+ = case takePrimTyConApps tt of+ Just (NameTyConFlow TyConFlowVector, [sc]) -> sc+ _ -> tt+++-- | Create map of types of binders+takeTypes :: [DDC.Bind Name] -> Map Name TypeF+takeTypes binds+ = Map.fromList $ concatMap get binds+ where+ get (BName n t) = [(n,t)]+ get _ = []+++getKlok :: SI.Env Name -> Name -> Name+getKlok e n+ | Just t <- SI.lookupV e n+ = ty $ goT t+ | otherwise+ = ty n+ where+ ty = flip NameVarMod "k"++ goT (SI.TVar kv)+ = goKV kv+ -- This doesn't matter much..+ goT (SI.TCross ta tb)+ = NameVarMod (goT ta) (show tb)++ goKV (SI.KV v)+ = v+ goKV (SI.K' kv)+ = NameVarMod (goKV kv) "'"++
+ DDC/Core/Flow/Transform/Rates/SizeInference.hs view
@@ -0,0 +1,485 @@+-- | Performing size inference on a program in Combinator Normal Form+module DDC.Core.Flow.Transform.Rates.SizeInference+ ( Type(..), K(..), Env, Scope(..), Scheme(..)+ , generate+ , lookupV+ , iter+ , parents+ , trans ) +where+import DDC.Core.Flow.Transform.Rates.Combinators+import DDC.Data.Pretty++import Data.List+import Data.Function (on)+import Data.Maybe+import qualified Control.Applicative as A+import Control.Monad++-----------------------------------+-- = Size types, constraints and schemes++-- | Given some variable type, append a number of primes onto it.+-- We want to be able to distinguish between the raw variable types and unification, existential Klock (rate) variables.+-- We generate constraints so that raw variables will appear on the left of equalities, and Ks may appear on the right.+data K v+ = KV v+ | K' (K v)+ deriving (Eq,Ord,Show)+++-- | tau ::=+data Type v+ -- | k+ = TVar (K v)+ -- | tau * tau+ | TCross (Type v) (Type v)+ deriving (Eq, Ord,Show)++-- | Find all variables in type+freeT :: Type a -> [K a]+freeT (TVar a) = [a]+freeT (TCross a b) = freeT a ++ freeT b+++-- | C ::=+data Constraint v+ -- | true+ = CTrue+ -- | v = tau+ | CEqual v (Type v)+ -- | C /\ C+ | CAnd (Constraint v) (Constraint v)+ deriving (Show)++-- | Big conjunction. Join a bunch of constraints together+ands :: [Constraint v] -> Constraint v+ands = foldr CAnd CTrue++-- | Flatten a set of constraints into a simpler, canonical form.+-- Turn it into a list of variable/type equalities, ordered by variable name.+flatten :: Ord v => Constraint v -> [(v, Type v)]+flatten = sortBy (compare `on` fst) . go+ where+ go CTrue = []+ go (CEqual v k) = [(v,k)]+ go (CAnd a b) = go a ++ go b++-- | Convert back from flattened form to a set of @Constraint@+unflatten :: [(v, Type v)] -> Constraint v+unflatten = ands . map (uncurry CEqual)+++-- | sigma ::= forall k... exists k... (x : t)... -> (x : t)...+-- Note that these are all raw variable types.+-- There is no point mentioning unification variables in this solved form.+data Scheme v+ = Scheme+ { _forall :: [K v]+ , _exists :: [K v]+ , _from :: [(v, Type v)]+ , _to :: [(v, Type v)]+ }+ deriving (Show)+++-----------------------------------+-- = Constraint generation+-- == Environment++-- | Gamma ::= • | Gamma, Gamma...+type Env v = [Scope v]++-- | Gamma ::= ...+data Scope v+ -- | v : k+ = EVar v (Type v)+ -- | k+ | EUnify (K v)+ -- | exists k+ | ERigid (K v)+ deriving (Show)++evar :: v -> Scope v+evar v+ = EVar v $ TVar $ KV v+++-- | Search for first (should be only) mention of k in environment, along with its index+lookupV :: Eq v => Env v -> v -> Maybe (Type v)+lookupV es v+ = go es+ where+ go [] = Nothing+ go (EVar v' t : _)+ | v == v'+ = Just t+ go (_:es')+ = go es'++-- | Search for first (should be only) mention of k in environment, along with its index+isUnify :: Eq v => Env v -> K v -> Bool+isUnify es k+ = go es+ where+ go [] = False+ go (EUnify k' : _)+ | k == k'+ = True+ go (_:es')+ = go es'+++-- | Find all free variables in types of environment+freeE :: Env a -> [K a]+freeE es+ = concatMap go es+ where+ go (EVar _ t) = freeT t+ go _ = []+++-- == Generation of constraints+-- For example, the program+--+-- > normalize2 :: Array Int -> (Array Int, Array Int)+-- > normalize2 xs+-- > = let sum1 = fold (+) 0 xs+-- > gts = filter (> 0) xs+-- > sum2 = fold (+) 0 gts+-- > ys1 = map (/ sum1) xs+-- > ys2 = map (/ sum2) xs+-- > in (ys1, ys2)+--+-- will generate environment and constraints+--+-- > xs : kxs, gts : kgts, ys1 : kys1, ys2 : kys2, ∃k1, k2, k3+-- > |- true ∧ kgts = k1 ∧ true+-- > ∧ kxs = k2 ∧ kys1 = k2 ∧ kxs = k3 ∧ kys2 = k3+--+-- | program :_s sigma+generate :: Ord a => Program s a -> Maybe (Env a, Scheme a)+generate program@(Program (_inSs,inAs) _binds (_outSs,outAs))+ = do e <- generateEnv program+ let fvs = freeE e++ let alls x = case x of+ EUnify v | v `elem` fvs -> [v]+ _ -> []+ let exis x = case x of+ ERigid v | v `elem` fvs -> [v]+ _ -> []++ let us = concatMap alls e+ let rs = concatMap exis e++ let inTs = catMaybes $ map (lookupV e) inAs+ let ouTs = catMaybes $ map (lookupV e) outAs++ let fvIn = nub $ concatMap freeT inTs+ let fvOu = nub $ concatMap freeT ouTs++ -- check if there are any rigids mentioned in input types:+ -- this means we'd have an existential input, which is nonsense.+ when (any (flip elem rs) fvIn)+ Nothing++ let sch = Scheme+ { _forall = fvIn `intersect` us+ , _exists = fvOu `intersect` rs+ , _from = inAs `zip` inTs+ , _to = outAs `zip` ouTs+ }+ return (e, sch)+++-- | Get environment+generateEnv :: Ord a => Program s a -> Maybe (Env a)+generateEnv (Program (_inSs,inAs) binds _outs)+ = do let e = concatMap (\i -> [EUnify (KV i), evar i]) inAs+ let (e', c') = generateLets e binds+ -- If solve succeeds, there will be no duplicate left-hand sides in c''.+ (e'', c'') <- solve e' c'+ -- Now, we must group the variables into equivalence classes.+ -- Take all the leftover constraints and substitute them into the environment+ return $ substEAll c'' e''+++-- | Gamma |- lets ~> Gamma |- C+generateLets :: Env a -> [Bind s a] -> (Env a, Constraint a)+generateLets e bs+ = foldl go (e, CTrue) bs+ where+ go (e',c') b+ = let (e'', c'') = generateBind e' b+ in (e'', c' `CAnd` c'')++-- | Gamma | z |- bind ~> Gamma |- C+generateBind :: Env a -> Bind s a -> (Env a, Constraint a)+generateBind env b+ = case b of+ ABind z (MapN _ xs)+ -> let u = K' (KV z)+ env' = evar z : EUnify u : env+ con = ands $ map (\i -> CEqual i (TVar u)) (z : xs)+ in (env', con)++ ABind z (Filter _ _)+ -> let u = K' (KV z)+ env' = evar z : ERigid u : env+ con = CEqual z (TVar u)+ in (env', con)++ SBind _ (Fold _ _ _)+ -> (env, CTrue)++ ABind z (Generate _ _)+ -> let u = K' (KV z)+ env' = evar z : ERigid u : env+ con = CEqual z (TVar u)+ in (env', con)++ ABind z (Gather _ i)+ -> let u = K' (KV z)+ env' = evar z : EUnify u : env+ con = CEqual z (TVar u) `CAnd` CEqual i (TVar u)+ in (env', con)++ ABind z (Cross x y)+ -> let u = K' (KV z)+ u' = K' (K' (KV z))+ env' = evar z : EUnify u' : EUnify u : env+ con = ands [ CEqual z (TCross (TVar u) (TVar u'))+ , CEqual x (TVar u)+ , CEqual y (TVar u') ]+ in (env', con)++ Ext (NameArray a) _ (_, _)+ -> let env' = [evar a, ERigid $ K' $ KV a] ++ env+ con = CEqual a $ TVar $ K' $ KV a+ in (env', con)++ Ext (NameScalar _) _ (_, _)+ -> (env, CTrue)++++ +-- | Solving constraints.+-- If we take the environment and constraints from @normalize2@,+-- > xs : kxs, gts : kgts, ys1 : kys1, ys2 : kys2, ∃k1, k2, k3+-- > |- true ∧ kgts = k1 ∧ true+-- > ∧ kxs = k2 ∧ kys1 = k2 ∧ kxs = k3 ∧ kys2 = k3+-- the constraints can be converted to canonical form by 'flatten':+-- > [kgts = k1, kxs = k2, kxs = k3, kys1 = k2, kys2 = k3]+-- After that, we iterate through the list of constraints, finding duplicate left hand sides.+-- For some duplicate left hand side, such as+-- > kxs = k2, kxs = k3+-- the k2 and k3 must be unified in Env.+solve :: Ord a => Env a -> Constraint a -> Maybe (Env a, Constraint a)+solve e c+ = let cs = flatten c+ in go cs e cs+ where+ go [ ] e' c' = return (e', unflatten c')+ go [_] e' c' = return (e', unflatten c')++ go ((x,a):(y,b):rs) e' c'+ | x == y+ = do sub <- unify e a b+ -- Substitute into both the full constraint set,+ -- and just those remaining to check+ let e'' = substE sub e'+ let c'' = substCs sub c'+ let rest= substCs sub ((y,b) : rs)+ go rest e'' c''+ | otherwise+ = go ((y,b) : rs) e' c'+++-- | A substitution, mapping some variable to a type+type Subst a = [(K a, Type a)]+++-- | Perform substitution over types+substT :: Ord a => Subst a -> Type a -> Type a+substT sub t@(TVar a)+ | Just t' <- lookup a sub+ = t'+ | otherwise+ = t+substT sub (TCross a b)+ = TCross (substT sub a) (substT sub b)+++-- | Perform substitution over already-flattened constraints+substCs :: Ord a => Subst a -> [(a, Type a)] -> [(a, Type a)]+substCs sub cs+ = map (\(v,t) -> (v, substT sub t)) cs+++-- | Perform substitution over environment+substE :: Ord a => Subst a -> Env a -> Env a+substE sub es+ = map go es+ where+ go (EVar v t) = EVar v (substT sub t)+ go e = e+++-- | Take all constraints, treat them as substitutions+substEAll :: Ord a => Constraint a -> Env a -> Env a+substEAll cs es+ = substE (map mkSub $ flatten cs) es+ where+ mkSub (v,t) = (KV v, t)+++-- | Given two types, find a substitution that unifies the two together+-- The substitution may only change the value of unifier variables+unify :: Ord a => Env a -> Type a -> Type a -> Maybe (Subst a)+unify e l r+ = go l r+ where+ go (TVar a) (TVar b)+ | a == b = Just []+ | isUnify e a = Just [(a, TVar b)]+ | isUnify e b = Just [(b, TVar a)]+ -- Neither variables are unifiers. It cannot be done.+ | otherwise = Nothing++ go (TCross a1 a2) (TCross b1 b2)+ = (++) A.<$> go a1 b1 A.<*> go a2 b2++ go (TVar a) b@(TCross _ _)+ | isUnify e a+ = Just [(a, b)]+ | otherwise+ = Nothing++ go a@(TCross _ _) (TVar b)+ | isUnify e b+ = Just [(b, a)]+ | otherwise+ = Nothing+++-- = Iteration size and transducers++-- | Find iteration size of given combinator+iter :: (Eq a, Eq s) => Program s a -> Env a -> CName s a -> Maybe (Type a)+iter program e nm+ | NameScalar nm' <- nm+ = do b <- lookupS program nm'+ case b of+ Fold _ _ n -> get n + | NameArray nm' <- nm+ = do b <- lookupA program nm'+ case b of+ MapN{} -> get nm'+ Filter _ as -> get as+ Generate _ _ -> get nm'+ Gather _d is -> get is+ Cross as bs -> TCross A.<$> get as A.<*> get bs+ -- Otherwise, it's external.+ | otherwise+ = Nothing+ where+ get = lookupV e+++-- | Find a bindings' transducer.+-- Only array bindings can have transducers.+trans :: (Eq a, Eq s) => Program s a -> CName s a -> Maybe (CName s a)+trans bs nm+ | NameArray nm' <- nm+ , Just (Filter _ n) <- lookupA bs nm' = trans' (NameArray n)+ | otherwise = trans' nm+ where+ trans' (NameScalar o)+ = case lookupS bs o of+ Just (Fold _ _ n)+ -> trans' (NameArray n)++ -- Not a binding, or an external+ Nothing+ -> Nothing++ trans' (NameArray o)+ = case lookupA bs o of+ Just (Filter _ _n)+ -> Just (NameArray o)++ Just (MapN _ ns)+ -> listToMaybe $ catMaybes $ map (trans' . NameArray) ns+ Just (Gather _d i)+ -> trans' (NameArray i)++ Just (Generate _ _)+ -> Nothing+ Just (Cross _ _)+ -> Nothing++ -- Not a binding, or an external+ Nothing+ -> Nothing+++-- | Find pair of parent transducers with same iteration size+parents :: (Eq a, Eq s) => Program s a -> Env a -> CName s a -> CName s a -> Maybe (CName s a, CName s a)+parents bs e a b+ | itsz a == itsz b+ = Just (a,b)++ | otherwise+ = let pas = trans bs a >>= \a'' -> parents bs e a'' b+ pbs = trans bs b >>= \b'' -> parents bs e a b''+ ps = catMaybes [pas, pbs]+ -- If @b@ is a child of @a@, we want to find the parents @(a,a)@.+ -- There may be other parents, but @(a,a)@ is the "most specific".+ -- There is actually an error in the paper - nodes may have multiple parents+ -- if one node is the parent/transducer of the other.+ same= filter (\(a',b') -> a' `elem` [a,b] || b' `elem` [a,b]) ps+ in case same of+ (s:_) -> Just s+ [] -> listToMaybe ps++ where+ itsz = iter bs e+ +-----------------------------------+-- == Pretty printing++instance (Pretty v) => Pretty (K v) where+ ppr (KV v) = ppr v+ ppr (K' v) = ppr v <> squote++instance (Pretty v) => Pretty (Type v) where+ ppr (TVar v) = ppr v+ ppr (TCross a b) = ppr a <+> text "*" <+> ppr b+++instance (Pretty v) => Pretty (Maybe (Type v)) where+ ppr (Just t) = ppr t+ ppr Nothing = text "(no type)"++instance (Pretty v) => Pretty (Scope v) where+ ppr (EVar v t) = ppr v <+> text ":" <+> ppr t+ ppr (EUnify v) = text "∀" <> ppr v+ ppr (ERigid v) = text "∃" <> ppr v++{-+instance (Pretty v) => Pretty (Env v) where+ ppr = hcat . map ppr+-}++instance (Pretty v) => Pretty (Scheme v) where+ ppr (Scheme foralls exists from to)+ = text "∀" <> hcat (map ppr foralls) <> text ". "+ <+> text "∃" <> hcat (map ppr exists) <> text ". "+ <+> tupled (map tppr from) <+> text "→"+ <+> tupled (map tppr to)+ where+ tppr (v,t) = ppr v <+> text ":" <+> ppr t++
DDC/Core/Flow/Transform/Schedule.hs view
@@ -1,252 +1,13 @@ module DDC.Core.Flow.Transform.Schedule- (scheduleProcess)-where-import DDC.Core.Flow.Transform.Schedule.SeriesEnv-import DDC.Core.Flow.Transform.Schedule.Nest-import DDC.Core.Flow.Procedure-import DDC.Core.Flow.Process-import DDC.Core.Flow.Compounds-import DDC.Core.Flow.Prim-import DDC.Core.Flow.Exp-import DDC.Base.Pretty-import Control.Monad----- | Create loops from a list of operators.------ * The input series must all have the same rate.----scheduleProcess :: Process -> Procedure-scheduleProcess - (Process - { processName = name- , processParamTypes = psType- , processParamValues = psValue- , processContexts = contexts- , processOperators = ops - , processStmts = stmts- , processResultType = tResult- , processResult = xResult})- = let- -- Create all the contexts, starting with an empty loop nest.- Just nest1 = foldM insertContext NestEmpty contexts-- -- Schedule the series operators into the nest.- nest2 = scheduleOperators nest1 emptySeriesEnv ops-- in Procedure- { procedureName = name- , procedureParamTypes = psType- , procedureParamValues = psValue- , procedureNest = nest2- , procedureStmts = stmts- , procedureResultType = tResult- , procedureResult = xResult }------------------------------------------------------------------------------------- | Schedule some series operators into a loop nest.-scheduleOperators - :: Nest -- ^ The starting loop nest.- -> SeriesEnv -- ^ Series environment maps series binds to elem binds.- -> [Operator] -- ^ The operators to schedule.- -> Nest--scheduleOperators nest0 env ops- = case ops of- [] -> nest0- op : ops' - -> let (env', nest') = scheduleOperator nest0 env op- in scheduleOperators nest' env' ops'----- | Schedule a single series operator into a loop nest.-scheduleOperator - :: Nest -- ^ The current loop nest- -> SeriesEnv -- ^ Series environment maps series binds to elem binds.- -> Operator -- ^ Operator to schedule.- -> (SeriesEnv, Nest)--scheduleOperator nest0 env op-- -- Id -------------------------------------------- | OpId{} <- op- = let- -- Get binders for the input elements.- Just nSeries- = takeNameOfBound (opInputSeries op)-- (uInput, env1, nest1)- = bindNextElem nSeries- (opInputRate op) (opElemType op)- env nest0-- Just bResultElem - = elemBindOfSeriesBind $ opResultSeries op-- context = ContextRate (opInputRate op)-- Just nest2 = insertBody nest1 context- $ [ BodyStmt bResultElem (XVar uInput) ]-- in (env1, nest2)--- -- Create ---------------------------------------- | OpCreate{} <- op- = let - -- Get binders for the input elements.- Just nSeries - = takeNameOfBound (opInputSeries op)- - (uInput, env1, nest1)- = bindNextElem nSeries - (opInputRate op) (opElemType op)- env nest0-- -- Insert statements that allocate the vector.- -- We use the type-level series rate to describe the length of- -- the vector. This will be repalced by a RateNat value during- -- the concretization phase.- BName nVec _ = opResultVector op- context = ContextRate (opInputRate op)-- -- Rate we're using to allocate the result vector.- -- This will be larger than the actual result series rate if we're- -- creating a vector inside a selector context.- Just tRateAlloc = opAllocRate op-- Just nest2 = insertStarts nest1 context- $ [ StartVecNew - nVec -- allocated vector- (opElemType op) -- elem type- tRateAlloc ] -- allocation rate-- -- Insert statements that write the current element to the vector.- Just nest3 = insertBody nest2 context - $ [ BodyVecWrite - nVec -- destination vector- (opElemType op) -- elem type- (XVar (UIx 0)) -- index- (XVar uInput) ] -- value-- -- Slice the vector at the end- Just nest4 = insertEnds nest3 context - $ [ EndVecSlice- nVec -- destination vector- (opElemType op) -- elem type- (opInputRate op) ] -- index-- -- But only slice it if the input rate is different to output rate- nest' = if opInputRate op == tRateAlloc- then nest3- else nest4- in (env1, nest')-- - -- Maps ------------------------------------------ | OpMap{} <- op- = let - -- Get binders for the input elements.- Just nsSeries = sequence $ map takeNameOfBound $ opInputSeriess op- tsRate = repeat (opInputRate op)- tsElem = map typeOfBind $ opWorkerParams op-- (usInputs, env1, nest1) - = bindNextElems (zip3 nsSeries tsRate tsElem) env nest0-- -- Variables for all the input elements.- xsInputs = map XVar usInputs-- -- Substitute input element vars into the worker body.- xBody = foldl (\x (b, p) -> XApp (XLam b x) p)- (opWorkerBody op)- (zip (opWorkerParams op) xsInputs)-- -- Binder for a single result element in the series context.- Just nResultSeries = takeNameOfBind $ opResultSeries op- nResultElem = NameVarMod nResultSeries "elem"- uResultElem = UName nResultElem-- Just bResultElem = elemBindOfSeriesBind (opResultSeries op)-- -- Insert the expression that computes the new result into the nest.- context = ContextRate $ opInputRate op- Just nest2 = insertBody nest1 context- $ [ BodyStmt bResultElem xBody ]-- -- Associate the variable for the result element with the result series.- env2 = insertElemForSeries nResultSeries uResultElem env1-- in (env2, nest2)--- -- Folds ---------------------------------------- | OpFold{} <- op- = let - -- Lookup binders for the input elements.- Just nSeries = takeNameOfBound (opInputSeries op)- tRate = opInputRate op- tInputElem = typeOfBind (opWorkerParamElem op)- (uInput, env1, nest1)- = bindNextElem nSeries tRate tInputElem env nest0-- -- Make a name for the accumulator.- BName nResult _ = opResultValue op- nAcc = NameVarMod nResult "acc"-- -- Type of the accumulator.- tAcc = typeOfBind (opWorkerParamAcc op)- - -- Insert statements that initialize the starting value- -- of the accumulator.- context = ContextRate $ opInputRate op- Just nest2 = insertStarts nest1 context- $ [ StartAcc nAcc tAcc (opZero op) ]-- -- Substitute input and accumulator vars into worker body.- xBody = XApp (XApp ( XLam (opWorkerParamElem op)- $ XLam (opWorkerParamIndex op) - (opWorkerBody op))- (XVar uInput))- (XVar (UIx 0))-- -- Insert statements that update the accumulator- -- into the loop body.- Just nest3 = insertBody nest2 context- $ [ BodyAccRead nAcc tAcc (opWorkerParamAcc op)- , BodyAccWrite nAcc tAcc xBody ]- - -- Insert statements that read back the final value- -- after the loop has finished.- Just nest4 = insertEnds nest3 context- $ [ EndAcc nResult tAcc nAcc ]- in (env1, nest4)--- -- Pack ----------------------------------------- | OpPack{} <- op- = let - -- Lookup binder for the input element.- Just nSeries = takeNameOfBound (opInputSeries op)- tRate = opInputRate op- tInputElem = opElemType op- (uInput, env1, nest1)- = bindNextElem nSeries tRate tInputElem env nest0-- -- Associate the variable for the result element with the result- -- series. We could instead add an explicit binding, but it's - -- easier just to insert an entry into the series environment.- Just nResultSeries = takeNameOfBind (opResultSeries op)- env2 = insertElemForSeries nResultSeries uInput env1-- in (env2, nest1)+ ( scheduleScalar - | otherwise- = error $ renderIndent - $ vcat [ text "ddc-core-flow.scheduleOperator"- , indent 4 $ text "Can't schedule operator."- , indent 4 $ ppr op ]+ -- * Scheduling process kernels+ , scheduleKernel+ , Error (..)+ , Lifting (..))+where+import DDC.Core.Flow.Transform.Schedule.Kernel+import DDC.Core.Flow.Transform.Schedule.Scalar
+ DDC/Core/Flow/Transform/Schedule/Base.hs view
@@ -0,0 +1,108 @@++module DDC.Core.Flow.Transform.Schedule.Base+ ( elemBindOfSeriesBind+ , elemBoundOfSeriesBound+ , elemTypeOfSeriesType+ , resultRateTypeOfSeriesType+ , procTypeOfSeriesType++ , rateTypeOfRateVecType++ , elemTypeOfVectorType+ , bufOfVectorName)+where+import DDC.Core.Flow.Compounds+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Exp+++-- | Given the bind of a series, produce the bound that refers to the+-- next element of the series in its context.+elemBindOfSeriesBind :: BindF -> Maybe BindF+elemBindOfSeriesBind bSeries+ | BName nSeries tSeries' <- bSeries+ , nElem <- NameVarMod nSeries "elem"+ , Just tElem <- elemTypeOfSeriesType tSeries'+ = Just $ BName nElem tElem++ | otherwise+ = Nothing+ ++-- | Given the bound of a series, produce the bound that refers to the+-- next element of the series in its context.+elemBoundOfSeriesBound :: BoundF -> Maybe BoundF+elemBoundOfSeriesBound uSeries+ | UName nSeries <- uSeries+ , nElem <- NameVarMod nSeries "elem"+ = Just $ UName nElem++ | otherwise+ = Nothing+++-- | Given the type of a series like @Series k e@, produce the type+-- of a single element, namely the @e@.+elemTypeOfSeriesType :: TypeF -> Maybe TypeF+elemTypeOfSeriesType tSeries'+ | Just (_tcSeries, [_tP, _tK, tE]) <- takeTyConApps tSeries'+ = Just tE++ | otherwise+ = Nothing+++-- | Given the type of a series like @Series p k l e@, produce the type+-- of the result rate, namely the @k@.+resultRateTypeOfSeriesType :: TypeF -> Maybe TypeF+resultRateTypeOfSeriesType tSeries'+ | isSeriesType tSeries'+ , Just (_tcSeries, [_tP, tK, _tE]) <- takeTyConApps tSeries'+ = Just tK++ | otherwise+ = Nothing++-- | Given the type of a series like @Series p k l e@, produce the type+-- of the process, namely the @p@+procTypeOfSeriesType :: TypeF -> Maybe TypeF+procTypeOfSeriesType tSeries'+ | isSeriesType tSeries'+ , Just (_tcSeries, [tP, _tK, _tE]) <- takeTyConApps tSeries'+ = Just tP++ | otherwise+ = Nothing+++-- | Given the type of a rate-annotated vector like @RateVec k e@, produce the type+-- of the rate, namely the @k@.+rateTypeOfRateVecType :: TypeF -> Maybe TypeF+rateTypeOfRateVecType tV'+ | isRateVecType tV'+ , Just (_tcV, [tK, _tE]) <- takeTyConApps tV'+ = Just tK++ | otherwise+ = Nothing+++++-- Vector ---------------------------------------------------------------------+-- | Given the type of a vector like @Vector k e@, produce the type+-- of a single element, namely the @e@.+elemTypeOfVectorType :: TypeF -> Maybe TypeF+elemTypeOfVectorType tVector'+ | Just (_tcVector, [tE]) <- takeTyConApps tVector'+ = Just tE++ | otherwise+ = Nothing++-- | Given the name of a vector, find the name of the binding of its underlying buffer.+-- This binding is produced by Extract.+bufOfVectorName :: BoundF -> BoundF+bufOfVectorName (UName n) = UName $ NameVarMod n "buf"+bufOfVectorName b = error (show b)+
+ DDC/Core/Flow/Transform/Schedule/Error.hs view
@@ -0,0 +1,75 @@++module DDC.Core.Flow.Transform.Schedule.Error+ (Error (..))+where+import DDC.Core.Flow.Exp+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Process.Operator+import DDC.Core.Flow.Transform.Annotate+import DDC.Core.Pretty+import qualified DDC.Core.Flow.Transform.Slurp.Error as Slurp+++-- | Reason a process kernel could not be scheduled into a procedure.+data Error+ -- | Process has no rate parameters.+ = ErrorNoRateParameters++ -- | Process has series of different rates,+ -- but all series must have the same rate.+ | ErrorMultipleRates++ -- | Primary rate variable of the process does not match+ -- the rate of the paramter series.+ | ErrorPrimaryRateMismatch++ -- | Cannot lift expression to vector operators.+ | ErrorCannotLiftExp (Exp () Name)++ -- | Cannot lift type to vector type.+ | ErrorCannotLiftType (Type Name)++ -- | Current scheduler does not support this operator.+ | ErrorUnsupported Operator++ -- | Multiple fills to the same output, in "interfering contexts" (eg same branch of an append)+ | ErrorMultipleFills++ -- | Cannot slurp process description from one of the top-level+ -- declarations.+ | ErrorSlurpError Slurp.Error+ deriving Show+++instance Pretty Error where+ ppr err+ = case err of+ ErrorNoRateParameters+ -> vcat [ text "Series process has no rate parameters." ]++ ErrorMultipleRates+ -> vcat [ text "Series process has multiple rate parameters."]++ ErrorPrimaryRateMismatch+ -> vcat [ text "Series process primary rate mismatch."]++ ErrorCannotLiftExp x+ -> vcat [ text "Cannot lift expression in series process."+ , empty+ , indent 4 $ ppr (annotate () x) ]++ ErrorCannotLiftType t+ -> vcat [ text "Cannot lift type in series process."+ , empty+ , indent 4 $ ppr t ]++ ErrorUnsupported _+ -> vcat [ text "Cannot lower series operator with this method."]++ ErrorMultipleFills+ -> vcat [ text "Multiple fills to the same output, in 'interfering contexts' (eg same branch of an append)" ]++ ErrorSlurpError errSlurp+ -> vcat [ text "Error slurping series process."+ , indent 2 $ ppr errSlurp ]+
+ DDC/Core/Flow/Transform/Schedule/Kernel.hs view
@@ -0,0 +1,320 @@++module DDC.Core.Flow.Transform.Schedule.Kernel+ ( scheduleKernel+ , Error (..)+ , Lifting (..))+where+import DDC.Core.Flow.Transform.Schedule.Nest+import DDC.Core.Flow.Transform.Schedule.Error+import DDC.Core.Flow.Transform.Schedule.Lifting+import DDC.Core.Flow.Transform.Schedule.Base+import DDC.Core.Flow.Process+import DDC.Core.Flow.Procedure+import DDC.Core.Flow.Compounds+import DDC.Core.Flow.Exp+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Context+++-- | Schedule a process kernel into a procedure.+--+-- A process kernel is a process with the following restricitions:+-- 1) All input series have the same rate.+-- 2) A kernel accumulates data into sinks, rather than allocating new values.+-- 3) A kernel can be scheduled into a single loop.+-- +--- The process kernel scheduler can produce code for+-- map, reduce, fill, gather, scatter+--+-- But not+-- fold -- use reduce instead.+-- create -- use fill instead.+-- pack -- we don't support SIMD masks.+--+scheduleKernel :: Lifting -> Process -> Either Error Procedure+scheduleKernel + lifting+ (Process { processName = name+ , processParamFlags = bsParams+ , processContext = context })+ = do + -- Lower rates of RateVec parameters.+ -- We also keep a copy of the original RateVec,+ -- in case it is used by a cross or a gather.+ let bsParams_lowered+ = map (\(flag, BName n t) + -> if not flag+ then case lowerSeriesRate lifting t of+ Just t'+ -> (flag, BName n t')+ Nothing+ -> (flag, BName n t)+ else (flag, BName n t))+ $ bsParams++ let bsParamValues+ = map snd+ $ filter (not.fst)+ $ bsParams++ let c = liftingFactor lifting++ let frate r _ = return $ tDown c r+ let fop = scheduleOperator lifting bsParamValues ++ nest <- scheduleContext frate fop context++ return $ Procedure+ { procedureName = name+ , procedureParamFlags = bsParams_lowered+ , procedureNest = nest }+++-------------------------------------------------------------------------------+-- | Schedule a single series operator into a loop nest.+scheduleOperator + :: Lifting+ -> ScalarEnv+ -> FillMap -- ^ Map of which operators use which write-to accs+ -> Operator -- ^ The operator to schedule.+ -> Either Error ([StmtStart], [StmtBody], [StmtEnd])++scheduleOperator lifting envScalar fills op+ -- Id -------------------------------------------+ | OpId{} <- op+ = do -- Get binders for the input elements.+ let Just bResult = elemBindOfSeriesBind (opResultSeries op)+ >>= liftTypeOfBind lifting+ let Just uInput = elemBoundOfSeriesBound (opInputSeries op)++ return ( [] + , [ BodyStmt bResult (XVar uInput) ]+ , [] )++ | OpSeriesOfArgument{} <- op+ = do let c = liftingFactor lifting+ let tK = opInputRate op+ let tA = opElemType op+ let BName n t = opResultSeries op+ let Just t' = lowerSeriesRate lifting t+ let bS = BName n t'+ let Just uS = takeSubstBoundOfBind bS+ let Just tP = procTypeOfSeriesType (typeOfBind bS)+ let Just bResult = elemBindOfSeriesBind bS+ >>= liftTypeOfBind lifting++ -- Body expressions that take the next element from each input series.+ let bodies+ = [ BodyStmt bResult+ (xNextC c tP tK tA (XVar uS) (XVar (UIx 0))) ]++ return ( []+ , bodies+ , [] )++ -- Map -----------------------------------------+ | OpMap{} <- op+ = do -- Bind for the result element.+ let Just bResultE = elemBindOfSeriesBind (opResultSeries op)+ >>= liftTypeOfBind lifting++ -- Bounds for all the input series.+ let Just usInput = sequence + $ map elemBoundOfSeriesBound + $ opInputSeriess op++ -- Bounds for the worker parameters, along with the lifted versions.+ let bsParam = opWorkerParams op+ bsParam_lifted <- mapM (liftTypeOfBindM lifting) bsParam+ let envLift = zip bsParam bsParam_lifted++ xWorker_lifted <- liftWorker lifting envScalar envLift+ $ opWorkerBody op++ -- Expression to apply the inputs to the worker.+ let xBody = foldl (\x (b, p) -> XApp (XLam b x) p)+ (xWorker_lifted)+ [(b, XVar u) + | b <- bsParam_lifted+ | u <- usInput ]++ let bodies = [ BodyStmt bResultE xBody ]++ return ([], bodies, [])++ -- Fill ----------------------------------------+ | OpFill{} <- op+ = do let c = liftingFactor lifting++ -- Bound for input element.+ let Just uInput = elemBoundOfSeriesBound + $ opInputSeries op++ let UName nVec = opTargetVector op+ let index+ | Just n <- getAcc fills nVec + = xRead tNat + $ XVar $ UName $ NameVarMod n "count"+ | otherwise+ = XVar $ UIx 0++ -- Write to target vector.+ let bodies = [ BodyStmt (BNone tUnit)+ (xWriteVectorC c+ (opElemType op)+ (XVar $ bufOfVectorName $ opTargetVector op)+ index+ (XVar $ uInput)) ]++ return ([], bodies, [])++ -- Reduce --------------------------------------+ | OpReduce{} <- op+ = do let c = liftingFactor lifting+ let tA = typeOfBind $ opWorkerParamElem op++ -- Evaluate the zero value and initialize the vector accumulator.+ let UName nRef = opTargetRef op+ let nAccZero = NameVarMod nRef "zero"+ let bAccZero = BName nAccZero tA+ let uAccZero = UName nAccZero++ let nAccVec = NameVarMod nRef "vec"+ let uAccVec = UName nAccVec++ let starts+ = [ StartStmt bAccZero (opZero op)+ , StartAcc nAccVec+ (tVec c tA)+ (xvRep c tA (XVar uAccZero)) ]++ -- Bound for input element.+ let Just uInput = elemBoundOfSeriesBound + $ opInputSeries op++ -- Bound for intermediate accumulator value.+ let nAccVal = NameVarMod nRef "val"+ let uAccVal = UName nAccVal+ let bAccVal = BName nAccVal (tVec c tA)++ -- Lift the worker function.+ let bsParam = [ opWorkerParamAcc op, opWorkerParamElem op ]+ bsParam_lifted <- mapM (liftTypeOfBindM lifting) bsParam+ let envLift = zip bsParam bsParam_lifted++ xWorker_lifted <- liftWorker lifting envScalar envLift + $ opWorkerBody op++ -- Read the current accumulator value and update it with the worker.+ let xBody_lifted x1 x2+ = XApp (XApp ( XLam (opWorkerParamAcc op)+ $ XLam (opWorkerParamElem op)+ (xWorker_lifted))+ x1)+ x2++ let bodies+ = [ BodyAccRead nAccVec (tVec c tA) bAccVal+ , BodyAccWrite nAccVec (tVec c tA) + (xBody_lifted (XVar uAccVal) (XVar uInput)) ]++ -- Read back the vector accumulator and to a final fold over its parts.+ let nAccResult = NameVarMod nRef "res"+ let bAccResult = BName nAccResult (tVec c tA)+ let uAccResult = UName nAccResult+ let bPart (i :: Int) = BName (NameVarMod nAccResult (show i)) tA+ let uPart (i :: Int) = UName (NameVarMod nAccResult (show i))++ let nAccInit = NameVarMod nRef "init"++ let xBody x1 x2+ = XApp (XApp ( XLam (opWorkerParamAcc op)+ $ XLam (opWorkerParamElem op)+ (opWorkerBody op))+ x1)+ x2++ let ends+ = [ EndStmt bAccResult+ (xRead (tVec c tA) (XVar uAccVec))++ , EndStmt (BName nAccInit tA)+ (xRead tA (XVar $ opTargetRef op)) ]++ ++ [ EndStmt (bPart 0)+ (xBody (XVar $ UName nAccInit)+ (xvProj c 0 tA (XVar uAccResult))) ]++ ++ [ EndStmt (bPart i)+ (xBody (XVar (uPart (i - 1)))+ (xvProj c i tA (XVar uAccResult)))+ | i <- [1.. c - 1]]+ -- Write final value to destination.+ ++ [ EndStmt (BNone tUnit)+ (xWrite tA (XVar $ opTargetRef op)+ (XVar $ uPart (c - 1))) ]+ -- Bind final unit value.+ ++ [ EndStmt (opResultBind op)+ xUnit ]+++ return (starts, bodies, ends)+++ -- Gather --------------------------------------+ | OpGather{} <- op+ = do + let c = liftingFactor lifting++ -- Bind for result element.+ let Just bResultE = elemBindOfSeriesBind (opResultBind op)+ >>= liftTypeOfBind lifting++ -- Bound of source index.+ let Just uIndex = elemBoundOfSeriesBound (opSourceIndices op)++ -- Read from vector.+ let bodies = [ BodyStmt bResultE+ (xvGather c + (opVectorRate op)+ (opElemType op)+ (XVar $ opSourceVector op)+ (XVar $ uIndex)) ]++ return ([], bodies, [])++ -- Scatter -------------------------------------+ | OpScatter{} <- op+ = do + let c = liftingFactor lifting++ -- Bound of source index.+ let Just uIndex = elemBoundOfSeriesBound (opSourceIndices op)++ -- Bound of source elements.+ let Just uElem = elemBoundOfSeriesBound (opSourceElems op)++ -- Read from vector.+ let bodies = [ BodyStmt (BNone tUnit)+ (xvScatter c+ (opElemType op)+ (XVar $ opTargetVector op)+ (XVar $ uIndex) (XVar $ uElem)) ]++ -- Bind final unit value.+ let ends = [ EndStmt (opResultBind op)+ xUnit ]++ return ([], bodies, ends)++ -- Unsupported ---------------------------------+ | otherwise+ = Left $ ErrorUnsupported op+++liftTypeOfBindM :: Lifting -> Bind Name -> Either Error (Bind Name)+liftTypeOfBindM lifting b+ = case liftTypeOfBind lifting b of+ Just b' -> return b'+ _ -> Left $ ErrorCannotLiftType (typeOfBind b)+
+ DDC/Core/Flow/Transform/Schedule/Lifting.hs view
@@ -0,0 +1,130 @@++module DDC.Core.Flow.Transform.Schedule.Lifting+ ( Lifting (..)+ , ScalarEnv+ , LiftEnv++ -- * Lifting Types+ , liftType+ , liftTypeOfBind+ , liftWorker++ -- * Lowering Types+ , lowerSeriesRate)+where+import DDC.Core.Flow.Transform.Schedule.Error+import DDC.Core.Flow.Compounds+import DDC.Core.Flow.Exp+import DDC.Core.Flow.Prim+import Control.Monad+import Data.List+++-- | Lifting config controls how many elements should be processed +-- per loop iteration.+data Lifting+ = Lifting+ { -- How many elements to process for each loop iteration.+ liftingFactor :: Int }+ deriving (Eq, Show)+++-- | Scalar values in scope.+type ScalarEnv+ = [BindF]++-- | Map original variable to lifted version.+type LiftEnv+ = [(BindF, BindF)]+++-- | Try to lift the given type.+liftType :: Lifting -> TypeF -> Maybe TypeF +liftType l tt+ | liftingFactor l == 1 + = Just tt++ | elem tt + [ tFloat 32, tFloat 64+ , tWord 8, tWord 16, tWord 32, tWord 64+ , tInt+ , tNat ]++ = Just (tVec (liftingFactor l) tt)++ | otherwise + = Nothing+++-- | Try to lift the type of a binder.+liftTypeOfBind :: Lifting -> BindF -> Maybe BindF+liftTypeOfBind l b+ = case b of+ BName n t -> liftM (BName n) (liftType l t)+ BAnon t -> liftM BAnon (liftType l t)+ BNone t -> liftM BNone (liftType l t)+++-- | Try to lift a first-order worker expression to so it operates on elements+-- of vec type instead of scalars.+liftWorker :: Lifting -> ScalarEnv -> LiftEnv -> ExpF -> Either Error ExpF+liftWorker lifting envScalar envLift xx+ = let down = liftWorker lifting envScalar envLift+ in case xx of+ XVar u+ -- Replace vars by their vector version.+ | Just (_, bL) <- find (\(bS', _) -> boundMatchesBind u bS') envLift+ , Just uL <- takeSubstBoundOfBind bL+ -> Right (XVar uL)++ -- Replicate scalar vars.+ -- ISSUE #328: Element type for rep opretora is hard coded to Float32+ | any (boundMatchesBind u) envScalar+ , nPrim <- PrimVecRep (liftingFactor lifting)+ , tPrim <- typePrimVec nPrim+ -> Right $ XApp (XApp (XVar (UPrim (NamePrimVec nPrim) tPrim))+ (XType $ tFloat 32))+ xx++ -- Replicate literals.+ -- ISSUE #328: Element type for rep opretora is hard coded to Float32+ XCon dc+ | DaConPrim (NameLitFloat _ 32) _+ <- dc+ , nPrim <- PrimVecRep (liftingFactor lifting)+ , tPrim <- typePrimVec nPrim+ -> Right $ XApp (XApp (XVar (UPrim (NamePrimVec nPrim) tPrim)) + (XType $ tFloat 32))+ xx++ -- Replace scalar primops by vector versions.+ XApp (XVar (UPrim (NamePrimArith prim) _)) (XType tElem)+ | Just prim' <- liftPrimArithToVec (liftingFactor lifting) prim+ -> Right $ XApp (XVar (UPrim (NamePrimVec prim') (typePrimVec prim')))+ (XType tElem)+++ -- Boiler plate application.+ XApp x1 x2 + -> do x1' <- down x1+ x2' <- down x2+ return $ XApp x1' x2'+++ _ -> Left (ErrorCannotLiftExp xx)+++-- Down -----------------------------------------------------------------------+-- | Lower the rate of a series,+-- to account for lifting of the code that consumes it.+lowerSeriesRate :: Lifting -> TypeF -> Maybe TypeF +lowerSeriesRate lifting tt+ | Just (NameTyConFlow TyConFlowSeries, [tP, tK, tA])+ <- takePrimTyConApps tt+ , c <- liftingFactor lifting+ = Just (tSeries tP (tDown c tK) tA)+++ | otherwise+ = Nothing+
DDC/Core/Flow/Transform/Schedule/Nest.hs view
@@ -1,177 +1,183 @@ module DDC.Core.Flow.Transform.Schedule.Nest- ( insertContext- , insertStarts- , insertBody- , insertEnds)+ ( -- * Insertion into a loop nest+ scheduleContext+ ) where import DDC.Core.Flow.Procedure-import DDC.Core.Flow.Compounds-import DDC.Core.Flow.Prim+import DDC.Core.Flow.Process import DDC.Core.Flow.Exp-import Data.Monoid+import DDC.Core.Flow.Transform.Schedule.Error+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Compounds+import DDC.Core.Flow.Context +import Control.Arrow+import qualified Data.Map as Map ----------------------------------------------------------------------------------- | Insert a skeleton context into a nest.--- The new context doesn't contain any statements, it just provides--- the infrastructure to execute statements at the new rate.-insertContext :: Nest -> Context -> Maybe Nest+scheduleContext+ :: (Type Name -> Context -> Either Error (Type Name))+ -> (FillMap -> Operator -> Either Error ([StmtStart], [StmtBody], [StmtEnd]))+ -> Context+ -> Either Error Nest --- Loop context at top level.-insertContext NestEmpty context@ContextRate{}- = Just $ nestOfContext context+scheduleContext frate fop topctx+ = do fills <- maybe (Left ErrorMultipleFills) Right+ $ pathsOfFills topctx --- Selector context inside loop context.-insertContext nest@NestLoop{} context@ContextSelect{}- | nestRate nest == contextOuterRate context- = Just $ nest - { nestInner = nestInner nest <> nestOfContext context - , nestStart = nestStart nest ++ startsForSelect context }+ let (starts', ends') = allocAndTrunc fills --- Selector context needs to be inserted deeper in this nest.-insertContext nest@NestLoop{} context@ContextSelect{}- | nestContainsRate nest (contextOuterRate context)- , Just inner' <- insertContext (nestInner nest) context- = Just $ nest - { nestInner = inner' - , nestStart = nestStart nest ++ startsForSelect context }+ (starts, nest, ends) <- go topctx+ + return $ insertStarts (starts' ++ starts)+ $ insertEnds (ends' ++ ends)+ $ nest+ where+ fop' op+ = do fills <- maybe (Left ErrorMultipleFills) Right+ $ pathsOfFills topctx+ fop fills op --- Nested selector context inside selector context.-insertContext nest@NestIf{} context@ContextSelect{}- | nestInnerRate nest == contextOuterRate context- = Just $ nest { nestInner = nestInner nest <> nestOfContext context } + go ctx+ = case ctx of+ ContextRate{}+ -> do (s1,bodies,e1) <- ops ctx+ (s2,i2, e2) <- inner ctx+ rate' <- frate (contextRate ctx) ctx -insertContext _nest _context- = Nothing+ let nest = NestLoop+ { nestRate = rate'+ , nestStart = []+ , nestBody = bodies+ , nestInner = i2+ , nestEnd = [] } + return ( s1 ++ s2+ , nest+ , e1 ++ e2) --- | Yield a skeleton nest for a given context.-nestOfContext :: Context -> Nest-nestOfContext context- = case context of- ContextRate tRate- -> NestLoop- { nestRate = tRate- , nestStart = []- , nestBody = []- , nestInner = NestEmpty- , nestEnd = []- , nestResult = xUnit }+ ContextSelect{}+ -> do (s1,bodies,e1) <- ops ctx+ (s2,i2, e2) <- inner ctx - ContextSelect{}- -> NestIf- { nestOuterRate = contextOuterRate context- , nestInnerRate = contextInnerRate context- , nestFlags = contextFlags context- , nestBody = [] - , nestInner = NestEmpty }+ rateOuter <- frate (contextOuterRate ctx) ctx+ rateInner <- frate (contextInnerRate ctx) ctx + let nest = NestGuard+ { nestOuterRate = rateOuter+ , nestInnerRate = rateInner+ , nestFlags = contextFlags ctx+ , nestBody = bodies+ , nestInner = i2 } --- | Check whether the top-level of this nest contains the given rate.--- It might be in a nested context.-nestContainsRate :: Nest -> TypeF -> Bool-nestContainsRate nest tRate- = case nest of- NestEmpty - -> False+ return ( s1 ++ s2+ , nest+ , e1 ++ e2) - NestList ns - -> any (flip nestContainsRate tRate) ns - NestLoop{}- -> nestRate nest == tRate- || nestContainsRate (nestInner nest) tRate+ ContextSegment{}+ -> do (s1,bodies,e1) <- ops ctx+ (s2,i2, e2) <- inner ctx - NestIf{}- -> nestInnerRate nest == tRate- || nestContainsRate (nestInner nest) tRate+ rateOuter <- frate (contextOuterRate ctx) ctx+ rateInner <- frate (contextInnerRate ctx) ctx --- | For a select context make statements that initialise the counter of --- how many times the inner context has been entered.-startsForSelect :: Context -> [StmtStart]-startsForSelect context- = let ContextSelect{} = context- TVar (UName nK) = contextInnerRate context- nCounter = NameVarMod nK "count"- in [StartAcc - { startAccName = nCounter- , startAccType = tNat- , startAccExp = xNat 0 }]+ let nest = NestSegment+ { nestOuterRate = rateOuter+ , nestInnerRate = rateInner+ , nestLength = contextLens ctx+ , nestBody = bodies+ , nestInner = i2 } + return ( s1 ++ s2+ , nest+ , e1 ++ e2) ----------------------------------------------------------------------------------- | Insert starting statements in the given context.-insertStarts :: Nest -> Context -> [StmtStart] -> Maybe Nest+ ContextAppend{}+ -> do (s1,i1,e1) <- go (contextInner1 ctx)+ (s2,i2,e2) <- go (contextInner2 ctx) --- The starts are for this loop.-insertStarts nest@NestLoop{} (ContextRate tRate) starts'- | tRate == nestRate nest- = Just $ nest { nestStart = nestStart nest ++ starts' }+ let nest = NestList+ [ i1, i2 ] --- The starts are for some inner context contained by this loop, --- so we can still drop them here.-insertStarts nest@NestLoop{} (ContextRate tRate) starts'- | nestContainsRate nest tRate- = Just $ nest { nestStart = nestStart nest ++ starts' }+ return ( s1 ++ s2+ , nest+ , e1 ++ e2) -insertStarts _ _ _- = Nothing ----------------------------------------------------------------------------------- | Insert starting statements in the given context.-insertBody :: Nest -> Context -> [StmtBody] -> Maybe Nest+ ops ctx+ = do outs <- mapM fop' (contextOps ctx)+ let (ss,bs,es) = unzip3 outs+ return (concat ss, concat bs, concat es) -insertBody nest@NestLoop{} context@(ContextRate tRate) body'- -- If the desired context is the same as the loop then we can drop- -- the statements right here.- | tRate == nestRate nest- = Just $ nest { nestBody = nestBody nest ++ body' }+ inner ctx+ = do outs <- mapM go (contextInner ctx)+ let (ss,ins,es) = unzip3 outs+ return (concat ss, listNest ins, concat es) - -- Try and insert them in an inner context.- | Just inner' <- insertBody (nestInner nest) context body'- = Just $ nest { nestInner = inner' }+ listNest []+ = NestEmpty+ listNest [n]+ = n+ listNest ns+ = NestList ns -insertBody nest@NestIf{} context@(ContextRate tRate) body'- | tRate == nestInnerRate nest- = Just $ nest { nestBody = nestBody nest ++ body' } - | Just inner' <- insertBody (nestInner nest) context body'- = Just $ nest { nestInner = inner' }+allocAndTrunc :: FillMap -> ([StmtStart], [StmtEnd])+allocAndTrunc fills+ = concat *** concat+ $ unzip+ $ map go + $ Map.toList fills+ where+ go (k,(f,t))+ | isSimple f || isNone f+ = ([], [])+ | otherwise+ = let k' = getAccForPath fills f+ kk = maybe k id k'+ co = NameVarMod kk "count" -insertBody (NestList (n:ns)) context body'- | Just n' <- insertBody n context body'- = Just $ NestList (n':ns)+ s | k == kk+ = [StartAcc+ { startAccName = co+ , startAccType = tNat+ , startAccExp = xNat 0 } ]+ | otherwise+ = [] -insertBody (NestList (n:ns)) context body'- | Just (NestList ns') <- insertBody (NestList ns) context body'- = Just $ NestList (n:ns')+ e = [EndVecTrunc+ k t+ (UName co) ] -insertBody (NestList []) _ _- = Nothing- -insertBody _ _ _- = Nothing+ in (s, e) ---------------------------------------------------------------------------------- | Insert ending statements in the given context.-insertEnds :: Nest -> Context -> [StmtEnd] -> Maybe Nest---- The ends are for this loop.-insertEnds nest@NestLoop{} (ContextRate tRate) ends'- | tRate == nestRate nest- = Just $ nest { nestEnd = nestEnd nest ++ ends' }+-- | Insert starting statements in the given context.+insertStarts :: [StmtStart] -> Nest -> Nest+insertStarts starts' nest+ = case nest of+ NestList (n:ns)+ -> NestList (insertStarts starts' n : ns) + NestLoop{}+ -> nest { nestStart = nestStart nest ++ starts' }+ _+ -> nest --- The ends are for some inner context contained by this loop,--- so we can still drop them here.-insertEnds nest@NestLoop{} (ContextRate tRate) ends'- | nestContainsRate nest tRate- = Just $ nest { nestEnd = nestEnd nest ++ ends' }- -insertEnds _ _ _- = Nothing+-------------------------------------------------------------------------------+-- | Insert ends statements in the given context.+insertEnds :: [StmtEnd] -> Nest -> Nest+insertEnds ends' nest+ = case nest of+ NestList ns+ | (r:rs) <- reverse ns+ -> NestList (reverse rs ++ [insertEnds ends' r])+ NestLoop{}+ -> nest { nestEnd = nestEnd nest ++ ends' }+ _+ -> nest
+ DDC/Core/Flow/Transform/Schedule/Scalar.hs view
@@ -0,0 +1,330 @@++module DDC.Core.Flow.Transform.Schedule.Scalar+ (scheduleScalar)+where+import DDC.Core.Flow.Transform.Schedule.Nest+import DDC.Core.Flow.Transform.Schedule.Error+import DDC.Core.Flow.Transform.Schedule.Base+import DDC.Core.Flow.Procedure+import DDC.Core.Flow.Process+import DDC.Core.Flow.Compounds+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Prim.OpStore+import DDC.Core.Flow.Exp+import DDC.Core.Flow.Context+++-- | Schedule a process into a procedure, producing scalar code.+scheduleScalar :: Process -> Either Error Procedure+scheduleScalar + (Process { processName = name+ , processParamFlags = bsParams+ , processContext = context })+ = do+ nest <- scheduleContext (\r _ -> return r)+ (scheduleOperator context) context++ return $ Procedure+ { procedureName = name+ , procedureParamFlags = bsParams+ , procedureNest = nest }+++-------------------------------------------------------------------------------+-- | Schedule a single series operator into a loop nest.+scheduleOperator + :: Context -- ^ Context of all operators+ -> FillMap -- ^ Map of which operators use which write-to accs+ -> Operator -- ^ Operator to schedule.+ -> Either Error ([StmtStart], [StmtBody], [StmtEnd])++scheduleOperator _ctx fills op++ -- Id -------------------------------------------+ | OpId{} <- op+ = do -- Get binders for the input elements.+ let Just bResult = elemBindOfSeriesBind (opResultSeries op)+ let Just uInput = elemBoundOfSeriesBound (opInputSeries op)++ return ( [] + , [ BodyStmt bResult (XVar uInput) ]+ , [] )++ | OpSeriesOfRateVec{} <- op+ = do let tK = opInputRate op+ let tA = opElemType op+ let bS = opResultSeries op+ let uInput = opInputRateVec op+ let Just uS = takeSubstBoundOfBind bS+ let Just tP = procTypeOfSeriesType (typeOfBind bS)+ let Just bResult = elemBindOfSeriesBind bS++ -- Convert the RateVec to a series+ let starts+ = [ StartStmt bS+ (xSeriesOfRateVec tP tK tA (XVar uInput)) ]++ -- Body expressions that take the next element from each input series.+ let bodies+ = [ BodyStmt bResult+ (xNext tP tK tA (XVar uS) (XVar (UIx 0))) ]++ return ( starts+ , bodies+ , [] )+++ | OpSeriesOfArgument{} <- op+ = do let tK = opInputRate op+ let tA = opElemType op+ let bS = opResultSeries op+ let Just uS = takeSubstBoundOfBind bS+ let Just tP = procTypeOfSeriesType (typeOfBind bS)+ let Just bResult = elemBindOfSeriesBind bS++ -- Body expressions that take the next element from each input series.+ -- Could be different to RateVec above, since could be from other source?+ let bodies+ = [ BodyStmt bResult+ (xNext tP tK tA (XVar uS) (XVar (UIx 0))) ]++ return ( []+ , bodies+ , [] )+++ -- Rep -----------------------------------------+ | OpRep{} <- op+ = do -- Make a binder for the replicated element.+ let BName nResult _ = opResultSeries op+ let nVal = NameVarMod nResult "val"+ let uVal = UName nVal+ let bVal = BName nVal (opElemType op)++ -- Get the binder for the use of it in the replicated context.+ let Just bResult = elemBindOfSeriesBind (opResultSeries op)++ -- Evaluate the expression to be replicated once, + -- before the main loop.+ let starts+ = [ StartStmt bVal (opInputExp op) ]++ -- Use the expression for each iteration of the loop.+ let bodies+ = [ BodyStmt bResult (XVar uVal) ]++ return (starts, bodies, [])++ -- Reps ----------------------------------------+ | OpReps{} <- op+ = do -- Lookup binder for the input element.+ let Just uInput = elemBoundOfSeriesBound (opInputSeries op)++ -- Set the result to point to the input element.+ let Just bResult = elemBindOfSeriesBind (opResultSeries op)++ let bodies+ = [ BodyStmt bResult+ (XVar uInput)]++ return ([], bodies, [])++ -- Indices --------------------------------------+ | OpIndices{} <- op+ = do + -- In a segment context the variable ^0 is the index into+ -- the current segment.+ let Just bResult = elemBindOfSeriesBind (opResultSeries op)++ let bodies+ = [ BodyStmt bResult+ (XVar (UIx 0)) ]++ return ([], bodies, [])++ -- Fill -----------------------------------------+ | OpFill{} <- op+ = do -- Get bound of the input element.+ let Just uInput = elemBoundOfSeriesBound (opInputSeries op)++ -- Write the current element to the vector.+ let UName nVec = opTargetVector op++ let index+ | Just n <- getAcc fills nVec + = xRead tNat + $ XVar $ UName $ NameVarMod n "count"+ | otherwise+ = XVar $ UIx 0++ let bodies+ = [ BodyVecWrite + nVec -- destination vector+ (opElemType op) -- series elem type+ index -- index+ (XVar uInput) ] -- value++ let inc+ | Just n <- getAcc fills nVec + , n == nVec+ = [ BodyAccWrite+ (NameVarMod n "count")+ tNat+ (xIncrement index) ]+ | otherwise+ = []++ return ([], bodies ++ inc, [])++ -- Gather ---------------------------------------+ | OpGather{} <- op+ = do -- Bind for result element.+ let Just bResult = elemBindOfSeriesBind (opResultBind op)++ -- Bound of source index.+ let Just uIndex = elemBoundOfSeriesBound (opSourceIndices op)+ let buf = xBufOfRateVec (opVectorRate op) (opElemType op)+ (XVar $ opSourceVector op)++ -- Read from the vector.+ let bodies = [ BodyStmt bResult+ (xReadVector + (opElemType op)+ buf+ (XVar $ uIndex)) ]++ return ([], bodies, [])+ + -- Scatter --------------------------------------+ | OpScatter{} <- op+ = do -- Bound of source index.+ let Just uIndex = elemBoundOfSeriesBound (opSourceIndices op)++ -- Bound of source elements.+ let Just uElem = elemBoundOfSeriesBound (opSourceElems op)++ -- Read from vector.+ let bodies = [ BodyStmt (BNone tUnit)+ (xWriteVector+ (opElemType op)+ (XVar $ bufOfVectorName $ opTargetVector op)+ (XVar $ uIndex) (XVar $ uElem)) ]++ -- Bind final unit value.+ let ends = [ EndStmt (opResultBind op)+ xUnit ]++ return ([], bodies, ends)++ -- Maps -----------------------------------------+ | OpMap{} <- op+ = do -- Bind for the result element.+ let Just bResult = elemBindOfSeriesBind (opResultSeries op)++ -- Binds for all the input elements.+ let Just usInput = sequence+ $ map elemBoundOfSeriesBound+ $ opInputSeriess op++ -- Apply input element vars into the worker body.+ let xBody + = foldl (\x (b, p) -> XApp (XLam b x) p)+ (opWorkerBody op)+ [(b, XVar u)+ | b <- opWorkerParams op+ | u <- usInput ]++ let bodies+ = [ BodyStmt bResult xBody ]++ return ([], bodies, [])++ -- Pack ----------------------------------------+ | OpPack{} <- op+ = do -- Lookup binder for the input element.+ let Just uInput = elemBoundOfSeriesBound (opInputSeries op)++ -- Set the result to point to the input element+ let Just bResult = elemBindOfSeriesBind (opResultSeries op)++ let bodies+ = [ BodyStmt bResult+ (XVar uInput)]++ return ([], bodies, [])++ -- Generate -------------------------------------+ | OpGenerate{} <- op+ = do -- Bind for the result element.+ let Just bResult = elemBindOfSeriesBind (opResultSeries op)++ -- Apply loop index into the worker body.+ let xBody+ = XApp ( XLam (opWorkerParamIndex op)+ (opWorkerBody op))+ (XVar (UIx 0)) -- index++ let bodies+ = [ BodyStmt bResult xBody ]++ return ([], bodies, [])++-- Reduce --------------------------------------+ | OpReduce{} <- op+ = do -- Initialize the accumulator.+ let UName nResult = opTargetRef op+ let nAcc = NameVarMod nResult "acc"+ let tAcc = typeOfBind (opWorkerParamAcc op)++ let nAccInit = NameVarMod nResult "init"++ let starts+ = [ StartStmt (BName nAccInit tAcc)+ (xRead tAcc (XVar $ opTargetRef op))+ , StartAcc nAcc tAcc (XVar (UName nAccInit)) ]++ -- Lookup binders for the input elements.+ let Just uInput = elemBoundOfSeriesBound (opInputSeries op)+ + -- Bind for intermediate accumulator value.+ let nAccVal = NameVarMod nResult "val"+ let uAccVal = UName nAccVal+ let bAccVal = BName nAccVal tAcc++ -- Substitute input and accumulator vars into worker body.+ let xBody x1 x2+ = XApp (XApp ( XLam (opWorkerParamAcc op)+ $ XLam (opWorkerParamElem op)+ (opWorkerBody op))+ x1)+ x2+ + -- Update the accumulator in the loop body.+ let bodies+ = [ BodyAccRead nAcc tAcc bAccVal+ , BodyAccWrite nAcc tAcc + (xBody (XVar uAccVal) + (XVar uInput)) ]+ + -- Read back the final value after the loop has finished and+ -- write it to the destination.+ let nAccRes = NameVarMod nResult "res"+ let ends+ = [ EndAcc nAccRes tAcc nAcc + , EndStmt (BNone tUnit)+ (xWrite tAcc (XVar $ opTargetRef op)+ (XVar $ UName nAccRes)) ]++ return (starts, bodies, ends)++ -- Unsupported ----------------------------------+ | otherwise+ = Left $ ErrorUnsupported op++-- | Build an expression that increments a natural.+xIncrement :: Exp a Name -> Exp a Name+xIncrement xx+ = xApps (XVar (UPrim (NamePrimArith PrimArithAdd) + (typePrimArith PrimArithAdd)))+ [ XType tNat, xx, XCon (dcNat 1) ]+
− DDC/Core/Flow/Transform/Schedule/SeriesEnv.hs
@@ -1,157 +0,0 @@--module DDC.Core.Flow.Transform.Schedule.SeriesEnv- ( SeriesEnv (..)- , emptySeriesEnv- , insertElemForSeries-- , bindNextElem- , bindNextElems- - , elemBindOfSeriesBind- , elemBoundOfSeriesBound- , elemTypeOfSeriesType- , rateTypeOfSeriesType )-where-import DDC.Core.Flow.Transform.Schedule.Nest-import DDC.Core.Flow.Procedure-import DDC.Core.Flow.Compounds-import DDC.Core.Flow.Prim-import DDC.Core.Flow.Exp-import qualified Data.Map as Map-import Data.Map (Map)---data SeriesEnv- = SeriesEnv- { -- | Maps the bound for a whole series to the bound for- -- a single element in the series context. - envSeriesElems :: Map Name (Bound Name) - }----- | An empty series environment.-emptySeriesEnv :: SeriesEnv-emptySeriesEnv- = SeriesEnv Map.empty----- | Insert an entry into the series environment.-insertElemForSeries- :: Name -> BoundF -> SeriesEnv -> SeriesEnv--insertElemForSeries n u (SeriesEnv env)- = SeriesEnv (Map.insert n u env)----- | Produce the `Bound` that holds the next element for the given series,--- which exists in the series's context.------ We first try to look up the required bound from the series environment,--- if it's not already available then insert a statement into the loop nest--- to get actually get the next element from the series.-bindNextElem - :: Name -- ^ Name of series.- -> TypeF -- ^ Rate of series- -> TypeF -- ^ Series element type.- -> SeriesEnv -- ^ Current series environment.- -> Nest -- ^ Current loop nest.- -> (BoundF, SeriesEnv, Nest)--bindNextElem nSeries tRate tElem env nest0- -- There is already a mapping in the environment.- | Just uElem <- Map.lookup nSeries (envSeriesElems env)- = (uElem, env, nest0)- - -- Insert a statement into the loop nest to get the next element- -- from the series.- | otherwise- = let -- bound for the single element- nElem = NameVarMod nSeries "elem"- uElem = UName nElem-- -- Expression to get the next element from the series.- uSeries = UName nSeries- uIndex = UIx 0- xGet = xNext tRate tElem (XVar uSeries) (XVar uIndex)-- -- Insert the statement into the loop nest.- Just nest1 - = (insertBody nest0 (ContextRate tRate)- [ BodyStmt (BName nElem tElem) xGet ])- - env' = env { envSeriesElems - = Map.insert nSeries uElem - (envSeriesElems env) }- - in (uElem, env', nest1)----- | Like `bindNextElem`, but handle several series at once.-bindNextElems - :: [(Name, TypeF, TypeF)] - -- ^ Names, rates, and element types.- -> SeriesEnv -- ^ Current series environment.- -> Nest -- ^ Current loop nest.- -> ([BoundF], SeriesEnv, Nest)--bindNextElems junk env nest0- = case junk of- [] - -> ([], env, nest0)- - (nSeries, tRate, tElem) : junk'- -> let (uElem1, env1, nest1) - = bindNextElem nSeries tRate tElem env nest0- - (uElems', env', nest')- = bindNextElems junk' env1 nest1- - in (uElem1 : uElems', env', nest')----- | Given the bind of a series, produce the bound that refers to the--- next element of the series in its context.-elemBindOfSeriesBind :: BindF -> Maybe BindF-elemBindOfSeriesBind bSeries- | BName nSeries tSeries' <- bSeries- , nElem <- NameVarMod nSeries "elem"- , Just tElem <- elemTypeOfSeriesType tSeries'- = Just $ BName nElem tElem-- | otherwise- = Nothing- ---- | Given the bound of a series, produce the bound that refers to the--- next element of the series in its context.-elemBoundOfSeriesBound :: BoundF -> Maybe BoundF-elemBoundOfSeriesBound uSeries- | UName nSeries <- uSeries- , nElem <- NameVarMod nSeries "elem"- = Just $ UName nElem-- | otherwise- = Nothing----- | Given the type of a series like @Series k e@, produce the type--- of a single element, namely the @e@.-elemTypeOfSeriesType :: TypeF -> Maybe TypeF-elemTypeOfSeriesType tSeries'- | Just (_tcSeries, [_tK, tE]) <- takeTyConApps tSeries'- = Just tE-- | otherwise- = Nothing----- | Given the type of a series like @Series k e@, produce the type--- of the rate, namely the @k@.-rateTypeOfSeriesType :: TypeF -> Maybe TypeF-rateTypeOfSeriesType tSeries'- | Just (_tcSeries, [tK, _tE]) <- takeTyConApps tSeries'- = Just tK-- | otherwise- = Nothing-
DDC/Core/Flow/Transform/Slurp.hs view
@@ -1,199 +1,401 @@ module DDC.Core.Flow.Transform.Slurp- (slurpProcesses)+ ( slurpProcesses+ , slurpOperator+ , isSeriesOperator+ , isVectorOperator) where-import DDC.Core.Flow.Transform.Slurp.Alloc+import DDC.Core.Flow.Transform.Slurp.Context import DDC.Core.Flow.Transform.Slurp.Operator+import DDC.Core.Flow.Transform.Slurp.Error+import DDC.Core.Flow.Transform.Slurp.Resize import DDC.Core.Flow.Prim import DDC.Core.Flow.Context import DDC.Core.Flow.Process import DDC.Core.Flow.Compounds import DDC.Core.Flow.Exp-import DDC.Core.Transform.Deannotate+import DDC.Core.Flow.Transform.Deannotate import DDC.Core.Module-import Data.Maybe-import Data.List+import qualified DDC.Type.Env as Env+import DDC.Type.Env (TypeEnv)+import qualified Data.Map as Map -- | Slurp stream processes from the top level of a module.-slurpProcesses :: Module () Name -> [Process]+slurpProcesses :: Module () Name -> Either Error [Either Process (Bind Name, Exp () Name)] slurpProcesses mm = slurpProcessesX (deannotate (const Nothing) $ moduleBody mm) -- | Slurp stream processes from a module body.-slurpProcessesX :: Exp () Name -> [Process]+-- A module consists of some let-bindings wrapping a unit data constructor.+slurpProcessesX :: Exp () Name -> Either Error [Either Process (Bind Name, Exp () Name)] slurpProcessesX xx = case xx of+ -- Slurp processes definitions from the let-bindings. XLet lts x'- -> slurpProcessesLts lts ++ slurpProcessesX x'+ -> do ps1 <- slurpProcessesLts lts + ps2 <- slurpProcessesX x'+ return $ ps1 ++ ps2 - _ -> []+ -- Ignore the unit data constructor at the end of the module.+ _+ | xx == xUnit -> Right []+ | otherwise -> Left $ ErrorBadProcess xx -- | Slurp stream processes from the top-level let expressions.-slurpProcessesLts :: Lets () Name -> [Process]+slurpProcessesLts :: Lets () Name -> Either Error [Either Process (Bind Name, Exp () Name)] slurpProcessesLts (LRec binds)- = catMaybes [slurpProcessLet b x | (b, x) <- binds]+ = sequence [slurpProcessLet b x | (b, x) <- binds] slurpProcessesLts (LLet b x)- = catMaybes [slurpProcessLet b x]+ = sequence [slurpProcessLet b x] slurpProcessesLts _- = []+ = return [] ------------------------------------------------------------------------------- -- | Slurp stream operators from a top-level binding.-slurpProcessLet :: Bind Name -> Exp () Name -> Maybe Process-slurpProcessLet (BName n tProcess) xx+slurpProcessLet + :: Bind Name -- ^ Binder for the whole process.+ -> Exp () Name -- ^ Expression of body.+ -> Either Error (Either Process (Bind Name, Exp () Name)) +slurpProcessLet (BName n t) xx+ -- We assume that all type params come before the value params.- | Just (fbs, xBody) <- takeXLamFlags xx+ | Just (NameTyConFlow TyConFlowProcess, [tProc, tLoopRate])+ <- takePrimTyConApps $ snd $ takeTFunAllArgResult t+ , Just (fbs, xBody) <- takeXLamFlags xx = let - -- Split binders into type and value binders.- (fbts, fbvs) = partition fst fbs-- -- Type binders.- bts = map snd fbts- tsRate = filter (\b -> typeOfBind b == kRate) bts-- -- Create contexts for all the parameter rate variables.- ctxParam = map (ContextRate . TVar . UName)- $ map (\(BName nRate _) -> nRate)- $ tsRate- -- Value binders.- bvs = map snd fbvs+ bvs = map snd+ $ filter (not.fst)+ $ fbs -- Slurp the body of the process.- (ctxLocal, ops, ltss, xResult) - = slurpProcessX xBody+ in do+ let series = slurpSeriesArguments bvs Map.empty+ ctx <- slurpProcessX Env.empty series Map.empty xBody - -- Decide what rates to use when allocating vectors.- ops_alloc = patchAllocRates ops+ return $ Left+ $ Process+ { processName = n+ , processProcType = tProc+ , processLoopRate = tLoopRate+ , processParamFlags = fbs - -- Determine the type of the result of the process.- tResult = snd $ takeTFunAllArgResult tProcess+ , processContext = ctx } - in Just $ Process- { processName = n- , processParamTypes = bts- , processParamValues = bvs+slurpProcessLet b xx+ = return $ Right (b, xx) - -- Note that the parameter contexts needs to come first- -- so they are scheduled before the local contexts, which- -- are inside - , processContexts = ctxParam ++ ctxLocal - , processOperators = ops_alloc- , processStmts = ltss- , processResultType = tResult- , processResult = xResult }+slurpSeriesArguments :: [BindF] -> Map.Map Name Context -> Map.Map Name Context+slurpSeriesArguments [] e+ = e+slurpSeriesArguments (b:bs) e+ | BName n t <- b+ , Just (NameTyConFlow TyConFlowSeries+ , [_P, tK, tA] )+ <- takePrimTyConApps t+ = let op = OpSeriesOfArgument+ { opResultSeries = b+ , opInputRate = tK+ , opElemType = tA } -slurpProcessLet _ _- = Nothing+ context = ContextRate+ { contextRate = tK+ , contextOps = [op]+ , contextInner = [] }+ in slurpSeriesArguments bs (Map.insert n context e)+ | otherwise+ = slurpSeriesArguments bs e ------------------------------------------------------------------------------- -- | Slurp stream operators from the body of a function and add them to --- the provided loop nest.+-- the provided loop nest. +-- +-- The process type environment records what process bindings are in scope,+-- so that we can check that the overall process is well formed. +-- This environment only needs to contain locally defined process variables,+-- not the global environment for the whole module.+-- slurpProcessX - :: ExpF -- A sequence of non-recursive let-bindings.- -> ( [Context] -- Nested contexts created by this process.- , [Operator] -- Series operators in this binding.- , [LetsF] -- Baseband statements that don't process series.- , ExpF) -- Final value of process.+ :: TypeEnv Name -- ^ Process type environment.+ -> Map.Map Name Context -- ^ Contexts of in-scope+ -> Map.Map Name Resize -- ^ Resizes of in-scope+ -> ExpF -- ^ A sequence of non-recursive let-bindings.+ -> Either Error Context -slurpProcessX xx- | XLet (LLet b x) xMore <- xx- , (ctxHere, opsHere, ltsHere) <- slurpBindingX b x- , (ctxMore, opsMore, ltsMore, xResult) <- slurpProcessX xMore- = ( ctxHere ++ ctxMore- , opsHere ++ opsMore- , ltsHere ++ ltsMore- , xResult)+slurpProcessX tenv ctxs rs xx+ | XLet (LLet b x) xMore <- xx+ = do + -- Slurp operators from the binding.+ (ctxs', rs') <- slurpBindingX tenv ctxs rs b x - -- Only handle very simple cases with one alt for now.- -- 'Invert' the case and create a let binding for each binder.- -- We can safely duplicate xScrut since it's in ANF.- | XCase xScrut [AAlt (PData dc bs) x] <- xx- , bs' <- takeSubstBoundsOfBinds bs- , length bs == length bs'- , lets <- zipWith- (\b b' -> LLet b- (XCase xScrut- [AAlt (PData dc bs)- (XVar b')])) bs bs'- = slurpProcessX (xLets lets x)+ -- If this binding defined a process then add it do the environment.+ let tenv'+ | isProcessType $ typeOfBind b = Env.extend b tenv+ | otherwise = tenv + -- Slurp the rest of the process using the new environment.+ slurpProcessX tenv' ctxs' rs' xMore++-- Slurp a process ending.+slurpProcessX tenv ctxs _rs xx+ -- The process ends with a variable that has Process# type.+ | XVar u <- xx+ , Just t <- Env.lookup u tenv+ , isProcessType t+ , UName u' <- u+ , Just c <- Map.lookup u' ctxs+ = return c++ -- Process finishes with some expression that doesn't look like it + -- actually defines a value of type Process#. | otherwise- = ([], [], [], xx)+ = Left (ErrorBadProcess xx) ------------------------------------------------------------------------------- -- | Slurp stream operators from a let-binding. slurpBindingX - :: BindF -- Binder to assign result to.- -> ExpF -- Right of the binding.- -> ( [Context] -- Nested contexts created by this binding.- , [Operator] -- Series operators in this binding.- , [LetsF]) -- Baseband statements that don't process series.+ :: TypeEnv Name -- ^ Process type environment.+ -> Map.Map Name Context -- ^ Contexts of in-scope+ -> Map.Map Name Resize -- ^ Resizes of in-scope+ -> BindF -- ^ Binder to assign result to.+ -> ExpF -- ^ Right of the binding.+ -> Either + Error+ ( Map.Map Name Context+ , Map.Map Name Resize ) + -- Decend into more let bindings. -- We get these when entering into a nested context.-slurpBindingX b1 xx+slurpBindingX tenv ctxs rs b1 xx | XLet (LLet b2 x2) xMore <- xx- , (ctxHere, opsHere, ltsHere) <- slurpBindingX b2 x2- , (ctxMore, opsMore, ltsMore) <- slurpBindingX b1 xMore- = ( ctxHere ++ ctxMore- , opsHere ++ opsMore- , ltsHere ++ ltsMore)+ = do + -- Slurp operators from the binding.+ (ctxs', rs') <- slurpBindingX tenv ctxs rs b2 x2 + -- If this binding defined a process then add it to the environement.+ let tenv'+ | isProcessType $ typeOfBind b2 = Env.extend b2 tenv+ | otherwise = tenv++ -- Slurp the rest of the process using the new environment.+ slurpBindingX tenv' ctxs' rs' b1 xMore+++-- Slurp a series#+-- This creates a new context+slurpBindingX _tenv ctxs rs b@(BName n _)+ ( takeXPrimApps + -> Just ( NameOpSeries OpSeriesSeriesOfRateVec+ , [ XType _tProc+ , XType tK+ , XType tA+ , XVar vec]))+ = do+ let op = OpSeriesOfRateVec+ { opResultSeries = b+ , opInputRate = tK+ , opInputRateVec = vec + , opElemType = tA }++ let context = ContextRate+ { contextRate = tK+ , contextOps = [op]+ , contextInner = [] }++ let ctxs' = Map.insert n context ctxs ++ return (ctxs', rs)++ -- Slurp a mkSel1# -- This creates a nested selector context.-slurpBindingX b +slurpBindingX tenv ctxs rs (BName n _) ( takeXPrimApps - -> Just ( NameOpFlow (OpFlowMkSel 1)- , [ XType tK1, XType _tA- , XVar uFlags- , XLAM (BName nR kR) (XLam bSel xBody)]))+ -> Just ( NameOpSeries (OpSeriesMkSel 1)+ , [ XType tProc+ , XType tK1+ , XType _+ , XVar uFlags@(UName nFlags)++ , XLAM (BName nR kR)+ (XLam bSel@(BName nSel _)+ xBody)])) | kR == kRate- = let - (ctxInner, osInner, ltsInner)- = slurpBindingX b xBody+ = do+ flagsContext <- lookupOrDie nFlags ctxs - -- Add an intermediate edge from the flags variable to its use. - -- This is needed for the case when the flags series is one of the- -- parameters to the process, because the intermediate OpId forces - -- the scheduler to add the flags_elem = next [k] flags_series - -- statement.- UName nFlags = uFlags- nFlagsUse = NameVarMod nFlags "use"- uFlagsUse = UName nFlagsUse- bFlagsUse = BName nFlagsUse (tSeries tK1 tBool)+ let nFlagsUse = NameVarMod nFlags "use"+ let bFlagsUse = BName nFlagsUse (tSeries tProc tK1 tBool) - opId = OpId- { opResultSeries = bFlagsUse- , opInputRate = tK1- , opInputSeries = uFlags - , opElemType = tBool }+ let opId = OpId+ { opResultSeries = bFlagsUse+ , opInputRate = tK1+ , opInputSeries = uFlags+ , opElemType = tBool } - context = ContextSelect- { contextOuterRate = tK1- , contextInnerRate = TVar (UName nR)- , contextFlags = uFlagsUse- , contextSelector = bSel }+ let context = ContextSelect+ { contextOuterRate = tK1+ , contextInnerRate = TVar (UName nR)+ , contextFlags = uFlags+ , contextSelector = bSel+ , contextOps = [opId]+ , contextInner = [] } - in (context : ctxInner, opId : osInner, ltsInner)+ context' <- insertContext context flagsContext+ let ctxsInner = Map.insert nSel context' ctxs+ selProc <- slurpProcessX tenv ctxsInner rs xBody --- | Slurp an operator that doesn't introduce a new context.-slurpBindingX b x- = case slurpOperator b x of+ let ctxsOuter = Map.insert n selProc ctxs+ return (ctxsOuter, rs) - -- This binding is a flow operator. - Just op -> ([], [op], []) - -- This is some base-band statement that doesn't - -- work on a flow operator.- _ -> ([], [], [LLet b x])+-- Slurp a mkSel1#+-- This creates a nested selector context.+slurpBindingX tenv ctxs rs (BName n _)+ ( takeXPrimApps + -> Just ( NameOpSeries OpSeriesMkSegd+ , [ XType tProc+ , XType tK1+ , XVar uLens@(UName nLens)++ , XLAM (BName nR kR)+ (XLam bSegd@(BName nSegd _)+ xBody)]))+ | kR == kRate+ = do+ lensContext <- lookupOrDie nLens ctxs++ -- Introduce new series with name of segd,+ -- as copy of lens series+ let nLensUse = NameVarMod nLens "use"+ let bLensUse = BName nLensUse (tSeries tProc tK1 tNat)++ let opId = OpId+ { opResultSeries = bLensUse+ , opInputRate = tK1+ , opInputSeries = uLens+ , opElemType = tNat }++ let context = ContextSegment+ { contextOuterRate = tK1+ , contextInnerRate = TVar (UName nR)+ , contextLens = uLens+ , contextSegd = bSegd+ , contextOps = [opId]+ , contextInner = [] }++ context' <- insertContext context lensContext+ let ctxsInner = Map.insert nSegd context' ctxs+ segProc <- slurpProcessX tenv ctxsInner rs xBody++ let ctxsOuter = Map.insert n segProc ctxs+ return (ctxsOuter, rs)+++-- Slurp a series operator that doesn't introduce a new context.+slurpBindingX _ ctxs rs b@(BName n _) xx+ | Just (ins, k,op) <- slurpOperator b xx+ = do ins' <- mapM (flip lookupOrDie ctxs) ins++ let ctx = ContextRate+ { contextRate = k+ , contextOps = [op]+ , contextInner = [] }++ let go [] c = insertContext ctx c+ go (i:is) c = insertContext c i >>= go is++ context' <- case reverse ins' of+ (i:is) -> go is i+ [] -> return ctx++ let ctxs' = Map.insert n context' ctxs+ return (ctxs', rs)++-- Slurp an append operator+slurpBindingX _ ctxs rs b@(BName n _) xx+ | Just (NameOpSeries OpSeriesAppend+ , [ XType _P, XType tK1, XType tK2, XType tA+ , XVar (UName nIn1), XVar (UName nIn2) ] ) + <- takeXPrimApps xx+ = do in1 <- lookupOrDie nIn1 ctxs+ in2 <- lookupOrDie nIn2 ctxs++ let opId iN iK = OpId+ { opResultSeries = b+ , opInputRate = iK+ , opInputSeries = UName iN+ , opElemType = tA }+ let idCtx iN iK = ContextRate+ { contextRate = iK+ , contextOps = [opId iN iK]+ , contextInner = [] }++ in1' <- insertContext (idCtx nIn1 tK1) in1+ in2' <- insertContext (idCtx nIn2 tK2) in2++ let ctx = ContextAppend+ { contextRate1 = tK1+ , contextInner1 = in1'+ , contextRate2 = tK2+ , contextInner2 = in2' }+++ let ctxs' = Map.insert n ctx ctxs+ return (ctxs', rs)+++-- Slurp a Resize+slurpBindingX _ ctxs rs (BName n _) xx+ | Just rr <- seqEitherMaybe $ slurpResize rs xx+ = do r <- rr+ return (ctxs, Map.insert n r rs)+++-- Slurp a process join or resize+slurpBindingX _tenv ctxs rs (BName n _) xx+ -- Just a plain variable, try to look it up in the environments+ | XVar u <- xx+ , UName var <- u+ = case (Map.lookup var ctxs, Map.lookup var rs) of+ (Just c', _) -> return (Map.insert n c' ctxs, rs)+ (_, Just r') -> return (ctxs, Map.insert n r' rs)+ (Nothing, Nothing)+ -> Left (ErrorNotInContext var)++ -- The process ends by joining two existing processes.+ -- We assume that the overall expression is well typed.+ | Just (NameOpSeries OpSeriesJoin, [_, _, XVar (UName a), XVar (UName b)])+ <- takeXPrimApps xx+ = do a' <- lookupOrDie a ctxs+ b' <- lookupOrDie b ctxs+ m' <- mergeContexts a' b'+ let ctxs' = Map.insert n m' ctxs+ return (ctxs', rs)++ -- The process ends by joining two existing processes.+ -- We assume that the overall expression is well typed.+ | Just (NameOpSeries OpSeriesResizeProc, [_, _, _, XVar (UName r), XVar (UName c)])+ <- takeXPrimApps xx+ = do r' <- lookupOrDie r rs+ c' <- lookupOrDie c ctxs+ m' <- resizeContext r' c'+ let ctxs' = Map.insert n m' ctxs+ return (ctxs', rs)+++ -- Process finishes with some expression that doesn't look like it + -- actually defines a value of type Process#.+slurpBindingX _ _ _ _ xx+ = Left (ErrorBadOperator xx)
− DDC/Core/Flow/Transform/Slurp/Alloc.hs
@@ -1,41 +0,0 @@--module DDC.Core.Flow.Transform.Slurp.Alloc- (patchAllocRates)-where-import DDC.Core.Flow.Process.Operator----- | Decide what rates should be used to allocate created vectors.--- When a vector is being created in a selector context then we need to --- use the maximum possible length, which is the outer context instead--- of the inner one created by the selector.-patchAllocRates :: [Operator] -> [Operator]-patchAllocRates ops- = let- -- Build a table of output to input rates for all pack operations.- packRates - = [ (opOutputRate op, opInputRate op)- | op@OpPack{} <- ops ]-- -- Fix the number of nested contexts to some finite number so we- -- don't end up diverging if there is a loop in the list of- -- operator descriptions.- maxNestedContexts = 1000 :: Int-- getAllocRate 0 _rate- = error $ unlines- [ "ddc-core-flow.patchAllocRates"- , " Too many nested contexts." ]-- getAllocRate n rate- = case lookup rate packRates of- Just inRate -> getAllocRate (n - 1) inRate- _ -> rate-- patchOperator op@OpCreate{}- = op { opAllocRate = Just $ getAllocRate maxNestedContexts (opInputRate op) }-- patchOperator op- = op-- in map patchOperator ops
+ DDC/Core/Flow/Transform/Slurp/Context.hs view
@@ -0,0 +1,287 @@++module DDC.Core.Flow.Transform.Slurp.Context+ ( insertContext+ , mergeContexts+ , resizeContext )+where+import DDC.Core.Flow.Context+import DDC.Core.Flow.Transform.Slurp.Error+import DDC.Core.Flow.Transform.Slurp.Resize+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp+import Data.List (nub)+++-- "embed" is to be pushed inside "into"+-- only one of "embed" or "into" can contain inner contexts;+-- otherwise, no promises are made about merging these+insertContext+ :: Context+ -> Context+ -> Either Error Context+insertContext embed into+ = case into of+ ContextRate{}+ -> case embed of+ ContextRate{}+ | contextRate into == contextRate embed+ -> dropops+ | otherwise+ -> descend++ ContextSelect{}+ -> descendorpush (contextRate into == contextOuterRate embed)++ ContextSegment{}+ -> descendorpush (contextRate into == contextOuterRate embed)++ ContextAppend{}+ -> app into embed+++ ContextSelect{}+ -> case embed of+ ContextRate{}+ | contextInnerRate into == contextRate embed+ -> dropops+ | otherwise+ -> descend++ ContextSelect{}+ | contextOuterRate into == contextOuterRate embed+ , contextInnerRate into == contextInnerRate embed+ , contextFlags into == contextFlags embed+ , contextSelector into == contextSelector embed+ -> dropops+ | otherwise+ -> descendorpush (contextInnerRate into == contextOuterRate embed)++ ContextSegment{}+ -> descendorpush (contextInnerRate into == contextOuterRate embed)++ ContextAppend{}+ -> app into embed+++ ContextSegment{}+ -> case embed of+ ContextRate{}+ | contextInnerRate into == contextRate embed+ -> dropops+ | otherwise+ -> descend++ ContextSelect{}+ -> descendorpush (contextInnerRate into == contextOuterRate embed)++ ContextSegment{}+ | contextOuterRate into == contextOuterRate embed+ , contextInnerRate into == contextInnerRate embed+ , contextLens into == contextLens embed+ , contextSegd into == contextSegd embed+ -> dropops+ | otherwise+ -> descendorpush (contextInnerRate into == contextOuterRate embed)++ ContextAppend{}+ -> app into embed+++ ContextAppend{}+ -> app embed into++ where+ descend =+ case tryInserts embed (contextInner into) of+ Nothing -> Left (ErrorCannotMergeContext embed into)+ Just cs -> return into { contextInner = cs }++ dropops =+ let ops' = contextOps into ++ contextOps embed+ in return+ into { contextOps = nub ops'+ , contextInner = mergeLists (contextInner into) (contextInner embed) }++ pushinner =+ return+ into { contextInner = mergeLists (contextInner into) [embed] }++ descendorpush p =+ case descend of+ Right v+ -> return v+ Left e+ | p+ -> pushinner+ | otherwise+ -> Left e++ app splittee injectee+ = do (ls, rs) <- splitContextIntoApps splittee+ ls' <- insertContext ls (contextInner1 injectee)+ rs' <- insertContext rs (contextInner2 injectee)+ return $ injectee+ { contextInner1 = ls'+ , contextInner2 = rs' }++mergeLists :: [Context] -> [Context] -> [Context]+mergeLists lefts []+ = lefts+mergeLists lefts (right:rest)+ = case mergeAny [] lefts right of+ Nothing -> mergeLists (lefts ++ [right]) rest+ Just ls' -> mergeLists ls' rest+ where+ mergeAny _ [] _+ = Nothing+ mergeAny pres (l:ls) r+ = case insertContext l r of+ Right l' -> Just (pres ++ [l'] ++ ls)+ Left _ -> mergeAny (pres ++ [l]) ls r ++++tryInserts :: Context -> [Context] -> Maybe [Context]+tryInserts embed intos+ = go intos []+ where+ go [] _+ = Nothing+ go (i:is) rs+ = case insertContext embed i of+ Right c' -> Just (rs ++ [c'] ++ is)+ Left _ -> go is (rs ++ [i])+++-- cannot split appends.+-- but only called by insertContext, which does not take appends anyway.+splitContextIntoApps :: Context -> Either Error (Context,Context)+splitContextIntoApps ctx+ = case ctx of+ ContextRate{}+ | Just (tl, tr) <- takeAppend $ contextRate ctx+ -> do (lis, ris) <- unzip <$> mapM splitContextIntoApps (contextInner ctx)+ return ( ctx { contextRate = tl+ , contextInner = lis }+ , ctx { contextRate = tr+ , contextInner = ris } )++ ContextSelect{}+ | Just (tl, tr) <- takeAppend $ contextOuterRate ctx+ -> do (lis, ris) <- unzip <$> mapM splitContextIntoApps (contextInner ctx)+ return ( ctx { contextOuterRate = tl+ , contextInner = lis }+ , ctx { contextOuterRate = tr+ , contextInner = ris } )++ ContextSegment{}+ | Just (tl, tr) <- takeAppend $ contextOuterRate ctx+ -> do (lis, ris) <- unzip <$> mapM splitContextIntoApps (contextInner ctx)+ return ( ctx { contextOuterRate = tl+ , contextInner = lis }+ , ctx { contextOuterRate = tr+ , contextInner = ris } )++ ContextAppend{}+ -> return ( contextInner1 ctx+ , contextInner2 ctx )++ _+ -> -- Left (ErrorCannotSplitContext ctx) + return (ctx, ctx)+++ where+++mergeContexts :: Context -> Context -> Either Error Context+mergeContexts a b+ = insertContext b a++resizeContext :: Resize -> Context -> Either Error Context+resizeContext resize ctx+ = case resize of+ Id _ + -> return ctx+ AppL a b+ -> return+ ContextAppend+ { contextRate1 = a+ , contextInner1 = wrapCtx b ctx+ , contextRate2 = b+ , contextInner2 = emptyCtx a+ }++ AppR a b+ -> return+ ContextAppend+ { contextRate1 = a+ , contextInner1 = emptyCtx a+ , contextRate2 = b+ , contextInner2 = wrapCtx b ctx+ }++ App _ k' _ l' ls rs+ | ContextAppend{} <- ctx+ -> do in1 <- resizeContext ls (contextInner1 ctx)+ in2 <- resizeContext rs (contextInner2 ctx)+ return+ ContextAppend+ { contextRate1 = k'+ , contextInner1 = in1+ , contextRate2 = l'+ , contextInner2 = in2 }+ | otherwise+ -> Left (ErrorCannotResizeContext ctx)++ Sel1 _ _k _ r+ -> do ctx' <- resizeContext r ctx+ return $ ctx'++ Segd _ _k _ r+ -> do ctx' <- resizeContext r ctx+ return $ ctx'++ Cross _ k _ r+ -> do ctx' <- resizeContext r ctx+ return $ wrapCtx k ctx'+ + +++emptyCtx :: Type Name -> Context+emptyCtx k+ = ContextRate+ { contextRate = k+ , contextInner = []+ , contextOps = [] }++wrapCtx :: Type Name -> Context -> Context+wrapCtx k ctx+ = case ctx of+ ContextRate{}+ | contextRate ctx == k+ -> ctx++ ContextAppend{}+ | Just (l,r) <- takeAppend k+ , contextRate1 ctx == l+ , contextRate2 ctx == r+ -> ctx+ + _+ | otherwise+ -> ContextRate+ { contextRate = k+ , contextInner = [ctx]+ , contextOps = [] }++takeAppend ty+ | Just (NameTyConFlow TyConFlowRateAppend, [tK, tL])+ <- takePrimTyConApps ty+ = Just (tK, tL)+ | otherwise+ = Nothing++
+ DDC/Core/Flow/Transform/Slurp/Error.hs view
@@ -0,0 +1,74 @@++module DDC.Core.Flow.Transform.Slurp.Error+ ( Error (..) )+where+import DDC.Core.Flow.Exp+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Transform.Annotate+import DDC.Core.Flow.Context+import DDC.Core.Flow.Process.Pretty ()+import DDC.Core.Pretty+++-- | Things that can go wrong when slurping a process spec from+-- Disciple Core Flow code.+data Error+ -- | Invalid series process definition.+ = ErrorBadProcess (Exp () Name)++ -- | Invalid operator definition in process.+ | ErrorBadOperator (Exp () Name)++ -- | A series, process or resize is not bound locally,+ -- so is not in context+ | ErrorNotInContext Name++ -- | Cannot merge contexts+ | ErrorCannotMergeContext Context Context++ -- | Cannot split contexts+ | ErrorCannotSplitContext Context++ -- | Cannot resize a non-append+ | ErrorCannotResizeContext Context+ deriving Show+++instance Pretty Error where+ ppr err+ = case err of+ ErrorBadProcess x+ -> vcat [ text "Bad series process definition."+ , empty+ , ppr (annotate () x) ]++ ErrorBadOperator x+ -> vcat [ text "Bad series operator."+ , empty+ , ppr (annotate () x) ]++ ErrorNotInContext n+ -> vcat [ text "Referenced name not in context."+ , text "All Series, Processes and Resizes must be locally bound"+ , empty+ , ppr n ]++ ErrorCannotMergeContext c1 c2+ -> vcat [ text "Cannot merge contexts"+ , empty+ , text "Embed:"+ , ppr c1+ , empty+ , text "Into:"+ , ppr c2 ]++ ErrorCannotSplitContext c+ -> vcat [ text "Cannot split context into its append parts"+ , empty+ , ppr c]++ ErrorCannotResizeContext c+ -> vcat [ text "Cannot resize append context, because it's not an append"+ , empty+ , ppr c]+
DDC/Core/Flow/Transform/Slurp/Operator.hs view
@@ -1,13 +1,15 @@ module DDC.Core.Flow.Transform.Slurp.Operator- (slurpOperator)+ ( slurpOperator+ , isSeriesOperator+ , isVectorOperator) where import DDC.Core.Flow.Process.Operator import DDC.Core.Flow.Exp import DDC.Core.Flow.Prim-import DDC.Core.Flow.Prim.TyConPrim-import DDC.Core.Compounds.Simple-import DDC.Type.Pretty ()+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Pretty ()+import Control.Monad -- | Slurp a stream operator from a let-binding binding.@@ -15,88 +17,181 @@ slurpOperator :: Bind Name -> Exp () Name - -> Maybe Operator+ -> Maybe ([Name], Type Name, Operator)+ -- name of contexts to insert into, rate, operator slurpOperator bResult xx+ + -- Rep -----------------------------------------+ | Just ( NameOpSeries OpSeriesRep+ , [ XType _P, XType tK1, XType tA, xVal])+ <- takeXPrimApps xx+ = Just ( []+ , tK1+ , OpRep+ { opResultSeries = bResult+ , opOutputRate = tK1+ , opElemType = tA+ , opInputExp = xVal } ) - -- Create --------------------------------------- | Just ( NameOpFlow OpFlowVectorOfSeries- , [ XType tRate, XType tA, (XVar uSeries) ])+ -- Reps ----------------------------------------+ | Just ( NameOpSeries OpSeriesReps+ , [ XType _P, XType tK1, XType tK2, XType tA, XVar uSegd@(UName nSegd), XVar uS@(UName nS) ]) <- takeXPrimApps xx- = Just $ OpCreate- { opResultVector = bResult- , opInputRate = tRate- , opInputSeries = uSeries - , opAllocRate = Nothing- , opElemType = tA }+ = Just ( [nSegd, nS]+ , tK2+ , OpReps+ { opResultSeries = bResult+ , opInputRate = tK1+ , opOutputRate = tK2+ , opElemType = tA+ , opSegdBound = uSegd+ , opInputSeries = uS } ) + -- Indices -------------------------------------+ | Just ( NameOpSeries OpSeriesIndices+ , [ XType _P, XType tK1, XType tK2, XVar uSegd@(UName nSegd)])+ <- takeXPrimApps xx+ = Just ( [nSegd]+ , tK2+ , OpIndices+ { opResultSeries = bResult+ , opInputRate = tK1+ , opOutputRate = tK2 + , opSegdBound = uSegd } )++ -- Fill ----------------------------------------+ | Just ( NameOpSeries OpSeriesFill+ , [ XType _P, XType tK, XType tA, XVar uV, XVar uS@(UName nS) ])+ <- takeXPrimApps xx+ = Just ( [nS]+ , tK+ , OpFill+ { opResultBind = bResult+ , opTargetVector = uV+ , opInputRate = tK + , opInputSeries = uS+ , opElemType = tA } )+++ -- Gather --------------------------------------+ | Just ( NameOpSeries OpSeriesGather+ , [ XType _P, XType tK1, XType tK2, XType tA, XVar uV, XVar uS@(UName nS) ])+ <- takeXPrimApps xx+ = Just ( [nS]+ , tK2+ , OpGather+ { opResultBind = bResult+ , opSourceVector = uV+ , opVectorRate = tK1+ , opSourceIndices = uS+ , opInputRate = tK2+ , opElemType = tA } )+++ -- Scatter -------------------------------------+ | Just ( NameOpSeries OpSeriesScatter+ , [ XType _P, XType tK, XType tA, XVar uV, XVar uIndices@(UName nIndices), XVar uElems@(UName nElems) ])+ <- takeXPrimApps xx+ = Just ( [nIndices, nElems]+ , tK+ , OpScatter+ { opResultBind = bResult+ , opTargetVector = uV+ , opSourceIndices = uIndices+ , opSourceElems = uElems+ , opInputRate = tK+ , opElemType = tA } )++ -- Map ------------------------------------------ | Just (NameOpFlow (OpFlowMap n), xs) + | Just (NameOpSeries (OpSeriesMap n), xs) <- takeXPrimApps xx , n >= 1- , XType tR : xsArgs2 <- xs+ , XType _P : XType tR : xsArgs2 <- xs , (xsA, xsArgs3) <- splitAt (n + 1) xsArgs2 , tsA <- [ t | XType t <- xsA ] , length tsA == n + 1 , xWorker : xsSeries <- xsArgs3- , usSeries <- [ u | XVar u <- xsSeries ]+ , usSeries <- [ u | XVar u <- xsSeries ]+ , nsSeries <- [ un | UName un <- usSeries ] , length usSeries == n , Just (psIn, xBody) <- takeXLams xWorker , length psIn == n- = Just $ OpMap+ = Just ( nsSeries+ , tR+ , OpMap { opArity = n , opResultSeries = bResult , opInputRate = tR , opInputSeriess = usSeries , opWorkerParams = psIn- , opWorkerBody = xBody }--- -- Fold ----------------------------------------- | Just ( NameOpFlow OpFlowFold- , [ XType tRate, XType _tAcc, XType _tElem- , xWorker, xZero, (XVar uSeries)])- <- takeXPrimApps xx- , Just ([pAcc, pElem], xBody) <- takeXLams xWorker- = Just $ OpFold- { opResultValue = bResult- , opInputRate = tRate- , opInputSeries = uSeries- , opZero = xZero- , opWorkerParamIndex = BNone tInt- , opWorkerParamAcc = pAcc- , opWorkerParamElem = pElem- , opWorkerBody = xBody }--- -- FoldIndex ------------------------------------ | Just ( NameOpFlow OpFlowFoldIndex- , [ XType tRate, XType _tAcc, XType _tElem- , xWorker, xZero, (XVar uSeries)])- <- takeXPrimApps xx- , Just ([pIx, pAcc, pElem], xBody) <- takeXLams xWorker- = Just $ OpFold- { opResultValue = bResult- , opInputRate = tRate- , opInputSeries = uSeries- , opZero = xZero- , opWorkerParamIndex = pIx- , opWorkerParamAcc = pAcc- , opWorkerParamElem = pElem- , opWorkerBody = xBody }+ , opWorkerBody = xBody } ) -- Pack ----------------------------------------- | Just ( NameOpFlow OpFlowPack- , [ XType tRateInput, XType tRateOutput, XType tElem- , _xSel, (XVar uSeries) ]) <- takeXPrimApps xx- = Just $ OpPack+ | Just ( NameOpSeries OpSeriesPack+ , [ XType _P+ , XType tRateInput, XType tRateOutput+ , XType tElem+ , XVar (UName nSel), XVar uSeries@(UName nSeries) ]) <- takeXPrimApps xx+ = Just ( [nSel, nSeries]+ , tRateOutput+ , OpPack { opResultSeries = bResult , opInputRate = tRateInput , opInputSeries = uSeries , opOutputRate = tRateOutput - , opElemType = tElem }+ , opElemType = tElem } ) ++ -- Generate ------------------------------------+ | Just ( NameOpSeries OpSeriesGenerate+ , [ XType _P, XType tK, XType _, xWorker ])+ <- takeXPrimApps xx+ , Just ([bIx], xBody) <- takeXLams xWorker+ = Just ( []+ , tK+ , OpGenerate+ { opResultSeries = bResult+ , opOutputRate = tK+ , opWorkerParamIndex = bIx+ , opWorkerBody = xBody } )++ -- Reduce --------------------------------------+ | Just ( NameOpSeries OpSeriesReduce+ , [ XType _P, XType tK, XType _+ , XVar uRef, xWorker, xZ, XVar uS@(UName nS) ])+ <- takeXPrimApps xx+ , Just ([bAcc, bElem], xBody) <- takeXLams xWorker+ = Just ( [nS]+ , tK+ , OpReduce+ { opResultBind = bResult+ , opTargetRef = uRef+ , opInputRate = tK+ , opInputSeries = uS+ , opZero = xZ+ , opWorkerParamAcc = bAcc+ , opWorkerParamElem = bElem+ , opWorkerBody = xBody } )+ | otherwise = Nothing+++-- | Check if some binding is a series operator.+isSeriesOperator :: Exp () Name -> Bool+isSeriesOperator xx+ = case liftM fst $ takeXPrimApps xx of+ Just (NameOpSeries _) -> True+ _ -> False+++-- | Check if some binding is a vector operator.+isVectorOperator :: Exp () Name -> Bool+isVectorOperator xx+ = case liftM fst $ takeXPrimApps xx of+ Just (NameOpVector _) -> True+ _ -> False
+ DDC/Core/Flow/Transform/Slurp/Resize.hs view
@@ -0,0 +1,120 @@++module DDC.Core.Flow.Transform.Slurp.Resize+ ( Resize(..)+ , slurpResize+ , lookupOrDie+ , seqEitherMaybe )+where+import DDC.Core.Flow.Transform.Slurp.Error+import DDC.Core.Flow.Prim+import DDC.Core.Flow.Exp.Simple.Compounds+import DDC.Core.Flow.Exp.Simple.Exp+import qualified Data.Map as Map++type Ty = Type Name++data Resize+ = Id Ty+ | AppL Ty Ty+ | AppR Ty Ty+ | App Ty Ty Ty Ty Resize Resize + | Sel1 Ty Ty Ty Resize+ | Segd Ty Ty Ty Resize+ | Cross Ty Ty Ty Resize+ deriving Show++slurpResize+ :: Map.Map Name Resize+ -> Exp () Name+ -> Either Error (Maybe Resize)++slurpResize rs xx++ | Just ( NameOpSeries OpSeriesResizeId+ , [ _, tK ] )+ <- takeXPrimApps xx+ = return (Id <$> nameOfType tK)++ | Just ( NameOpSeries OpSeriesResizeAppL+ , [ _, tK, tL ] )+ <- takeXPrimApps xx+ = return (AppL <$> nameOfType tK <*> nameOfType tL)++ | Just ( NameOpSeries OpSeriesResizeAppR+ , [ _, tK, tL ] )+ <- takeXPrimApps xx+ = return (AppR <$> nameOfType tK <*> nameOfType tL)++ | Just ( NameOpSeries OpSeriesResizeApp+ , [ _, tK, tK', tL, tL'+ , XVar (UName rL)+ , XVar (UName rR) ] )+ <- takeXPrimApps xx+ = do rL' <- lookupOrDie rL rs+ rR' <- lookupOrDie rR rs+ return (App <$> nameOfType tK <*> nameOfType tK'+ <*> nameOfType tL <*> nameOfType tL'+ <*> Just rL' <*> Just rR')++ | Just ( NameOpSeries OpSeriesResizeSel1+ , [ _, tJ, tK, tL+ , _+ , XVar (UName r) ] )+ <- takeXPrimApps xx+ = do r' <- lookupOrDie r rs+ return (Sel1 <$> nameOfType tJ <*> nameOfType tK+ <*> nameOfType tL+ <*> Just r')++ | Just ( NameOpSeries OpSeriesResizeSegd+ , [ _, tJ, tK, tL+ , _+ , XVar (UName r) ] )+ <- takeXPrimApps xx+ = do r' <- lookupOrDie r rs+ return (Segd <$> nameOfType tJ <*> nameOfType tK+ <*> nameOfType tL+ <*> Just r')+++ | Just ( NameOpSeries OpSeriesResizeCross+ , [ _, tJ, tK, tL+ , _+ , XVar (UName r) ] )+ <- takeXPrimApps xx+ = do r' <- lookupOrDie r rs+ return (Cross <$> nameOfType tJ <*> nameOfType tK+ <*> nameOfType tL+ <*> Just r')++++ | otherwise+ = return Nothing+++nameOfType :: Exp () Name -> Maybe (Type Name)++nameOfType (XType t)+ = Just t++nameOfType _+ = Nothing+++lookupOrDie+ :: Name+ -> Map.Map Name v+ -> Either Error v+lookupOrDie n m+ = case Map.lookup n m of+ Just v -> return v+ Nothing -> Left $ ErrorNotInContext n++seqEitherMaybe :: Either a (Maybe b) -> Maybe (Either a b)+seqEitherMaybe x+ = case x of+ Left a -> Just (Left a)+ Right Nothing -> Nothing+ Right (Just b) -> Just (Right b)+
DDC/Core/Flow/Transform/Thread.hs view
@@ -10,11 +10,10 @@ import DDC.Core.Flow.Compounds import DDC.Core.Flow.Profile import DDC.Core.Flow.Prim-import DDC.Core.Compounds as C-import DDC.Core.Exp+import DDC.Core.Exp.Annot as C import DDC.Core.Transform.Thread import DDC.Core.Transform.Reannotate-import DDC.Core.Check (AnTEC (..))+import DDC.Core.Check (AnTEC (..)) import qualified DDC.Core.Check as Check @@ -28,7 +27,7 @@ , configVoidType = tUnit , configWrapResultType = wrapResultType , configWrapResultExp = wrapResultExp- , configThreadMe = threadType + , configThreadMe = threadType , configThreadPat = unwrapResult } @@ -45,53 +44,38 @@ -- | Wrap the result of a stateful computation with the state token.-wrapResultExp +wrapResultExp :: Exp (AnTEC () Name) Name -- ^ World expression -> Exp (AnTEC () Name) Name -- ^ Result expression -> Exp () Name wrapResultExp xWorld xResult -- Rewrite Unit => World- | Just aResult <- takeAnnotOfExp xResult- , annotType aResult == tUnit + | aResult <- annotOfExp xResult+ , annotType aResult == tUnit = reannotate annotTail xWorld - -- Rewrite (TupleN a1 a2 .. x1 x2 ..) + -- Rewrite (TupleN a1 a2 .. x1 x2 ..) -- => (TupleN World# a1 a2 .. world x1 x2 ..)- | Just aWorld <- takeAnnotOfExp xWorld- , Just aResult <- takeAnnotOfExp xResult+ | aWorld <- annotOfExp xWorld+ , aResult <- annotOfExp xResult = let tWorld' = annotType aWorld tResult = annotType aResult xWorld' = reannotate annotTail xWorld xResult' = reannotate annotTail xResult- in - -- ISSUE #308: Handle Tuple arities generically in thread transform.- case C.takeXConApps xResult' of- Just (dc, [xT1, xT2- , x1, x2])- | dc == dcTupleN 2- -> C.xApps () (XCon () (dcTupleN 3))- [ XType tWorld', xT1, xT2- , xWorld', x1, x2]-- Just (dc, [xT1, xT2, xT3- , x1, x2, x3])- | dc == dcTupleN 3- -> C.xApps () (XCon () (dcTupleN 4))- [ XType tWorld', xT1, xT2, xT3- , xWorld', x1, x2, x3]-- Just (dc, [xT1, xT2, xT3, xT4- , x1, x2, x3, x4])- | dc == dcTupleN 4- -> C.xApps () (XCon () (dcTupleN 5))- [ XType tWorld', xT1, xT2, xT3, xT4- , xWorld', x1, x2, x3, x4]-+ in case C.takeXConApps xResult' of+ Just (dc, xa)+ | DaConPrim (NameDaConFlow (DaConFlowTuple n)) _ <- dc+ , x <- length xa+ , x >= 2+ -> let (b, a) = splitAt (x `quot` 2) xa+ in C.xApps () (XCon () (dcTupleN $ n + 1))+ $ XType (annotTail aWorld) tWorld' : b -- World# : a1 a2 ..+ ++ xWorld' : a -- world : x1 x2 .. _ -> C.xApps () (XCon () (dcTupleN 2))- [ XType tWorld'- , XType tResult+ [ XType (annotTail aWorld) tWorld'+ , XType (annotTail aResult) tResult , xWorld' , xResult' ] @@ -104,10 +88,10 @@ unwrapResult _ = Just unwrap - where unwrap bWorld bsResult + where unwrap bWorld bsResult | [bResult] <- bsResult , typeOfBind bResult == tUnit- = PData dcTuple1 [bWorld] + = PData dcTuple1 [bWorld] | otherwise = PData (dcTupleN (length (bWorld : bsResult)))@@ -124,80 +108,99 @@ -- Assignables -------------------------- -- new# :: [a : Data]. a -> World# -> T2# (World#, Ref# a) NameOpStore OpStoreNew- -> Just $ tForall kData - $ \tA -> tA + -> Just $ tForall kData+ $ \tA -> tA `tFun` tWorld `tFun` (tTuple2 tWorld (tRef tA)) -- read# :: [a : Data]. Ref# a -> World# -> T2# (World#, a) NameOpStore OpStoreRead -> Just $ tForall kData- $ \tA -> tRef tA + $ \tA -> tRef tA `tFun` tWorld `tFun` (tTuple2 tWorld (tRef tA)) -- write# :: [a : Data]. Ref# -> a -> World# -> World#- NameOpStore OpStoreWrite + NameOpStore OpStoreWrite -> Just $ tForall kData- $ \tA -> tRef tA `tFun` tA + $ \tA -> tRef tA `tFun` tA `tFun` tWorld `tFun` tWorld -- Vectors -------------------------------- -- newVector# :: [a : Data]. Nat# -> World# -> T2# World# (Vector# a)+ -- vnew# :: [a : Data]. Nat# -> World# -> T2# World# (Vector# a) NameOpStore OpStoreNewVector -> Just $ tForall kData- $ \tA -> tNat + $ \tA -> tNat `tFun` tWorld `tFun` (tTuple2 tWorld (tVector tA)) - -- newVectorN# :: [a : Data]. [k : Rate]. RateNat# k - -- -> World# -> T2# (World#, Vector# a)+ -- vnew# :: [a : Data]. [k : Rate]. RateNat# k+ -- -> World# -> T2# (World#, Vector# a) NameOpStore OpStoreNewVectorN -> Just $ tForalls [kData, kRate]- $ \[tA, tK] - -> tRateNat tK + $ \[tA, tK]+ -> tRateNat tK `tFun` tWorld `tFun` (tTuple2 tWorld (tVector tA)) - -- readVector# :: [a : Data]. Vector# a -> Nat# -> World# -> T2# World# a- NameOpStore OpStoreReadVector+ -- vread# :: [a : Data]. Vector# a -> Nat# -> World# -> T2# World# a+ NameOpStore (OpStoreReadVector _) -> Just $ tForall kData- $ \tA -> tA `tFun` tVector tA `tFun` tNat + $ \tA -> tA `tFun` tBuffer tA `tFun` tNat `tFun` tWorld `tFun` (tTuple2 tWorld tA) - -- writeVector# :: [a : Data]. Vector# a -> Nat# -> a -> World# -> World#- NameOpStore OpStoreWriteVector+ -- vwrite# :: [a : Data]. Vector# a -> Nat# -> a -> World# -> World#+ NameOpStore (OpStoreWriteVector _) -> Just $ tForall kData- $ \tA -> tA `tFun` tVector tA `tFun` tNat `tFun` tA + $ \tA -> tA `tFun` tBuffer tA `tFun` tNat `tFun` tA `tFun` tWorld `tFun` tWorld - -- sliceVector# :: [a : Data]. Nat# -> Vector# a -> World# -> T2# World# (Vector# a)- NameOpStore OpStoreSliceVector+ -- vtrunc# :: [a : Data]. Nat# -> Vector# a -> World# -> World#+ NameOpStore OpStoreTruncVector -> Just $ tForall kData- $ \tA -> tNat `tFun` tVector tA - `tFun` tWorld `tFun` (tTuple2 tWorld (tVector tA))-+ $ \tA -> tNat `tFun` tVector tA+ `tFun` tWorld `tFun` tWorld - -- Streams ------------------------------+ -- Series ------------------------------ -- next# :: [k : Rate]. [a : Data] -- . Series# k a -> Int# -> World# -> (World#, a)- NameOpStore OpStoreNext- -> Just $ tForalls [kRate, kData]- $ \[tK, tA] -> tSeries tK tA `tFun` tInt - `tFun` tWorld `tFun` (tTuple2 tWorld tA)+ NameOpConcrete (OpConcreteNext 1)+ -> Just $ tForalls [kProc, kRate, kData]+ $ \[tP, tK, tA]+ -> tSeries tP tK tA `tFun` tInt+ `tFun` tWorld `tFun` (tTuple2 tWorld tA) - -- Contexts ------------------------------ -- loopn# :: [k : Rate]. RateNat# k - -- -> (Nat# -> World# -> World#) + -- nextN# :: [k : Rate]. [a : Data]+ -- . Series# k a -> Int# -> World# -> (World#, a)+ NameOpConcrete (OpConcreteNext c)+ | c >= 2+ -> Just $ tForalls [kProc, kRate, kData]+ $ \[tP, tK, tA]+ -> tSeries tP (tDown c tK) tA `tFun` tInt + `tFun` tWorld `tFun` (tTuple2 tWorld (tVec c tA))++ -- Control -----------------------------+ -- loopn# :: [k : Rate]. RateNat# k+ -- -> (Nat# -> World# -> World#) -- -> World# -> World#- NameOpLoop OpLoopLoopN+ NameOpControl OpControlLoopN -> Just $ tForalls [kRate] $ \[tK] -> tRateNat tK `tFun` (tNat `tFun` tWorld `tFun` tWorld) `tFun` tWorld `tFun` tWorld- + -- guard#- NameOpLoop OpLoopGuard- -> Just $ tRef tNat- `tFun` tBool- `tFun` (tNat `tFun` tWorld `tFun` tWorld)+ NameOpControl OpControlGuard+ -> Just $ tBool+ `tFun` (tUnit `tFun` tWorld `tFun` tWorld) `tFun` tWorld `tFun` tWorld++ -- split# :: [k : Rate]. RateNat# k+ -- -> (RateNat# (Down8# k) -> World# -> World#)+ -- -> (RateNat# (Tail8# k) -> World# -> World#)+ -- -> World# -> World#+ NameOpControl (OpControlSplit c)+ -> Just $ tForall kRate+ $ \tK -> tRateNat tK+ `tFun` (tRateNat (tDown c tK) `tFun` tWorld `tFun` tWorld)+ `tFun` (tRateNat (tTail c tK) `tFun` tWorld `tFun` tWorld)+ `tFun` tWorld `tFun` tWorld _ -> Nothing
+ DDC/Core/Flow/Transform/TransformUpX.hs view
@@ -0,0 +1,85 @@++-- | General purpose tree walking boilerplate.+module DDC.Core.Flow.Transform.TransformUpX+ ( TransformUpMX(..)+ , transformUpX+ , transformUpX'++ -- * Via the Simple AST+ , transformSimpleUpMX+ , transformSimpleUpX+ , transformSimpleUpX')+where+import DDC.Core.Exp.Annot+import DDC.Core.Transform.TransformUpX +import DDC.Core.Flow.Transform.Annotate+import DDC.Core.Flow.Transform.Deannotate+import Data.Functor.Identity+import DDC.Core.Env.EnvX (EnvX)+import qualified DDC.Core.Flow.Exp.Simple.Exp as S+import qualified DDC.Core.Env.EnvX as EnvX+++-- Simple ---------------------------------------------------------------------+-- | Like `transformUpMX`, but the worker takes the Simple version of the AST.+--+-- * To avoid repeated conversions between the different versions of the AST,+-- the worker should return `Nothing` if the provided expression is unchanged.+transformSimpleUpMX + :: (Ord n, TransformUpMX m c, Monad m)+ => (EnvX n -> S.Exp a n -> m (Maybe (S.Exp a n)))+ -- ^ The worker function is given the current+ -- kind and type environments.+ -> EnvX n -- ^ Initial type environment.+ -> c a n -- ^ Transform thing thing.+ -> m (c a n)++transformSimpleUpMX f env0 xx0+ = let + f' env xx+ = do let a = annotOfExp xx+ let sxx = deannotate (const Nothing) xx+ msxx' <- f env sxx+ case msxx' of+ Nothing -> return $ xx+ Just sxx' -> return $ annotate a sxx'++ in transformUpMX f' env0 xx0+++-- | Like `transformUpX`, but the worker takes the Simple version of the AST.+--+-- * To avoid repeated conversions between the different versions of the AST,+-- the worker should return `Nothing` if the provided expression is unchanged.+transformSimpleUpX+ :: forall (c :: * -> * -> *) a n+ . (Ord n, TransformUpMX Identity c)+ => (EnvX n -> S.Exp a n -> Maybe (S.Exp a n))+ -- ^ The worker function is given the current+ -- kind and type environments.+ -> EnvX n -- ^ Initial type environment.+ -> c a n -- ^ Transform this thing.+ -> c a n++transformSimpleUpX f env xx+ = runIdentity + $ transformSimpleUpMX + (\env' x -> return (f env' x)) env xx+++-- | Like `transformUpX'`, but the worker takes the Simple version of the AST.+--+-- * To avoid repeated conversions between the different versions of the AST,+-- the worker should return `Nothing` if the provided expression is unchanged.+transformSimpleUpX'+ :: forall (c :: * -> * -> *) a n+ . (Ord n, TransformUpMX Identity c)+ => (S.Exp a n -> Maybe (S.Exp a n))+ -- ^ The worker function is given the current+ -- kind and type environments.+ -> c a n -- ^ Transform this thing.+ -> c a n++transformSimpleUpX' f xx+ = transformSimpleUpX (\_ -> f) EnvX.empty xx+
DDC/Core/Flow/Transform/Wind.hs view
@@ -28,11 +28,12 @@ , windModule) where import DDC.Core.Module-import DDC.Core.Exp import DDC.Core.Flow import DDC.Core.Flow.Prim-import DDC.Core.Compounds-import DDC.Core.Flow.Compounds (tNat, dcNat, dcTupleN, dcBool, tTupleN)+import DDC.Core.Exp.Annot+import DDC.Core.Transform.TransformModX+import DDC.Core.Flow.Compounds + (tNat, dcNat, dcTupleN, dcBool, tTupleN, kRate) import qualified Data.Map as Map import Data.Map (Map) @@ -103,15 +104,19 @@ -- | We're currently in the body of a guard. | ContextGuard- { -- | Name of the entry counter,- -- the number of times this guard has matched.- contextGuardCounter :: Name-- -- | Whether we're in the matching or non-matching branch.- , contextGuardFlag :: Bool }+ { -- | Whether we're in the matching or non-matching branch.+ contextGuardFlag :: Bool } deriving Show +-- | Check if some `Context` is a `ContextLoop`.+isContextLoop :: Context -> Bool+isContextLoop cc+ = case cc of+ ContextLoop{} -> True+ _ -> False++ -- | Build a tailcall from the current context. -- This tells us where to go after finishing the body of a loop. makeTailCallFromContexts :: a -> RefMap -> [Context] -> Exp a Name@@ -122,12 +127,14 @@ in xApps a xLoop xArgs -makeTailCallFromContexts _ _ _+makeTailCallFromContexts _ _ contexts = error $ unlines [ "ddc-core-flow.makeTailCallFromContexts" - , " Can't make a tailcall for this context." ]+ , " Can't make a tailcall for this context."+ , " context = " ++ show contexts ] +------------------------------------------------------------------------------- -- | Slurp expressions to update each of the accumulators of the loop. -- We assume that there have been no other updates to the loop -- counter, and we generated the code ourselves.@@ -156,17 +163,7 @@ -- If we're inside the true branch of a guard then update -- the associated entry counter for the guard.-slurpArgUpdates a refMap args (ContextGuard nCounter flag : more)- | flag == True- = let - update [] = []- update ((n, x) : args')- | n == nCounter = (n, xIncrement a x) : update args'- | otherwise = (n, x) : update args'-- in slurpArgUpdates a refMap (update args) more-- | otherwise+slurpArgUpdates a refMap args (ContextGuard _flag : more) = slurpArgUpdates a refMap args more slurpArgUpdates _ _ _ (ContextLoop{} : _)@@ -183,42 +180,32 @@ xIncrement a xx = xApps a (XVar a (UPrim (NamePrimArith PrimArithAdd) (typePrimArith PrimArithAdd)))- [ XType tNat, xx, XCon a (dcNat 1) ]+ [ XType a tNat, xx, XCon a (dcNat 1) ] -- | Build an expression that substracts two integers. xSubInt :: a -> Exp a Name -> Exp a Name -> Exp a Name xSubInt a x1 x2 = xApps a (XVar a (UPrim (NamePrimArith PrimArithSub) (typePrimArith PrimArithSub)))- [ XType tNat, x1, x2]+ [ XType a tNat, x1, x2] -------------------------------------------------------------------------------+-- | Apply the wind transform to a single module.+-- Only apply wind to top-level let binds with Forall (k : Rate)...,+-- as that seems like a good indication that something is a lowered series. windModule :: Module () Name -> Module () Name windModule m- = let body' = windModuleBodyX (moduleBody m)- in m { moduleBody = body' }----- | Do winding in the body of a module.-windModuleBodyX :: Exp () Name -> Exp () Name-windModuleBodyX xx- = case xx of- XLet a (LLet b x1) x2- -> let x1' = windBodyX refMapZero [] x1- x2' = windModuleBodyX x2- in XLet a (LLet b x1') x2'-- XLet a (LRec bxs) x2- -> let bxs' = [(b, windBodyX refMapZero [] x) | (b, x) <- bxs]- x2' = windModuleBodyX x2- in XLet a (LRec bxs') x2'-- XLet a lts x2- -> let x2' = windModuleBodyX x2- in XLet a lts x2'+ = transformModLet check m+ where+ check b x+ | t <- typeOfBind b+ , Just (bs, _) <- takeTForalls t+ , elem kRate $ map typeOfBind bs+ = windBodyX refMapZero [] x - _ -> xx+ | otherwise+ = x -------------------------------------------------------------------------------@@ -242,7 +229,7 @@ -- XLet a (LLet (BName nRef _) x) x2 | Just ( NameOpStore OpStoreNew- , [XType tElem, xVal] ) <- takeXPrimApps x+ , [XType _ tElem, xVal] ) <- takeXPrimApps x -> let -- Add the new ref record to the map. info = RefInfo @@ -268,7 +255,7 @@ -- XLet a (LLet bResult x) x2 | Just ( NameOpStore OpStoreRead- , [XType _tElem, XVar _ (UName nRef)] ) + , [XType _ _tElem, XVar _ (UName nRef)] ) <- takeXPrimApps x , Just info <- lookupRefInfo refMap nRef , Just nVal <- nameOfRefInfo info@@ -281,7 +268,7 @@ -- to just bind the new value. XLet a (LLet (BNone _) x) x2 | Just ( NameOpStore OpStoreWrite - , [XType _tElem, XVar _ (UName nRef), xVal])+ , [XType _ _tElem, XVar _ (UName nRef), xVal]) <- takeXPrimApps x , refMap' <- bumpVersionInRefMap nRef refMap , Just info <- lookupRefInfo refMap' nRef@@ -294,17 +281,16 @@ ----------------------------------------- -- Detect loop combinator. XLet a (LLet (BNone _) x) x2- | Just ( NameOpLoop OpLoopLoopN- , [ XType tK, xLength+ | Just ( NameOpControl OpControlLoopN+ , [ XType _ tK, xLength , XLam _ bIx@(BName nIx _) xBody]) <- takeXPrimApps x -> let -- Name of the new loop function.- TVar (UName nK) = tK- nLoop = NameVarMod nK "loop"+ nLoop = NameVar "loop" bLoop = BName nLoop tLoop uLoop = UName nLoop - nLength = NameVarMod nK "length"+ nLength = NameVarMod nLoop "length" bLength = BName nLength tNat uLength = UName nLength @@ -383,22 +369,16 @@ ----------------------------------------- -- Detect guard combinator. XLet a (LLet (BNone _) x) x2- | Just ( NameOpLoop OpLoopGuard- , [ XVar _ (UName nCountRef)- , xFlag- , XLam _ bCount xBody ]) <- takeXPrimApps x+ | Just ( NameOpControl OpControlGuard+ , [ xFlag+ , XLam _ _unit xBody ]) <- takeXPrimApps x -> let - Just infoCount = lookupRefInfo refMap nCountRef-- Just nCount = nameOfRefInfo infoCount- context' = context ++ [ ContextGuard- { contextGuardCounter = nCountRef- , contextGuardFlag = True } ]+ { contextGuardFlag = True } ] - xBody' = XLet a (LLet bCount (XVar a (UName nCount)))- $ windBodyX refMap context' xBody+ xBody' = -- XLet a (LLet bCount (XVar a (UName nCount)))+ windBodyX refMap context' xBody in XCase a xFlag [ AAlt (PData (dcBool True) []) xBody'@@ -407,13 +387,24 @@ ----------------------------------------- -- Detect end value.- -- When we hit a Unit at the top level of the body of a loop then- -- we know it's time to do the recursive call.+ -- If we're inside a loop and hit a Unit at the top-level of the body+ -- then we know it's time to do the recursive call. XCon a dc- | dc == dcUnit+ | any isContextLoop context+ , dc == dcUnit -> makeTailCallFromContexts a refMap context + -----------------------------------------+ -- Enter into both branches of a split.+ XApp{}+ | Just ( NameOpControl (OpControlSplit n)+ , [ XType _ tK, xN, xBranch1, xBranch2 ]) <- takeXPrimApps xx+ -> let xBranch1' = down xBranch1+ xBranch2' = down xBranch2+ in xSplit n tK xN xBranch1' xBranch2'+ + -- Boilerplate -------------------------- XVar{} -> xx XCon{} -> xx@@ -449,17 +440,38 @@ XWitness{} -> xx ++-------------------------------------------------------------------------------+type TypeF = Type Name+type ExpF = Exp () Name+ xNatOfRateNat :: Type Name -> Exp () Name -> Exp () Name xNatOfRateNat tK xR = xApps () - (xVarOpFlow OpFlowNatOfRateNat)- [XType tK, xR]+ (xVarOpConcrete OpConcreteNatOfRateNat)+ [XType () tK, xR] -xVarOpFlow :: OpFlow -> Exp () Name-xVarOpFlow op- = XVar () (UPrim (NameOpFlow op) (typeOpFlow op))+xVarOpConcrete :: OpConcrete -> Exp () Name+xVarOpConcrete op+ = XVar () (UPrim (NameOpConcrete op) (typeOpConcrete op)) ++xSplit :: Int + -> TypeF+ -> ExpF+ -> ExpF -> ExpF -> ExpF+xSplit n tK xRN xDownFn xTailFn + = xApps () + (xVarOpControl $ OpControlSplit n)+ [ XType () tK, xRN, xDownFn, xTailFn ]+++xVarOpControl :: OpControl -> Exp () Name+xVarOpControl op+ = XVar () (UPrim (NameOpControl op) (typeOpControl op))++ ------------------------------------------------------------------------------- -- | Make the type of a loop result, -- given the types of the accumulators for that loop. @@ -484,7 +496,7 @@ [] -> xUnit a [x] -> x _ -> xApps a (XCon a (dcTupleN $ length tsAccs)) - ([XType t | t <- tsAccs] ++ xsAccs)+ ([XType a t | t <- tsAccs] ++ xsAccs) -- | Call a loop, and unpack its result.
LICENSE view
@@ -1,7 +1,7 @@ -------------------------------------------------------------------------------- The Disciplined Disciple Compiler License (MIT style) -Copyrite (K) 2007-2013 The Disciplined Disciple Compiler Strike Force+Copyrite (K) 2007-2016 The Disciplined Disciple Compiler Strike Force All rights reversed. Permission is hereby granted, free of charge, to any person obtaining a copy@@ -13,18 +13,4 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.----------------------------------------------------------------------------------Under Australian law copyright is free and automatic.-By contributing to DDC authors grant all rights they have regarding their-contributions to the other members of the Disciplined Disciple Compiler Strike-Force, past, present and future, as well as placing their contributions under-the above license.--Use "darcs show authors" to get a list of Strike Force members.- ---------------------------------------------------------------------------------Redistributions of libraries in ./external are governed by their own licenses:-- - TinyPTC GNU Lesser General Public License-
ddc-core-flow.cabal view
@@ -1,5 +1,5 @@ Name: ddc-core-flow-Version: 0.3.2.1+Version: 0.4.3.1 License: MIT License-file: LICENSE Author: The Disciplined Disciple Compiler Strike Force@@ -30,76 +30,117 @@ Library Build-Depends: - base == 4.6.*,- deepseq == 1.3.*,+ base >= 4.6 && < 4.10,+ array >= 0.4 && < 0.6,+ deepseq >= 1.3 && < 1.5, containers == 0.5.*,- array == 0.4.*,- transformers == 0.3.*,- mtl == 2.1.*,- ddc-base == 0.3.2.*,- ddc-core == 0.3.2.*,- ddc-core-salt == 0.3.2.*,- ddc-core-simpl == 0.3.2.*+ limp == 0.3.2.*,+ limp-cbc == 0.3.2.*,+ transformers == 0.5.*,+ mtl == 2.2.1.*,+ ddc-core == 0.4.3.*,+ ddc-core-salt == 0.4.3.*,+ ddc-core-simpl == 0.4.3.*,+ ddc-core-tetra == 0.4.3.* Exposed-modules:- DDC.Core.Flow - DDC.Core.Flow.Profile- DDC.Core.Flow.Exp- DDC.Core.Flow.Compounds- DDC.Core.Flow.Env- DDC.Core.Flow.Context-- DDC.Core.Flow.Prim-- DDC.Core.Flow.Procedure+ DDC.Core.Flow.Convert.Base+ DDC.Core.Flow.Convert.Exp+ DDC.Core.Flow.Convert.Type - DDC.Core.Flow.Process.Process DDC.Core.Flow.Process.Operator- DDC.Core.Flow.Process.Pretty- DDC.Core.Flow.Process+ DDC.Core.Flow.Process.Process + DDC.Core.Flow.Transform.Rates.Clusters.Base+ DDC.Core.Flow.Transform.Rates.Clusters.Greedy+ DDC.Core.Flow.Transform.Rates.Clusters.Linear+ DDC.Core.Flow.Transform.Rates.Clusters+ DDC.Core.Flow.Transform.Rates.CnfFromExp+ DDC.Core.Flow.Transform.Rates.Combinators+ DDC.Core.Flow.Transform.Rates.Fail+ DDC.Core.Flow.Transform.Rates.Graph+ DDC.Core.Flow.Transform.Rates.SeriesOfVector+ DDC.Core.Flow.Transform.Rates.SizeInference++ DDC.Core.Flow.Transform.Annotate+ DDC.Core.Flow.Transform.Concretize+ DDC.Core.Flow.Transform.Deannotate+ DDC.Core.Flow.Transform.Extract+ DDC.Core.Flow.Transform.Forward+ DDC.Core.Flow.Transform.Melt DDC.Core.Flow.Transform.Schedule- DDC.Core.Flow.Transform.Prep DDC.Core.Flow.Transform.Slurp- DDC.Core.Flow.Transform.Extract- DDC.Core.Flow.Transform.Concretize DDC.Core.Flow.Transform.Thread+ DDC.Core.Flow.Transform.TransformUpX DDC.Core.Flow.Transform.Wind + DDC.Core.Flow.Compounds+ DDC.Core.Flow.Context+ DDC.Core.Flow.Convert+ DDC.Core.Flow.Env+ DDC.Core.Flow.Exp+ DDC.Core.Flow.Lower+ DDC.Core.Flow.Prim+ DDC.Core.Flow.Procedure+ DDC.Core.Flow.Process+ DDC.Core.Flow.Profile+ DDC.Core.Flow+ Other-modules:+ DDC.Core.Flow.Context.Base+ DDC.Core.Flow.Context.FillPath++ DDC.Core.Flow.Process.Pretty+ DDC.Core.Flow.Prim.Base- DDC.Core.Flow.Prim.KiConFlow- DDC.Core.Flow.Prim.TyConFlow- DDC.Core.Flow.Prim.TyConPrim DDC.Core.Flow.Prim.DaConFlow DDC.Core.Flow.Prim.DaConPrim- DDC.Core.Flow.Prim.OpFlow- DDC.Core.Flow.Prim.OpLoop- DDC.Core.Flow.Prim.OpStore+ DDC.Core.Flow.Prim.KiConFlow+ DDC.Core.Flow.Prim.OpConcrete+ DDC.Core.Flow.Prim.OpControl DDC.Core.Flow.Prim.OpPrim-- DDC.Core.Flow.Transform.Slurp.Operator- DDC.Core.Flow.Transform.Slurp.Alloc+ DDC.Core.Flow.Prim.OpSeries+ DDC.Core.Flow.Prim.OpStore+ DDC.Core.Flow.Prim.OpVector+ DDC.Core.Flow.Prim.TyConFlow+ DDC.Core.Flow.Prim.TyConPrim - DDC.Core.Flow.Transform.Schedule.SeriesEnv+ DDC.Core.Flow.Transform.Schedule.Base+ DDC.Core.Flow.Transform.Schedule.Error+ DDC.Core.Flow.Transform.Schedule.Kernel+ DDC.Core.Flow.Transform.Schedule.Lifting DDC.Core.Flow.Transform.Schedule.Nest+ DDC.Core.Flow.Transform.Schedule.Scalar - DDC.Core.Flow.Transform.Extract.Intersperse+ DDC.Core.Flow.Transform.Slurp.Context+ DDC.Core.Flow.Transform.Slurp.Error+ DDC.Core.Flow.Transform.Slurp.Operator+ DDC.Core.Flow.Transform.Slurp.Resize + DDC.Core.Flow.Exp.Simple.Collect+ DDC.Core.Flow.Exp.Simple.Compounds+ DDC.Core.Flow.Exp.Simple.Exp+ GHC-options:+ -Wall -fno-warn-orphans -fno-warn-missing-signatures+ -fno-warn-missing-methods -fno-warn-unused-do-bind Extensions:- KindSignatures NoMonomorphismRestriction+ FunctionalDependencies+ MultiParamTypeClasses+ FlexibleContexts ScopedTypeVariables StandaloneDeriving- PatternGuards- ParallelListComp DeriveDataTypeable+ FlexibleInstances+ ParallelListComp+ KindSignatures+ PatternGuards ViewPatterns- + BangPatterns