futhark 0.22.7 → 0.23.1
raw patch · 174 files changed
+5936/−6087 lines, 174 filesdep −zip-archivedep ~futhark-manifestPVP ok
version bump matches the API change (PVP)
Dependencies removed: zip-archive
Dependency ranges changed: futhark-manifest
API changes (from Hackage documentation)
- Futhark.AD.Fwd: instance (GHC.Base.Monoid (Futhark.AD.Fwd.Bundled a), Futhark.AD.Fwd.TanBuilder a) => Futhark.AD.Fwd.TanBuilder [a]
- Futhark.AD.Fwd: instance (GHC.Base.Monoid (Futhark.AD.Fwd.BundledTan a), Futhark.AD.Fwd.Tangent a) => Futhark.AD.Fwd.Tangent [a]
- Futhark.AD.Fwd: instance Futhark.AD.Fwd.TanBuilder (Futhark.IR.Syntax.Pat (Futhark.IR.Syntax.Core.TypeBase s u))
- Futhark.Actions: printLastUseGPUSS :: Action GPUMem
- Futhark.Analysis.HORep.MapNest: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.Analysis.HORep.MapNest.MapNest rep)
- Futhark.Analysis.HORep.SOAC: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.Analysis.HORep.SOAC.SOAC rep)
- Futhark.Analysis.HORep.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.Analysis.HORep.SOAC.SOAC rep)
- Futhark.Analysis.HORep.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.Analysis.HORep.SOAC.SOAC rep)
- Futhark.Analysis.LastUse: analyseGPUMem :: Prog GPUMem -> LastUseMap
- Futhark.Analysis.LastUse: analyseSeqMem :: Prog SeqMem -> LastUseMap
- Futhark.Analysis.LastUse: type LastUse = Map VName VName
- Futhark.Analysis.LastUse: type LastUseMap = Map VName Names
- Futhark.Analysis.LastUse: type Used = Names
- Futhark.Analysis.Metrics: instance Futhark.Analysis.Metrics.OpMetrics ()
- Futhark.Analysis.Rephrase: Rephraser :: (ExpDec from -> m (ExpDec to)) -> (LetDec from -> m (LetDec to)) -> (FParamInfo from -> m (FParamInfo to)) -> (LParamInfo from -> m (LParamInfo to)) -> (BodyDec from -> m (BodyDec to)) -> (RetType from -> m (RetType to)) -> (BranchType from -> m (BranchType to)) -> (Op from -> m (Op to)) -> Rephraser m from to
- Futhark.Analysis.Rephrase: [rephraseBodyDec] :: Rephraser m from to -> BodyDec from -> m (BodyDec to)
- Futhark.Analysis.Rephrase: [rephraseBranchType] :: Rephraser m from to -> BranchType from -> m (BranchType to)
- Futhark.Analysis.Rephrase: [rephraseExpDec] :: Rephraser m from to -> ExpDec from -> m (ExpDec to)
- Futhark.Analysis.Rephrase: [rephraseFParamDec] :: Rephraser m from to -> FParamInfo from -> m (FParamInfo to)
- Futhark.Analysis.Rephrase: [rephraseLParamDec] :: Rephraser m from to -> LParamInfo from -> m (LParamInfo to)
- Futhark.Analysis.Rephrase: [rephraseLetBoundDec] :: Rephraser m from to -> LetDec from -> m (LetDec to)
- Futhark.Analysis.Rephrase: [rephraseOp] :: Rephraser m from to -> Op from -> m (Op to)
- Futhark.Analysis.Rephrase: [rephraseRetType] :: Rephraser m from to -> RetType from -> m (RetType to)
- Futhark.Analysis.Rephrase: data Rephraser m from to
- Futhark.Analysis.Rephrase: rephraseBody :: Monad m => Rephraser m from to -> Body from -> m (Body to)
- Futhark.Analysis.Rephrase: rephraseExp :: Monad m => Rephraser m from to -> Exp from -> m (Exp to)
- Futhark.Analysis.Rephrase: rephraseFunDef :: Monad m => Rephraser m from to -> FunDef from -> m (FunDef to)
- Futhark.Analysis.Rephrase: rephraseLambda :: Monad m => Rephraser m from to -> Lambda from -> m (Lambda to)
- Futhark.Analysis.Rephrase: rephrasePat :: Monad m => (from -> m to) -> Pat from -> m (Pat to)
- Futhark.Analysis.Rephrase: rephrasePatElem :: Monad m => (from -> m to) -> PatElem from -> m (PatElem to)
- Futhark.Analysis.Rephrase: rephraseProg :: Monad m => Rephraser m from to -> Prog from -> m (Prog to)
- Futhark.Analysis.Rephrase: rephraseStm :: Monad m => Rephraser m from to -> Stm from -> m (Stm to)
- Futhark.Analysis.SymbolTable: instance Futhark.Analysis.SymbolTable.IndexOp ()
- Futhark.Analysis.SymbolTable: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Types.Typed (Futhark.Analysis.SymbolTable.Entry rep)
- Futhark.Analysis.SymbolTable: instance forall k (rep :: k). GHC.Base.Monoid (Futhark.Analysis.SymbolTable.SymbolTable rep)
- Futhark.Analysis.SymbolTable: instance forall k (rep :: k). GHC.Base.Semigroup (Futhark.Analysis.SymbolTable.SymbolTable rep)
- Futhark.Builder: instance forall k (m :: * -> *) (rep :: k). Futhark.MonadFreshNames.MonadFreshNames m => Futhark.MonadFreshNames.MonadFreshNames (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k (rep :: k) (m :: * -> *). (Futhark.IR.Prop.ASTRep rep, GHC.Base.Monad m) => Futhark.IR.Prop.Scope.HasScope rep (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k (rep :: k) (m :: * -> *). (Futhark.IR.Prop.ASTRep rep, GHC.Base.Monad m) => Futhark.IR.Prop.Scope.LocalScope rep (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Functor m => GHC.Base.Functor (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Monad m => GHC.Base.Applicative (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Monad m => GHC.Base.Monad (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k (rep :: k). Control.Monad.Trans.Class.MonadTrans (Futhark.Builder.BuilderT rep)
- Futhark.Builder: instance forall k e (m :: * -> *) (rep :: k). Control.Monad.Error.Class.MonadError e m => Control.Monad.Error.Class.MonadError e (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k r (m :: * -> *) (rep :: k). Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k s (m :: * -> *) (rep :: k). Control.Monad.State.Class.MonadState s m => Control.Monad.State.Class.MonadState s (Futhark.Builder.BuilderT rep m)
- Futhark.Builder: instance forall k w (m :: * -> *) (rep :: k). Control.Monad.Writer.Class.MonadWriter w m => Control.Monad.Writer.Class.MonadWriter w (Futhark.Builder.BuilderT rep m)
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: failureSwitch :: [FailureMsg] -> Stm
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: failureSwitch :: [FailureMsg] -> Stm
- Futhark.CodeGen.Backends.GenericC.Monad: [compInit] :: CompilerState s -> [Stm]
- Futhark.CodeGen.Backends.GenericC.Monad: [opsStaticArray] :: Operations op s -> StaticArray op s
- Futhark.CodeGen.Backends.GenericC.Monad: atInit :: Stm -> CompilerM op s ()
- Futhark.CodeGen.Backends.GenericC.Monad: contextContents :: CompilerM op s ([FieldGroup], [Stm], [Stm])
- Futhark.CodeGen.Backends.GenericC.Monad: contextFinalInits :: CompilerM op s [Stm]
- Futhark.CodeGen.Backends.GenericC.Monad: isValidCName :: Text -> Bool
- Futhark.CodeGen.Backends.GenericC.Monad: type StaticArray op s = VName -> SpaceId -> PrimType -> ArrayContents -> CompilerM op s ()
- Futhark.CodeGen.Backends.GenericPython: [opsStaticArray] :: Operations op s -> StaticArray op s
- Futhark.CodeGen.Backends.GenericPython: type StaticArray op s = VName -> SpaceId -> PrimType -> ArrayContents -> CompilerM op s ()
- Futhark.CodeGen.Backends.MulticoreC: generateContext :: CompilerM op s ()
- Futhark.CodeGen.ImpGen: instance forall k (rep :: k) r op. Control.Monad.Reader.Class.MonadReader (Futhark.CodeGen.ImpGen.Env rep r op) (Futhark.CodeGen.ImpGen.ImpM rep r op)
- Futhark.CodeGen.ImpGen: instance forall k (rep :: k) r op. Control.Monad.State.Class.MonadState (Futhark.CodeGen.ImpGen.ImpState rep r op) (Futhark.CodeGen.ImpGen.ImpM rep r op)
- Futhark.CodeGen.ImpGen: instance forall k (rep :: k) r op. Futhark.IR.Prop.Scope.HasScope Futhark.IR.SOACS.SOACS (Futhark.CodeGen.ImpGen.ImpM rep r op)
- Futhark.CodeGen.ImpGen: instance forall k (rep :: k) r op. Futhark.MonadFreshNames.MonadFreshNames (Futhark.CodeGen.ImpGen.ImpM rep r op)
- Futhark.CodeGen.ImpGen: instance forall k (rep :: k) r op. GHC.Base.Applicative (Futhark.CodeGen.ImpGen.ImpM rep r op)
- Futhark.CodeGen.ImpGen: instance forall k (rep :: k) r op. GHC.Base.Functor (Futhark.CodeGen.ImpGen.ImpM rep r op)
- Futhark.CodeGen.ImpGen: instance forall k (rep :: k) r op. GHC.Base.Monad (Futhark.CodeGen.ImpGen.ImpM rep r op)
- Futhark.CodeGen.ImpGen: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.CodeGen.ImpGen.VarEntry rep)
- Futhark.CodeGen.RTS.C: cudaH :: Text
- Futhark.CodeGen.RTS.C: openclH :: Text
- Futhark.CodeGen.SetDefaultSpace: setDefaultCodeSpace :: Space -> Code op -> Code op
- Futhark.CodeGen.SetDefaultSpace: setDefaultSpace :: Space -> Definitions op -> Definitions op
- Futhark.IR.Aliases: instance forall k (rep :: k). (Futhark.Builder.Class.Buildable rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep)) => Futhark.Builder.Class.Buildable (Futhark.IR.Aliases.Aliases rep)
- Futhark.IR.Aliases: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep)) => Futhark.IR.Pretty.PrettyRep (Futhark.IR.Aliases.Aliases rep)
- Futhark.IR.Aliases: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.ASTRep (Futhark.IR.Aliases.Aliases rep)
- Futhark.IR.Aliases: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Aliases.Aliased (Futhark.IR.Aliases.Aliases rep)
- Futhark.IR.Aliases: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep), Futhark.Builder.Class.Buildable (Futhark.IR.Aliases.Aliases rep)) => Futhark.Builder.BuilderOps (Futhark.IR.Aliases.Aliases rep)
- Futhark.IR.Aliases: instance forall k (rep :: k). (Futhark.IR.Rep.RepTypes rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep)) => Futhark.IR.Rep.RepTypes (Futhark.IR.Aliases.Aliases rep)
- Futhark.IR.GPU: instance Futhark.IR.TypeCheck.CheckableOp Futhark.IR.GPU.GPU
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.Op rep), Futhark.Analysis.Metrics.OpMetrics op) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Pretty.PrettyRep rep, Prettyprinter.Internal.Pretty op) => Prettyprinter.Internal.Pretty (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.Analysis.SymbolTable.IndexOp op) => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.IsOp op) => Futhark.IR.Prop.IsOp (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Names.FreeIn op) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Rename.Rename op) => Futhark.Transform.Rename.Rename (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Substitute.Substitute op) => Futhark.Transform.Substitute.Substitute (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.Aliases.Aliased rep, Futhark.IR.Prop.Aliases.AliasedOp op, Futhark.IR.Prop.ASTRep rep) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep), Futhark.IR.Prop.Aliases.CanBeAliased op, Futhark.IR.Prop.ASTRep rep) => Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Eq op) => GHC.Classes.Eq (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Ord op) => GHC.Classes.Ord (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.IR.Rep.RepTypes rep, GHC.Show.Show op) => GHC.Show.Show (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k (rep :: k) op. (Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep), Futhark.Optimise.Simplify.Rep.CanBeWise op, Futhark.IR.Prop.ASTRep rep) => Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPU.Op: instance forall k op (rep :: k). Futhark.IR.Prop.TypeOf.TypedOp op => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.IR.GPUMem: instance Futhark.IR.Mem.OpReturns (Futhark.IR.GPU.Op.HostOp (Futhark.Optimise.Simplify.Rep.Wise Futhark.IR.GPUMem.GPUMem) ())
- Futhark.IR.GPUMem: instance Futhark.IR.Mem.OpReturns (Futhark.IR.GPU.Op.HostOp Futhark.IR.GPUMem.GPUMem ())
- Futhark.IR.GPUMem: instance Futhark.IR.TypeCheck.CheckableOp Futhark.IR.GPUMem.GPUMem
- Futhark.IR.MC: instance Futhark.IR.TypeCheck.CheckableOp Futhark.IR.MC.MC
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.Op rep), Futhark.Analysis.Metrics.OpMetrics op) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Pretty.PrettyRep rep, Prettyprinter.Internal.Pretty op) => Prettyprinter.Internal.Pretty (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.Analysis.SymbolTable.IndexOp op) => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.IsOp op) => Futhark.IR.Prop.IsOp (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Names.FreeIn op) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Rename.Rename op) => Futhark.Transform.Rename.Rename (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Substitute.Substitute op) => Futhark.Transform.Substitute.Substitute (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.Aliases.Aliased rep, Futhark.IR.Prop.Aliases.AliasedOp op, Futhark.IR.Prop.ASTRep rep) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep), Futhark.IR.Prop.Aliases.CanBeAliased op, Futhark.IR.Prop.ASTRep rep) => Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Eq op) => GHC.Classes.Eq (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Ord op) => GHC.Classes.Ord (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.IR.Rep.RepTypes rep, GHC.Show.Show op) => GHC.Show.Show (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k (rep :: k) op. (Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep), Futhark.Optimise.Simplify.Rep.CanBeWise op, Futhark.IR.Prop.ASTRep rep) => Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MC.Op: instance forall k op (rep :: k). Futhark.IR.Prop.TypeOf.TypedOp op => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.IR.MCMem: instance Futhark.IR.Mem.OpReturns (Futhark.IR.MC.Op.MCOp (Futhark.Optimise.Simplify.Rep.Wise Futhark.IR.MCMem.MCMem) ())
- Futhark.IR.MCMem: instance Futhark.IR.Mem.OpReturns (Futhark.IR.MC.Op.MCOp Futhark.IR.MCMem.MCMem ())
- Futhark.IR.MCMem: instance Futhark.IR.TypeCheck.CheckableOp Futhark.IR.MCMem.MCMem
- Futhark.IR.Mem: instance Futhark.Analysis.Metrics.OpMetrics inner => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.Analysis.SymbolTable.IndexOp inner => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.IR.Mem.OpReturns ()
- Futhark.IR.Mem: instance Futhark.IR.Mem.OpReturns inner => Futhark.IR.Mem.OpReturns (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.IR.Prop.Aliases.AliasedOp inner => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.IR.Prop.Aliases.CanBeAliased inner => Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.IR.Prop.IsOp inner => Futhark.IR.Prop.IsOp (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.IR.Prop.Names.FreeIn inner => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.IR.Prop.TypeOf.TypedOp inner => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.Transform.Rename.Rename inner => Futhark.Transform.Rename.Rename (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Futhark.Transform.Substitute.Substitute inner => Futhark.Transform.Substitute.Substitute (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance GHC.Classes.Eq inner => GHC.Classes.Eq (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance GHC.Classes.Ord inner => GHC.Classes.Ord (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance GHC.Show.Show inner => GHC.Show.Show (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Mem: instance Prettyprinter.Internal.Pretty inner => Prettyprinter.Internal.Pretty (Futhark.IR.Mem.MemOp inner)
- Futhark.IR.Pretty: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Body rep)
- Futhark.IR.Pretty: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Case (Futhark.IR.Syntax.Body rep))
- Futhark.IR.Pretty: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Exp rep)
- Futhark.IR.Pretty: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.FunDef rep)
- Futhark.IR.Pretty: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Lambda rep)
- Futhark.IR.Pretty: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Prog rep)
- Futhark.IR.Pretty: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Stm rep)
- Futhark.IR.Pretty: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Stms rep)
- Futhark.IR.Prop: instance Futhark.IR.Prop.IsOp ()
- Futhark.IR.Prop.Aliases: -- | The op that results when we add aliases to this op.
- Futhark.IR.Prop.Aliases: addOpAliases :: CanBeAliased op => AliasTable -> op -> OpWithAliases op
- Futhark.IR.Prop.Aliases: class AliasedOp (OpWithAliases op) => CanBeAliased op where {
- Futhark.IR.Prop.Aliases: instance Futhark.IR.Prop.Aliases.AliasedOp ()
- Futhark.IR.Prop.Aliases: instance Futhark.IR.Prop.Aliases.CanBeAliased ()
- Futhark.IR.Prop.Aliases: removeOpAliases :: CanBeAliased op => OpWithAliases op -> op
- Futhark.IR.Prop.Aliases: type OpWithAliases op :: Type;
- Futhark.IR.Prop.Aliases: }
- Futhark.IR.Prop.Names: instance forall k (rep :: k). (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Body rep)
- Futhark.IR.Prop.Names: instance forall k (rep :: k). (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Exp rep)
- Futhark.IR.Prop.Names: instance forall k (rep :: k). (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.FunDef rep)
- Futhark.IR.Prop.Names: instance forall k (rep :: k). (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Lambda rep)
- Futhark.IR.Prop.Names: instance forall k (rep :: k). (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Stm rep)
- Futhark.IR.Prop.Names: instance forall k (rep :: k). Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.LoopForm rep)
- Futhark.IR.Prop.Names: instance forall k (rep :: k). Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Stm rep) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Stms rep)
- Futhark.IR.Prop.Scope: instance forall k (m :: * -> *) (rep :: k) e. (GHC.Base.Monad m, Futhark.IR.Prop.Scope.HasScope rep m) => Futhark.IR.Prop.Scope.HasScope rep (Control.Monad.Trans.Except.ExceptT e m)
- Futhark.IR.Prop.Scope: instance forall k (m :: * -> *) (rep :: k). (GHC.Base.Monad m, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.HasScope rep (Control.Monad.Trans.Reader.ReaderT (Futhark.IR.Prop.Scope.Scope rep) m)
- Futhark.IR.Prop.Scope: instance forall k (m :: * -> *) (rep :: k). (GHC.Base.Monad m, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.LocalScope rep (Control.Monad.Trans.Reader.ReaderT (Futhark.IR.Prop.Scope.Scope rep) m)
- Futhark.IR.Prop.Scope: instance forall k (m :: * -> *) w (rep :: k) s. (GHC.Base.Monad m, GHC.Base.Monoid w, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.HasScope rep (Control.Monad.Trans.RWS.Lazy.RWST (Futhark.IR.Prop.Scope.Scope rep) w s m)
- Futhark.IR.Prop.Scope: instance forall k (m :: * -> *) w (rep :: k) s. (GHC.Base.Monad m, GHC.Base.Monoid w, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.HasScope rep (Control.Monad.Trans.RWS.Strict.RWST (Futhark.IR.Prop.Scope.Scope rep) w s m)
- Futhark.IR.Prop.Scope: instance forall k (m :: * -> *) w (rep :: k) s. (GHC.Base.Monad m, GHC.Base.Monoid w, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.LocalScope rep (Control.Monad.Trans.RWS.Lazy.RWST (Futhark.IR.Prop.Scope.Scope rep) w s m)
- Futhark.IR.Prop.Scope: instance forall k (m :: * -> *) w (rep :: k) s. (GHC.Base.Monad m, GHC.Base.Monoid w, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.LocalScope rep (Control.Monad.Trans.RWS.Strict.RWST (Futhark.IR.Prop.Scope.Scope rep) w s m)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k) (m :: * -> *) e. Futhark.IR.Prop.Scope.LocalScope rep m => Futhark.IR.Prop.Scope.LocalScope rep (Control.Monad.Trans.Except.ExceptT e m)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k) (m :: * -> *). (Futhark.IR.Prop.Scope.HasScope rep m, GHC.Base.Monad m) => Futhark.IR.Prop.Scope.HasScope rep (Futhark.IR.Prop.Scope.ExtendedScope rep m)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Applicative m => GHC.Base.Applicative (Futhark.IR.Prop.Scope.ExtendedScope rep m)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Functor m => GHC.Base.Functor (Futhark.IR.Prop.Scope.ExtendedScope rep m)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Futhark.IR.Prop.Scope.Scope rep) (Futhark.IR.Prop.Scope.ExtendedScope rep m)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Monad m => GHC.Base.Monad (Futhark.IR.Prop.Scope.ExtendedScope rep m)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k) a. Futhark.IR.Prop.Scope.Scoped rep a => Futhark.IR.Prop.Scope.Scoped rep [a]
- Futhark.IR.Prop.Scope: instance forall k (rep :: k). Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.FunDef rep)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k). Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.Lambda rep)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k). Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.LoopForm rep)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k). Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.Stm rep)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k). Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.Stms rep)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k). Futhark.IR.Prop.Scope.Scoped rep (Language.Futhark.Core.VName, Futhark.IR.Prop.Scope.NameInfo rep)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => Futhark.IR.Prop.Types.Typed (Futhark.IR.Prop.Scope.NameInfo rep)
- Futhark.IR.Prop.Scope: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Prop.Scope.NameInfo rep)
- Futhark.IR.Prop.TypeOf: expExtTypeSize :: (RepTypes rep, TypedOp (Op rep)) => Exp rep -> Int
- Futhark.IR.Prop.TypeOf: instance Futhark.IR.Prop.TypeOf.TypedOp ()
- Futhark.IR.Prop.TypeOf: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => Futhark.IR.Prop.Scope.HasScope rep (Futhark.IR.Prop.TypeOf.FeelBad rep)
- Futhark.IR.Prop.TypeOf: instance forall k (rep :: k). GHC.Base.Applicative (Futhark.IR.Prop.TypeOf.FeelBad rep)
- Futhark.IR.Prop.TypeOf: instance forall k (rep :: k). GHC.Base.Functor (Futhark.IR.Prop.TypeOf.FeelBad rep)
- Futhark.IR.SOACS: instance Futhark.IR.TypeCheck.CheckableOp Futhark.IR.SOACS.SOACS
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.ASTRep (Futhark.IR.Aliases.Aliases rep), Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.Aliased rep) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep)) => Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.Op rep) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SOACS.SOAC.Reduce rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SOACS.SOAC.Scan rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.IsOp (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.HistOp rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.Reduce rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.Scan rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.ScremaForm rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.Transform.Rename.Rename (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.HistOp rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.Reduce rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.Scan rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.ScremaForm rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.HistOp rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.Reduce rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.Scan rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.ScremaForm rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.HistOp rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.Reduce rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.SOAC rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.Scan rep)
- Futhark.IR.SOACS.SOAC: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.ScremaForm rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. (Futhark.IR.Pretty.PrettyRep rep, Prettyprinter.Internal.Pretty lvl) => Prettyprinter.Internal.Pretty (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.ASTConstraints lvl) => Futhark.IR.Prop.IsOp (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.ASTConstraints lvl) => Futhark.Transform.Rename.Rename (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.ASTRep (Futhark.IR.Aliases.Aliases rep), Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep), Futhark.IR.Prop.ASTConstraints lvl) => Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.Aliased rep, Futhark.IR.Prop.ASTConstraints lvl) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Names.FreeIn lvl) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Substitute.Substitute lvl) => Futhark.Transform.Substitute.Substitute (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. (Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep), Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.ASTConstraints lvl) => Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.Op rep) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k) lvl. Futhark.IR.Prop.ASTRep rep => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SegOp.KernelBody rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SegOp.SegBinOp rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SegOp.KernelBody rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.Transform.Rename.Rename (Futhark.IR.SegOp.KernelBody rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.SegOp.KernelBody rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SegOp.HistOp rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SegOp.KernelBody rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SegOp.SegBinOp rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SegOp.HistOp rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SegOp.KernelBody rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SegOp.SegBinOp rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SegOp.HistOp rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SegOp.KernelBody rep)
- Futhark.IR.SegOp: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SegOp.SegBinOp rep)
- Futhark.IR.SegOp: instance forall k lvl (rep :: k). Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall lvl k (rep :: k). (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Eq lvl) => GHC.Classes.Eq (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall lvl k (rep :: k). (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Ord lvl) => GHC.Classes.Ord (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.SegOp: instance forall lvl k (rep :: k). (Futhark.IR.Rep.RepTypes rep, GHC.Show.Show lvl) => GHC.Show.Show (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.IR.Seq: instance Futhark.IR.TypeCheck.CheckableOp Futhark.IR.Seq.Seq
- Futhark.IR.SeqMem: instance Futhark.IR.TypeCheck.CheckableOp Futhark.IR.SeqMem.SeqMem
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Body rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Exp rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.FunDef rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Lambda rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.LoopForm rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Prog rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Stm rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Body rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Exp rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.FunDef rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Lambda rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.LoopForm rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Prog rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Stm rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Body rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Exp rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.FunDef rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Lambda rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.LoopForm rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Prog rep)
- Futhark.IR.Syntax: instance forall k (rep :: k). Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Stm rep)
- Futhark.IR.TypeCheck: class ASTRep rep => CheckableOp rep
- Futhark.IR.TypeCheck: instance forall k (rep :: k). Control.Monad.Reader.Class.MonadReader (Futhark.IR.TypeCheck.Env rep) (Futhark.IR.TypeCheck.TypeM rep)
- Futhark.IR.TypeCheck: instance forall k (rep :: k). Control.Monad.State.Class.MonadState Futhark.IR.TypeCheck.TState (Futhark.IR.TypeCheck.TypeM rep)
- Futhark.IR.TypeCheck: instance forall k (rep :: k). Futhark.IR.TypeCheck.Checkable rep => Futhark.IR.Prop.Scope.HasScope (Futhark.IR.Aliases.Aliases rep) (Futhark.IR.TypeCheck.TypeM rep)
- Futhark.IR.TypeCheck: instance forall k (rep :: k). Futhark.IR.TypeCheck.Checkable rep => GHC.Show.Show (Futhark.IR.TypeCheck.ErrorCase rep)
- Futhark.IR.TypeCheck: instance forall k (rep :: k). Futhark.IR.TypeCheck.Checkable rep => GHC.Show.Show (Futhark.IR.TypeCheck.TypeError rep)
- Futhark.IR.TypeCheck: instance forall k (rep :: k). GHC.Base.Applicative (Futhark.IR.TypeCheck.TypeM rep)
- Futhark.IR.TypeCheck: instance forall k (rep :: k). GHC.Base.Functor (Futhark.IR.TypeCheck.TypeM rep)
- Futhark.IR.TypeCheck: instance forall k (rep :: k). GHC.Base.Monad (Futhark.IR.TypeCheck.TypeM rep)
- Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance forall k (rep :: k). Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitReader rep) (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
- Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance forall k (rep :: k). Control.Monad.State.Class.MonadState Futhark.FreshNames.VNameSource (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
- Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance forall k (rep :: k). Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
- Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance forall k (rep :: k). GHC.Base.Applicative (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
- Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance forall k (rep :: k). GHC.Base.Functor (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
- Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance forall k (rep :: k). GHC.Base.Monad (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
- Futhark.Optimise.ArrayShortCircuiting.LastUse: instance forall k (rep :: k). (Futhark.IR.Rep.RepTypes rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Scope.HasScope (Futhark.IR.Aliases.Aliases rep) (Futhark.Optimise.ArrayShortCircuiting.LastUse.LastUseM rep)
- Futhark.Optimise.ArrayShortCircuiting.LastUse: instance forall k (rep :: k). (Futhark.IR.Rep.RepTypes rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Scope.LocalScope (Futhark.IR.Aliases.Aliases rep) (Futhark.Optimise.ArrayShortCircuiting.LastUse.LastUseM rep)
- Futhark.Optimise.ArrayShortCircuiting.LastUse: instance forall k (rep :: k). Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.ArrayShortCircuiting.LastUse.LastUseReader rep) (Futhark.Optimise.ArrayShortCircuiting.LastUse.LastUseM rep)
- Futhark.Optimise.ArrayShortCircuiting.LastUse: instance forall k (rep :: k). Control.Monad.State.Class.MonadState Futhark.Optimise.ArrayShortCircuiting.LastUse.AliasTab (Futhark.Optimise.ArrayShortCircuiting.LastUse.LastUseM rep)
- Futhark.Optimise.ArrayShortCircuiting.LastUse: instance forall k (rep :: k). GHC.Base.Applicative (Futhark.Optimise.ArrayShortCircuiting.LastUse.LastUseM rep)
- Futhark.Optimise.ArrayShortCircuiting.LastUse: instance forall k (rep :: k). GHC.Base.Functor (Futhark.Optimise.ArrayShortCircuiting.LastUse.LastUseM rep)
- Futhark.Optimise.ArrayShortCircuiting.LastUse: instance forall k (rep :: k). GHC.Base.Monad (Futhark.Optimise.ArrayShortCircuiting.LastUse.LastUseM rep)
- Futhark.Optimise.ArrayShortCircuiting.LastUse: lastUseGPUMem :: Prog (Aliases GPUMem) -> LUTabProg
- Futhark.Optimise.ArrayShortCircuiting.LastUse: lastUseMCMem :: Prog (Aliases MCMem) -> LUTabProg
- Futhark.Optimise.ArrayShortCircuiting.LastUse: lastUseSeqMem :: Prog (Aliases SeqMem) -> LUTabProg
- Futhark.Optimise.ArrayShortCircuiting.LastUse: type LUTabFun = Map VName Names
- Futhark.Optimise.ArrayShortCircuiting.LastUse: type LUTabProg = (LUTabFun, Map Name LUTabFun)
- Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: instance Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper ()
- Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: instance Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper (Futhark.IR.GPU.Op.HostOp (Futhark.IR.Aliases.Aliases Futhark.IR.GPUMem.GPUMem) ())
- Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: instance Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper inner => Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper (Futhark.IR.MC.Op.MCOp (Futhark.IR.Aliases.Aliases Futhark.IR.MCMem.MCMem) inner)
- Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: instance forall k lvl (rep :: k). Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.Optimise.CSE: instance Futhark.Optimise.CSE.CSEInOp ()
- Futhark.Optimise.CSE: instance Futhark.Optimise.CSE.CSEInOp op => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Mem.MemOp op)
- Futhark.Optimise.CSE: instance forall k (rep :: k) lvl. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.Aliased rep, Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Rep.Op rep)) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.Optimise.CSE: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.Aliased rep, Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Rep.Op rep), Futhark.Optimise.CSE.CSEInOp op) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.Optimise.CSE: instance forall k (rep :: k) op. (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.Aliased rep, Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Rep.Op rep), Futhark.Optimise.CSE.CSEInOp op) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.Optimise.CSE: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Rep.Op rep), Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Prop.Aliases.OpWithAliases (Futhark.IR.Rep.Op rep))) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.SOACS.SOAC.SOAC (Futhark.IR.Aliases.Aliases rep))
- Futhark.Optimise.DoubleBuffer: instance forall k (rep :: k). Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.DoubleBuffer.Env rep) (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
- Futhark.Optimise.DoubleBuffer: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Scope.HasScope rep (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
- Futhark.Optimise.DoubleBuffer: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Scope.LocalScope rep (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
- Futhark.Optimise.DoubleBuffer: instance forall k (rep :: k). Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
- Futhark.Optimise.DoubleBuffer: instance forall k (rep :: k). GHC.Base.Applicative (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
- Futhark.Optimise.DoubleBuffer: instance forall k (rep :: k). GHC.Base.Functor (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
- Futhark.Optimise.DoubleBuffer: instance forall k (rep :: k). GHC.Base.Monad (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
- Futhark.Optimise.Fusion.GraphRep: FinalNode :: Stms SOACS -> NodeT -> Stms SOACS -> NodeT
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.InPlaceLowering.TopDown rep) (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). Control.Monad.State.Class.MonadState Futhark.FreshNames.VNameSource (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). Control.Monad.Writer.Class.MonadWriter (Futhark.Optimise.InPlaceLowering.BottomUp rep) (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). Futhark.Optimise.InPlaceLowering.Constraints rep => Futhark.IR.Prop.Scope.HasScope (Futhark.IR.Aliases.Aliases rep) (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). GHC.Base.Applicative (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). GHC.Base.Functor (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). GHC.Base.Monad (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). GHC.Base.Monoid (Futhark.Optimise.InPlaceLowering.BottomUp rep)
- Futhark.Optimise.InPlaceLowering: instance forall k (rep :: k). GHC.Base.Semigroup (Futhark.Optimise.InPlaceLowering.BottomUp rep)
- Futhark.Optimise.Simplify.Engine: instance forall k (rep :: k). Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.Simplify.Engine.SimpleOps rep, Futhark.Optimise.Simplify.Engine.Env rep) (Futhark.Optimise.Simplify.Engine.SimpleM rep)
- Futhark.Optimise.Simplify.Engine: instance forall k (rep :: k). Control.Monad.State.Class.MonadState (Futhark.FreshNames.VNameSource, GHC.Types.Bool, Futhark.IR.Syntax.Core.Certs) (Futhark.Optimise.Simplify.Engine.SimpleM rep)
- Futhark.Optimise.Simplify.Engine: instance forall k (rep :: k). Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.Simplify.Engine.SimpleM rep)
- Futhark.Optimise.Simplify.Engine: instance forall k (rep :: k). Futhark.Optimise.Simplify.Engine.SimplifiableRep rep => Futhark.IR.Prop.Scope.HasScope (Futhark.Optimise.Simplify.Rep.Wise rep) (Futhark.Optimise.Simplify.Engine.SimpleM rep)
- Futhark.Optimise.Simplify.Engine: instance forall k (rep :: k). Futhark.Optimise.Simplify.Engine.SimplifiableRep rep => Futhark.IR.Prop.Scope.LocalScope (Futhark.Optimise.Simplify.Rep.Wise rep) (Futhark.Optimise.Simplify.Engine.SimpleM rep)
- Futhark.Optimise.Simplify.Engine: instance forall k (rep :: k). GHC.Base.Applicative (Futhark.Optimise.Simplify.Engine.SimpleM rep)
- Futhark.Optimise.Simplify.Engine: instance forall k (rep :: k). GHC.Base.Functor (Futhark.Optimise.Simplify.Engine.SimpleM rep)
- Futhark.Optimise.Simplify.Engine: instance forall k (rep :: k). GHC.Base.Monad (Futhark.Optimise.Simplify.Engine.SimpleM rep)
- Futhark.Optimise.Simplify.Rep: instance Futhark.Optimise.Simplify.Rep.CanBeWise ()
- Futhark.Optimise.Simplify.Rep: instance forall k (rep :: k). (Futhark.Builder.Class.Buildable rep, Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep)) => Futhark.Builder.Class.Buildable (Futhark.Optimise.Simplify.Rep.Wise rep)
- Futhark.Optimise.Simplify.Rep: instance forall k (rep :: k). (Futhark.IR.Pretty.PrettyRep rep, Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep)) => Futhark.IR.Pretty.PrettyRep (Futhark.Optimise.Simplify.Rep.Wise rep)
- Futhark.Optimise.Simplify.Rep: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.ASTRep (Futhark.Optimise.Simplify.Rep.Wise rep)
- Futhark.Optimise.Simplify.Rep: instance forall k (rep :: k). (Futhark.IR.Prop.ASTRep rep, Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Aliases.Aliased (Futhark.Optimise.Simplify.Rep.Wise rep)
- Futhark.Optimise.Simplify.Rep: instance forall k (rep :: k). (Futhark.IR.Rep.RepTypes rep, Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.Rep.Op rep)) => Futhark.IR.Rep.RepTypes (Futhark.Optimise.Simplify.Rep.Wise rep)
- Futhark.Optimise.Simplify.Rep: removeOpWisdom :: CanBeWise op => OpWithWisdom op -> op
- Futhark.Optimise.Simplify.Rep: type OpWithWisdom op :: Type;
- Futhark.Optimise.Simplify.Rep: }
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k) a. GHC.Base.Monoid (Futhark.Optimise.Simplify.Rule.Rules rep a)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k) a. GHC.Base.Semigroup (Futhark.Optimise.Simplify.Rule.Rules rep a)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Scope.HasScope rep (Futhark.Optimise.Simplify.Rule.RuleM rep)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k). Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Scope.LocalScope rep (Futhark.Optimise.Simplify.Rule.RuleM rep)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k). Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.Simplify.Rule.RuleM rep)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k). GHC.Base.Applicative (Futhark.Optimise.Simplify.Rule.RuleM rep)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k). GHC.Base.Functor (Futhark.Optimise.Simplify.Rule.RuleM rep)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k). GHC.Base.Monad (Futhark.Optimise.Simplify.Rule.RuleM rep)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k). GHC.Base.Monoid (Futhark.Optimise.Simplify.Rule.RuleBook rep)
- Futhark.Optimise.Simplify.Rule: instance forall k (rep :: k). GHC.Base.Semigroup (Futhark.Optimise.Simplify.Rule.RuleBook rep)
- Futhark.Pass.ExplicitAllocations: instance Futhark.Pass.ExplicitAllocations.SizeSubst ()
- Futhark.Pass.ExplicitAllocations: instance Futhark.Pass.ExplicitAllocations.SizeSubst op => Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.Mem.MemOp op)
- Futhark.Pass.ExplicitAllocations: instance forall k (fromrep :: k) torep inner. Futhark.Pass.ExplicitAllocations.Allocable fromrep torep inner => Futhark.Builder.Class.MonadBuilder (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
- Futhark.Pass.ExplicitAllocations: instance forall k1 (fromrep :: k1) k2 (torep :: k2). Control.Monad.Reader.Class.MonadReader (Futhark.Pass.ExplicitAllocations.AllocEnv fromrep torep) (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
- Futhark.Pass.ExplicitAllocations: instance forall k1 (fromrep :: k1) k2 (torep :: k2). Futhark.IR.Prop.ASTRep torep => Futhark.IR.Prop.Scope.HasScope torep (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
- Futhark.Pass.ExplicitAllocations: instance forall k1 (fromrep :: k1) k2 (torep :: k2). Futhark.IR.Prop.ASTRep torep => Futhark.IR.Prop.Scope.LocalScope torep (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
- Futhark.Pass.ExplicitAllocations: instance forall k1 (fromrep :: k1) k2 (torep :: k2). Futhark.MonadFreshNames.MonadFreshNames (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
- Futhark.Pass.ExplicitAllocations: instance forall k1 (fromrep :: k1) k2 (torep :: k2). GHC.Base.Applicative (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
- Futhark.Pass.ExplicitAllocations: instance forall k1 (fromrep :: k1) k2 (torep :: k2). GHC.Base.Functor (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
- Futhark.Pass.ExplicitAllocations: instance forall k1 (fromrep :: k1) k2 (torep :: k2). GHC.Base.Monad (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
- Futhark.Pass.ExplicitAllocations.GPU: instance forall k (rep :: k) op. Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.GPU.Op.HostOp rep op)
- Futhark.Pass.ExplicitAllocations.MC: instance forall k (rep :: k) op. Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.MC.Op.MCOp rep op)
- Futhark.Pass.ExplicitAllocations.SegOp: instance forall k lvl (rep :: k). Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.SegOp.SegOp lvl rep)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (m :: * -> *) (rep :: k). (GHC.Base.Monad m, Futhark.IR.Prop.ASTRep rep) => Futhark.IR.Prop.Scope.HasScope rep (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (m :: * -> *) (rep :: k). (GHC.Base.Monad m, Futhark.IR.Prop.ASTRep rep) => Futhark.IR.Prop.Scope.LocalScope rep (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (m :: * -> *) (rep :: k). Futhark.MonadFreshNames.MonadFreshNames m => Futhark.MonadFreshNames.MonadFreshNames (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (m :: * -> *) (rep :: k). GHC.Base.Monad m => Futhark.Util.Log.MonadLogger (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Applicative m => GHC.Base.Applicative (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Functor m => GHC.Base.Functor (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Futhark.Pass.ExtractKernels.DistributeNests.DistEnv rep m) (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Monad m => Control.Monad.Writer.Class.MonadWriter (Futhark.Pass.ExtractKernels.DistributeNests.DistRes rep) (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k) (m :: * -> *). GHC.Base.Monad m => GHC.Base.Monad (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k). GHC.Base.Monoid (Futhark.Pass.ExtractKernels.DistributeNests.DistRes rep)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k). GHC.Base.Monoid (Futhark.Pass.ExtractKernels.DistributeNests.PostStms rep)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k). GHC.Base.Semigroup (Futhark.Pass.ExtractKernels.DistributeNests.DistRes rep)
- Futhark.Pass.ExtractKernels.DistributeNests: instance forall k (rep :: k). GHC.Base.Semigroup (Futhark.Pass.ExtractKernels.DistributeNests.PostStms rep)
- Futhark.Pkg.Info: [pkgRevZipballDir] :: PkgRevInfo m -> FilePath
- Futhark.Pkg.Info: [pkgRevZipballUrl] :: PkgRevInfo m -> Text
- Futhark.Pkg.Info: downloadZipball :: (MonadLogger m, MonadIO m, MonadFail m) => PkgRevInfo m -> m Archive
- Futhark.Transform.Rename: instance forall k (rep :: k). Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.Body rep)
- Futhark.Transform.Rename: instance forall k (rep :: k). Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.Exp rep)
- Futhark.Transform.Rename: instance forall k (rep :: k). Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.FunDef rep)
- Futhark.Transform.Rename: instance forall k (rep :: k). Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.Lambda rep)
- Futhark.Transform.Rename: instance forall k (rep :: k). Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.Stm rep)
- Futhark.Transform.Substitute: instance forall k (rep :: k). Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Prop.Scope.NameInfo rep)
- Futhark.Transform.Substitute: instance forall k (rep :: k). Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Body rep)
- Futhark.Transform.Substitute: instance forall k (rep :: k). Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Exp rep)
- Futhark.Transform.Substitute: instance forall k (rep :: k). Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Lambda rep)
- Futhark.Transform.Substitute: instance forall k (rep :: k). Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Stm rep)
- Futhark.Transform.Substitute: instance forall k (rep :: k). Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Stm rep) => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Stms rep)
- Language.Futhark.Pretty: instance Prettyprinter.Internal.Pretty (Language.Futhark.Syntax.Shape dim) => Prettyprinter.Internal.Pretty (Language.Futhark.Syntax.TypeArg dim)
+ Futhark.Analysis.Alias: analyseStm :: AliasableRep rep => AliasTable -> Stm rep -> Stm (Aliases rep)
+ Futhark.Analysis.Alias: type AliasableRep rep = (ASTRep rep, RephraseOp (OpC rep), CanBeAliased (OpC rep), AliasedOp (OpC rep (Aliases rep)))
+ Futhark.Analysis.HORep.MapNest: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.Analysis.HORep.MapNest.MapNest rep)
+ Futhark.Analysis.HORep.SOAC: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.Analysis.HORep.SOAC.SOAC rep)
+ Futhark.Analysis.HORep.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.Analysis.HORep.SOAC.SOAC rep)
+ Futhark.Analysis.HORep.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.Analysis.HORep.SOAC.SOAC rep)
+ Futhark.Analysis.HORep.SOAC: transformToExp :: (Monad m, HasScope rep m) => ArrayTransform -> VName -> m (Certs, Exp rep)
+ Futhark.Analysis.LastUse: instance Control.Monad.Reader.Class.MonadReader (Futhark.Analysis.LastUse.LastUseReader rep) (Futhark.Analysis.LastUse.LastUseM rep)
+ Futhark.Analysis.LastUse: instance Control.Monad.State.Class.MonadState Futhark.Analysis.LastUse.AliasTab (Futhark.Analysis.LastUse.LastUseM rep)
+ Futhark.Analysis.LastUse: instance Futhark.IR.Rep.RepTypes (Futhark.IR.Aliases.Aliases rep) => Futhark.IR.Prop.Scope.HasScope (Futhark.IR.Aliases.Aliases rep) (Futhark.Analysis.LastUse.LastUseM rep)
+ Futhark.Analysis.LastUse: instance Futhark.IR.Rep.RepTypes (Futhark.IR.Aliases.Aliases rep) => Futhark.IR.Prop.Scope.LocalScope (Futhark.IR.Aliases.Aliases rep) (Futhark.Analysis.LastUse.LastUseM rep)
+ Futhark.Analysis.LastUse: instance GHC.Base.Applicative (Futhark.Analysis.LastUse.LastUseM rep)
+ Futhark.Analysis.LastUse: instance GHC.Base.Functor (Futhark.Analysis.LastUse.LastUseM rep)
+ Futhark.Analysis.LastUse: instance GHC.Base.Monad (Futhark.Analysis.LastUse.LastUseM rep)
+ Futhark.Analysis.LastUse: lastUseGPUMem :: Prog (Aliases GPUMem) -> LUTabProg
+ Futhark.Analysis.LastUse: lastUseMCMem :: Prog (Aliases MCMem) -> LUTabProg
+ Futhark.Analysis.LastUse: lastUseSeqMem :: Prog (Aliases SeqMem) -> LUTabProg
+ Futhark.Analysis.LastUse: type LUTabFun = Map VName Names
+ Futhark.Analysis.LastUse: type LUTabProg = (LUTabFun, Map Name LUTabFun)
+ Futhark.Analysis.Metrics: instance forall k (rep :: k). Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.NoOp rep)
+ Futhark.Analysis.SymbolTable: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Types.Typed (Futhark.Analysis.SymbolTable.Entry rep)
+ Futhark.Analysis.SymbolTable: instance GHC.Base.Monoid (Futhark.Analysis.SymbolTable.SymbolTable rep)
+ Futhark.Analysis.SymbolTable: instance GHC.Base.Semigroup (Futhark.Analysis.SymbolTable.SymbolTable rep)
+ Futhark.Analysis.SymbolTable: instance forall k (rep :: k). Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.Rep.NoOp rep)
+ Futhark.Analysis.SymbolTable: subExpAvailable :: SubExp -> SymbolTable rep -> Bool
+ Futhark.Builder: instance (Futhark.IR.Prop.ASTRep rep, GHC.Base.Monad m) => Futhark.IR.Prop.Scope.HasScope rep (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance (Futhark.IR.Prop.ASTRep rep, GHC.Base.Monad m) => Futhark.IR.Prop.Scope.LocalScope rep (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance Control.Monad.Error.Class.MonadError e m => Control.Monad.Error.Class.MonadError e (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance Control.Monad.State.Class.MonadState s m => Control.Monad.State.Class.MonadState s (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance Control.Monad.Trans.Class.MonadTrans (Futhark.Builder.BuilderT rep)
+ Futhark.Builder: instance Control.Monad.Writer.Class.MonadWriter w m => Control.Monad.Writer.Class.MonadWriter w (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance Futhark.MonadFreshNames.MonadFreshNames m => Futhark.MonadFreshNames.MonadFreshNames (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance GHC.Base.Functor m => GHC.Base.Functor (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance GHC.Base.Monad m => GHC.Base.Applicative (Futhark.Builder.BuilderT rep m)
+ Futhark.Builder: instance GHC.Base.Monad m => GHC.Base.Monad (Futhark.Builder.BuilderT rep m)
+ Futhark.CLI.Benchcmp: instance GHC.Show.Show Futhark.CLI.Benchcmp.SpeedUp
+ Futhark.CLI.Benchcmp: main :: String -> [String] -> IO ()
+ Futhark.CLI.Eval: main :: String -> [String] -> IO ()
+ Futhark.CodeGen.Backends.CCUDA.Boilerplate: failureMsgFunction :: [FailureMsg] -> Definition
+ Futhark.CodeGen.Backends.CCUDA.Boilerplate: generateTuningParams :: Map Name SizeClass -> CompilerM op a ()
+ Futhark.CodeGen.Backends.COpenCL.Boilerplate: failureMsgFunction :: [FailureMsg] -> Definition
+ Futhark.CodeGen.Backends.COpenCL.Boilerplate: generateTuningParams :: Map Name SizeClass -> CompilerM op a ()
+ Futhark.CodeGen.Backends.GenericC.Monad: generateProgramStruct :: CompilerM op s ()
+ Futhark.CodeGen.Backends.MulticoreC.Boilerplate: generateBoilerplate :: CompilerM op s ()
+ Futhark.CodeGen.Backends.SimpleRep: escapeName :: Text -> Text
+ Futhark.CodeGen.Backends.SimpleRep: isValidCName :: Text -> Bool
+ Futhark.CodeGen.ImpCode: instance GHC.Base.Monoid (Futhark.CodeGen.ImpCode.Constants a)
+ Futhark.CodeGen.ImpCode: instance GHC.Base.Semigroup (Futhark.CodeGen.ImpCode.Constants a)
+ Futhark.CodeGen.ImpGen: genConstants :: ImpM rep r op (Names, a) -> ImpM rep r op a
+ Futhark.CodeGen.ImpGen: instance Control.Monad.Reader.Class.MonadReader (Futhark.CodeGen.ImpGen.Env rep r op) (Futhark.CodeGen.ImpGen.ImpM rep r op)
+ Futhark.CodeGen.ImpGen: instance Control.Monad.State.Class.MonadState (Futhark.CodeGen.ImpGen.ImpState rep r op) (Futhark.CodeGen.ImpGen.ImpM rep r op)
+ Futhark.CodeGen.ImpGen: instance Futhark.IR.Prop.Scope.HasScope Futhark.IR.SOACS.SOACS (Futhark.CodeGen.ImpGen.ImpM rep r op)
+ Futhark.CodeGen.ImpGen: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.CodeGen.ImpGen.VarEntry rep)
+ Futhark.CodeGen.ImpGen: instance Futhark.MonadFreshNames.MonadFreshNames (Futhark.CodeGen.ImpGen.ImpM rep r op)
+ Futhark.CodeGen.ImpGen: instance GHC.Base.Applicative (Futhark.CodeGen.ImpGen.ImpM rep r op)
+ Futhark.CodeGen.ImpGen: instance GHC.Base.Functor (Futhark.CodeGen.ImpGen.ImpM rep r op)
+ Futhark.CodeGen.ImpGen: instance GHC.Base.Monad (Futhark.CodeGen.ImpGen.ImpM rep r op)
+ Futhark.CodeGen.ImpGen.GPU.Base: genZeroes :: String -> Int -> CallKernelGen VName
+ Futhark.CodeGen.RTS.C: backendsCH :: Text
+ Futhark.CodeGen.RTS.C: backendsCudaH :: Text
+ Futhark.CodeGen.RTS.C: backendsMulticoreH :: Text
+ Futhark.CodeGen.RTS.C: backendsOpenclH :: Text
+ Futhark.Compiler.Program: [fileScope] :: FileModule -> Env
+ Futhark.IR.Aliases: addOpAliases :: (CanBeAliased op, AliasableRep rep) => AliasTable -> op rep -> op (Aliases rep)
+ Futhark.IR.Aliases: class CanBeAliased op
+ Futhark.IR.Aliases: instance (Futhark.Builder.Class.Buildable rep, Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.Rep.OpC rep (Futhark.IR.Aliases.Aliases rep))) => Futhark.Builder.Class.Buildable (Futhark.IR.Aliases.Aliases rep)
+ Futhark.IR.Aliases: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.Rep.OpC rep (Futhark.IR.Aliases.Aliases rep))) => Futhark.IR.Pretty.PrettyRep (Futhark.IR.Aliases.Aliases rep)
+ Futhark.IR.Aliases: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.Rep.OpC rep (Futhark.IR.Aliases.Aliases rep))) => Futhark.IR.Prop.ASTRep (Futhark.IR.Aliases.Aliases rep)
+ Futhark.IR.Aliases: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.Rep.OpC rep (Futhark.IR.Aliases.Aliases rep))) => Futhark.IR.Prop.Aliases.Aliased (Futhark.IR.Aliases.Aliases rep)
+ Futhark.IR.Aliases: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.Rep.OpC rep (Futhark.IR.Aliases.Aliases rep)), Futhark.Builder.Class.Buildable (Futhark.IR.Aliases.Aliases rep)) => Futhark.Builder.BuilderOps (Futhark.IR.Aliases.Aliases rep)
+ Futhark.IR.Aliases: instance (Futhark.IR.Rep.RepTypes rep, Futhark.IR.Prop.ASTConstraints (Futhark.IR.Rep.OpC rep (Futhark.IR.Aliases.Aliases rep))) => Futhark.IR.Rep.RepTypes (Futhark.IR.Aliases.Aliases rep)
+ Futhark.IR.Aliases: instance Futhark.IR.Aliases.CanBeAliased Futhark.IR.Rep.NoOp
+ Futhark.IR.Aliases: type AliasableRep rep = (ASTRep rep, RephraseOp (OpC rep), CanBeAliased (OpC rep), AliasedOp (OpC rep (Aliases rep)))
+ Futhark.IR.GPU.Op: instance (Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.Op rep), Futhark.Analysis.Metrics.OpMetrics (op rep)) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Pretty.PrettyRep rep, Prettyprinter.Internal.Pretty (op rep)) => Prettyprinter.Internal.Pretty (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.Analysis.SymbolTable.IndexOp (op rep)) => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.IsOp (op rep)) => Futhark.IR.Prop.IsOp (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Names.FreeIn (op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Rename.Rename (op rep)) => Futhark.Transform.Rename.Rename (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Substitute.Substitute (op rep)) => Futhark.Transform.Substitute.Substitute (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Prop.Aliases.Aliased rep, Futhark.IR.Prop.Aliases.AliasedOp (op rep)) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Eq (op rep)) => GHC.Classes.Eq (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Ord (op rep)) => GHC.Classes.Ord (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance (Futhark.IR.Rep.RepTypes rep, GHC.Show.Show (op rep)) => GHC.Show.Show (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance Futhark.IR.Aliases.CanBeAliased op => Futhark.IR.Aliases.CanBeAliased (Futhark.IR.GPU.Op.HostOp op)
+ Futhark.IR.GPU.Op: instance Futhark.IR.Prop.TypeOf.TypedOp (op rep) => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.IR.GPU.Op: instance Futhark.IR.Rephrase.RephraseOp op => Futhark.IR.Rephrase.RephraseOp (Futhark.IR.GPU.Op.HostOp op)
+ Futhark.IR.GPU.Op: instance Futhark.Optimise.Simplify.Rep.CanBeWise op => Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.GPU.Op.HostOp op)
+ Futhark.IR.GPUMem: instance Futhark.IR.Mem.OpReturns (Futhark.IR.GPU.Op.HostOp Futhark.IR.Rep.NoOp (Futhark.Optimise.Simplify.Rep.Wise Futhark.IR.GPUMem.GPUMem))
+ Futhark.IR.GPUMem: instance Futhark.IR.Mem.OpReturns (Futhark.IR.GPU.Op.HostOp Futhark.IR.Rep.NoOp Futhark.IR.GPUMem.GPUMem)
+ Futhark.IR.MC.Op: instance (Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.Op rep), Futhark.Analysis.Metrics.OpMetrics (op rep)) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Pretty.PrettyRep rep, Prettyprinter.Internal.Pretty (op rep)) => Prettyprinter.Internal.Pretty (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.Analysis.SymbolTable.IndexOp (op rep)) => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.IsOp (op rep)) => Futhark.IR.Prop.IsOp (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Names.FreeIn (op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Rename.Rename (op rep)) => Futhark.Transform.Rename.Rename (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Substitute.Substitute (op rep)) => Futhark.Transform.Substitute.Substitute (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.Aliases.Aliased rep, Futhark.IR.Prop.Aliases.AliasedOp (op rep)) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Eq (op rep)) => GHC.Classes.Eq (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Ord (op rep)) => GHC.Classes.Ord (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Rep.RepTypes rep, GHC.Show.Show (op rep)) => GHC.Show.Show (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance Futhark.IR.Aliases.CanBeAliased op => Futhark.IR.Aliases.CanBeAliased (Futhark.IR.MC.Op.MCOp op)
+ Futhark.IR.MC.Op: instance Futhark.IR.Prop.TypeOf.TypedOp (op rep) => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.IR.MC.Op: instance Futhark.IR.Rephrase.RephraseOp op => Futhark.IR.Rephrase.RephraseOp (Futhark.IR.MC.Op.MCOp op)
+ Futhark.IR.MC.Op: instance Futhark.Optimise.Simplify.Rep.CanBeWise op => Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.MC.Op.MCOp op)
+ Futhark.IR.MCMem: instance Futhark.IR.Mem.OpReturns (Futhark.IR.MC.Op.MCOp Futhark.IR.Rep.NoOp (Futhark.Optimise.Simplify.Rep.Wise Futhark.IR.MCMem.MCMem))
+ Futhark.IR.MCMem: instance Futhark.IR.Mem.OpReturns (Futhark.IR.MC.Op.MCOp Futhark.IR.Rep.NoOp Futhark.IR.MCMem.MCMem)
+ Futhark.IR.Mem: instance Futhark.Analysis.Metrics.OpMetrics (inner rep) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Futhark.Analysis.SymbolTable.IndexOp (inner rep) => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Futhark.IR.Aliases.CanBeAliased inner => Futhark.IR.Aliases.CanBeAliased (Futhark.IR.Mem.MemOp inner)
+ Futhark.IR.Mem: instance Futhark.IR.Mem.OpReturns (inner rep) => Futhark.IR.Mem.OpReturns (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Futhark.IR.Prop.Aliases.AliasedOp (inner rep) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Futhark.IR.Prop.IsOp (inner rep) => Futhark.IR.Prop.IsOp (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Futhark.IR.Prop.Names.FreeIn (inner rep) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Futhark.IR.Prop.TypeOf.TypedOp (inner rep) => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Futhark.IR.Rephrase.RephraseOp inner => Futhark.IR.Rephrase.RephraseOp (Futhark.IR.Mem.MemOp inner)
+ Futhark.IR.Mem: instance Futhark.Transform.Rename.Rename (inner rep) => Futhark.Transform.Rename.Rename (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Futhark.Transform.Substitute.Substitute (inner rep) => Futhark.Transform.Substitute.Substitute (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance GHC.Classes.Eq (inner rep) => GHC.Classes.Eq (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance GHC.Classes.Ord (inner rep) => GHC.Classes.Ord (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance GHC.Show.Show (inner rep) => GHC.Show.Show (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance Prettyprinter.Internal.Pretty (inner rep) => Prettyprinter.Internal.Pretty (Futhark.IR.Mem.MemOp inner rep)
+ Futhark.IR.Mem: instance forall k (rep :: k). Futhark.IR.Mem.OpReturns (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Pretty: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Body rep)
+ Futhark.IR.Pretty: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Case (Futhark.IR.Syntax.Body rep))
+ Futhark.IR.Pretty: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Exp rep)
+ Futhark.IR.Pretty: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.FunDef rep)
+ Futhark.IR.Pretty: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Lambda rep)
+ Futhark.IR.Pretty: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Prog rep)
+ Futhark.IR.Pretty: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Stm rep)
+ Futhark.IR.Pretty: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.Syntax.Stms rep)
+ Futhark.IR.Pretty: instance forall k (rep :: k). Prettyprinter.Internal.Pretty (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Prop: instance forall k (rep :: k). Futhark.IR.Prop.IsOp (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Prop.Aliases: instance forall k (rep :: k). Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Prop.Names: instance (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Body rep)
+ Futhark.IR.Prop.Names: instance (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Exp rep)
+ Futhark.IR.Prop.Names: instance (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.FunDef rep)
+ Futhark.IR.Prop.Names: instance (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Lambda rep)
+ Futhark.IR.Prop.Names: instance (Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.ExpDec rep), Futhark.IR.Prop.Names.FreeDec (Futhark.IR.Rep.BodyDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.FParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LetDec rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.RetType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.BranchType rep), Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.Op rep)) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Stm rep)
+ Futhark.IR.Prop.Names: instance Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.LParamInfo rep) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.LoopForm rep)
+ Futhark.IR.Prop.Names: instance Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Stm rep) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Syntax.Stms rep)
+ Futhark.IR.Prop.Names: instance forall k (rep :: k). Futhark.IR.Prop.Names.FreeIn (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Prop.Scope: instance (Futhark.IR.Prop.Scope.HasScope rep m, GHC.Base.Monad m) => Futhark.IR.Prop.Scope.HasScope rep (Futhark.IR.Prop.Scope.ExtendedScope rep m)
+ Futhark.IR.Prop.Scope: instance (GHC.Base.Monad m, Futhark.IR.Prop.Scope.HasScope rep m) => Futhark.IR.Prop.Scope.HasScope rep (Control.Monad.Trans.Except.ExceptT e m)
+ Futhark.IR.Prop.Scope: instance (GHC.Base.Monad m, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.HasScope rep (Control.Monad.Trans.Reader.ReaderT (Futhark.IR.Prop.Scope.Scope rep) m)
+ Futhark.IR.Prop.Scope: instance (GHC.Base.Monad m, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.LocalScope rep (Control.Monad.Trans.Reader.ReaderT (Futhark.IR.Prop.Scope.Scope rep) m)
+ Futhark.IR.Prop.Scope: instance (GHC.Base.Monad m, GHC.Base.Monoid w, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.HasScope rep (Control.Monad.Trans.RWS.Lazy.RWST (Futhark.IR.Prop.Scope.Scope rep) w s m)
+ Futhark.IR.Prop.Scope: instance (GHC.Base.Monad m, GHC.Base.Monoid w, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.HasScope rep (Control.Monad.Trans.RWS.Strict.RWST (Futhark.IR.Prop.Scope.Scope rep) w s m)
+ Futhark.IR.Prop.Scope: instance (GHC.Base.Monad m, GHC.Base.Monoid w, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.LocalScope rep (Control.Monad.Trans.RWS.Lazy.RWST (Futhark.IR.Prop.Scope.Scope rep) w s m)
+ Futhark.IR.Prop.Scope: instance (GHC.Base.Monad m, GHC.Base.Monoid w, Futhark.IR.Rep.RepTypes rep) => Futhark.IR.Prop.Scope.LocalScope rep (Control.Monad.Trans.RWS.Strict.RWST (Futhark.IR.Prop.Scope.Scope rep) w s m)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Prop.Scope.LocalScope rep m => Futhark.IR.Prop.Scope.LocalScope rep (Control.Monad.Trans.Except.ExceptT e m)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.FunDef rep)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.Lambda rep)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.LoopForm rep)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.Stm rep)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Prop.Scope.Scoped rep (Futhark.IR.Syntax.Stms rep)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Prop.Scope.Scoped rep (Language.Futhark.Core.VName, Futhark.IR.Prop.Scope.NameInfo rep)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Prop.Scope.Scoped rep a => Futhark.IR.Prop.Scope.Scoped rep [a]
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Rep.RepTypes rep => Futhark.IR.Prop.Types.Typed (Futhark.IR.Prop.Scope.NameInfo rep)
+ Futhark.IR.Prop.Scope: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Prop.Scope.NameInfo rep)
+ Futhark.IR.Prop.Scope: instance GHC.Base.Applicative m => GHC.Base.Applicative (Futhark.IR.Prop.Scope.ExtendedScope rep m)
+ Futhark.IR.Prop.Scope: instance GHC.Base.Functor m => GHC.Base.Functor (Futhark.IR.Prop.Scope.ExtendedScope rep m)
+ Futhark.IR.Prop.Scope: instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Futhark.IR.Prop.Scope.Scope rep) (Futhark.IR.Prop.Scope.ExtendedScope rep m)
+ Futhark.IR.Prop.Scope: instance GHC.Base.Monad m => GHC.Base.Monad (Futhark.IR.Prop.Scope.ExtendedScope rep m)
+ Futhark.IR.Prop.TypeOf: instance forall k (rep :: k). Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Rep: -- definition is to ensure that we can change the "inner" representation
+ Futhark.IR.Rep: -- in a generic way (e.g. add aliasing information) In most code, you
+ Futhark.IR.Rep: -- will use the <a>Op</a> alias instead.
+ Futhark.IR.Rep: NoOp :: NoOp rep
+ Futhark.IR.Rep: data NoOp rep
+ Futhark.IR.Rep: instance forall k (rep :: k). GHC.Classes.Eq (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Rep: instance forall k (rep :: k). GHC.Classes.Ord (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Rep: instance forall k (rep :: k). GHC.Show.Show (Futhark.IR.Rep.NoOp rep)
+ Futhark.IR.Rep: type OpC l = NoOp;
+ Futhark.IR.Rephrase: Rephraser :: (ExpDec from -> m (ExpDec to)) -> (LetDec from -> m (LetDec to)) -> (FParamInfo from -> m (FParamInfo to)) -> (LParamInfo from -> m (LParamInfo to)) -> (BodyDec from -> m (BodyDec to)) -> (RetType from -> m (RetType to)) -> (BranchType from -> m (BranchType to)) -> (Op from -> m (Op to)) -> Rephraser m from to
+ Futhark.IR.Rephrase: [rephraseBodyDec] :: Rephraser m from to -> BodyDec from -> m (BodyDec to)
+ Futhark.IR.Rephrase: [rephraseBranchType] :: Rephraser m from to -> BranchType from -> m (BranchType to)
+ Futhark.IR.Rephrase: [rephraseExpDec] :: Rephraser m from to -> ExpDec from -> m (ExpDec to)
+ Futhark.IR.Rephrase: [rephraseFParamDec] :: Rephraser m from to -> FParamInfo from -> m (FParamInfo to)
+ Futhark.IR.Rephrase: [rephraseLParamDec] :: Rephraser m from to -> LParamInfo from -> m (LParamInfo to)
+ Futhark.IR.Rephrase: [rephraseLetBoundDec] :: Rephraser m from to -> LetDec from -> m (LetDec to)
+ Futhark.IR.Rephrase: [rephraseOp] :: Rephraser m from to -> Op from -> m (Op to)
+ Futhark.IR.Rephrase: [rephraseRetType] :: Rephraser m from to -> RetType from -> m (RetType to)
+ Futhark.IR.Rephrase: class RephraseOp op
+ Futhark.IR.Rephrase: data Rephraser m from to
+ Futhark.IR.Rephrase: instance Futhark.IR.Rephrase.RephraseOp Futhark.IR.Rep.NoOp
+ Futhark.IR.Rephrase: rephraseBody :: Monad m => Rephraser m from to -> Body from -> m (Body to)
+ Futhark.IR.Rephrase: rephraseExp :: Monad m => Rephraser m from to -> Exp from -> m (Exp to)
+ Futhark.IR.Rephrase: rephraseFunDef :: Monad m => Rephraser m from to -> FunDef from -> m (FunDef to)
+ Futhark.IR.Rephrase: rephraseInOp :: (RephraseOp op, Monad m) => Rephraser m from to -> op from -> m (op to)
+ Futhark.IR.Rephrase: rephraseLambda :: Monad m => Rephraser m from to -> Lambda from -> m (Lambda to)
+ Futhark.IR.Rephrase: rephrasePat :: Monad m => (from -> m to) -> Pat from -> m (Pat to)
+ Futhark.IR.Rephrase: rephrasePatElem :: Monad m => (from -> m to) -> PatElem from -> m (PatElem to)
+ Futhark.IR.Rephrase: rephraseProg :: Monad m => Rephraser m from to -> Prog from -> m (Prog to)
+ Futhark.IR.Rephrase: rephraseStm :: Monad m => Rephraser m from to -> Stm from -> m (Stm to)
+ Futhark.IR.SOACS.SOAC: instance Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.Op rep) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Aliases.CanBeAliased Futhark.IR.SOACS.SOAC.SOAC
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SOACS.SOAC.Reduce rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SOACS.SOAC.Scan rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.IsOp (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.HistOp rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.Reduce rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.Scan rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.ScremaForm rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.Transform.Rename.Rename (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.Aliases.Aliased rep => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.HistOp rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.Reduce rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.Scan rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SOACS.SOAC.ScremaForm rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.HistOp rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.Reduce rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.Scan rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SOACS.SOAC.ScremaForm rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.HistOp rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.Reduce rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.SOAC rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.Scan rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SOACS.SOAC.ScremaForm rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Rephrase.RephraseOp Futhark.IR.SOACS.SOAC.SOAC
+ Futhark.IR.SOACS.SOAC: instance Futhark.Optimise.Simplify.Rep.CanBeWise Futhark.IR.SOACS.SOAC.SOAC
+ Futhark.IR.SegOp: instance (Futhark.IR.Pretty.PrettyRep rep, Prettyprinter.Internal.Pretty lvl) => Prettyprinter.Internal.Pretty (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance (Futhark.IR.Prop.ASTConstraints lvl, Futhark.IR.Prop.Aliases.Aliased rep) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.ASTConstraints lvl) => Futhark.IR.Prop.IsOp (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.ASTConstraints lvl) => Futhark.Transform.Rename.Rename (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance (Futhark.IR.Prop.ASTRep rep, Futhark.IR.Prop.Names.FreeIn lvl) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance (Futhark.IR.Prop.ASTRep rep, Futhark.Transform.Substitute.Substitute lvl) => Futhark.Transform.Substitute.Substitute (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Eq lvl) => GHC.Classes.Eq (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance (Futhark.IR.Rep.RepTypes rep, GHC.Classes.Ord lvl) => GHC.Classes.Ord (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance (Futhark.IR.Rep.RepTypes rep, GHC.Show.Show lvl) => GHC.Show.Show (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Rep.Op rep) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Aliases.CanBeAliased (Futhark.IR.SegOp.SegOp lvl)
+ Futhark.IR.SegOp: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SegOp.KernelBody rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Pretty.PrettyRep rep => Prettyprinter.Internal.Pretty (Futhark.IR.SegOp.SegBinOp rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Prop.ASTRep rep => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SegOp.KernelBody rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Prop.ASTRep rep => Futhark.Transform.Rename.Rename (Futhark.IR.SegOp.KernelBody rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Prop.ASTRep rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.SegOp.KernelBody rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SegOp.HistOp rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SegOp.KernelBody rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.SegOp.SegBinOp rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SegOp.HistOp rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SegOp.KernelBody rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.SegOp.SegBinOp rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SegOp.HistOp rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SegOp.KernelBody rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.SegOp.SegBinOp rep)
+ Futhark.IR.SegOp: instance Futhark.IR.Rephrase.RephraseOp (Futhark.IR.SegOp.SegOp lvl)
+ Futhark.IR.SegOp: instance Futhark.Optimise.Simplify.Rep.CanBeWise (Futhark.IR.SegOp.SegOp lvl)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Body rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Exp rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.FunDef rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Lambda rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.LoopForm rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Prog rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Eq (Futhark.IR.Syntax.Stm rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Body rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Exp rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.FunDef rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Lambda rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.LoopForm rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Prog rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Classes.Ord (Futhark.IR.Syntax.Stm rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Body rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Exp rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.FunDef rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Lambda rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.LoopForm rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Prog rep)
+ Futhark.IR.Syntax: instance Futhark.IR.Rep.RepTypes rep => GHC.Show.Show (Futhark.IR.Syntax.Stm rep)
+ Futhark.IR.TypeCheck: instance Control.Monad.Reader.Class.MonadReader (Futhark.IR.TypeCheck.Env rep) (Futhark.IR.TypeCheck.TypeM rep)
+ Futhark.IR.TypeCheck: instance Control.Monad.State.Class.MonadState Futhark.IR.TypeCheck.TState (Futhark.IR.TypeCheck.TypeM rep)
+ Futhark.IR.TypeCheck: instance Futhark.IR.TypeCheck.Checkable rep => Futhark.IR.Prop.Scope.HasScope (Futhark.IR.Aliases.Aliases rep) (Futhark.IR.TypeCheck.TypeM rep)
+ Futhark.IR.TypeCheck: instance Futhark.IR.TypeCheck.Checkable rep => GHC.Show.Show (Futhark.IR.TypeCheck.ErrorCase rep)
+ Futhark.IR.TypeCheck: instance Futhark.IR.TypeCheck.Checkable rep => GHC.Show.Show (Futhark.IR.TypeCheck.TypeError rep)
+ Futhark.IR.TypeCheck: instance GHC.Base.Applicative (Futhark.IR.TypeCheck.TypeM rep)
+ Futhark.IR.TypeCheck: instance GHC.Base.Functor (Futhark.IR.TypeCheck.TypeM rep)
+ Futhark.IR.TypeCheck: instance GHC.Base.Monad (Futhark.IR.TypeCheck.TypeM rep)
+ Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitReader rep) (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
+ Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance Control.Monad.State.Class.MonadState Futhark.FreshNames.VNameSource (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
+ Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
+ Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance GHC.Base.Applicative (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
+ Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance GHC.Base.Functor (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
+ Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing: instance GHC.Base.Monad (Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing.ShortCircuitM rep)
+ Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: instance Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper (Futhark.IR.GPU.Op.HostOp Futhark.IR.Rep.NoOp (Futhark.IR.Aliases.Aliases Futhark.IR.GPUMem.GPUMem))
+ Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: instance Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: instance Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper (inner (Futhark.IR.Aliases.Aliases Futhark.IR.MCMem.MCMem)) => Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper (Futhark.IR.MC.Op.MCOp inner (Futhark.IR.Aliases.Aliases Futhark.IR.MCMem.MCMem))
+ Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: instance forall k (rep :: k). Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis.TopDownHelper (Futhark.IR.Rep.NoOp rep)
+ Futhark.Optimise.CSE: instance (Futhark.IR.Aliases.AliasableRep rep, Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Rep.Op (Futhark.IR.Aliases.Aliases rep))) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.SOACS.SOAC.SOAC (Futhark.IR.Aliases.Aliases rep))
+ Futhark.Optimise.CSE: instance (Futhark.IR.Prop.Aliases.Aliased rep, Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Rep.Op rep)) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.Optimise.CSE: instance (Futhark.IR.Prop.Aliases.Aliased rep, Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Rep.Op rep), Futhark.Optimise.CSE.CSEInOp (op rep)) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.GPU.Op.HostOp op rep)
+ Futhark.Optimise.CSE: instance (Futhark.IR.Prop.Aliases.Aliased rep, Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Rep.Op rep), Futhark.Optimise.CSE.CSEInOp (op rep)) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.MC.Op.MCOp op rep)
+ Futhark.Optimise.CSE: instance Futhark.Optimise.CSE.CSEInOp (op rep) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Mem.MemOp op rep)
+ Futhark.Optimise.CSE: instance forall k (rep :: k). Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Rep.NoOp rep)
+ Futhark.Optimise.DoubleBuffer: instance Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.DoubleBuffer.Env rep) (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
+ Futhark.Optimise.DoubleBuffer: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Scope.HasScope rep (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
+ Futhark.Optimise.DoubleBuffer: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Scope.LocalScope rep (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
+ Futhark.Optimise.DoubleBuffer: instance Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
+ Futhark.Optimise.DoubleBuffer: instance GHC.Base.Applicative (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
+ Futhark.Optimise.DoubleBuffer: instance GHC.Base.Functor (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
+ Futhark.Optimise.DoubleBuffer: instance GHC.Base.Monad (Futhark.Optimise.DoubleBuffer.DoubleBufferM rep)
+ Futhark.Optimise.Fusion.GraphRep: TransNode :: VName -> ArrayTransform -> VName -> NodeT
+ Futhark.Optimise.InPlaceLowering: instance Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.InPlaceLowering.TopDown rep) (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
+ Futhark.Optimise.InPlaceLowering: instance Control.Monad.State.Class.MonadState Futhark.FreshNames.VNameSource (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
+ Futhark.Optimise.InPlaceLowering: instance Control.Monad.Writer.Class.MonadWriter (Futhark.Optimise.InPlaceLowering.BottomUp rep) (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
+ Futhark.Optimise.InPlaceLowering: instance Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
+ Futhark.Optimise.InPlaceLowering: instance Futhark.Optimise.InPlaceLowering.Constraints rep => Futhark.IR.Prop.Scope.HasScope (Futhark.IR.Aliases.Aliases rep) (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
+ Futhark.Optimise.InPlaceLowering: instance GHC.Base.Applicative (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
+ Futhark.Optimise.InPlaceLowering: instance GHC.Base.Functor (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
+ Futhark.Optimise.InPlaceLowering: instance GHC.Base.Monad (Futhark.Optimise.InPlaceLowering.ForwardingM rep)
+ Futhark.Optimise.InPlaceLowering: instance GHC.Base.Monoid (Futhark.Optimise.InPlaceLowering.BottomUp rep)
+ Futhark.Optimise.InPlaceLowering: instance GHC.Base.Semigroup (Futhark.Optimise.InPlaceLowering.BottomUp rep)
+ Futhark.Optimise.Simplify.Engine: instance Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.Simplify.Engine.SimpleOps rep, Futhark.Optimise.Simplify.Engine.Env rep) (Futhark.Optimise.Simplify.Engine.SimpleM rep)
+ Futhark.Optimise.Simplify.Engine: instance Control.Monad.State.Class.MonadState (Futhark.FreshNames.VNameSource, GHC.Types.Bool, Futhark.IR.Syntax.Core.Certs) (Futhark.Optimise.Simplify.Engine.SimpleM rep)
+ Futhark.Optimise.Simplify.Engine: instance Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.Simplify.Engine.SimpleM rep)
+ Futhark.Optimise.Simplify.Engine: instance Futhark.Optimise.Simplify.Engine.SimplifiableRep rep => Futhark.IR.Prop.Scope.HasScope (Futhark.Optimise.Simplify.Rep.Wise rep) (Futhark.Optimise.Simplify.Engine.SimpleM rep)
+ Futhark.Optimise.Simplify.Engine: instance Futhark.Optimise.Simplify.Engine.SimplifiableRep rep => Futhark.IR.Prop.Scope.LocalScope (Futhark.Optimise.Simplify.Rep.Wise rep) (Futhark.Optimise.Simplify.Engine.SimpleM rep)
+ Futhark.Optimise.Simplify.Engine: instance GHC.Base.Applicative (Futhark.Optimise.Simplify.Engine.SimpleM rep)
+ Futhark.Optimise.Simplify.Engine: instance GHC.Base.Functor (Futhark.Optimise.Simplify.Engine.SimpleM rep)
+ Futhark.Optimise.Simplify.Engine: instance GHC.Base.Monad (Futhark.Optimise.Simplify.Engine.SimpleM rep)
+ Futhark.Optimise.Simplify.Rep: instance (Futhark.Builder.Class.Buildable rep, Futhark.Optimise.Simplify.Rep.Informing rep) => Futhark.Builder.Class.Buildable (Futhark.Optimise.Simplify.Rep.Wise rep)
+ Futhark.Optimise.Simplify.Rep: instance Futhark.Optimise.Simplify.Rep.CanBeWise Futhark.IR.Rep.NoOp
+ Futhark.Optimise.Simplify.Rep: instance Futhark.Optimise.Simplify.Rep.Informing rep => Futhark.IR.Pretty.PrettyRep (Futhark.Optimise.Simplify.Rep.Wise rep)
+ Futhark.Optimise.Simplify.Rep: instance Futhark.Optimise.Simplify.Rep.Informing rep => Futhark.IR.Prop.ASTRep (Futhark.Optimise.Simplify.Rep.Wise rep)
+ Futhark.Optimise.Simplify.Rep: instance Futhark.Optimise.Simplify.Rep.Informing rep => Futhark.IR.Prop.Aliases.Aliased (Futhark.Optimise.Simplify.Rep.Wise rep)
+ Futhark.Optimise.Simplify.Rep: instance Futhark.Optimise.Simplify.Rep.Informing rep => Futhark.IR.Rep.RepTypes (Futhark.Optimise.Simplify.Rep.Wise rep)
+ Futhark.Optimise.Simplify.Rule: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Scope.HasScope rep (Futhark.Optimise.Simplify.Rule.RuleM rep)
+ Futhark.Optimise.Simplify.Rule: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Scope.LocalScope rep (Futhark.Optimise.Simplify.Rule.RuleM rep)
+ Futhark.Optimise.Simplify.Rule: instance Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.Simplify.Rule.RuleM rep)
+ Futhark.Optimise.Simplify.Rule: instance GHC.Base.Applicative (Futhark.Optimise.Simplify.Rule.RuleM rep)
+ Futhark.Optimise.Simplify.Rule: instance GHC.Base.Functor (Futhark.Optimise.Simplify.Rule.RuleM rep)
+ Futhark.Optimise.Simplify.Rule: instance GHC.Base.Monad (Futhark.Optimise.Simplify.Rule.RuleM rep)
+ Futhark.Optimise.Simplify.Rule: instance GHC.Base.Monoid (Futhark.Optimise.Simplify.Rule.RuleBook rep)
+ Futhark.Optimise.Simplify.Rule: instance GHC.Base.Monoid (Futhark.Optimise.Simplify.Rule.Rules rep a)
+ Futhark.Optimise.Simplify.Rule: instance GHC.Base.Semigroup (Futhark.Optimise.Simplify.Rule.RuleBook rep)
+ Futhark.Optimise.Simplify.Rule: instance GHC.Base.Semigroup (Futhark.Optimise.Simplify.Rule.Rules rep a)
+ Futhark.Pass.ExplicitAllocations: askDefaultSpace :: AllocM fromrep torep Space
+ Futhark.Pass.ExplicitAllocations: instance Control.Monad.Reader.Class.MonadReader (Futhark.Pass.ExplicitAllocations.AllocEnv fromrep torep) (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
+ Futhark.Pass.ExplicitAllocations: instance Futhark.IR.Prop.ASTRep torep => Futhark.IR.Prop.Scope.HasScope torep (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
+ Futhark.Pass.ExplicitAllocations: instance Futhark.IR.Prop.ASTRep torep => Futhark.IR.Prop.Scope.LocalScope torep (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
+ Futhark.Pass.ExplicitAllocations: instance Futhark.MonadFreshNames.MonadFreshNames (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
+ Futhark.Pass.ExplicitAllocations: instance Futhark.Pass.ExplicitAllocations.Allocable fromrep torep inner => Futhark.Builder.Class.MonadBuilder (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
+ Futhark.Pass.ExplicitAllocations: instance Futhark.Pass.ExplicitAllocations.SizeSubst (op rep) => Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.Mem.MemOp op rep)
+ Futhark.Pass.ExplicitAllocations: instance GHC.Base.Applicative (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
+ Futhark.Pass.ExplicitAllocations: instance GHC.Base.Functor (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
+ Futhark.Pass.ExplicitAllocations: instance GHC.Base.Monad (Futhark.Pass.ExplicitAllocations.AllocM fromrep torep)
+ Futhark.Pass.ExplicitAllocations: instance forall k (rep :: k). Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.Rep.NoOp rep)
+ Futhark.Pass.ExplicitAllocations.GPU: instance Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.GPU.Op.HostOp rep op)
+ Futhark.Pass.ExplicitAllocations.MC: instance Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.MC.Op.MCOp rep op)
+ Futhark.Pass.ExplicitAllocations.SegOp: instance Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.SegOp.SegOp lvl rep)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance (GHC.Base.Monad m, Futhark.IR.Prop.ASTRep rep) => Futhark.IR.Prop.Scope.HasScope rep (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance (GHC.Base.Monad m, Futhark.IR.Prop.ASTRep rep) => Futhark.IR.Prop.Scope.LocalScope rep (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance Futhark.MonadFreshNames.MonadFreshNames m => Futhark.MonadFreshNames.MonadFreshNames (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Applicative m => GHC.Base.Applicative (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Functor m => GHC.Base.Functor (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Futhark.Pass.ExtractKernels.DistributeNests.DistEnv rep m) (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Monad m => Control.Monad.Writer.Class.MonadWriter (Futhark.Pass.ExtractKernels.DistributeNests.DistRes rep) (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Monad m => Futhark.Util.Log.MonadLogger (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Monad m => GHC.Base.Monad (Futhark.Pass.ExtractKernels.DistributeNests.DistNestT rep m)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Monoid (Futhark.Pass.ExtractKernels.DistributeNests.DistRes rep)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Monoid (Futhark.Pass.ExtractKernels.DistributeNests.PostStms rep)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Semigroup (Futhark.Pass.ExtractKernels.DistributeNests.DistRes rep)
+ Futhark.Pass.ExtractKernels.DistributeNests: instance GHC.Base.Semigroup (Futhark.Pass.ExtractKernels.DistributeNests.PostStms rep)
+ Futhark.Pkg.Info: CacheDir :: FilePath -> CacheDir
+ Futhark.Pkg.Info: [pkgGetFiles] :: PkgRevInfo m -> GetFiles m
+ Futhark.Pkg.Info: data GetFiles m
+ Futhark.Pkg.Info: instance GHC.Classes.Eq (Futhark.Pkg.Info.GetFiles m)
+ Futhark.Pkg.Info: instance GHC.Show.Show (Futhark.Pkg.Info.GetFiles m)
+ Futhark.Pkg.Info: newtype CacheDir
+ Futhark.Script: scriptBuiltin :: (MonadIO m, MonadError Text m) => FilePath -> EvalBuiltin m
+ Futhark.Transform.Rename: instance Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.Body rep)
+ Futhark.Transform.Rename: instance Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.Exp rep)
+ Futhark.Transform.Rename: instance Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.FunDef rep)
+ Futhark.Transform.Rename: instance Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.Lambda rep)
+ Futhark.Transform.Rename: instance Futhark.Transform.Rename.Renameable rep => Futhark.Transform.Rename.Rename (Futhark.IR.Syntax.Stm rep)
+ Futhark.Transform.Rename: instance forall k (rep :: k). Futhark.Transform.Rename.Rename (Futhark.IR.Rep.NoOp rep)
+ Futhark.Transform.Substitute: instance Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Prop.Scope.NameInfo rep)
+ Futhark.Transform.Substitute: instance Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Body rep)
+ Futhark.Transform.Substitute: instance Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Exp rep)
+ Futhark.Transform.Substitute: instance Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Lambda rep)
+ Futhark.Transform.Substitute: instance Futhark.Transform.Substitute.Substitutable rep => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Stm rep)
+ Futhark.Transform.Substitute: instance Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Stm rep) => Futhark.Transform.Substitute.Substitute (Futhark.IR.Syntax.Stms rep)
+ Futhark.Transform.Substitute: instance forall k (rep :: k). Futhark.Transform.Substitute.Substitute (Futhark.IR.Rep.NoOp rep)
+ Futhark.Util.Log: instance Futhark.Util.Log.MonadLogger GHC.Types.IO
+ Language.Futhark.Pretty: instance Prettyprinter.Internal.Pretty (Language.Futhark.Syntax.TypeArg Language.Futhark.Syntax.Size)
+ Language.Futhark.Semantic: [fileScope] :: FileModule -> Env
+ Language.Futhark.Syntax: Bang :: BinOp
+ Language.Futhark.Syntax: Equ :: BinOp
- Futhark.Actions: printAliasesAction :: (ASTRep rep, CanBeAliased (Op rep)) => Action rep
+ Futhark.Actions: printAliasesAction :: AliasableRep rep => Action rep
- Futhark.Analysis.Alias: aliasAnalysis :: (ASTRep rep, CanBeAliased (Op rep)) => Prog rep -> Prog (Aliases rep)
+ Futhark.Analysis.Alias: aliasAnalysis :: AliasableRep rep => Prog rep -> Prog (Aliases rep)
- Futhark.Analysis.Alias: analyseBody :: (ASTRep rep, CanBeAliased (Op rep)) => AliasTable -> Body rep -> Body (Aliases rep)
+ Futhark.Analysis.Alias: analyseBody :: AliasableRep rep => AliasTable -> Body rep -> Body (Aliases rep)
- Futhark.Analysis.Alias: analyseExp :: (ASTRep rep, CanBeAliased (Op rep)) => AliasTable -> Exp rep -> Exp (Aliases rep)
+ Futhark.Analysis.Alias: analyseExp :: AliasableRep rep => AliasTable -> Exp rep -> Exp (Aliases rep)
- Futhark.Analysis.Alias: analyseFun :: (ASTRep rep, CanBeAliased (Op rep)) => FunDef rep -> FunDef (Aliases rep)
+ Futhark.Analysis.Alias: analyseFun :: AliasableRep rep => FunDef rep -> FunDef (Aliases rep)
- Futhark.Analysis.Alias: analyseLambda :: (ASTRep rep, CanBeAliased (Op rep)) => AliasTable -> Lambda rep -> Lambda (Aliases rep)
+ Futhark.Analysis.Alias: analyseLambda :: AliasableRep rep => AliasTable -> Lambda rep -> Lambda (Aliases rep)
- Futhark.Analysis.Alias: analyseStms :: (ASTRep rep, CanBeAliased (Op rep)) => AliasTable -> Stms rep -> (Stms (Aliases rep), AliasesAndConsumed)
+ Futhark.Analysis.Alias: analyseStms :: AliasableRep rep => AliasTable -> Stms rep -> (Stms (Aliases rep), AliasesAndConsumed)
- Futhark.Analysis.SymbolTable: insertStm :: (ASTRep rep, IndexOp (Op rep), Aliased rep) => Stm rep -> SymbolTable rep -> SymbolTable rep
+ Futhark.Analysis.SymbolTable: insertStm :: (IndexOp (Op rep), Aliased rep) => Stm rep -> SymbolTable rep -> SymbolTable rep
- Futhark.Analysis.SymbolTable: insertStms :: (ASTRep rep, IndexOp (Op rep), Aliased rep) => Stms rep -> SymbolTable rep -> SymbolTable rep
+ Futhark.Analysis.SymbolTable: insertStms :: (IndexOp (Op rep), Aliased rep) => Stms rep -> SymbolTable rep -> SymbolTable rep
- Futhark.Analysis.UsageTable: usageInStm :: (ASTRep rep, Aliased rep) => Stm rep -> UsageTable
+ Futhark.Analysis.UsageTable: usageInStm :: Aliased rep => Stm rep -> UsageTable
- Futhark.Bench: DataResult :: String -> Either Text Result -> DataResult
+ Futhark.Bench: DataResult :: Text -> Either Text Result -> DataResult
- Futhark.CodeGen.Backends.GenericC.Monad: CompilerState :: Map ArrayType Publicness -> DList Definition -> [Stm] -> VNameSource -> s -> Map HeaderSection (DList Definition) -> DList Definition -> DList (Id, Type, Maybe Exp, Maybe Stm) -> DList BlockItem -> DList BlockItem -> [(VName, Space)] -> DList BlockItem -> CompilerState s
+ Futhark.CodeGen.Backends.GenericC.Monad: CompilerState :: Map ArrayType Publicness -> DList Definition -> VNameSource -> s -> Map HeaderSection (DList Definition) -> DList Definition -> DList (Id, Type, Maybe Exp, Maybe (Stm, Stm)) -> DList BlockItem -> DList BlockItem -> [(VName, Space)] -> DList BlockItem -> CompilerState s
- Futhark.CodeGen.Backends.GenericC.Monad: Operations :: WriteScalar op s -> ReadScalar op s -> Allocate op s -> Deallocate op s -> Copy op s -> StaticArray op s -> MemoryType op s -> OpCompiler op s -> ErrorCompiler op s -> CallCompiler op s -> Bool -> ([BlockItem], [BlockItem]) -> Operations op s
+ Futhark.CodeGen.Backends.GenericC.Monad: Operations :: WriteScalar op s -> ReadScalar op s -> Allocate op s -> Deallocate op s -> Copy op s -> MemoryType op s -> OpCompiler op s -> ErrorCompiler op s -> CallCompiler op s -> Bool -> ([BlockItem], [BlockItem]) -> Operations op s
- Futhark.CodeGen.Backends.GenericC.Monad: [compCtxFields] :: CompilerState s -> DList (Id, Type, Maybe Exp, Maybe Stm)
+ Futhark.CodeGen.Backends.GenericC.Monad: [compCtxFields] :: CompilerState s -> DList (Id, Type, Maybe Exp, Maybe (Stm, Stm))
- Futhark.CodeGen.Backends.GenericC.Monad: contextFieldDyn :: Id -> Type -> Maybe Exp -> Stm -> CompilerM op s ()
+ Futhark.CodeGen.Backends.GenericC.Monad: contextFieldDyn :: Id -> Type -> Stm -> Stm -> CompilerM op s ()
- Futhark.CodeGen.Backends.GenericC.Monad: readScalarPointerWithQuals :: PointerQuals op s -> ReadScalar op s
+ Futhark.CodeGen.Backends.GenericC.Monad: readScalarPointerWithQuals :: PointerQuals -> ReadScalar op s
- Futhark.CodeGen.Backends.GenericC.Monad: type PointerQuals op s = String -> CompilerM op s [TypeQual]
+ Futhark.CodeGen.Backends.GenericC.Monad: type PointerQuals = String -> [TypeQual]
- Futhark.CodeGen.Backends.GenericC.Monad: writeScalarPointerWithQuals :: PointerQuals op s -> WriteScalar op s
+ Futhark.CodeGen.Backends.GenericC.Monad: writeScalarPointerWithQuals :: PointerQuals -> WriteScalar op s
- Futhark.CodeGen.Backends.GenericPython: CompilerEnv :: Operations op s -> Map VName PyExp -> CompilerEnv op s
+ Futhark.CodeGen.Backends.GenericPython: CompilerEnv :: Operations op s -> Map String PyExp -> CompilerEnv op s
- Futhark.CodeGen.Backends.GenericPython: Operations :: WriteScalar op s -> ReadScalar op s -> Allocate op s -> Copy op s -> StaticArray op s -> OpCompiler op s -> EntryOutput op s -> EntryInput op s -> Operations op s
+ Futhark.CodeGen.Backends.GenericPython: Operations :: WriteScalar op s -> ReadScalar op s -> Allocate op s -> Copy op s -> OpCompiler op s -> EntryOutput op s -> EntryInput op s -> Operations op s
- Futhark.CodeGen.Backends.GenericPython: [envVarExp] :: CompilerEnv op s -> Map VName PyExp
+ Futhark.CodeGen.Backends.GenericPython: [envVarExp] :: CompilerEnv op s -> Map String PyExp
- Futhark.CodeGen.ImpCode: DeclareArray :: VName -> Space -> PrimType -> ArrayContents -> Code a
+ Futhark.CodeGen.ImpCode: DeclareArray :: VName -> PrimType -> ArrayContents -> Code a
- Futhark.CodeGen.ImpGen: sStaticArray :: String -> Space -> PrimType -> ArrayContents -> ImpM rep r op VName
+ Futhark.CodeGen.ImpGen: sStaticArray :: String -> PrimType -> ArrayContents -> ImpM rep r op VName
- Futhark.Compiler.Program: FileModule :: TySet -> Env -> Prog -> FileModule
+ Futhark.Compiler.Program: FileModule :: TySet -> Env -> Prog -> Env -> FileModule
- Futhark.IR.Aliases: data Aliases rep
+ Futhark.IR.Aliases: data Aliases (rep :: Type)
- Futhark.IR.Aliases: mkAliasedBody :: (ASTRep rep, CanBeAliased (Op rep)) => BodyDec rep -> Stms (Aliases rep) -> Result -> Body (Aliases rep)
+ Futhark.IR.Aliases: mkAliasedBody :: (ASTRep rep, AliasedOp (OpC rep (Aliases rep))) => BodyDec rep -> Stms (Aliases rep) -> Result -> Body (Aliases rep)
- Futhark.IR.Aliases: removeBodyAliases :: CanBeAliased (Op rep) => Body (Aliases rep) -> Body rep
+ Futhark.IR.Aliases: removeBodyAliases :: RephraseOp (OpC rep) => Body (Aliases rep) -> Body rep
- Futhark.IR.Aliases: removeExpAliases :: CanBeAliased (Op rep) => Exp (Aliases rep) -> Exp rep
+ Futhark.IR.Aliases: removeExpAliases :: RephraseOp (OpC rep) => Exp (Aliases rep) -> Exp rep
- Futhark.IR.Aliases: removeFunDefAliases :: CanBeAliased (Op rep) => FunDef (Aliases rep) -> FunDef rep
+ Futhark.IR.Aliases: removeFunDefAliases :: RephraseOp (OpC rep) => FunDef (Aliases rep) -> FunDef rep
- Futhark.IR.Aliases: removeLambdaAliases :: CanBeAliased (Op rep) => Lambda (Aliases rep) -> Lambda rep
+ Futhark.IR.Aliases: removeLambdaAliases :: RephraseOp (OpC rep) => Lambda (Aliases rep) -> Lambda rep
- Futhark.IR.Aliases: removeProgAliases :: CanBeAliased (Op rep) => Prog (Aliases rep) -> Prog rep
+ Futhark.IR.Aliases: removeProgAliases :: RephraseOp (OpC rep) => Prog (Aliases rep) -> Prog rep
- Futhark.IR.Aliases: removeStmAliases :: CanBeAliased (Op rep) => Stm (Aliases rep) -> Stm rep
+ Futhark.IR.Aliases: removeStmAliases :: RephraseOp (OpC rep) => Stm (Aliases rep) -> Stm rep
- Futhark.IR.GPU.Op: GPUBody :: [Type] -> Body rep -> HostOp rep op
+ Futhark.IR.GPU.Op: GPUBody :: [Type] -> Body rep -> HostOp op rep
- Futhark.IR.GPU.Op: OtherOp :: op -> HostOp rep op
+ Futhark.IR.GPU.Op: OtherOp :: op rep -> HostOp op rep
- Futhark.IR.GPU.Op: SegOp :: SegOp SegLevel rep -> HostOp rep op
+ Futhark.IR.GPU.Op: SegOp :: SegOp SegLevel rep -> HostOp op rep
- Futhark.IR.GPU.Op: SizeOp :: SizeOp -> HostOp rep op
+ Futhark.IR.GPU.Op: SizeOp :: SizeOp -> HostOp op rep
- Futhark.IR.GPU.Op: data HostOp rep op
+ Futhark.IR.GPU.Op: data HostOp op rep
- Futhark.IR.GPU.Op: traverseHostOpStms :: Monad m => OpStmsTraverser m op rep -> OpStmsTraverser m (HostOp rep op) rep
+ Futhark.IR.GPU.Op: traverseHostOpStms :: Monad m => OpStmsTraverser m (op rep) rep -> OpStmsTraverser m (HostOp op rep) rep
- Futhark.IR.GPU.Op: typeCheckHostOp :: Checkable rep => (SegLevel -> OpWithAliases (Op rep) -> TypeM rep ()) -> Maybe SegLevel -> (op -> TypeM rep ()) -> HostOp (Aliases rep) op -> TypeM rep ()
+ Futhark.IR.GPU.Op: typeCheckHostOp :: Checkable rep => (SegLevel -> Op (Aliases rep) -> TypeM rep ()) -> Maybe SegLevel -> (op (Aliases rep) -> TypeM rep ()) -> HostOp op (Aliases rep) -> TypeM rep ()
- Futhark.IR.GPU.Simplify: simplifyKernelOp :: (SimplifiableRep rep, BodyDec rep ~ ()) => SimplifyOp rep op -> HostOp (Wise rep) op -> SimpleM rep (HostOp (Wise rep) op, Stms (Wise rep))
+ Futhark.IR.GPU.Simplify: simplifyKernelOp :: (SimplifiableRep rep, BodyDec rep ~ ()) => SimplifyOp rep (op (Wise rep)) -> HostOp op (Wise rep) -> SimpleM rep (HostOp op (Wise rep), Stms (Wise rep))
- Futhark.IR.MC.Op: OtherOp :: op -> MCOp rep op
+ Futhark.IR.MC.Op: OtherOp :: op rep -> MCOp op rep
- Futhark.IR.MC.Op: ParOp :: Maybe (SegOp () rep) -> SegOp () rep -> MCOp rep op
+ Futhark.IR.MC.Op: ParOp :: Maybe (SegOp () rep) -> SegOp () rep -> MCOp op rep
- Futhark.IR.MC.Op: data MCOp rep op
+ Futhark.IR.MC.Op: data MCOp op rep
- Futhark.IR.MC.Op: simplifyMCOp :: (SimplifiableRep rep, BodyDec rep ~ ()) => SimplifyOp rep op -> MCOp (Wise rep) op -> SimpleM rep (MCOp (Wise rep) op, Stms (Wise rep))
+ Futhark.IR.MC.Op: simplifyMCOp :: (SimplifiableRep rep, BodyDec rep ~ ()) => SimplifyOp rep (op (Wise rep)) -> MCOp op (Wise rep) -> SimpleM rep (MCOp op (Wise rep), Stms (Wise rep))
- Futhark.IR.MC.Op: traverseMCOpStms :: Monad m => OpStmsTraverser m op rep -> OpStmsTraverser m (MCOp rep op) rep
+ Futhark.IR.MC.Op: traverseMCOpStms :: Monad m => OpStmsTraverser m (op rep) rep -> OpStmsTraverser m (MCOp op rep) rep
- Futhark.IR.MC.Op: typeCheckMCOp :: Checkable rep => (op -> TypeM rep ()) -> MCOp (Aliases rep) op -> TypeM rep ()
+ Futhark.IR.MC.Op: typeCheckMCOp :: Checkable rep => (op (Aliases rep) -> TypeM rep ()) -> MCOp op (Aliases rep) -> TypeM rep ()
- Futhark.IR.Mem: Alloc :: SubExp -> Space -> MemOp inner
+ Futhark.IR.Mem: Alloc :: SubExp -> Space -> MemOp (inner :: Type -> Type) (rep :: Type)
- Futhark.IR.Mem: Inner :: inner -> MemOp inner
+ Futhark.IR.Mem: Inner :: inner rep -> MemOp (inner :: Type -> Type) (rep :: Type)
- Futhark.IR.Mem: data MemOp inner
+ Futhark.IR.Mem: data MemOp (inner :: Type -> Type) (rep :: Type)
- Futhark.IR.Mem: traverseMemOpStms :: Monad m => OpStmsTraverser m inner rep -> OpStmsTraverser m (MemOp inner) rep
+ Futhark.IR.Mem: traverseMemOpStms :: Monad m => OpStmsTraverser m (inner rep) rep -> OpStmsTraverser m (MemOp inner rep) rep
- Futhark.IR.Mem: type Mem rep inner = (FParamInfo rep ~ FParamMem, LParamInfo rep ~ LParamMem, HasLetDecMem (LetDec rep), RetType rep ~ RetTypeMem, BranchType rep ~ BranchTypeMem, ASTRep rep, OpReturns inner, Op rep ~ MemOp inner)
+ Futhark.IR.Mem: type Mem rep inner = (FParamInfo rep ~ FParamMem, LParamInfo rep ~ LParamMem, HasLetDecMem (LetDec rep), RetType rep ~ RetTypeMem, BranchType rep ~ BranchTypeMem, ASTRep rep, OpReturns (inner rep), RephraseOp inner, Op rep ~ MemOp inner rep)
- Futhark.IR.Mem.Simplify: simpleGeneric :: SimplifyMemory rep inner => (OpWithWisdom inner -> UsageTable) -> SimplifyOp rep (OpWithWisdom inner) -> SimpleOps rep
+ Futhark.IR.Mem.Simplify: simpleGeneric :: SimplifyMemory rep inner => (inner (Wise rep) -> UsageTable) -> SimplifyOp rep (inner (Wise rep)) -> SimpleOps rep
- Futhark.IR.Mem.Simplify: type SimplifyMemory rep inner = (SimplifiableRep rep, LetDec rep ~ LetDecMem, ExpDec rep ~ (), BodyDec rep ~ (), CanBeWise (Op rep), BuilderOps (Wise rep), OpReturns (OpWithWisdom inner), IndexOp (OpWithWisdom inner), AliasedOp (OpWithWisdom inner), Mem rep inner)
+ Futhark.IR.Mem.Simplify: type SimplifyMemory rep inner = (SimplifiableRep rep, LetDec rep ~ LetDecMem, ExpDec rep ~ (), BodyDec rep ~ (), CanBeWise (OpC rep), BuilderOps (Wise rep), OpReturns (inner (Wise rep)), IndexOp (inner (Wise rep)), AliasedOp (inner (Wise rep)), Mem rep inner, CanBeWise inner, RephraseOp inner)
- Futhark.IR.Prop: class (RepTypes rep, PrettyRep rep, Renameable rep, Substitutable rep, FreeDec (ExpDec rep), FreeIn (LetDec rep), FreeDec (BodyDec rep), FreeIn (FParamInfo rep), FreeIn (LParamInfo rep), FreeIn (RetType rep), FreeIn (BranchType rep), IsOp (Op rep)) => ASTRep rep
+ Futhark.IR.Prop: class (RepTypes rep, PrettyRep rep, Renameable rep, Substitutable rep, FreeDec (ExpDec rep), FreeIn (LetDec rep), FreeDec (BodyDec rep), FreeIn (FParamInfo rep), FreeIn (LParamInfo rep), FreeIn (RetType rep), FreeIn (BranchType rep), IsOp (Op rep), RephraseOp (OpC rep)) => ASTRep rep
- Futhark.IR.Prop.Aliases: class (RepTypes rep, AliasedOp (Op rep), AliasesOf (LetDec rep)) => Aliased rep
+ Futhark.IR.Prop.Aliases: class (ASTRep rep, AliasedOp (Op rep), AliasesOf (LetDec rep)) => Aliased rep
- Futhark.IR.Prop.Aliases: expAliases :: Aliased rep => Exp rep -> [Names]
+ Futhark.IR.Prop.Aliases: expAliases :: Aliased rep => [PatElem dec] -> Exp rep -> [Names]
- Futhark.IR.Rep: -- | Extensible operation.
+ Futhark.IR.Rep: -- | Type constructor for the extensible operation. The somewhat funky
- Futhark.IR.Rep: type Op l = ();
+ Futhark.IR.Rep: type Op l = OpC l l
- Futhark.IR.SegOp: aliasAnalyseKernelBody :: (ASTRep rep, CanBeAliased (Op rep)) => AliasTable -> KernelBody rep -> KernelBody (Aliases rep)
+ Futhark.IR.SegOp: aliasAnalyseKernelBody :: AliasableRep rep => AliasTable -> KernelBody rep -> KernelBody (Aliases rep)
- Futhark.IR.TypeCheck: checkOp :: CheckableOp rep => OpWithAliases (Op rep) -> TypeM rep ()
+ Futhark.IR.TypeCheck: checkOp :: Checkable rep => Op (Aliases rep) -> TypeM rep ()
- Futhark.IR.TypeCheck: checkOpWith :: (OpWithAliases (Op rep) -> TypeM rep ()) -> TypeM rep a -> TypeM rep a
+ Futhark.IR.TypeCheck: checkOpWith :: (Op (Aliases rep) -> TypeM rep ()) -> TypeM rep a -> TypeM rep a
- Futhark.IR.TypeCheck: class (ASTRep rep, CanBeAliased (Op rep), CheckableOp rep) => Checkable rep
+ Futhark.IR.TypeCheck: class (AliasableRep rep, TypedOp (OpC rep (Aliases rep))) => Checkable rep
- Futhark.Optimise.ArrayShortCircuiting.DataStructs: vnameToPrimExp :: (CanBeAliased (Op rep), RepTypes rep) => ScopeTab rep -> ScalarTab -> VName -> Maybe (PrimExp VName)
+ Futhark.Optimise.ArrayShortCircuiting.DataStructs: vnameToPrimExp :: AliasableRep rep => ScopeTab rep -> ScalarTab -> VName -> Maybe (PrimExp VName)
- Futhark.Optimise.ArrayShortCircuiting.MemRefAggreg: noMemOverlap :: (CanBeAliased (Op rep), RepTypes rep) => TopdownEnv rep -> AccessSummary -> AccessSummary -> Bool
+ Futhark.Optimise.ArrayShortCircuiting.MemRefAggreg: noMemOverlap :: AliasableRep rep => TopdownEnv rep -> AccessSummary -> AccessSummary -> Bool
- Futhark.Optimise.ArrayShortCircuiting.MemRefAggreg: recordMemRefUses :: (CanBeAliased (Op rep), RepTypes rep, Op rep ~ MemOp inner, HasMemBlock (Aliases rep)) => TopdownEnv rep -> BotUpEnv -> Stm (Aliases rep) -> (CoalsTab, InhibitTab)
+ Futhark.Optimise.ArrayShortCircuiting.MemRefAggreg: recordMemRefUses :: (AliasableRep rep, Op rep ~ MemOp inner rep, HasMemBlock (Aliases rep)) => TopdownEnv rep -> BotUpEnv -> Stm (Aliases rep) -> (CoalsTab, InhibitTab)
- Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: updateTopdownEnv :: (ASTRep rep, Op rep ~ MemOp inner, TopDownHelper (OpWithAliases inner)) => TopdownEnv rep -> Stm (Aliases rep) -> TopdownEnv rep
+ Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis: updateTopdownEnv :: (ASTRep rep, Op rep ~ MemOp inner rep, TopDownHelper (inner (Aliases rep))) => TopdownEnv rep -> Stm (Aliases rep) -> TopdownEnv rep
- Futhark.Optimise.CSE: performCSE :: (ASTRep rep, CanBeAliased (Op rep), CSEInOp (OpWithAliases (Op rep))) => Bool -> Pass rep rep
+ Futhark.Optimise.CSE: performCSE :: (AliasableRep rep, CSEInOp (Op (Aliases rep))) => Bool -> Pass rep rep
- Futhark.Optimise.CSE: performCSEOnFunDef :: (ASTRep rep, CanBeAliased (Op rep), CSEInOp (OpWithAliases (Op rep))) => Bool -> FunDef rep -> FunDef rep
+ Futhark.Optimise.CSE: performCSEOnFunDef :: (AliasableRep rep, CSEInOp (Op (Aliases rep))) => Bool -> FunDef rep -> FunDef rep
- Futhark.Optimise.CSE: performCSEOnStms :: (ASTRep rep, CanBeAliased (Op rep), CSEInOp (OpWithAliases (Op rep))) => Bool -> Stms rep -> Stms rep
+ Futhark.Optimise.CSE: performCSEOnStms :: (AliasableRep rep, CSEInOp (Op (Aliases rep))) => Bool -> Stms rep -> Stms rep
- Futhark.Optimise.InPlaceLowering.LowerIntoStm: lowerUpdate :: (MonadFreshNames m, Buildable rep, LetDec rep ~ Type, CanBeAliased (Op rep)) => LowerUpdate rep m
+ Futhark.Optimise.InPlaceLowering.LowerIntoStm: lowerUpdate :: (MonadFreshNames m, Buildable rep, LetDec rep ~ Type, AliasableRep rep) => LowerUpdate rep m
- Futhark.Optimise.Simplify: type SimplifiableRep rep = (ASTRep rep, Simplifiable (LetDec rep), Simplifiable (FParamInfo rep), Simplifiable (LParamInfo rep), Simplifiable (RetType rep), Simplifiable (BranchType rep), TraverseOpStms (Wise rep), CanBeWise (Op rep), IndexOp (OpWithWisdom (Op rep)), BuilderOps (Wise rep), IsOp (Op rep))
+ Futhark.Optimise.Simplify: type SimplifiableRep rep = (ASTRep rep, Simplifiable (LetDec rep), Simplifiable (FParamInfo rep), Simplifiable (LParamInfo rep), Simplifiable (RetType rep), Simplifiable (BranchType rep), TraverseOpStms (Wise rep), CanBeWise (OpC rep), IndexOp (Op (Wise rep)), AliasedOp (Op (Wise rep)), RephraseOp (OpC rep), BuilderOps (Wise rep), IsOp (Op rep))
- Futhark.Optimise.Simplify.Engine: type SimplifiableRep rep = (ASTRep rep, Simplifiable (LetDec rep), Simplifiable (FParamInfo rep), Simplifiable (LParamInfo rep), Simplifiable (RetType rep), Simplifiable (BranchType rep), TraverseOpStms (Wise rep), CanBeWise (Op rep), IndexOp (OpWithWisdom (Op rep)), BuilderOps (Wise rep), IsOp (Op rep))
+ Futhark.Optimise.Simplify.Engine: type SimplifiableRep rep = (ASTRep rep, Simplifiable (LetDec rep), Simplifiable (FParamInfo rep), Simplifiable (LParamInfo rep), Simplifiable (RetType rep), Simplifiable (BranchType rep), TraverseOpStms (Wise rep), CanBeWise (OpC rep), IndexOp (Op (Wise rep)), AliasedOp (Op (Wise rep)), RephraseOp (OpC rep), BuilderOps (Wise rep), IsOp (Op rep))
- Futhark.Optimise.Simplify.Rep: addOpWisdom :: CanBeWise op => op -> OpWithWisdom op
+ Futhark.Optimise.Simplify.Rep: addOpWisdom :: (CanBeWise op, Informing rep) => op rep -> op (Wise rep)
- Futhark.Optimise.Simplify.Rep: addWisdomToPat :: (ASTRep rep, CanBeWise (Op rep)) => Pat (LetDec rep) -> Exp (Wise rep) -> Pat (LetDec (Wise rep))
+ Futhark.Optimise.Simplify.Rep: addWisdomToPat :: Informing rep => Pat (LetDec rep) -> Exp (Wise rep) -> Pat (LetDec (Wise rep))
- Futhark.Optimise.Simplify.Rep: class (AliasedOp (OpWithWisdom op), IsOp (OpWithWisdom op)) => CanBeWise op where {
+ Futhark.Optimise.Simplify.Rep: class CanBeWise op
- Futhark.Optimise.Simplify.Rep: mkWiseBody :: (ASTRep rep, CanBeWise (Op rep)) => BodyDec rep -> Stms (Wise rep) -> Result -> Body (Wise rep)
+ Futhark.Optimise.Simplify.Rep: mkWiseBody :: Informing rep => BodyDec rep -> Stms (Wise rep) -> Result -> Body (Wise rep)
- Futhark.Optimise.Simplify.Rep: mkWiseExpDec :: (ASTRep rep, CanBeWise (Op rep)) => Pat (LetDec (Wise rep)) -> ExpDec rep -> Exp (Wise rep) -> ExpDec (Wise rep)
+ Futhark.Optimise.Simplify.Rep: mkWiseExpDec :: Informing rep => Pat (LetDec (Wise rep)) -> ExpDec rep -> Exp (Wise rep) -> ExpDec (Wise rep)
- Futhark.Optimise.Simplify.Rep: mkWiseStm :: (ASTRep rep, CanBeWise (Op rep)) => Pat (LetDec rep) -> StmAux (ExpDec rep) -> Exp (Wise rep) -> Stm (Wise rep)
+ Futhark.Optimise.Simplify.Rep: mkWiseStm :: Informing rep => Pat (LetDec rep) -> StmAux (ExpDec rep) -> Exp (Wise rep) -> Stm (Wise rep)
- Futhark.Optimise.Simplify.Rep: removeBodyWisdom :: CanBeWise (Op rep) => Body (Wise rep) -> Body rep
+ Futhark.Optimise.Simplify.Rep: removeBodyWisdom :: RephraseOp (OpC rep) => Body (Wise rep) -> Body rep
- Futhark.Optimise.Simplify.Rep: removeExpWisdom :: CanBeWise (Op rep) => Exp (Wise rep) -> Exp rep
+ Futhark.Optimise.Simplify.Rep: removeExpWisdom :: RephraseOp (OpC rep) => Exp (Wise rep) -> Exp rep
- Futhark.Optimise.Simplify.Rep: removeFunDefWisdom :: CanBeWise (Op rep) => FunDef (Wise rep) -> FunDef rep
+ Futhark.Optimise.Simplify.Rep: removeFunDefWisdom :: RephraseOp (OpC rep) => FunDef (Wise rep) -> FunDef rep
- Futhark.Optimise.Simplify.Rep: removeLambdaWisdom :: CanBeWise (Op rep) => Lambda (Wise rep) -> Lambda rep
+ Futhark.Optimise.Simplify.Rep: removeLambdaWisdom :: RephraseOp (OpC rep) => Lambda (Wise rep) -> Lambda rep
- Futhark.Optimise.Simplify.Rep: removeStmWisdom :: CanBeWise (Op rep) => Stm (Wise rep) -> Stm rep
+ Futhark.Optimise.Simplify.Rep: removeStmWisdom :: RephraseOp (OpC rep) => Stm (Wise rep) -> Stm rep
- Futhark.Optimise.Simplify.Rep: type Informing rep = (ASTRep rep, CanBeWise (Op rep))
+ Futhark.Optimise.Simplify.Rep: type Informing rep = (ASTRep rep, AliasedOp (OpC rep (Wise rep)), RephraseOp (OpC rep), CanBeWise (OpC rep), FreeIn (OpC rep (Wise rep)))
- Futhark.Pass.ExplicitAllocations: defaultExpHints :: (Monad m, ASTRep rep) => Exp rep -> m [ExpHint]
+ Futhark.Pass.ExplicitAllocations: defaultExpHints :: (ASTRep rep, HasScope rep m) => Exp rep -> m [ExpHint]
- Futhark.Pass.ExplicitAllocations: explicitAllocationsGeneric :: Allocable fromrep torep inner => (Op fromrep -> AllocM fromrep torep (Op torep)) -> (Exp torep -> AllocM fromrep torep [ExpHint]) -> Pass fromrep torep
+ Futhark.Pass.ExplicitAllocations: explicitAllocationsGeneric :: Allocable fromrep torep inner => Space -> (Op fromrep -> AllocM fromrep torep (Op torep)) -> (Exp torep -> AllocM fromrep torep [ExpHint]) -> Pass fromrep torep
- Futhark.Pass.ExplicitAllocations: explicitAllocationsInStmsGeneric :: (MonadFreshNames m, HasScope torep m, Allocable fromrep torep inner) => (Op fromrep -> AllocM fromrep torep (Op torep)) -> (Exp torep -> AllocM fromrep torep [ExpHint]) -> Stms fromrep -> m (Stms torep)
+ Futhark.Pass.ExplicitAllocations: explicitAllocationsInStmsGeneric :: (MonadFreshNames m, HasScope torep m, Allocable fromrep torep inner) => Space -> (Op fromrep -> AllocM fromrep torep (Op torep)) -> (Exp torep -> AllocM fromrep torep [ExpHint]) -> Stms fromrep -> m (Stms torep)
- Futhark.Pass.ExplicitAllocations: mkLetNamesB' :: (LetDec (Rep m) ~ LetDecMem, Mem (Rep m) inner, MonadBuilder m, ExpDec (Rep m) ~ ()) => ExpDec (Rep m) -> [VName] -> Exp (Rep m) -> m (Stm (Rep m))
+ Futhark.Pass.ExplicitAllocations: mkLetNamesB' :: (LetDec (Rep m) ~ LetDecMem, Mem (Rep m) inner, MonadBuilder m, ExpDec (Rep m) ~ ()) => Space -> ExpDec (Rep m) -> [VName] -> Exp (Rep m) -> m (Stm (Rep m))
- Futhark.Pass.ExplicitAllocations: mkLetNamesB'' :: (Mem rep inner, LetDec rep ~ LetDecMem, OpReturns (OpWithWisdom inner), ExpDec rep ~ (), Rep m ~ Wise rep, HasScope (Wise rep) m, MonadBuilder m, CanBeWise inner) => [VName] -> Exp (Wise rep) -> m (Stm (Wise rep))
+ Futhark.Pass.ExplicitAllocations: mkLetNamesB'' :: (Mem rep inner, LetDec rep ~ LetDecMem, OpReturns (inner (Wise rep)), ExpDec rep ~ (), Rep m ~ Wise rep, HasScope (Wise rep) m, MonadBuilder m, AliasedOp (inner (Wise rep)), RephraseOp (MemOp inner), CanBeWise inner) => Space -> [VName] -> Exp (Wise rep) -> m (Stm (Wise rep))
- Futhark.Pass.ExplicitAllocations: simplifiable :: (SimplifiableRep rep, LetDec rep ~ LetDecMem, ExpDec rep ~ (), BodyDec rep ~ (), OpReturns (OpWithWisdom inner), AliasedOp (OpWithWisdom inner), IndexOp (OpWithWisdom inner), Mem rep inner) => (OpWithWisdom inner -> UsageTable) -> (OpWithWisdom inner -> SimpleM rep (OpWithWisdom inner, Stms (Wise rep))) -> SimpleOps rep
+ Futhark.Pass.ExplicitAllocations: simplifiable :: (SimplifiableRep rep, LetDec rep ~ LetDecMem, ExpDec rep ~ (), BodyDec rep ~ (), Mem (Wise rep) inner, CanBeWise inner, RephraseOp inner, IsOp (inner rep), OpReturns (inner (Wise rep)), AliasedOp (inner (Wise rep)), IndexOp (inner (Wise rep))) => (inner (Wise rep) -> UsageTable) -> (inner (Wise rep) -> SimpleM rep (inner (Wise rep), Stms (Wise rep))) -> SimpleOps rep
- Futhark.Pass.ExplicitAllocations: type Allocable fromrep torep inner = (PrettyRep fromrep, PrettyRep torep, Mem torep inner, LetDec torep ~ LetDecMem, FParamInfo fromrep ~ DeclType, LParamInfo fromrep ~ Type, BranchType fromrep ~ ExtType, RetType fromrep ~ DeclExtType, BodyDec fromrep ~ (), BodyDec torep ~ (), ExpDec torep ~ (), SizeSubst inner, BuilderOps torep)
+ Futhark.Pass.ExplicitAllocations: type Allocable fromrep torep inner = (PrettyRep fromrep, PrettyRep torep, Mem torep inner, LetDec torep ~ LetDecMem, FParamInfo fromrep ~ DeclType, LParamInfo fromrep ~ Type, BranchType fromrep ~ ExtType, RetType fromrep ~ DeclExtType, BodyDec fromrep ~ (), BodyDec torep ~ (), ExpDec torep ~ (), SizeSubst (inner torep), BuilderOps torep)
- Futhark.Pass.ExplicitAllocations.Seq: simplifiable :: (SimplifiableRep rep, LetDec rep ~ LetDecMem, ExpDec rep ~ (), BodyDec rep ~ (), OpReturns (OpWithWisdom inner), AliasedOp (OpWithWisdom inner), IndexOp (OpWithWisdom inner), Mem rep inner) => (OpWithWisdom inner -> UsageTable) -> (OpWithWisdom inner -> SimpleM rep (OpWithWisdom inner, Stms (Wise rep))) -> SimpleOps rep
+ Futhark.Pass.ExplicitAllocations.Seq: simplifiable :: (SimplifiableRep rep, LetDec rep ~ LetDecMem, ExpDec rep ~ (), BodyDec rep ~ (), Mem (Wise rep) inner, CanBeWise inner, RephraseOp inner, IsOp (inner rep), OpReturns (inner (Wise rep)), AliasedOp (inner (Wise rep)), IndexOp (inner (Wise rep))) => (inner (Wise rep) -> UsageTable) -> (inner (Wise rep) -> SimpleM rep (inner (Wise rep), Stms (Wise rep))) -> SimpleOps rep
- Futhark.Pass.ExtractKernels.BlockedKernel: type DistRep rep = (Buildable rep, HasSegOp rep, BuilderOps rep, LetDec rep ~ Type, ExpDec rep ~ (), BodyDec rep ~ (), CanBeAliased (Op rep))
+ Futhark.Pass.ExtractKernels.BlockedKernel: type DistRep rep = (Buildable rep, HasSegOp rep, BuilderOps rep, LetDec rep ~ Type, ExpDec rep ~ (), BodyDec rep ~ (), AliasableRep rep)
- Futhark.Pass.ExtractKernels.ToGPU: getSize :: (MonadBuilder m, Op (Rep m) ~ HostOp (Rep m) inner) => String -> SizeClass -> m SubExp
+ Futhark.Pass.ExtractKernels.ToGPU: getSize :: (MonadBuilder m, Op (Rep m) ~ HostOp inner (Rep m)) => String -> SizeClass -> m SubExp
- Futhark.Pass.ExtractKernels.ToGPU: segThread :: (MonadBuilder m, Op (Rep m) ~ HostOp (Rep m) inner) => String -> m SegLevel
+ Futhark.Pass.ExtractKernels.ToGPU: segThread :: (MonadBuilder m, Op (Rep m) ~ HostOp inner (Rep m)) => String -> m SegLevel
- Futhark.Pkg.Info: PkgRevInfo :: Text -> FilePath -> Text -> GetManifest m -> UTCTime -> PkgRevInfo m
+ Futhark.Pkg.Info: PkgRevInfo :: GetFiles m -> Text -> GetManifest m -> UTCTime -> PkgRevInfo m
- Futhark.Pkg.Info: lookupNewestRev :: MonadPkgRegistry m => PkgPath -> m SemVer
+ Futhark.Pkg.Info: lookupNewestRev :: MonadPkgRegistry m => CacheDir -> PkgPath -> m SemVer
- Futhark.Pkg.Info: lookupPackage :: MonadPkgRegistry m => PkgPath -> m (PkgInfo m)
+ Futhark.Pkg.Info: lookupPackage :: MonadPkgRegistry m => CacheDir -> PkgPath -> m (PkgInfo m)
- Futhark.Pkg.Info: lookupPackageRev :: MonadPkgRegistry m => PkgPath -> SemVer -> m (PkgRevInfo m)
+ Futhark.Pkg.Info: lookupPackageRev :: MonadPkgRegistry m => CacheDir -> PkgPath -> SemVer -> m (PkgRevInfo m)
- Futhark.Pkg.Info: pkgInfo :: (MonadIO m, MonadLogger m, MonadFail m) => PkgPath -> m (Either Text (PkgInfo m))
+ Futhark.Pkg.Info: pkgInfo :: (MonadIO m, MonadLogger m, MonadFail m) => CacheDir -> PkgPath -> m (PkgInfo m)
- Futhark.Pkg.Solve: solveDeps :: MonadPkgRegistry m => PkgRevDeps -> m BuildList
+ Futhark.Pkg.Solve: solveDeps :: MonadPkgRegistry m => CacheDir -> PkgRevDeps -> m BuildList
- Futhark.Test.Spec: TestRun :: [String] -> Values -> ExpectedResult Success -> Int -> String -> TestRun
+ Futhark.Test.Spec: TestRun :: [String] -> Values -> ExpectedResult Success -> Int -> Text -> TestRun
- Futhark.Test.Spec: [runDescription] :: TestRun -> String
+ Futhark.Test.Spec: [runDescription] :: TestRun -> Text
- Futhark.Test.Spec: genValueType :: GenValue -> String
+ Futhark.Test.Spec: genValueType :: GenValue -> Text
- Futhark.Transform.FirstOrderTransform: transformLambda :: (MonadFreshNames m, Buildable rep, BuilderOps rep, LocalScope somerep m, SameScope somerep rep, LetDec rep ~ LetDec SOACS, CanBeAliased (Op rep)) => Lambda SOACS -> m (Lambda rep)
+ Futhark.Transform.FirstOrderTransform: transformLambda :: (MonadFreshNames m, Buildable rep, BuilderOps rep, LocalScope somerep m, SameScope somerep rep, LetDec rep ~ LetDec SOACS, AliasableRep rep) => Lambda SOACS -> m (Lambda rep)
- Futhark.Transform.FirstOrderTransform: type FirstOrderRep rep = (Buildable rep, BuilderOps rep, LetDec SOACS ~ LetDec rep, LParamInfo SOACS ~ LParamInfo rep, CanBeAliased (Op rep))
+ Futhark.Transform.FirstOrderTransform: type FirstOrderRep rep = (Buildable rep, BuilderOps rep, LetDec SOACS ~ LetDec rep, LParamInfo SOACS ~ LParamInfo rep, AliasableRep rep)
- Futhark.Transform.FirstOrderTransform: type Transformer m = (MonadBuilder m, LocalScope (Rep m) m, Buildable (Rep m), BuilderOps (Rep m), LParamInfo SOACS ~ LParamInfo (Rep m), CanBeAliased (Op (Rep m)))
+ Futhark.Transform.FirstOrderTransform: type Transformer m = (MonadBuilder m, LocalScope (Rep m) m, Buildable (Rep m), BuilderOps (Rep m), LParamInfo SOACS ~ LParamInfo (Rep m), AliasableRep (Rep m))
- Futhark.Util: atMostChars :: Int -> String -> String
+ Futhark.Util: atMostChars :: Int -> Text -> Text
- Language.Futhark.Semantic: FileModule :: TySet -> Env -> Prog -> FileModule
+ Language.Futhark.Semantic: FileModule :: TySet -> Env -> Prog -> Env -> FileModule
Files
- docs/c-api.rst +6/−4
- docs/error-index.rst +26/−0
- docs/language-reference.rst +23/−9
- docs/man/futhark-dataset.rst +1/−1
- docs/man/futhark-literate.rst +5/−0
- docs/man/futhark-pkg.rst +4/−6
- docs/man/futhark-test.rst +7/−1
- docs/man/futhark.rst +13/−0
- docs/package-management.rst +25/−3
- docs/performance.rst +2/−1
- futhark.cabal +10/−8
- prelude/math.fut +5/−0
- prelude/soacs.fut +1/−1
- rts/c/backends/c.h +61/−0
- rts/c/backends/cuda.h +947/−0
- rts/c/backends/multicore.h +95/−0
- rts/c/backends/opencl.h +1232/−0
- rts/c/context.h +59/−2
- rts/c/context_prototypes.h +14/−5
- rts/c/cuda.h +0/−766
- rts/c/opencl.h +0/−1066
- rts/c/scalar.h +26/−0
- rts/c/scalar_f16.h +19/−0
- rts/c/server.h +33/−27
- rts/c/uniform.h +21/−0
- rts/c/util.h +13/−0
- rts/javascript/server.js +7/−7
- rts/python/scalar.py +9/−0
- rts/python/server.py +11/−6
- src/Futhark/AD/Derivatives.hs +6/−0
- src/Futhark/AD/Fwd.hs +47/−56
- src/Futhark/Actions.hs +2/−14
- src/Futhark/Analysis/Alias.hs +16/−10
- src/Futhark/Analysis/HORep/SOAC.hs +27/−18
- src/Futhark/Analysis/Interference.hs +17/−16
- src/Futhark/Analysis/LastUse.hs +407/−202
- src/Futhark/Analysis/MemAlias.hs +20/−6
- src/Futhark/Analysis/Metrics.hs +2/−2
- src/Futhark/Analysis/Rephrase.hs +0/−103
- src/Futhark/Analysis/SymbolTable.hs +10/−4
- src/Futhark/Analysis/UsageTable.hs +1/−1
- src/Futhark/Bench.hs +4/−4
- src/Futhark/CLI/Autotune.hs +45/−41
- src/Futhark/CLI/Bench.hs +10/−9
- src/Futhark/CLI/Benchcmp.hs +327/−0
- src/Futhark/CLI/Dataset.hs +2/−2
- src/Futhark/CLI/Dev.hs +3/−12
- src/Futhark/CLI/Eval.hs +130/−0
- src/Futhark/CLI/Literate.hs +32/−17
- src/Futhark/CLI/Main.hs +5/−1
- src/Futhark/CLI/Misc.hs +9/−8
- src/Futhark/CLI/Pkg.hs +72/−115
- src/Futhark/CLI/REPL.hs +20/−33
- src/Futhark/CLI/Run.hs +9/−21
- src/Futhark/CLI/Test.hs +5/−4
- src/Futhark/CodeGen/Backends/CCUDA.hs +6/−44
- src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs +73/−403
- src/Futhark/CodeGen/Backends/COpenCL.hs +15/−57
- src/Futhark/CodeGen/Backends/COpenCL/Boilerplate.hs +136/−530
- src/Futhark/CodeGen/Backends/GenericC.hs +48/−31
- src/Futhark/CodeGen/Backends/GenericC/CLI.hs +3/−1
- src/Futhark/CodeGen/Backends/GenericC/Code.hs +7/−20
- src/Futhark/CodeGen/Backends/GenericC/EntryPoints.hs +1/−4
- src/Futhark/CodeGen/Backends/GenericC/Fun.hs +3/−2
- src/Futhark/CodeGen/Backends/GenericC/Monad.hs +36/−44
- src/Futhark/CodeGen/Backends/GenericPython.hs +47/−44
- src/Futhark/CodeGen/Backends/GenericWASM.hs +4/−3
- src/Futhark/CodeGen/Backends/MulticoreC.hs +30/−205
- src/Futhark/CodeGen/Backends/MulticoreC/Boilerplate.hs +23/−0
- src/Futhark/CodeGen/Backends/MulticoreISPC.hs +12/−13
- src/Futhark/CodeGen/Backends/MulticoreWASM.hs +2/−1
- src/Futhark/CodeGen/Backends/PyOpenCL.hs +3/−57
- src/Futhark/CodeGen/Backends/SequentialC/Boilerplate.hs +10/−125
- src/Futhark/CodeGen/Backends/SimpleRep.hs +18/−1
- src/Futhark/CodeGen/ImpCode.hs +19/−12
- src/Futhark/CodeGen/ImpGen.hs +53/−32
- src/Futhark/CodeGen/ImpGen/GPU.hs +3/−16
- src/Futhark/CodeGen/ImpGen/GPU/Base.hs +11/−0
- src/Futhark/CodeGen/ImpGen/GPU/SegHist.hs +3/−5
- src/Futhark/CodeGen/ImpGen/GPU/SegRed.hs +2/−6
- src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs +1/−1
- src/Futhark/CodeGen/ImpGen/GPU/ToOpenCL.hs +27/−25
- src/Futhark/CodeGen/ImpGen/Multicore.hs +3/−4
- src/Futhark/CodeGen/ImpGen/Multicore/SegHist.hs +1/−1
- src/Futhark/CodeGen/ImpGen/Sequential.hs +1/−1
- src/Futhark/CodeGen/RTS/C.hs +24/−12
- src/Futhark/CodeGen/SetDefaultSpace.hs +0/−112
- src/Futhark/Doc/Generator.hs +2/−2
- src/Futhark/IR/Aliases.hs +48/−32
- src/Futhark/IR/GPU.hs +8/−4
- src/Futhark/IR/GPU/Op.hs +25/−33
- src/Futhark/IR/GPU/Simplify.hs +3/−3
- src/Futhark/IR/GPUMem.hs +13/−9
- src/Futhark/IR/MC.hs +2/−4
- src/Futhark/IR/MC/Op.hs +28/−43
- src/Futhark/IR/MCMem.hs +9/−11
- src/Futhark/IR/Mem.hs +26/−26
- src/Futhark/IR/Mem/Simplify.hs +12/−10
- src/Futhark/IR/Parse.hs +4/−4
- src/Futhark/IR/Pretty.hs +3/−1
- src/Futhark/IR/Prop.hs +8/−5
- src/Futhark/IR/Prop/Aliases.hs +53/−53
- src/Futhark/IR/Prop/Names.hs +3/−0
- src/Futhark/IR/Prop/TypeOf.hs +2/−24
- src/Futhark/IR/Rep.hs +17/−3
- src/Futhark/IR/Rephrase.hs +114/−0
- src/Futhark/IR/SOACS.hs +2/−4
- src/Futhark/IR/SOACS/SOAC.hs +29/−19
- src/Futhark/IR/SegOp.hs +44/−61
- src/Futhark/IR/Seq.hs +4/−7
- src/Futhark/IR/SeqMem.hs +6/−10
- src/Futhark/IR/Syntax.hs +2/−2
- src/Futhark/IR/TypeCheck.hs +7/−9
- src/Futhark/Internalise/Defunctionalise.hs +3/−2
- src/Futhark/Optimise/ArrayShortCircuiting.hs +21/−14
- src/Futhark/Optimise/ArrayShortCircuiting/ArrayCoalescing.hs +49/−43
- src/Futhark/Optimise/ArrayShortCircuiting/DataStructs.hs +1/−1
- src/Futhark/Optimise/ArrayShortCircuiting/LastUse.hs +0/−458
- src/Futhark/Optimise/ArrayShortCircuiting/MemRefAggreg.hs +3/−3
- src/Futhark/Optimise/ArrayShortCircuiting/TopdownAnalysis.hs +7/−7
- src/Futhark/Optimise/CSE.hs +19/−33
- src/Futhark/Optimise/Fusion.hs +40/−29
- src/Futhark/Optimise/Fusion/GraphRep.hs +34/−41
- src/Futhark/Optimise/Fusion/TryFusion.hs +8/−4
- src/Futhark/Optimise/InPlaceLowering.hs +2/−2
- src/Futhark/Optimise/InPlaceLowering/LowerIntoStm.hs +1/−1
- src/Futhark/Optimise/InliningDeadFun.hs +3/−4
- src/Futhark/Optimise/MergeGPUBodies.hs +1/−1
- src/Futhark/Optimise/ReduceDeviceSyncs.hs +1/−1
- src/Futhark/Optimise/Simplify/Engine.hs +6/−4
- src/Futhark/Optimise/Simplify/Rep.hs +28/−28
- src/Futhark/Optimise/Simplify/Rules/BasicOp.hs +4/−7
- src/Futhark/Optimise/Simplify/Rules/Index.hs +4/−0
- src/Futhark/Optimise/Sink.hs +2/−2
- src/Futhark/Pass/ExpandAllocations.hs +41/−31
- src/Futhark/Pass/ExplicitAllocations.hs +69/−44
- src/Futhark/Pass/ExplicitAllocations/GPU.hs +10/−11
- src/Futhark/Pass/ExplicitAllocations/MC.hs +1/−1
- src/Futhark/Pass/ExplicitAllocations/SegOp.hs +1/−1
- src/Futhark/Pass/ExplicitAllocations/Seq.hs +5/−1
- src/Futhark/Pass/ExtractKernels.hs +51/−43
- src/Futhark/Pass/ExtractKernels/BlockedKernel.hs +2/−2
- src/Futhark/Pass/ExtractKernels/StreamKernel.hs +1/−1
- src/Futhark/Pass/ExtractKernels/ToGPU.hs +2/−3
- src/Futhark/Pass/ExtractMulticore.hs +0/−1
- src/Futhark/Pass/LiftAllocations.hs +8/−5
- src/Futhark/Pass/LowerAllocations.hs +8/−5
- src/Futhark/Pipeline.hs +61/−19
- src/Futhark/Pkg/Info.hs +155/−277
- src/Futhark/Pkg/Solve.hs +3/−2
- src/Futhark/Script.hs +36/−0
- src/Futhark/Test.hs +6/−8
- src/Futhark/Test/Spec.hs +37/−16
- src/Futhark/Transform/FirstOrderTransform.hs +3/−3
- src/Futhark/Transform/Rename.hs +3/−0
- src/Futhark/Transform/Substitute.hs +3/−0
- src/Futhark/Util.hs +2/−2
- src/Futhark/Util/Log.hs +5/−0
- src/Language/Futhark/Interpreter.hs +7/−8
- src/Language/Futhark/Interpreter/Values.hs +6/−4
- src/Language/Futhark/Parser/Lexer.x +4/−4
- src/Language/Futhark/Parser/Parser.y +34/−22
- src/Language/Futhark/Pretty.hs +5/−3
- src/Language/Futhark/Primitive.hs +5/−0
- src/Language/Futhark/Prop.hs +4/−2
- src/Language/Futhark/Semantic.hs +5/−1
- src/Language/Futhark/Syntax.hs +8/−1
- src/Language/Futhark/Traversals.hs +2/−2
- src/Language/Futhark/TypeChecker.hs +58/−43
- src/Language/Futhark/TypeChecker/Terms.hs +2/−0
- src/Language/Futhark/TypeChecker/Terms/Monad.hs +3/−2
- src/Language/Futhark/TypeChecker/Terms/Pat.hs +4/−2
- src/Language/Futhark/TypeChecker/Unify.hs +36/−28
- unittests/Futhark/BenchTests.hs +1/−1
docs/c-api.rst view
@@ -496,11 +496,13 @@ Immediately conduct an interactive dialogue on standard output to select the platform and device from a list. -.. c:function:: struct futhark_context *futhark_context_new_with_command_queue(struct futhark_context_config *cfg, cl_command_queue queue)+.. c:function:: void futhark_context_config_set_command_queue(struct futhark_context_config *cfg, cl_command_queue queue) - Construct a context that uses a pre-existing command queue. This- allows the caller to directly customise which device and platform- is used.+ Use exactly this command queue for the context. If this is set,+ all other device/platform configuration options are ignored. Once+ the context is active, the command queue belongs to Futhark and+ should not be used by anything else. This is useful for+ implementing custom device selection logic in application code. .. c:function:: cl_command_queue futhark_context_get_command_queue(struct futhark_context *ctx)
docs/error-index.rst view
@@ -533,6 +533,32 @@ technique, but often necessary when writing advanced size-dependent code. +.. _unify-consuming-param:++"Parameter types *x* and *y* are incompatible regarding consuming their arguments+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++This error occurs when you provide a function that *does* consume its+argument in a context that expects a function that *does not* allow a+function that consumes its argument.++As a simple example, consider the following contrived function that+does consume its argument:++.. code-block:: futhark++ def f (xs: *[]f32) : f32 = 0f32++Now we define another function that is merely ``f``, but with a type+annotation that tries to hide the consumption:++.. code-block:: futhark++ def g : []f32 -> f32 = f++Allowing this would permit us to hide the fact that ``f`` consumes its+argument, which would not be sound, so the type checker complains.+ .. _ambiguous-size: "Ambiguous size *x*"
docs/language-reference.rst view
@@ -542,12 +542,20 @@ * Function and type application, and prefix operators, bind more tightly than any infix operator. Note that the only prefix- operators are ``!`` and ``-``, and more cannot be defined.+ operators are the builtin ``!`` and ``-``, and more cannot be+ defined. In particular, a user-defined operator beginning with+ ``!`` binds as ``!=``, as on the table below, not as the prefix+ operator ``!`` * ``#foo #bar`` is interpreted as a constructor with a ``#bar`` payload, not as applying ``#foo`` to ``#bar`` (the latter would be semantically invalid anyway). +* A type application ``pt [n]t`` is parsed as an application of the+ type constructor ``pt`` to the size argument ``[n]`` and the type+ ``t``. To pass a single array-typed parameter, enclose it in+ parens.+ * The following table describes the precedence and associativity of infix operators in both expressions and type expressions. All operators in the same row have the same precedence. The rows are@@ -563,7 +571,7 @@ left ```op``` left ``||`` left ``&&``- left ``<=`` ``>=`` ``>`` ``<`` ``==`` ``!=``+ left ``<=`` ``>=`` ``>`` ``<`` ``==`` ``!=`` ``!`` ``=`` left ``&`` ``^`` ``|`` left ``<<`` ``>>`` left ``+`` ``-``@@ -767,8 +775,8 @@ Apply an operator to ``x`` and ``y``. Operators are functions like any other, and can be user-defined. Futhark pre-defines certain-"magical" *overloaded* operators that work on many different types.-Overloaded functions cannot be defined by the user. Both operands+"magical" *overloaded* operators that work on several types.+Overloaded operators cannot be defined by the user. Both operands must have the same type. The predefined operators and their semantics are: @@ -801,16 +809,16 @@ ``==``, ``!=`` - Compare any two values of builtin or compound type for equality.+ Compare any two values of builtin or compound type for equality. ``<``, ``<=``. ``>``, ``>=`` - Company any two values of numeric type for equality.+ Company any two values of numeric type for equality. ```op``` - Use ``op``, which may be any non-operator function name, as an- infix operator.+ Use ``op``, which may be any non-operator function name, as an+ infix operator. ``x && y`` ..........@@ -927,7 +935,9 @@ Evaluate ``e`` and bind the result to the irrefutable pattern ``pat`` (see :ref:`patterns`) while evaluating ``body``. The ``in`` keyword-is optional if ``body`` is a ``let`` expression.+is optional if ``body`` is a ``let`` expression. The binding is not+let-generalised, meaning it has a monomorphic type. This can be+significant if ``e`` is of functional type. ``let [n] pat = e in body`` ...........................@@ -1072,6 +1082,10 @@ definition site. Specifically, if a top-level function uses overloaded arithmetic operators, the resolution of those overloads cannot be influenced by later uses of the function.++Local bindings made with ``let`` are not made polymorphic through+let-generalisation *unless* they are syntactically functions, meaning+they have at least one named parameter. .. _size-types:
docs/man/futhark-dataset.rst view
@@ -42,7 +42,7 @@ generated. -s int- Set the seed used for the RNG. Zero by default.+ Set the seed used for the RNG. 1 by default. --T-bounds=<min:max> Set inclusive lower and upper bounds on generated values of type
docs/man/futhark-literate.rst view
@@ -270,6 +270,11 @@ of values is returned, which should be destructured before use. For example: ``let (a, b) = $loaddata "foo.in" in bar a b``. +* ``$loadaudio "file"`` reads audio from the given file and returns it as a+ ``[][]f64``, where each row corresponds to a channel of the original+ soundfile. Most common audio-formats are supported, including mp3, ogg, wav,+ flac and opus.+ SAFETY ======
docs/man/futhark-pkg.rst view
@@ -53,8 +53,8 @@ Most commands take a ``-v``/``--verbose`` option that makes ``futhark pkg`` write running diagnostics to stderr. -Network requests (exclusively HTTP GETs) are done via ``curl``, which-must be available on the ``PATH``.+Packages must correspond to Git repositories, and all interactions are+done by invoking ``git``. COMMANDS ========@@ -159,10 +159,8 @@ the dependencies of its dependencies, without the ``futhark.pkg`` file reflecting this. -There is no caching of zipballs and version lists between invocations,-so the network traffic can be rather heavy.--Only GitHub and GitLab are supported as code hosting sites.+There is no caching of package metadata between invocations, so the+network traffic can be rather heavy. SEE ALSO ========
docs/man/futhark-test.rst view
@@ -37,9 +37,14 @@ [tags { tags... }] [entry: names...]- [compiled|nobench|random|script] input ({ values... } | @ filename)+ ["name..."] [compiled|nobench|random|script] input ({ values... } | @ filename) output { values... } | auto output | error: regex +If a test case begins with a quoted string, that string is reported as+the dataset name, including in the JSON file produced by+:ref:`futhark-bench(1)`. If no name is provided, one is automatically+generated. The name must be unique across all test cases.+ If ``compiled`` is present before the ``input`` keyword, this test case will never be passed to the interpreter. This is useful for test cases that are annoyingly slow to interpret. The ``nobench`` keyword@@ -60,6 +65,7 @@ It must use only functions explicitly declared as entry points. If the expression produces an *n*-element tuple, it will be unpacked and its components passed as *n* distinct arguments to the test function.+The only builtin function supported is ``$loaddata``. If ``input`` is followed by an ``@`` and a file name (which must not contain any whitespace) instead of curly braces, values or
docs/man/futhark.rst view
@@ -24,6 +24,13 @@ COMMANDS ======== +futhark benchcmp FILE_A FILE_B+------------------------------++Compares two Futhark benchmarks and reports changes in performance.+The files must be formatted in the same manner as a JSON file returned+from :ref:`futhark-bench(1)`.+ futhark check [-w] PROGRAM -------------------------- @@ -65,6 +72,12 @@ A Futhark compiler development command, intentionally undocumented and intended for use in developing the Futhark compiler, not for programmers writing in Futhark.++futhark eval [-f FILE] [-w] <exprs...>+--------------------------------------++Evaluates expressions given as command-line arguments. Optionally +allows a file import using ``-f``. futhark hash PROGRAM --------------------
docs/package-management.rst view
@@ -14,9 +14,11 @@ A package is uniquely identified with a *package path*, which is similar to a URL, except without a protocol. At the moment, package-paths are always links to Git repositories hosted on GitHub or GitLab.-In the future, this will become more flexible. As an example, a-package path may be ``github.com/athas/fut-foo``.+paths must be something that can be passed to ``git clone``. In+particular, this includes paths to repositories on major code hosting+sites such as GitLab and GitHub. In the future, this will become more+flexible. As an example, a package path may be+``github.com/athas/fut-foo``. Packages are versioned with `semantic version numbers <https://semver.org/>`_ of the form ``X.Y.Z``. Whenever versions are@@ -359,3 +361,23 @@ (but the ``--safe`` compiler option may help). However, this is not any worse than calling external code in a conventional impure language, which generally can perform any conceivable harmful action.++Private repositories+--------------------++The Futhark package manager is intentionally very simple - perhaps+even simplistic. The key philosophy is that if you can ``git clone``+a repository from the command line, then ``futhark pkg`` can also+access it. However, ``futhark pkg`` always uses the ``https://``+protocol when converting package paths to the URLs that are passed to+``git``, which is sometimes inconvenient for self-hosted or private+repositories. As a workaround, you can modify your Git configuration+file to transparently replace ``https://`` with ``ssh://`` for certain+repositories. For example, you can add the following entry+``$HOME/.gitconfig``::++ [url "ssh://git@github.com/sturluson"]+ insteadOf = https://github.com/sturluson++This will make all interactions with repositories owned by the+``sturluson`` user on GitHub use SSH instead of HTTPS.
docs/performance.rst view
@@ -242,12 +242,13 @@ (u8, [n]i32) +However the type .. code-block:: futhark #foo [n]i32 | #bar [n]f32 -becomes+is represented as .. code-block:: futhark
futhark.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: futhark-version: 0.22.7+version: 0.23.1 synopsis: An optimising compiler for a functional, array-oriented language. description: Futhark is a small programming language designed to be compiled to@@ -39,6 +39,10 @@ rts/c/atomics.h rts/c/context.h rts/c/context_prototypes.h+ rts/c/backends/c.h+ rts/c/backends/cuda.h+ rts/c/backends/multicore.h+ rts/c/backends/opencl.h rts/c/lock.h rts/c/timing.h rts/c/errors.h@@ -46,8 +50,6 @@ rts/c/tuning.h rts/c/values.h rts/c/half.h- rts/c/opencl.h- rts/c/cuda.h rts/c/cache.h rts/c/ispc_util.h rts/c/scalar.h@@ -172,7 +174,6 @@ Futhark.Analysis.PrimExp.Convert Futhark.Analysis.PrimExp.Parse Futhark.Analysis.PrimExp.Simplify- Futhark.Analysis.Rephrase Futhark.Analysis.SymbolTable Futhark.Analysis.UsageTable Futhark.Bench@@ -183,11 +184,13 @@ Futhark.CLI.C Futhark.CLI.CUDA Futhark.CLI.Check+ Futhark.CLI.Benchcmp Futhark.CLI.Datacmp Futhark.CLI.Dataset Futhark.CLI.Defs Futhark.CLI.Dev Futhark.CLI.Doc+ Futhark.CLI.Eval Futhark.CLI.Literate Futhark.CLI.LSP Futhark.CLI.Main@@ -223,6 +226,7 @@ Futhark.CodeGen.Backends.GenericPython.Options Futhark.CodeGen.Backends.GenericWASM Futhark.CodeGen.Backends.MulticoreC+ Futhark.CodeGen.Backends.MulticoreC.Boilerplate Futhark.CodeGen.Backends.MulticoreISPC Futhark.CodeGen.Backends.MulticoreWASM Futhark.CodeGen.Backends.PyOpenCL@@ -263,7 +267,6 @@ Futhark.CodeGen.ImpGen.Sequential Futhark.CodeGen.ImpGen.Transpose Futhark.CodeGen.OpenCL.Heuristics- Futhark.CodeGen.SetDefaultSpace Futhark.Compiler Futhark.Compiler.CLI Futhark.Compiler.Config@@ -299,6 +302,7 @@ Futhark.IR.Prop.TypeOf Futhark.IR.Prop.Types Futhark.IR.Rep+ Futhark.IR.Rephrase Futhark.IR.RetType Futhark.IR.SOACS Futhark.IR.SOACS.SOAC@@ -348,7 +352,6 @@ Futhark.Optimise.ArrayShortCircuiting Futhark.Optimise.ArrayShortCircuiting.ArrayCoalescing Futhark.Optimise.ArrayShortCircuiting.DataStructs- Futhark.Optimise.ArrayShortCircuiting.LastUse Futhark.Optimise.ArrayShortCircuiting.MemRefAggreg Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis Futhark.Optimise.MergeGPUBodies@@ -507,7 +510,6 @@ , transformers >=0.3 , vector >=0.12 , versions >=5.0.0- , zip-archive >=0.3.1.1 , zlib >=0.6.1.2 , statistics , mwc-random@@ -517,7 +519,7 @@ executable futhark import: common main-is: src/main.hs- ghc-options: -threaded -rtsopts "-with-rtsopts=-N -qg1 -A16M"+ ghc-options: -threaded -rtsopts "-with-rtsopts=-maxN16 -qg1 -A16M" build-depends: base, futhark test-suite unit
prelude/math.fut view
@@ -187,6 +187,8 @@ val log2: t -> t -- | Base-10 logarithm. val log10: t -> t+ -- | Compute `log (1 + x)` accurately even when `x` is very small.+ val log1p: t -> t -- | Round towards infinity. val ceil : t -> t@@ -927,6 +929,7 @@ def log (x: f64) = intrinsics.log64 x def log2 (x: f64) = intrinsics.log2_64 x def log10 (x: f64) = intrinsics.log10_64 x+ def log1p (x: f64) = intrinsics.log1p_64 x def exp (x: f64) = intrinsics.exp64 x def sin (x: f64) = intrinsics.sin64 x def cos (x: f64) = intrinsics.cos64 x@@ -1041,6 +1044,7 @@ def log (x: f32) = intrinsics.log32 x def log2 (x: f32) = intrinsics.log2_32 x def log10 (x: f32) = intrinsics.log10_32 x+ def log1p (x: f32) = intrinsics.log1p_32 x def exp (x: f32) = intrinsics.exp32 x def sin (x: f32) = intrinsics.sin32 x def cos (x: f32) = intrinsics.cos32 x@@ -1159,6 +1163,7 @@ def log (x: f16) = intrinsics.log16 x def log2 (x: f16) = intrinsics.log2_16 x def log10 (x: f16) = intrinsics.log10_16 x+ def log1p (x: f16) = intrinsics.log1p_16 x def exp (x: f16) = intrinsics.exp16 x def sin (x: f16) = intrinsics.sin16 x def cos (x: f16) = intrinsics.cos16 x
prelude/soacs.fut view
@@ -211,7 +211,7 @@ def any [n] 'a (f: a -> bool) (as: [n]a): bool = reduce (||) false (map f as) --- | `r = spread x k is vs` produces an array `r` such that `r[i] =+-- | `r = spread k x is vs` produces an array `r` such that `r[i] = -- vs[j]` where `is[j] == i`, or `x` if no such `j` exists. -- Intuitively, `is` is an array indicating where the corresponding -- elements of `vs` should be located in the result. Out-of-bounds
+ rts/c/backends/c.h view
@@ -0,0 +1,61 @@+// Start of backends/c.h++struct futhark_context_config {+ int in_use;+ int debugging;+ int profiling;+ int logging;+ const char *cache_fname;+ int num_tuning_params;+ int64_t *tuning_params;+ const char** tuning_param_names;+ const char** tuning_param_vars;+ const char** tuning_param_classes;+};++static void backend_context_config_setup(struct futhark_context_config* cfg) {+ (void)cfg;+}++static void backend_context_config_teardown(struct futhark_context_config* cfg) {+ (void)cfg;+}++int futhark_context_config_set_tuning_param(struct futhark_context_config* cfg, const char *param_name, size_t param_value) {+ (void)cfg; (void)param_name; (void)param_value;+ return 1;+}++struct futhark_context {+ struct futhark_context_config* cfg;+ int detail_memory;+ int debugging;+ int profiling;+ int profiling_paused;+ int logging;+ lock_t lock;+ char *error;+ lock_t error_lock;+ FILE *log;+ struct constants *constants;+ struct free_list free_list;+ int64_t peak_mem_usage_default;+ int64_t cur_mem_usage_default;+ struct program* program;+};++int backend_context_setup(struct futhark_context* ctx) {+ (void)ctx;+ return 0;+}++void backend_context_teardown(struct futhark_context* ctx) {+ (void)ctx;+}++int futhark_context_sync(struct futhark_context* ctx) {+ (void)ctx;+ return 0;+}++// End of backends/c.h
+ rts/c/backends/cuda.h view
@@ -0,0 +1,947 @@+// Start of backends/cuda.h.++// Forward declarations.+// Invoked by setup_opencl() after the platform and device has been+// found, but before the program is loaded. Its intended use is to+// tune constants based on the selected platform and device.+static void set_tuning_params(struct futhark_context* ctx);+static char* get_failure_msg(int failure_idx, int64_t args[]);++#define CUDA_SUCCEED_FATAL(x) cuda_api_succeed_fatal(x, #x, __FILE__, __LINE__)+#define CUDA_SUCCEED_NONFATAL(x) cuda_api_succeed_nonfatal(x, #x, __FILE__, __LINE__)+#define NVRTC_SUCCEED_FATAL(x) nvrtc_api_succeed_fatal(x, #x, __FILE__, __LINE__)+#define NVRTC_SUCCEED_NONFATAL(x) nvrtc_api_succeed_nonfatal(x, #x, __FILE__, __LINE__)+// Take care not to override an existing error.+#define CUDA_SUCCEED_OR_RETURN(e) { \+ char *serror = CUDA_SUCCEED_NONFATAL(e); \+ if (serror) { \+ if (!ctx->error) { \+ ctx->error = serror; \+ return bad; \+ } else { \+ free(serror); \+ } \+ } \+ }++// CUDA_SUCCEED_OR_RETURN returns the value of the variable 'bad' in+// scope. By default, it will be this one. Create a local variable+// of some other type if needed. This is a bit of a hack, but it+// saves effort in the code generator.+static const int bad = 1;++static inline void cuda_api_succeed_fatal(CUresult res, const char *call,+ const char *file, int line) {+ if (res != CUDA_SUCCESS) {+ const char *err_str;+ cuGetErrorString(res, &err_str);+ if (err_str == NULL) { err_str = "Unknown"; }+ futhark_panic(-1, "%s:%d: CUDA call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, res, err_str);+ }+}++static char* cuda_api_succeed_nonfatal(CUresult res, const char *call,+ const char *file, int line) {+ if (res != CUDA_SUCCESS) {+ const char *err_str;+ cuGetErrorString(res, &err_str);+ if (err_str == NULL) { err_str = "Unknown"; }+ return msgprintf("%s:%d: CUDA call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, res, err_str);+ } else {+ return NULL;+ }+}++static inline void nvrtc_api_succeed_fatal(nvrtcResult res, const char *call,+ const char *file, int line) {+ if (res != NVRTC_SUCCESS) {+ const char *err_str = nvrtcGetErrorString(res);+ futhark_panic(-1, "%s:%d: NVRTC call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, res, err_str);+ }+}++static char* nvrtc_api_succeed_nonfatal(nvrtcResult res, const char *call,+ const char *file, int line) {+ if (res != NVRTC_SUCCESS) {+ const char *err_str = nvrtcGetErrorString(res);+ return msgprintf("%s:%d: NVRTC call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, res, err_str);+ } else {+ return NULL;+ }+}++struct futhark_context_config {+ int in_use;+ int debugging;+ int profiling;+ int logging;+ const char *cache_fname;+ int num_tuning_params;+ int64_t *tuning_params;+ const char** tuning_param_names;+ const char** tuning_param_vars;+ const char** tuning_param_classes;+ // Uniform fields above.++ int num_nvrtc_opts;+ const char **nvrtc_opts;++ const char *preferred_device;+ int preferred_device_num;++ const char *dump_program_to;+ const char *load_program_from;++ const char *dump_ptx_to;+ const char *load_ptx_from;++ size_t default_block_size;+ size_t default_grid_size;+ size_t default_tile_size;+ size_t default_reg_tile_size;+ size_t default_threshold;++ int default_block_size_changed;+ int default_grid_size_changed;+ int default_tile_size_changed;+};++static void backend_context_config_setup(struct futhark_context_config *cfg) {+ cfg->num_nvrtc_opts = 0;+ cfg->nvrtc_opts = (const char**) malloc(sizeof(const char*));+ cfg->nvrtc_opts[0] = NULL;++ cfg->preferred_device_num = 0;+ cfg->preferred_device = "";+ cfg->dump_program_to = NULL;+ cfg->load_program_from = NULL;++ cfg->dump_ptx_to = NULL;+ cfg->load_ptx_from = NULL;++ cfg->default_block_size = 256;+ cfg->default_grid_size = 0; // Set properly later.+ cfg->default_tile_size = 32;+ cfg->default_reg_tile_size = 2;+ cfg->default_threshold = 32*1024;++ cfg->default_block_size_changed = 0;+ cfg->default_grid_size_changed = 0;+ cfg->default_tile_size_changed = 0;+}++static void backend_context_config_teardown(struct futhark_context_config* cfg) {+ free(cfg->nvrtc_opts);+}++void futhark_context_config_add_nvrtc_option(struct futhark_context_config *cfg, const char *opt) {+ cfg->nvrtc_opts[cfg->num_nvrtc_opts] = opt;+ cfg->num_nvrtc_opts++;+ cfg->nvrtc_opts = (const char **) realloc(cfg->nvrtc_opts, (cfg->num_nvrtc_opts + 1) * sizeof(const char *));+ cfg->nvrtc_opts[cfg->num_nvrtc_opts] = NULL;+}++void futhark_context_config_set_device(struct futhark_context_config *cfg, const char *s) {+ int x = 0;+ if (*s == '#') {+ s++;+ while (isdigit(*s)) {+ x = x * 10 + (*s++)-'0';+ }+ // Skip trailing spaces.+ while (isspace(*s)) {+ s++;+ }+ }+ cfg->preferred_device = s;+ cfg->preferred_device_num = x;+}++void futhark_context_config_dump_program_to(struct futhark_context_config *cfg, const char *path) {+ cfg->dump_program_to = path;+}++void futhark_context_config_load_program_from(struct futhark_context_config *cfg, const char *path) {+ cfg->load_program_from = path;+}++void futhark_context_config_dump_ptx_to(struct futhark_context_config *cfg, const char *path) {+ cfg->dump_ptx_to = path;+}++void futhark_context_config_load_ptx_from(struct futhark_context_config *cfg, const char *path) {+ cfg->load_ptx_from = path;+}++void futhark_context_config_set_default_group_size(struct futhark_context_config *cfg, int size) {+ cfg->default_block_size = size;+ cfg->default_block_size_changed = 1;+}++void futhark_context_config_set_default_num_groups(struct futhark_context_config *cfg, int num) {+ cfg->default_grid_size = num;+ cfg->default_grid_size_changed = 1;+}++void futhark_context_config_set_default_tile_size(struct futhark_context_config *cfg, int size) {+ cfg->default_tile_size = size;+ cfg->default_tile_size_changed = 1;+}++void futhark_context_config_set_default_reg_tile_size(struct futhark_context_config *cfg, int size) {+ cfg->default_reg_tile_size = size;+}++void futhark_context_config_set_default_threshold(struct futhark_context_config *cfg, int size) {+ cfg->default_threshold = size;+}++int futhark_context_config_set_tuning_param(struct futhark_context_config *cfg,+ const char *param_name,+ size_t new_value) {+ for (int i = 0; i < cfg->num_tuning_params; i++) {+ if (strcmp(param_name, cfg->tuning_param_names[i]) == 0) {+ cfg->tuning_params[i] = new_value;+ return 0;+ }+ }+ if (strcmp(param_name, "default_group_size") == 0) {+ cfg->default_block_size = new_value;+ return 0;+ }+ if (strcmp(param_name, "default_num_groups") == 0) {+ cfg->default_grid_size = new_value;+ return 0;+ }+ if (strcmp(param_name, "default_threshold") == 0) {+ cfg->default_threshold = new_value;+ return 0;+ }+ if (strcmp(param_name, "default_tile_size") == 0) {+ cfg->default_tile_size = new_value;+ return 0;+ }+ if (strcmp(param_name, "default_reg_tile_size") == 0) {+ cfg->default_reg_tile_size = new_value;+ return 0;+ }+ return 1;+}++// A record of something that happened.+struct profiling_record {+ cudaEvent_t *events; // Points to two events.+ int *runs;+ int64_t *runtime;+};++struct futhark_context {+ struct futhark_context_config* cfg;+ int detail_memory;+ int debugging;+ int profiling;+ int profiling_paused;+ int logging;+ lock_t lock;+ char *error;+ lock_t error_lock;+ FILE *log;+ struct constants *constants;+ struct free_list cu_free_list;+ int64_t peak_mem_usage_default;+ int64_t cur_mem_usage_default;+ // Uniform above++ CUdeviceptr global_failure;+ CUdeviceptr global_failure_args;+ struct tuning_params tuning_params;+ // True if a potentially failing kernel has been enqueued.+ int32_t failure_is_an_option;+ int total_runs;+ long int total_runtime;+ int64_t peak_mem_usage_device;+ int64_t cur_mem_usage_device;+ struct program* program;++ CUdevice dev;+ CUcontext cu_ctx;+ CUmodule module;++ struct free_list free_list;++ size_t max_block_size;+ size_t max_grid_size;+ size_t max_tile_size;+ size_t max_threshold;+ size_t max_shared_memory;+ size_t max_bespoke;++ size_t lockstep_width;++ struct profiling_record *profiling_records;+ int profiling_records_capacity;+ int profiling_records_used;+};++#define CU_DEV_ATTR(x) (CU_DEVICE_ATTRIBUTE_##x)+#define device_query(dev,attrib) _device_query(dev, CU_DEV_ATTR(attrib))+static int _device_query(CUdevice dev, CUdevice_attribute attrib) {+ int val;+ CUDA_SUCCEED_FATAL(cuDeviceGetAttribute(&val, attrib, dev));+ return val;+}++#define CU_FUN_ATTR(x) (CU_FUNC_ATTRIBUTE_##x)+#define function_query(fn,attrib) _function_query(dev, CU_FUN_ATTR(attrib))+static int _function_query(CUfunction dev, CUfunction_attribute attrib) {+ int val;+ CUDA_SUCCEED_FATAL(cuFuncGetAttribute(&val, attrib, dev));+ return val;+}++static int cuda_device_setup(struct futhark_context *ctx) {+ struct futhark_context_config *cfg = ctx->cfg;+ char name[256];+ int count, chosen = -1, best_cc = -1;+ int cc_major_best, cc_minor_best;+ int cc_major, cc_minor;+ CUdevice dev;++ CUDA_SUCCEED_FATAL(cuDeviceGetCount(&count));+ if (count == 0) { return 1; }++ int num_device_matches = 0;++ // XXX: Current device selection policy is to choose the device with the+ // highest compute capability (if no preferred device is set).+ // This should maybe be changed, since greater compute capability is not+ // necessarily an indicator of better performance.+ for (int i = 0; i < count; i++) {+ CUDA_SUCCEED_FATAL(cuDeviceGet(&dev, i));++ cc_major = device_query(dev, COMPUTE_CAPABILITY_MAJOR);+ cc_minor = device_query(dev, COMPUTE_CAPABILITY_MINOR);++ CUDA_SUCCEED_FATAL(cuDeviceGetName(name, sizeof(name) - 1, dev));+ name[sizeof(name) - 1] = 0;++ if (cfg->logging) {+ fprintf(stderr, "Device #%d: name=\"%s\", compute capability=%d.%d\n",+ i, name, cc_major, cc_minor);+ }++ if (device_query(dev, COMPUTE_MODE) == CU_COMPUTEMODE_PROHIBITED) {+ if (cfg->logging) {+ fprintf(stderr, "Device #%d is compute-prohibited, ignoring\n", i);+ }+ continue;+ }++ if (best_cc == -1 || cc_major > cc_major_best ||+ (cc_major == cc_major_best && cc_minor > cc_minor_best)) {+ best_cc = i;+ cc_major_best = cc_major;+ cc_minor_best = cc_minor;+ }++ if (strstr(name, cfg->preferred_device) != NULL &&+ num_device_matches++ == cfg->preferred_device_num) {+ chosen = i;+ break;+ }+ }++ if (chosen == -1) { chosen = best_cc; }+ if (chosen == -1) { return 1; }++ if (cfg->logging) {+ fprintf(stderr, "Using device #%d\n", chosen);+ }++ CUDA_SUCCEED_FATAL(cuDeviceGet(&ctx->dev, chosen));+ return 0;+}++static char *concat_fragments(const char *src_fragments[]) {+ size_t src_len = 0;+ const char **p;++ for (p = src_fragments; *p; p++) {+ src_len += strlen(*p);+ }++ char *src = (char*) malloc(src_len + 1);+ size_t n = 0;+ for (p = src_fragments; *p; p++) {+ strcpy(src + n, *p);+ n += strlen(*p);+ }++ return src;+}++static const char *cuda_nvrtc_get_arch(CUdevice dev) {+ struct {+ int major;+ int minor;+ const char *arch_str;+ } static const x[] = {+ { 3, 0, "compute_30" },+ { 3, 2, "compute_32" },+ { 3, 5, "compute_35" },+ { 3, 7, "compute_37" },+ { 5, 0, "compute_50" },+ { 5, 2, "compute_52" },+ { 5, 3, "compute_53" },+ { 6, 0, "compute_60" },+ { 6, 1, "compute_61" },+ { 6, 2, "compute_62" },+ { 7, 0, "compute_70" },+ { 7, 2, "compute_72" },+ { 7, 5, "compute_75" },+ { 8, 0, "compute_80" },+ { 8, 6, "compute_80" },+ { 8, 7, "compute_80" }+ };++ int major = device_query(dev, COMPUTE_CAPABILITY_MAJOR);+ int minor = device_query(dev, COMPUTE_CAPABILITY_MINOR);++ int chosen = -1;+ int num_archs = sizeof(x)/sizeof(x[0]);+ for (int i = 0; i < num_archs; i++) {+ if (x[i].major < major || (x[i].major == major && x[i].minor <= minor)) {+ chosen = i;+ } else {+ break;+ }+ }++ if (chosen == -1) {+ futhark_panic(-1, "Unsupported compute capability %d.%d\n", major, minor);+ }++ if (x[chosen].major != major || x[chosen].minor != minor) {+ fprintf(stderr,+ "Warning: device compute capability is %d.%d, but newest supported by Futhark is %d.%d.\n",+ major, minor, x[chosen].major, x[chosen].minor);+ }++ return x[chosen].arch_str;+}++static void cuda_nvrtc_mk_build_options(struct futhark_context *ctx, const char *extra_opts[],+ char*** opts_out, size_t *n_opts) {+ int arch_set = 0, num_extra_opts;+ struct futhark_context_config *cfg = ctx->cfg;++ // nvrtc cannot handle multiple -arch options. Hence, if one of the+ // extra_opts is -arch, we have to be careful not to do our usual+ // automatic generation.+ for (num_extra_opts = 0; extra_opts[num_extra_opts] != NULL; num_extra_opts++) {+ if (strstr(extra_opts[num_extra_opts], "-arch")+ == extra_opts[num_extra_opts] ||+ strstr(extra_opts[num_extra_opts], "--gpu-architecture")+ == extra_opts[num_extra_opts]) {+ arch_set = 1;+ }+ }++ size_t i = 0, n_opts_alloc = 20 + num_extra_opts + cfg->num_tuning_params;+ char **opts = (char**) malloc(n_opts_alloc * sizeof(char *));+ if (!arch_set) {+ opts[i++] = strdup("-arch");+ opts[i++] = strdup(cuda_nvrtc_get_arch(ctx->dev));+ }+ opts[i++] = strdup("-default-device");+ if (cfg->debugging) {+ opts[i++] = strdup("-G");+ opts[i++] = strdup("-lineinfo");+ } else {+ opts[i++] = strdup("--disable-warnings");+ }+ opts[i++] = msgprintf("-D%s=%d",+ "max_group_size",+ (int)ctx->max_block_size);+ for (int j = 0; j < cfg->num_tuning_params; j++) {+ opts[i++] = msgprintf("-D%s=%zu", cfg->tuning_param_vars[j],+ cfg->tuning_params[j]);+ }+ opts[i++] = msgprintf("-DLOCKSTEP_WIDTH=%zu", ctx->lockstep_width);+ opts[i++] = msgprintf("-DMAX_THREADS_PER_BLOCK=%zu", ctx->max_block_size);++ // Time for the best lines of the code in the entire compiler.+ if (getenv("CUDA_HOME") != NULL) {+ opts[i++] = msgprintf("-I%s/include", getenv("CUDA_HOME"));+ }+ if (getenv("CUDA_ROOT") != NULL) {+ opts[i++] = msgprintf("-I%s/include", getenv("CUDA_ROOT"));+ }+ if (getenv("CUDA_PATH") != NULL) {+ opts[i++] = msgprintf("-I%s/include", getenv("CUDA_PATH"));+ }+ opts[i++] = msgprintf("-I/usr/local/cuda/include");+ opts[i++] = msgprintf("-I/usr/include");++ for (int j = 0; extra_opts[j] != NULL; j++) {+ opts[i++] = strdup(extra_opts[j]);+ }++ *n_opts = i;+ *opts_out = opts;+}++static char* cuda_nvrtc_build(const char *src, const char *opts[], size_t n_opts,+ char **ptx) {+ nvrtcProgram prog;+ char *problem = NULL;++ problem = NVRTC_SUCCEED_NONFATAL(nvrtcCreateProgram(&prog, src, "futhark-cuda", 0, NULL, NULL));++ if (problem) {+ return problem;+ }++ nvrtcResult res = nvrtcCompileProgram(prog, n_opts, opts);+ if (res != NVRTC_SUCCESS) {+ size_t log_size;+ if (nvrtcGetProgramLogSize(prog, &log_size) == NVRTC_SUCCESS) {+ char *log = (char*) malloc(log_size);+ if (nvrtcGetProgramLog(prog, log) == NVRTC_SUCCESS) {+ problem = msgprintf("NVRTC compilation failed.\n\n%s\n", log);+ } else {+ problem = msgprintf("Could not retrieve compilation log\n");+ }+ free(log);+ }+ return problem;+ }++ size_t ptx_size;+ NVRTC_SUCCEED_FATAL(nvrtcGetPTXSize(prog, &ptx_size));+ *ptx = (char*) malloc(ptx_size);+ NVRTC_SUCCEED_FATAL(nvrtcGetPTX(prog, *ptx));++ NVRTC_SUCCEED_FATAL(nvrtcDestroyProgram(&prog));++ return NULL;+}++static void cuda_load_ptx_from_cache(struct futhark_context_config *cfg,+ const char *src,+ const char *opts[], size_t n_opts,+ struct cache_hash *h, const char *cache_fname,+ char **ptx) {+ if (cfg->logging) {+ fprintf(stderr, "Restoring cache from from %s...\n", cache_fname);+ }+ cache_hash_init(h);+ for (size_t i = 0; i < n_opts; i++) {+ cache_hash(h, opts[i], strlen(opts[i]));+ }+ cache_hash(h, src, strlen(src));+ size_t ptxsize;+ errno = 0;+ if (cache_restore(cache_fname, h, (unsigned char**)ptx, &ptxsize) != 0) {+ if (cfg->logging) {+ fprintf(stderr, "Failed to restore cache (errno: %s)\n", strerror(errno));+ }+ }+}++static void cuda_size_setup(struct futhark_context *ctx)+{+ struct futhark_context_config *cfg = ctx->cfg;+ if (cfg->default_block_size > ctx->max_block_size) {+ if (cfg->default_block_size_changed) {+ fprintf(stderr,+ "Note: Device limits default block size to %zu (down from %zu).\n",+ ctx->max_block_size, cfg->default_block_size);+ }+ cfg->default_block_size = ctx->max_block_size;+ }+ if (cfg->default_grid_size > ctx->max_grid_size) {+ if (cfg->default_grid_size_changed) {+ fprintf(stderr,+ "Note: Device limits default grid size to %zu (down from %zu).\n",+ ctx->max_grid_size, cfg->default_grid_size);+ }+ cfg->default_grid_size = ctx->max_grid_size;+ }+ if (cfg->default_tile_size > ctx->max_tile_size) {+ if (cfg->default_tile_size_changed) {+ fprintf(stderr,+ "Note: Device limits default tile size to %zu (down from %zu).\n",+ ctx->max_tile_size, cfg->default_tile_size);+ }+ cfg->default_tile_size = ctx->max_tile_size;+ }++ if (!cfg->default_grid_size_changed) {+ cfg->default_grid_size =+ (device_query(ctx->dev, MULTIPROCESSOR_COUNT) *+ device_query(ctx->dev, MAX_THREADS_PER_MULTIPROCESSOR))+ / cfg->default_block_size;+ }++ for (int i = 0; i < cfg->num_tuning_params; i++) {+ const char *size_class = cfg->tuning_param_classes[i];+ int64_t *size_value = &cfg->tuning_params[i];+ const char* size_name = cfg->tuning_param_names[i];+ int64_t max_value = 0, default_value = 0;++ if (strstr(size_class, "group_size") == size_class) {+ max_value = ctx->max_block_size;+ default_value = cfg->default_block_size;+ } else if (strstr(size_class, "num_groups") == size_class) {+ max_value = ctx->max_grid_size;+ default_value = cfg->default_grid_size;+ // XXX: as a quick and dirty hack, use twice as many threads for+ // histograms by default. We really should just be smarter+ // about sizes somehow.+ if (strstr(size_name, ".seghist_") != NULL) {+ default_value *= 2;+ }+ } else if (strstr(size_class, "tile_size") == size_class) {+ max_value = ctx->max_tile_size;+ default_value = cfg->default_tile_size;+ } else if (strstr(size_class, "reg_tile_size") == size_class) {+ max_value = 0; // No limit.+ default_value = cfg->default_reg_tile_size;+ } else if (strstr(size_class, "threshold") == size_class) {+ // Threshold can be as large as it takes.+ default_value = cfg->default_threshold;+ } else {+ // Bespoke sizes have no limit or default.+ }++ if (*size_value == 0) {+ *size_value = default_value;+ } else if (max_value > 0 && *size_value > max_value) {+ fprintf(stderr, "Note: Device limits %s to %zu (down from %zu)\n",+ size_name, max_value, *size_value);+ *size_value = max_value;+ }+ }+}++static char* cuda_module_setup(struct futhark_context *ctx,+ const char *src_fragments[],+ const char *extra_opts[],+ const char* cache_fname) {+ char *ptx = NULL, *src = NULL;+ struct futhark_context_config *cfg = ctx->cfg;++ if (cfg->load_program_from == NULL) {+ src = concat_fragments(src_fragments);+ } else {+ src = slurp_file(cfg->load_program_from, NULL);+ }++ if (cfg->load_ptx_from) {+ if (cfg->load_program_from != NULL) {+ fprintf(stderr,+ "WARNING: Using PTX from %s instead of C code from %s\n",+ cfg->load_ptx_from, cfg->load_program_from);+ }+ ptx = slurp_file(cfg->load_ptx_from, NULL);+ }++ if (cfg->dump_program_to != NULL) {+ dump_file(cfg->dump_program_to, src, strlen(src));+ }++ char **opts;+ size_t n_opts;+ cuda_nvrtc_mk_build_options(ctx, extra_opts, &opts, &n_opts);++ if (cfg->logging) {+ fprintf(stderr, "NVRTC compile options:\n");+ for (size_t j = 0; j < n_opts; j++) {+ fprintf(stderr, "\t%s\n", opts[j]);+ }+ fprintf(stderr, "\n");+ }++ struct cache_hash h;+ int loaded_ptx_from_cache = 0;+ if (cache_fname != NULL) {+ cuda_load_ptx_from_cache(cfg, src, (const char**)opts, n_opts, &h, cache_fname, &ptx);++ if (ptx != NULL) {+ if (cfg->logging) {+ fprintf(stderr, "Restored PTX from cache; now loading module...\n");+ }+ if (cuModuleLoadData(&ctx->module, ptx) == CUDA_SUCCESS) {+ if (cfg->logging) {+ fprintf(stderr, "Success!\n");+ }+ loaded_ptx_from_cache = 1;+ } else {+ if (cfg->logging) {+ fprintf(stderr, "Failed!\n");+ }+ free(ptx);+ ptx = NULL;+ }+ }+ }++ if (ptx == NULL) {+ char* problem = cuda_nvrtc_build(src, (const char**)opts, n_opts, &ptx);+ if (problem != NULL) {+ free(src);+ return problem;+ }+ }++ if (cfg->dump_ptx_to != NULL) {+ dump_file(cfg->dump_ptx_to, ptx, strlen(ptx));+ }++ if (!loaded_ptx_from_cache) {+ CUDA_SUCCEED_FATAL(cuModuleLoadData(&ctx->module, ptx));+ }++ if (cache_fname != NULL && !loaded_ptx_from_cache) {+ if (cfg->logging) {+ fprintf(stderr, "Caching PTX in %s...\n", cache_fname);+ }+ errno = 0;+ if (cache_store(cache_fname, &h, (const unsigned char*)ptx, strlen(ptx)) != 0) {+ fprintf(stderr, "Failed to cache PTX: %s\n", strerror(errno));+ }+ }++ for (size_t i = 0; i < n_opts; i++) {+ free((char *)opts[i]);+ }+ free(opts);++ free(ptx);+ if (src != NULL) {+ free(src);+ }++ return NULL;+}++static char* cuda_setup(struct futhark_context *ctx, const char *src_fragments[],+ const char *extra_opts[], const char* cache_fname) {+ CUDA_SUCCEED_FATAL(cuInit(0));++ if (cuda_device_setup(ctx) != 0) {+ futhark_panic(-1, "No suitable CUDA device found.\n");+ }+ CUDA_SUCCEED_FATAL(cuCtxCreate(&ctx->cu_ctx, 0, ctx->dev));++ free_list_init(&ctx->cu_free_list);++ ctx->max_shared_memory = device_query(ctx->dev, MAX_SHARED_MEMORY_PER_BLOCK);+ ctx->max_block_size = device_query(ctx->dev, MAX_THREADS_PER_BLOCK);+ ctx->max_grid_size = device_query(ctx->dev, MAX_GRID_DIM_X);+ ctx->max_tile_size = sqrt(ctx->max_block_size);+ ctx->max_threshold = 0;+ ctx->max_bespoke = 0;+ ctx->lockstep_width = device_query(ctx->dev, WARP_SIZE);++ cuda_size_setup(ctx);+ return cuda_module_setup(ctx, src_fragments, extra_opts, cache_fname);+}++// Count up the runtime all the profiling_records that occured during execution.+// Also clears the buffer of profiling_records.+static cudaError_t cuda_tally_profiling_records(struct futhark_context *ctx) {+ cudaError_t err;+ for (int i = 0; i < ctx->profiling_records_used; i++) {+ struct profiling_record record = ctx->profiling_records[i];++ float ms;+ if ((err = cudaEventElapsedTime(&ms, record.events[0], record.events[1])) != cudaSuccess) {+ return err;+ }++ // CUDA provides milisecond resolution, but we want microseconds.+ *record.runs += 1;+ *record.runtime += ms*1000;++ if ((err = cudaEventDestroy(record.events[0])) != cudaSuccess) {+ return err;+ }+ if ((err = cudaEventDestroy(record.events[1])) != cudaSuccess) {+ return err;+ }++ free(record.events);+ }++ ctx->profiling_records_used = 0;++ return cudaSuccess;+}++// Returns pointer to two events.+static cudaEvent_t* cuda_get_events(struct futhark_context *ctx, int *runs, int64_t *runtime) {+ if (ctx->profiling_records_used == ctx->profiling_records_capacity) {+ ctx->profiling_records_capacity *= 2;+ ctx->profiling_records =+ realloc(ctx->profiling_records,+ ctx->profiling_records_capacity *+ sizeof(struct profiling_record));+ }+ cudaEvent_t *events = calloc(2, sizeof(cudaEvent_t));+ cudaEventCreate(&events[0]);+ cudaEventCreate(&events[1]);+ ctx->profiling_records[ctx->profiling_records_used].events = events;+ ctx->profiling_records[ctx->profiling_records_used].runs = runs;+ ctx->profiling_records[ctx->profiling_records_used].runtime = runtime;+ ctx->profiling_records_used++;+ return events;+}++static CUresult cuda_alloc(struct futhark_context *ctx, FILE *log,+ size_t min_size, const char *tag,+ CUdeviceptr *mem_out, size_t *size_out) {+ if (min_size < sizeof(int)) {+ min_size = sizeof(int);+ }++ if (free_list_find(&ctx->cu_free_list, min_size, tag, size_out, (fl_mem*)mem_out) == 0) {+ if (*size_out >= min_size) {+ if (ctx->cfg->debugging) {+ fprintf(log, "No need to allocate: Found a block in the free list.\n");+ }+ return CUDA_SUCCESS;+ } else {+ if (ctx->cfg->debugging) {+ fprintf(log, "Found a free block, but it was too small.\n");+ }++ CUresult res = cuMemFree(*mem_out);+ if (res != CUDA_SUCCESS) {+ return res;+ }+ }+ }++ *size_out = min_size;++ if (ctx->cfg->debugging) {+ fprintf(log, "Actually allocating the desired block.\n");+ }++ CUresult res = cuMemAlloc(mem_out, min_size);+ while (res == CUDA_ERROR_OUT_OF_MEMORY) {+ CUdeviceptr mem;+ if (free_list_first(&ctx->cu_free_list, (fl_mem*)&mem) == 0) {+ res = cuMemFree(mem);+ if (res != CUDA_SUCCESS) {+ return res;+ }+ } else {+ break;+ }+ res = cuMemAlloc(mem_out, min_size);+ }++ return res;+}++static CUresult cuda_free(struct futhark_context *ctx,+ CUdeviceptr mem, size_t size, const char *tag) {+ free_list_insert(&ctx->cu_free_list, size, (fl_mem)mem, tag);+ return CUDA_SUCCESS;+}++static CUresult cuda_free_all(struct futhark_context *ctx) {+ CUdeviceptr mem;+ free_list_pack(&ctx->cu_free_list);+ while (free_list_first(&ctx->cu_free_list, (fl_mem*)&mem) == 0) {+ CUresult res = cuMemFree(mem);+ if (res != CUDA_SUCCESS) {+ return res;+ }+ }++ return CUDA_SUCCESS;+}++int futhark_context_sync(struct futhark_context* ctx) {+ CUDA_SUCCEED_OR_RETURN(cuCtxPushCurrent(ctx->cu_ctx));+ CUDA_SUCCEED_OR_RETURN(cuCtxSynchronize());+ if (ctx->failure_is_an_option) {+ // Check for any delayed error.+ int32_t failure_idx;+ CUDA_SUCCEED_OR_RETURN(+ cuMemcpyDtoH(&failure_idx,+ ctx->global_failure,+ sizeof(int32_t)));+ ctx->failure_is_an_option = 0;++ if (failure_idx >= 0) {+ // We have to clear global_failure so that the next entry point+ // is not considered a failure from the start.+ int32_t no_failure = -1;+ CUDA_SUCCEED_OR_RETURN(+ cuMemcpyHtoD(ctx->global_failure,+ &no_failure,+ sizeof(int32_t)));++ int64_t args[max_failure_args+1];+ CUDA_SUCCEED_OR_RETURN(+ cuMemcpyDtoH(&args,+ ctx->global_failure_args,+ sizeof(args)));++ ctx->error = get_failure_msg(failure_idx, args);++ return FUTHARK_PROGRAM_ERROR;+ }+ }+ CUDA_SUCCEED_OR_RETURN(cuCtxPopCurrent(&ctx->cu_ctx));+ return 0;+}++int backend_context_setup(struct futhark_context* ctx) {+ ctx->profiling_records_capacity = 200;+ ctx->profiling_records_used = 0;+ ctx->profiling_records =+ malloc(ctx->profiling_records_capacity *+ sizeof(struct profiling_record));+ ctx->failure_is_an_option = 0;+ ctx->total_runs = 0;+ ctx->total_runtime = 0;+ ctx->peak_mem_usage_device = 0;+ ctx->cur_mem_usage_device = 0;++ ctx->error = cuda_setup(ctx, cuda_program, ctx->cfg->nvrtc_opts, ctx->cfg->cache_fname);++ if (ctx->error != NULL) {+ futhark_panic(1, "%s\n", ctx->error);+ }++ int32_t no_error = -1;+ CUDA_SUCCEED_FATAL(cuMemAlloc(&ctx->global_failure, sizeof(no_error)));+ CUDA_SUCCEED_FATAL(cuMemcpyHtoD(ctx->global_failure, &no_error, sizeof(no_error)));+ // The +1 is to avoid zero-byte allocations.+ CUDA_SUCCEED_FATAL(cuMemAlloc(&ctx->global_failure_args, sizeof(int64_t)*(max_failure_args+1)));++ set_tuning_params(ctx);+ return 0;+}++void backend_context_teardown(struct futhark_context* ctx) {+ cuMemFree(ctx->global_failure);+ cuMemFree(ctx->global_failure_args);+ CUDA_SUCCEED_FATAL(cuda_free_all(ctx));+ (void)cuda_tally_profiling_records(ctx);+ free(ctx->profiling_records);+ CUDA_SUCCEED_FATAL(cuModuleUnload(ctx->module));+ CUDA_SUCCEED_FATAL(cuCtxDestroy(ctx->cu_ctx));+}++// End of backends/cuda.h.
+ rts/c/backends/multicore.h view
@@ -0,0 +1,95 @@+// Start of backends/multicore.h++struct futhark_context_config {+ int in_use;+ int debugging;+ int profiling;+ int logging;+ const char *cache_fname;+ int num_tuning_params;+ int64_t *tuning_params;+ const char** tuning_param_names;+ const char** tuning_param_vars;+ const char** tuning_param_classes;+ // Uniform fields above.++ int num_threads;+};++static void backend_context_config_setup(struct futhark_context_config* cfg) {+ cfg->num_threads = 0;+}++static void backend_context_config_teardown(struct futhark_context_config* cfg) {+ (void)cfg;+}++void futhark_context_config_set_num_threads(struct futhark_context_config *cfg, int n) {+ cfg->num_threads = n;+}++int futhark_context_config_set_tuning_param(struct futhark_context_config* cfg, const char *param_name, size_t param_value) {+ (void)cfg; (void)param_name; (void)param_value;+ return 1;+}++struct futhark_context {+ struct futhark_context_config* cfg;+ int detail_memory;+ int debugging;+ int profiling;+ int profiling_paused;+ int logging;+ lock_t lock;+ char *error;+ lock_t error_lock;+ FILE *log;+ struct constants *constants;+ struct free_list free_list;+ int64_t peak_mem_usage_default;+ int64_t cur_mem_usage_default;+ struct program* program;+ // Uniform fields above.++ struct scheduler scheduler;+ int total_runs;+ long int total_runtime;+ int64_t tuning_timing;+ int64_t tuning_iter;+};++int backend_context_setup(struct futhark_context* ctx) {+ // Initialize rand()+ fast_srand(time(0));++ int tune_kappa = 0;+ double kappa = 5.1f * 1000;++ if (tune_kappa) {+ if (determine_kappa(&kappa) != 0) {+ ctx->error = strdup("Failed to determine kappa.");+ return 1;+ }+ }++ if (scheduler_init(&ctx->scheduler,+ ctx->cfg->num_threads > 0 ?+ ctx->cfg->num_threads : num_processors(),+ kappa) != 0) {+ ctx->error = strdup("Failed to initialise scheduler.");+ return 1;+ }++ return 0;+}++void backend_context_teardown(struct futhark_context* ctx) {+ (void)scheduler_destroy(&ctx->scheduler);+}++int futhark_context_sync(struct futhark_context* ctx) {+ (void)ctx;+ return 0;+}++// End of backends/multicore.h
+ rts/c/backends/opencl.h view
@@ -0,0 +1,1232 @@+// Start of backends/opencl.h++// Forward declarations.+struct opencl_device_option;+// Invoked by setup_opencl() after the platform and device has been+// found, but before the program is loaded. Its intended use is to+// tune constants based on the selected platform and device.+static void post_opencl_setup(struct futhark_context*, struct opencl_device_option*);+static void set_tuning_params(struct futhark_context* ctx);+static char* get_failure_msg(int failure_idx, int64_t args[]);++#define OPENCL_SUCCEED_FATAL(e) opencl_succeed_fatal(e, #e, __FILE__, __LINE__)+#define OPENCL_SUCCEED_NONFATAL(e) opencl_succeed_nonfatal(e, #e, __FILE__, __LINE__)+// Take care not to override an existing error.+#define OPENCL_SUCCEED_OR_RETURN(e) { \+ char *serror = OPENCL_SUCCEED_NONFATAL(e); \+ if (serror) { \+ if (!ctx->error) { \+ ctx->error = serror; \+ return bad; \+ } else { \+ free(serror); \+ } \+ } \+ }++// OPENCL_SUCCEED_OR_RETURN returns the value of the variable 'bad' in+// scope. By default, it will be this one. Create a local variable+// of some other type if needed. This is a bit of a hack, but it+// saves effort in the code generator.+static const int bad = 1;++static const char* opencl_error_string(cl_int err) {+ switch (err) {+ case CL_SUCCESS: return "Success!";+ case CL_DEVICE_NOT_FOUND: return "Device not found.";+ case CL_DEVICE_NOT_AVAILABLE: return "Device not available";+ case CL_COMPILER_NOT_AVAILABLE: return "Compiler not available";+ case CL_MEM_OBJECT_ALLOCATION_FAILURE: return "Memory object allocation failure";+ case CL_OUT_OF_RESOURCES: return "Out of resources";+ case CL_OUT_OF_HOST_MEMORY: return "Out of host memory";+ case CL_PROFILING_INFO_NOT_AVAILABLE: return "Profiling information not available";+ case CL_MEM_COPY_OVERLAP: return "Memory copy overlap";+ case CL_IMAGE_FORMAT_MISMATCH: return "Image format mismatch";+ case CL_IMAGE_FORMAT_NOT_SUPPORTED: return "Image format not supported";+ case CL_BUILD_PROGRAM_FAILURE: return "Program build failure";+ case CL_MAP_FAILURE: return "Map failure";+ case CL_INVALID_VALUE: return "Invalid value";+ case CL_INVALID_DEVICE_TYPE: return "Invalid device type";+ case CL_INVALID_PLATFORM: return "Invalid platform";+ case CL_INVALID_DEVICE: return "Invalid device";+ case CL_INVALID_CONTEXT: return "Invalid context";+ case CL_INVALID_QUEUE_PROPERTIES: return "Invalid queue properties";+ case CL_INVALID_COMMAND_QUEUE: return "Invalid command queue";+ case CL_INVALID_HOST_PTR: return "Invalid host pointer";+ case CL_INVALID_MEM_OBJECT: return "Invalid memory object";+ case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: return "Invalid image format descriptor";+ case CL_INVALID_IMAGE_SIZE: return "Invalid image size";+ case CL_INVALID_SAMPLER: return "Invalid sampler";+ case CL_INVALID_BINARY: return "Invalid binary";+ case CL_INVALID_BUILD_OPTIONS: return "Invalid build options";+ case CL_INVALID_PROGRAM: return "Invalid program";+ case CL_INVALID_PROGRAM_EXECUTABLE: return "Invalid program executable";+ case CL_INVALID_KERNEL_NAME: return "Invalid kernel name";+ case CL_INVALID_KERNEL_DEFINITION: return "Invalid kernel definition";+ case CL_INVALID_KERNEL: return "Invalid kernel";+ case CL_INVALID_ARG_INDEX: return "Invalid argument index";+ case CL_INVALID_ARG_VALUE: return "Invalid argument value";+ case CL_INVALID_ARG_SIZE: return "Invalid argument size";+ case CL_INVALID_KERNEL_ARGS: return "Invalid kernel arguments";+ case CL_INVALID_WORK_DIMENSION: return "Invalid work dimension";+ case CL_INVALID_WORK_GROUP_SIZE: return "Invalid work group size";+ case CL_INVALID_WORK_ITEM_SIZE: return "Invalid work item size";+ case CL_INVALID_GLOBAL_OFFSET: return "Invalid global offset";+ case CL_INVALID_EVENT_WAIT_LIST: return "Invalid event wait list";+ case CL_INVALID_EVENT: return "Invalid event";+ case CL_INVALID_OPERATION: return "Invalid operation";+ case CL_INVALID_GL_OBJECT: return "Invalid OpenGL object";+ case CL_INVALID_BUFFER_SIZE: return "Invalid buffer size";+ case CL_INVALID_MIP_LEVEL: return "Invalid mip-map level";+ default: return "Unknown";+ }+}++static void opencl_succeed_fatal(cl_int ret,+ const char *call,+ const char *file,+ int line) {+ if (ret != CL_SUCCESS) {+ futhark_panic(-1, "%s:%d: OpenCL call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, ret, opencl_error_string(ret));+ }+}++static char* opencl_succeed_nonfatal(cl_int ret,+ const char *call,+ const char *file,+ int line) {+ if (ret != CL_SUCCESS) {+ return msgprintf("%s:%d: OpenCL call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, ret, opencl_error_string(ret));+ } else {+ return NULL;+ }+}++struct futhark_context_config {+ int in_use;+ int debugging;+ int profiling;+ int logging;+ const char *cache_fname;+ int num_tuning_params;+ int64_t *tuning_params;+ const char** tuning_param_names;+ const char** tuning_param_vars;+ const char** tuning_param_classes;+ // Uniform fields above.++ int preferred_device_num;+ const char *preferred_platform;+ const char *preferred_device;+ int ignore_blacklist;++ const char* dump_program_to;+ const char* load_program_from;+ const char* dump_binary_to;+ const char* load_binary_from;++ size_t default_group_size;+ size_t default_num_groups;+ size_t default_tile_size;+ size_t default_reg_tile_size;+ size_t default_threshold;++ int default_group_size_changed;+ int default_tile_size_changed;+ int num_build_opts;+ const char **build_opts;++ cl_command_queue queue;+ int queue_set;+};++static void backend_context_config_setup(struct futhark_context_config* cfg) {+ cfg->num_build_opts = 0;+ cfg->build_opts = (const char**) malloc(sizeof(const char*));+ cfg->build_opts[0] = NULL;+ cfg->preferred_device_num = 0;+ cfg->preferred_platform = "";+ cfg->preferred_device = "";+ cfg->ignore_blacklist = 0;+ cfg->dump_program_to = NULL;+ cfg->load_program_from = NULL;+ cfg->dump_binary_to = NULL;+ cfg->load_binary_from = NULL;++ // The following are dummy sizes that mean the concrete defaults+ // will be set during initialisation via hardware-inspection-based+ // heuristics.+ cfg->default_group_size = 0;+ cfg->default_num_groups = 0;+ cfg->default_tile_size = 0;+ cfg->default_reg_tile_size = 0;+ cfg->default_threshold = 0;++ cfg->default_group_size_changed = 0;+ cfg->default_tile_size_changed = 0;++ cfg->queue_set = 0;+}++static void backend_context_config_teardown(struct futhark_context_config* cfg) {+ free(cfg->build_opts);+}++void futhark_context_config_add_build_option(struct futhark_context_config* cfg, const char *opt) {+ cfg->build_opts[cfg->num_build_opts] = opt;+ cfg->num_build_opts++;+ cfg->build_opts = (const char**) realloc(cfg->build_opts, (cfg->num_build_opts+1) * sizeof(const char*));+ cfg->build_opts[cfg->num_build_opts] = NULL;+}++void futhark_context_config_set_device(struct futhark_context_config *cfg, const char* s) {+ int x = 0;+ if (*s == '#') {+ s++;+ while (isdigit(*s)) {+ x = x * 10 + (*s++)-'0';+ }+ // Skip trailing spaces.+ while (isspace(*s)) {+ s++;+ }+ }+ cfg->preferred_device = s;+ cfg->preferred_device_num = x;+ cfg->ignore_blacklist = 1;+}++void futhark_context_config_set_platform(struct futhark_context_config *cfg, const char *s) {+ cfg->preferred_platform = s;+ cfg->ignore_blacklist = 1;+}++void futhark_context_config_set_command_queue(struct futhark_context_config *cfg, cl_command_queue q) {+ cfg->queue = q;+ cfg->queue_set = 1;+}++struct opencl_device_option {+ cl_platform_id platform;+ cl_device_id device;+ cl_device_type device_type;+ char *platform_name;+ char *device_name;+};++static char* opencl_platform_info(cl_platform_id platform,+ cl_platform_info param) {+ size_t req_bytes;+ char *info;++ OPENCL_SUCCEED_FATAL(clGetPlatformInfo(platform, param, 0, NULL, &req_bytes));++ info = (char*) malloc(req_bytes);++ OPENCL_SUCCEED_FATAL(clGetPlatformInfo(platform, param, req_bytes, info, NULL));++ return info;+}++static char* opencl_device_info(cl_device_id device,+ cl_device_info param) {+ size_t req_bytes;+ char *info;++ OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device, param, 0, NULL, &req_bytes));++ info = (char*) malloc(req_bytes);++ OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device, param, req_bytes, info, NULL));++ return info;+}++static int is_blacklisted(const char *platform_name, const char *device_name,+ const struct futhark_context_config *cfg) {+ if (strcmp(cfg->preferred_platform, "") != 0 ||+ strcmp(cfg->preferred_device, "") != 0) {+ return 0;+ } else if (strstr(platform_name, "Apple") != NULL &&+ strstr(device_name, "Intel(R) Core(TM)") != NULL) {+ return 1;+ } else {+ return 0;+ }+}++static void opencl_all_device_options(struct opencl_device_option **devices_out,+ size_t *num_devices_out) {+ size_t num_devices = 0, num_devices_added = 0;++ cl_platform_id *all_platforms;+ cl_uint *platform_num_devices;++ cl_uint num_platforms;++ // Find the number of platforms.+ OPENCL_SUCCEED_FATAL(clGetPlatformIDs(0, NULL, &num_platforms));++ // Make room for them.+ all_platforms = calloc(num_platforms, sizeof(cl_platform_id));+ platform_num_devices = calloc(num_platforms, sizeof(cl_uint));++ // Fetch all the platforms.+ OPENCL_SUCCEED_FATAL(clGetPlatformIDs(num_platforms, all_platforms, NULL));++ // Count the number of devices for each platform, as well as the+ // total number of devices.+ for (cl_uint i = 0; i < num_platforms; i++) {+ if (clGetDeviceIDs(all_platforms[i], CL_DEVICE_TYPE_ALL,+ 0, NULL, &platform_num_devices[i]) == CL_SUCCESS) {+ num_devices += platform_num_devices[i];+ } else {+ platform_num_devices[i] = 0;+ }+ }++ // Make room for all the device options.+ struct opencl_device_option *devices =+ calloc(num_devices, sizeof(struct opencl_device_option));++ // Loop through the platforms, getting information about their devices.+ for (cl_uint i = 0; i < num_platforms; i++) {+ cl_platform_id platform = all_platforms[i];+ cl_uint num_platform_devices = platform_num_devices[i];++ if (num_platform_devices == 0) {+ continue;+ }++ char *platform_name = opencl_platform_info(platform, CL_PLATFORM_NAME);+ cl_device_id *platform_devices =+ calloc(num_platform_devices, sizeof(cl_device_id));++ // Fetch all the devices.+ OPENCL_SUCCEED_FATAL(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL,+ num_platform_devices, platform_devices, NULL));++ // Loop through the devices, adding them to the devices array.+ for (cl_uint i = 0; i < num_platform_devices; i++) {+ char *device_name = opencl_device_info(platform_devices[i], CL_DEVICE_NAME);+ devices[num_devices_added].platform = platform;+ devices[num_devices_added].device = platform_devices[i];+ OPENCL_SUCCEED_FATAL(clGetDeviceInfo(platform_devices[i], CL_DEVICE_TYPE,+ sizeof(cl_device_type),+ &devices[num_devices_added].device_type,+ NULL));+ // We don't want the structs to share memory, so copy the platform name.+ // Each device name is already unique.+ devices[num_devices_added].platform_name = strclone(platform_name);+ devices[num_devices_added].device_name = device_name;+ num_devices_added++;+ }+ free(platform_devices);+ free(platform_name);+ }+ free(all_platforms);+ free(platform_num_devices);++ *devices_out = devices;+ *num_devices_out = num_devices;+}++void futhark_context_config_select_device_interactively(struct futhark_context_config *cfg) {+ struct opencl_device_option *devices;+ size_t num_devices;++ opencl_all_device_options(&devices, &num_devices);++ printf("Choose OpenCL device:\n");+ const char *cur_platform = "";+ for (size_t i = 0; i < num_devices; i++) {+ struct opencl_device_option device = devices[i];+ if (strcmp(cur_platform, device.platform_name) != 0) {+ printf("Platform: %s\n", device.platform_name);+ cur_platform = device.platform_name;+ }+ printf("[%d] %s\n", (int)i, device.device_name);+ }++ int selection;+ printf("Choice: ");+ if (scanf("%d", &selection) == 1) {+ cfg->preferred_platform = "";+ cfg->preferred_device = "";+ cfg->preferred_device_num = selection;+ cfg->ignore_blacklist = 1;+ }++ // Free all the platform and device names.+ for (size_t j = 0; j < num_devices; j++) {+ free(devices[j].platform_name);+ free(devices[j].device_name);+ }+ free(devices);+}++void futhark_context_config_list_devices(struct futhark_context_config *cfg) {+ (void)cfg;+ struct opencl_device_option *devices;+ size_t num_devices;++ opencl_all_device_options(&devices, &num_devices);++ const char *cur_platform = "";+ for (size_t i = 0; i < num_devices; i++) {+ struct opencl_device_option device = devices[i];+ if (strcmp(cur_platform, device.platform_name) != 0) {+ printf("Platform: %s\n", device.platform_name);+ cur_platform = device.platform_name;+ }+ printf("[%d]: %s\n", (int)i, device.device_name);+ }++ // Free all the platform and device names.+ for (size_t j = 0; j < num_devices; j++) {+ free(devices[j].platform_name);+ free(devices[j].device_name);+ }+ free(devices);+}++void futhark_context_config_dump_program_to(struct futhark_context_config *cfg, const char *path) {+ cfg->dump_program_to = path;+}++void futhark_context_config_load_program_from(struct futhark_context_config *cfg, const char *path) {+ cfg->load_program_from = path;+}++void futhark_context_config_dump_binary_to(struct futhark_context_config *cfg, const char *path) {+ cfg->dump_binary_to = path;+}++void futhark_context_config_load_binary_from(struct futhark_context_config *cfg, const char *path) {+ cfg->load_binary_from = path;+}++void futhark_context_config_set_default_group_size(struct futhark_context_config *cfg, int size) {+ cfg->default_group_size = size;+ cfg->default_group_size_changed = 1;+}++void futhark_context_config_set_default_num_groups(struct futhark_context_config *cfg, int num) {+ cfg->default_num_groups = num;+}++void futhark_context_config_set_default_tile_size(struct futhark_context_config *cfg, int size) {+ cfg->default_tile_size = size;+ cfg->default_tile_size_changed = 1;+}++void futhark_context_config_set_default_reg_tile_size(struct futhark_context_config *cfg, int size) {+ cfg->default_reg_tile_size = size;+}++void futhark_context_config_set_default_threshold(struct futhark_context_config *cfg, int size) {+ cfg->default_threshold = size;+}++int futhark_context_config_set_tuning_param(struct futhark_context_config *cfg,+ const char *param_name,+ size_t new_value) {+ for (int i = 0; i < cfg->num_tuning_params; i++) {+ if (strcmp(param_name, cfg->tuning_param_names[i]) == 0) {+ cfg->tuning_params[i] = new_value;+ return 0;+ }+ }+ if (strcmp(param_name, "default_group_size") == 0) {+ cfg->default_group_size = new_value;+ return 0;+ }+ if (strcmp(param_name, "default_num_groups") == 0) {+ cfg->default_num_groups = new_value;+ return 0;+ }+ if (strcmp(param_name, "default_threshold") == 0) {+ cfg->default_threshold = new_value;+ return 0;+ }+ if (strcmp(param_name, "default_tile_size") == 0) {+ cfg->default_tile_size = new_value;+ return 0;+ }+ if (strcmp(param_name, "default_reg_tile_size") == 0) {+ cfg->default_reg_tile_size = new_value;+ return 0;+ }+ return 1;+}++// A record of something that happened.+struct profiling_record {+ cl_event *event;+ int *runs;+ int64_t *runtime;+};++struct futhark_context {+ struct futhark_context_config* cfg;+ int detail_memory;+ int debugging;+ int profiling;+ int profiling_paused;+ int logging;+ lock_t lock;+ char *error;+ lock_t error_lock;+ FILE *log;+ struct constants *constants;+ struct free_list free_list;+ int64_t peak_mem_usage_default;+ int64_t cur_mem_usage_default;+ struct program* program;++ // Common fields above.++ cl_mem global_failure;+ cl_mem global_failure_args;+ struct tuning_params tuning_params;+ // True if a potentially failing kernel has been enqueued.+ cl_int failure_is_an_option;+ int total_runs;+ long int total_runtime;+ int64_t peak_mem_usage_device;+ int64_t cur_mem_usage_device;++ cl_device_id device;+ cl_context ctx;+ cl_command_queue queue;+ cl_program clprogram;++ struct free_list cl_free_list;++ size_t max_group_size;+ size_t max_num_groups;+ size_t max_tile_size;+ size_t max_threshold;+ size_t max_local_memory;++ size_t lockstep_width;++ struct profiling_record *profiling_records;+ int profiling_records_capacity;+ int profiling_records_used;++};++static cl_build_status build_opencl_program(cl_program program, cl_device_id device, const char* options) {+ cl_int clBuildProgram_error = clBuildProgram(program, 1, &device, options, NULL, NULL);++ // Avoid termination due to CL_BUILD_PROGRAM_FAILURE+ if (clBuildProgram_error != CL_SUCCESS &&+ clBuildProgram_error != CL_BUILD_PROGRAM_FAILURE) {+ OPENCL_SUCCEED_FATAL(clBuildProgram_error);+ }++ cl_build_status build_status;+ OPENCL_SUCCEED_FATAL(clGetProgramBuildInfo(program,+ device,+ CL_PROGRAM_BUILD_STATUS,+ sizeof(cl_build_status),+ &build_status,+ NULL));++ if (build_status != CL_SUCCESS) {+ char *build_log;+ size_t ret_val_size;+ OPENCL_SUCCEED_FATAL(clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size));++ build_log = (char*) malloc(ret_val_size+1);+ OPENCL_SUCCEED_FATAL(clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL));++ // The spec technically does not say whether the build log is zero-terminated, so let's be careful.+ build_log[ret_val_size] = '\0';++ fprintf(stderr, "Build log:\n%s\n", build_log);++ free(build_log);+ }++ return build_status;+}++static char* mk_compile_opts(struct futhark_context *ctx,+ const char *extra_build_opts[],+ struct opencl_device_option device_option) {+ int compile_opts_size = 1024;++ for (int i = 0; i < ctx->cfg->num_tuning_params; i++) {+ compile_opts_size += strlen(ctx->cfg->tuning_param_names[i]) + 20;+ }++ for (int i = 0; extra_build_opts[i] != NULL; i++) {+ compile_opts_size += strlen(extra_build_opts[i] + 1);+ }++ char *compile_opts = (char*) malloc(compile_opts_size);++ int w = snprintf(compile_opts, compile_opts_size,+ "-DLOCKSTEP_WIDTH=%d ",+ (int)ctx->lockstep_width);++ w += snprintf(compile_opts+w, compile_opts_size-w,+ "-D%s=%d ",+ "max_group_size",+ (int)ctx->max_group_size);++ for (int i = 0; i < ctx->cfg->num_tuning_params; i++) {+ w += snprintf(compile_opts+w, compile_opts_size-w,+ "-D%s=%d ",+ ctx->cfg->tuning_param_vars[i],+ (int)ctx->cfg->tuning_params[i]);+ }++ for (int i = 0; extra_build_opts[i] != NULL; i++) {+ w += snprintf(compile_opts+w, compile_opts_size-w,+ "%s ", extra_build_opts[i]);+ }++ // Oclgrind claims to support cl_khr_fp16, but this is not actually+ // the case.+ if (strcmp(device_option.platform_name, "Oclgrind") == 0) {+ w += snprintf(compile_opts+w, compile_opts_size-w, "-DEMULATE_F16 ");+ }++ return compile_opts;+}++// Count up the runtime all the profiling_records that occured during execution.+// Also clears the buffer of profiling_records.+static cl_int opencl_tally_profiling_records(struct futhark_context *ctx) {+ cl_int err;+ for (int i = 0; i < ctx->profiling_records_used; i++) {+ struct profiling_record record = ctx->profiling_records[i];++ cl_ulong start_t, end_t;++ if ((err = clGetEventProfilingInfo(*record.event,+ CL_PROFILING_COMMAND_START,+ sizeof(start_t),+ &start_t,+ NULL)) != CL_SUCCESS) {+ return err;+ }++ if ((err = clGetEventProfilingInfo(*record.event,+ CL_PROFILING_COMMAND_END,+ sizeof(end_t),+ &end_t,+ NULL)) != CL_SUCCESS) {+ return err;+ }++ // OpenCL provides nanosecond resolution, but we want+ // microseconds.+ *record.runs += 1;+ *record.runtime += (end_t - start_t)/1000;++ if ((err = clReleaseEvent(*record.event)) != CL_SUCCESS) {+ return err;+ }+ free(record.event);+ }++ ctx->profiling_records_used = 0;++ return CL_SUCCESS;+}++// If profiling, produce an event associated with a profiling record.+static cl_event* opencl_get_event(struct futhark_context *ctx, int *runs, int64_t *runtime) {+ if (ctx->profiling_records_used == ctx->profiling_records_capacity) {+ ctx->profiling_records_capacity *= 2;+ ctx->profiling_records =+ realloc(ctx->profiling_records,+ ctx->profiling_records_capacity *+ sizeof(struct profiling_record));+ }+ cl_event *event = malloc(sizeof(cl_event));+ ctx->profiling_records[ctx->profiling_records_used].event = event;+ ctx->profiling_records[ctx->profiling_records_used].runs = runs;+ ctx->profiling_records[ctx->profiling_records_used].runtime = runtime;+ ctx->profiling_records_used++;+ return event;+}++// Allocate memory from driver. The problem is that OpenCL may perform+// lazy allocation, so we cannot know whether an allocation succeeded+// until the first time we try to use it. Hence we immediately+// perform a write to see if the allocation succeeded. This is slow,+// but the assumption is that this operation will be rare (most things+// will go through the free list).+static int opencl_alloc_actual(struct futhark_context *ctx, size_t size, cl_mem *mem_out) {+ int error;+ *mem_out = clCreateBuffer(ctx->ctx, CL_MEM_READ_WRITE, size, NULL, &error);++ if (error != CL_SUCCESS) {+ return error;+ }++ int x = 2;+ error = clEnqueueWriteBuffer(ctx->queue, *mem_out,+ CL_TRUE,+ 0, sizeof(x), &x,+ 0, NULL, NULL);++ // No need to wait for completion here. clWaitForEvents() cannot+ // return mem object allocation failures. This implies that the+ // buffer is faulted onto the device on enqueue. (Observation by+ // Andreas Kloeckner.)++ return error;+}++static int opencl_alloc(struct futhark_context *ctx, FILE *log,+ size_t min_size, const char *tag,+ cl_mem *mem_out, size_t *size_out) {+ (void)tag;+ if (min_size < sizeof(int)) {+ min_size = sizeof(int);+ }++ cl_mem* memptr;+ if (free_list_find(&ctx->cl_free_list, min_size, tag, size_out, (fl_mem*)&memptr) == 0) {+ // Successfully found a free block. Is it big enough?+ if (*size_out >= min_size) {+ if (ctx->cfg->debugging) {+ fprintf(log, "No need to allocate: Found a block in the free list.\n");+ }+ *mem_out = *memptr;+ free(memptr);+ return CL_SUCCESS;+ } else {+ if (ctx->cfg->debugging) {+ fprintf(log, "Found a free block, but it was too small.\n");+ }+ int error = clReleaseMemObject(*memptr);+ free(*memptr);+ if (error != CL_SUCCESS) {+ return error;+ }+ }+ }++ *size_out = min_size;++ // We have to allocate a new block from the driver. If the+ // allocation does not succeed, then we might be in an out-of-memory+ // situation. We now start freeing things from the free list until+ // we think we have freed enough that the allocation will succeed.+ // Since we don't know how far the allocation is from fitting, we+ // have to check after every deallocation. This might be pretty+ // expensive. Let's hope that this case is hit rarely.++ if (ctx->cfg->debugging) {+ fprintf(log, "Actually allocating the desired block.\n");+ }++ int error = opencl_alloc_actual(ctx, min_size, mem_out);++ while (error == CL_MEM_OBJECT_ALLOCATION_FAILURE) {+ if (ctx->cfg->debugging) {+ fprintf(log, "Out of OpenCL memory: releasing entry from the free list...\n");+ }+ cl_mem* memptr;+ if (free_list_first(&ctx->cl_free_list, (fl_mem*)&memptr) == 0) {+ cl_mem mem = *memptr;+ free(memptr);+ error = clReleaseMemObject(mem);+ if (error != CL_SUCCESS) {+ return error;+ }+ } else {+ break;+ }+ error = opencl_alloc_actual(ctx, min_size, mem_out);+ }++ return error;+}++static int opencl_free(struct futhark_context *ctx,+ cl_mem mem, size_t size, const char *tag) {+ cl_mem* memptr = malloc(sizeof(cl_mem));+ *memptr = mem;+ free_list_insert(&ctx->cl_free_list, size, (fl_mem)memptr, tag);+ return CL_SUCCESS;+}++static int opencl_free_all(struct futhark_context *ctx) {+ free_list_pack(&ctx->cl_free_list);+ cl_mem* memptr;+ while (free_list_first(&ctx->cl_free_list, (fl_mem*)&memptr) == 0) {+ cl_mem mem = *memptr;+ free(memptr);+ int error = clReleaseMemObject(mem);+ if (error != CL_SUCCESS) {+ return error;+ }+ }++ return CL_SUCCESS;+}++int futhark_context_sync(struct futhark_context* ctx) {+ // Check for any delayed error.+ cl_int failure_idx = -1;+ if (ctx->failure_is_an_option) {+ OPENCL_SUCCEED_OR_RETURN(+ clEnqueueReadBuffer(ctx->queue,+ ctx->global_failure,+ CL_FALSE,+ 0, sizeof(cl_int), &failure_idx,+ 0, NULL, NULL));+ ctx->failure_is_an_option = 0;+ }++ OPENCL_SUCCEED_OR_RETURN(clFinish(ctx->queue));++ if (failure_idx >= 0) {+ // We have to clear global_failure so that the next entry point+ // is not considered a failure from the start.+ cl_int no_failure = -1;+ OPENCL_SUCCEED_OR_RETURN(+ clEnqueueWriteBuffer(ctx->queue, ctx->global_failure, CL_TRUE,+ 0, sizeof(cl_int), &no_failure,+ 0, NULL, NULL));++ int64_t args[max_failure_args+1];+ OPENCL_SUCCEED_OR_RETURN(+ clEnqueueReadBuffer(ctx->queue,+ ctx->global_failure_args,+ CL_TRUE,+ 0, sizeof(args), &args,+ 0, NULL, NULL));++ ctx->error = get_failure_msg(failure_idx, args);++ return FUTHARK_PROGRAM_ERROR;+ }+ return 0;+}+++// We take as input several strings representing the program, because+// C does not guarantee that the compiler supports particularly large+// literals. Notably, Visual C has a limit of 2048 characters. The+// array must be NULL-terminated.+static void setup_opencl_with_command_queue(struct futhark_context *ctx,+ cl_command_queue queue,+ const char *srcs[],+ const char *extra_build_opts[],+ const char* cache_fname) {+ int error;++ free_list_init(&ctx->cl_free_list);+ ctx->queue = queue;++ OPENCL_SUCCEED_FATAL(clGetCommandQueueInfo(ctx->queue, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx->ctx, NULL));++ // Fill out the device info. This is redundant work if we are+ // called from setup_opencl() (which is the common case), but I+ // doubt it matters much.+ struct opencl_device_option device_option;+ OPENCL_SUCCEED_FATAL(clGetCommandQueueInfo(ctx->queue, CL_QUEUE_DEVICE,+ sizeof(cl_device_id),+ &device_option.device,+ NULL));+ OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_PLATFORM,+ sizeof(cl_platform_id),+ &device_option.platform,+ NULL));+ OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_TYPE,+ sizeof(cl_device_type),+ &device_option.device_type,+ NULL));+ device_option.platform_name = opencl_platform_info(device_option.platform, CL_PLATFORM_NAME);+ device_option.device_name = opencl_device_info(device_option.device, CL_DEVICE_NAME);++ ctx->device = device_option.device;++ if (f64_required) {+ cl_uint supported;+ OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE,+ sizeof(cl_uint), &supported, NULL));+ if (!supported) {+ futhark_panic(1, "Program uses double-precision floats, but this is not supported on the chosen device: %s\n",+ device_option.device_name);+ }+ }++ size_t max_group_size;+ OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_MAX_WORK_GROUP_SIZE,+ sizeof(size_t), &max_group_size, NULL));++ size_t max_tile_size = sqrt(max_group_size);++ cl_ulong max_local_memory;+ OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_LOCAL_MEM_SIZE,+ sizeof(size_t), &max_local_memory, NULL));++ // Futhark reserves 4 bytes for bookkeeping information.+ max_local_memory -= 4;++ // The OpenCL implementation may reserve some local memory bytes for+ // various purposes. In principle, we should use+ // clGetKernelWorkGroupInfo() to figure out for each kernel how much+ // is actually available, but our current code generator design+ // makes this infeasible. Instead, we have this nasty hack where we+ // arbitrarily subtract some bytes, based on empirical measurements+ // (but which might be arbitrarily wrong). Fortunately, we rarely+ // try to really push the local memory usage.+ if (strstr(device_option.platform_name, "NVIDIA CUDA") != NULL) {+ max_local_memory -= 12;+ } else if (strstr(device_option.platform_name, "AMD") != NULL) {+ max_local_memory -= 16;+ }++ // Make sure this function is defined.+ post_opencl_setup(ctx, &device_option);++ if (max_group_size < ctx->cfg->default_group_size) {+ if (ctx->cfg->default_group_size_changed) {+ fprintf(stderr, "Note: Device limits default group size to %zu (down from %zu).\n",+ max_group_size, ctx->cfg->default_group_size);+ }+ ctx->cfg->default_group_size = max_group_size;+ }++ if (max_tile_size < ctx->cfg->default_tile_size) {+ if (ctx->cfg->default_tile_size_changed) {+ fprintf(stderr, "Note: Device limits default tile size to %zu (down from %zu).\n",+ max_tile_size, ctx->cfg->default_tile_size);+ }+ ctx->cfg->default_tile_size = max_tile_size;+ }++ ctx->max_group_size = max_group_size;+ ctx->max_tile_size = max_tile_size; // No limit.+ ctx->max_threshold = ctx->max_num_groups = 0; // No limit.+ ctx->max_local_memory = max_local_memory;++ // Now we go through all the sizes, clamp them to the valid range,+ // or set them to the default.+ for (int i = 0; i < ctx->cfg->num_tuning_params; i++) {+ const char *size_class = ctx->cfg->tuning_param_classes[i];+ int64_t *size_value = &ctx->cfg->tuning_params[i];+ const char* size_name = ctx->cfg->tuning_param_names[i];+ int64_t max_value = 0, default_value = 0;++ if (strstr(size_class, "group_size") == size_class) {+ max_value = max_group_size;+ default_value = ctx->cfg->default_group_size;+ } else if (strstr(size_class, "num_groups") == size_class) {+ max_value = max_group_size; // Futhark assumes this constraint.+ default_value = ctx->cfg->default_num_groups;+ // XXX: as a quick and dirty hack, use twice as many threads for+ // histograms by default. We really should just be smarter+ // about sizes somehow.+ if (strstr(size_name, ".seghist_") != NULL) {+ default_value *= 2;+ }+ } else if (strstr(size_class, "tile_size") == size_class) {+ max_value = sqrt(max_group_size);+ default_value = ctx->cfg->default_tile_size;+ } else if (strstr(size_class, "reg_tile_size") == size_class) {+ max_value = 0; // No limit.+ default_value = ctx->cfg->default_reg_tile_size;+ } else if (strstr(size_class, "threshold") == size_class) {+ // Threshold can be as large as it takes.+ default_value = ctx->cfg->default_threshold;+ } else {+ // Bespoke sizes have no limit or default.+ }+ if (*size_value == 0) {+ *size_value = default_value;+ } else if (max_value > 0 && *size_value > max_value) {+ fprintf(stderr, "Note: Device limits %s to %d (down from %d)\n",+ size_name, (int)max_value, (int)*size_value);+ *size_value = max_value;+ }+ }++ if (ctx->lockstep_width == 0) {+ ctx->lockstep_width = 1;+ }++ if (ctx->cfg->logging) {+ fprintf(stderr, "Lockstep width: %d\n", (int)ctx->lockstep_width);+ fprintf(stderr, "Default group size: %d\n", (int)ctx->cfg->default_group_size);+ fprintf(stderr, "Default number of groups: %d\n", (int)ctx->cfg->default_num_groups);+ }++ char *compile_opts = mk_compile_opts(ctx, extra_build_opts, device_option);++ if (ctx->cfg->logging) {+ fprintf(stderr, "OpenCL compiler options: %s\n", compile_opts);+ }++ char *fut_opencl_src = NULL;+ cl_program prog;+ error = CL_SUCCESS;++ struct cache_hash h;++ int loaded_from_cache = 0;+ if (ctx->cfg->load_binary_from == NULL) {+ size_t src_size = 0;++ // Maybe we have to read OpenCL source from somewhere else (used for debugging).+ if (ctx->cfg->load_program_from != NULL) {+ fut_opencl_src = slurp_file(ctx->cfg->load_program_from, NULL);+ assert(fut_opencl_src != NULL);+ } else {+ // Construct the OpenCL source concatenating all the fragments.+ for (const char **src = srcs; src && *src; src++) {+ src_size += strlen(*src);+ }++ fut_opencl_src = (char*) malloc(src_size + 1);++ size_t n, i;+ for (i = 0, n = 0; srcs && srcs[i]; i++) {+ strncpy(fut_opencl_src+n, srcs[i], src_size-n);+ n += strlen(srcs[i]);+ }+ fut_opencl_src[src_size] = 0;+ }++ if (ctx->cfg->dump_program_to != NULL) {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Dumping OpenCL source to %s...\n", ctx->cfg->dump_program_to);+ }++ dump_file(ctx->cfg->dump_program_to, fut_opencl_src, strlen(fut_opencl_src));+ }++ if (cache_fname != NULL) {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Restoring cache from from %s...\n", cache_fname);+ }+ cache_hash_init(&h);+ cache_hash(&h, fut_opencl_src, strlen(fut_opencl_src));+ cache_hash(&h, compile_opts, strlen(compile_opts));++ unsigned char *buf;+ size_t bufsize;+ errno = 0;+ if (cache_restore(cache_fname, &h, &buf, &bufsize) != 0) {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Failed to restore cache (errno: %s)\n", strerror(errno));+ }+ } else {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Cache restored; loading OpenCL binary...\n");+ }++ cl_int status = 0;+ prog = clCreateProgramWithBinary(ctx->ctx, 1, &device_option.device,+ &bufsize, (const unsigned char**)&buf,+ &status, &error);+ if (status == CL_SUCCESS) {+ loaded_from_cache = 1;+ if (ctx->cfg->logging) {+ fprintf(stderr, "Loading succeeded.\n");+ }+ } else {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Loading failed.\n");+ }+ }+ }+ }++ if (!loaded_from_cache) {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Creating OpenCL program...\n");+ }++ const char* src_ptr[] = {fut_opencl_src};+ prog = clCreateProgramWithSource(ctx->ctx, 1, src_ptr, &src_size, &error);+ OPENCL_SUCCEED_FATAL(error);+ }+ } else {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Loading OpenCL binary from %s...\n", ctx->cfg->load_binary_from);+ }+ size_t binary_size;+ unsigned char *fut_opencl_bin =+ (unsigned char*) slurp_file(ctx->cfg->load_binary_from, &binary_size);+ assert(fut_opencl_bin != NULL);+ const unsigned char *binaries[1] = { fut_opencl_bin };+ cl_int status = 0;++ prog = clCreateProgramWithBinary(ctx->ctx, 1, &device_option.device,+ &binary_size, binaries,+ &status, &error);++ OPENCL_SUCCEED_FATAL(status);+ OPENCL_SUCCEED_FATAL(error);+ }++ if (ctx->cfg->logging) {+ fprintf(stderr, "Building OpenCL program...\n");+ }+ OPENCL_SUCCEED_FATAL(build_opencl_program(prog, device_option.device, compile_opts));++ free(compile_opts);+ free(fut_opencl_src);++ size_t binary_size = 0;+ unsigned char *binary = NULL;+ int store_in_cache = cache_fname != NULL && !loaded_from_cache;+ if (store_in_cache || ctx->cfg->dump_binary_to != NULL) {+ OPENCL_SUCCEED_FATAL(clGetProgramInfo(prog, CL_PROGRAM_BINARY_SIZES,+ sizeof(size_t), &binary_size, NULL));+ binary = (unsigned char*) malloc(binary_size);+ OPENCL_SUCCEED_FATAL(clGetProgramInfo(prog, CL_PROGRAM_BINARIES,+ sizeof(unsigned char*), &binary, NULL));+ }++ if (store_in_cache) {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Caching OpenCL binary in %s...\n", cache_fname);+ }+ if (cache_store(cache_fname, &h, binary, binary_size) != 0) {+ printf("Failed to cache binary: %s\n", strerror(errno));+ }+ }++ if (ctx->cfg->dump_binary_to != NULL) {+ if (ctx->cfg->logging) {+ fprintf(stderr, "Dumping OpenCL binary to %s...\n", ctx->cfg->dump_binary_to);+ }+ dump_file(ctx->cfg->dump_binary_to, binary, binary_size);+ }++ ctx->clprogram = prog;+}++static struct opencl_device_option get_preferred_device(const struct futhark_context_config *cfg) {+ struct opencl_device_option *devices;+ size_t num_devices;++ opencl_all_device_options(&devices, &num_devices);++ int num_device_matches = 0;++ for (size_t i = 0; i < num_devices; i++) {+ struct opencl_device_option device = devices[i];+ if (strstr(device.platform_name, cfg->preferred_platform) != NULL &&+ strstr(device.device_name, cfg->preferred_device) != NULL &&+ (cfg->ignore_blacklist ||+ !is_blacklisted(device.platform_name, device.device_name, cfg)) &&+ num_device_matches++ == cfg->preferred_device_num) {+ // Free all the platform and device names, except the ones we have chosen.+ for (size_t j = 0; j < num_devices; j++) {+ if (j != i) {+ free(devices[j].platform_name);+ free(devices[j].device_name);+ }+ }+ free(devices);+ return device;+ }+ }++ futhark_panic(1, "Could not find acceptable OpenCL device.\n");+ exit(1); // Never reached+}++static void setup_opencl(struct futhark_context *ctx,+ const char *srcs[],+ const char *extra_build_opts[],+ const char* cache_fname) {+ struct opencl_device_option device_option = get_preferred_device(ctx->cfg);++ if (ctx->cfg->logging) {+ fprintf(stderr, "Using platform: %s\n", device_option.platform_name);+ fprintf(stderr, "Using device: %s\n", device_option.device_name);+ }++ // Note that NVIDIA's OpenCL requires the platform property+ cl_context_properties properties[] = {+ CL_CONTEXT_PLATFORM,+ (cl_context_properties)device_option.platform,+ 0+ };++ cl_int clCreateContext_error;+ ctx->ctx = clCreateContext(properties, 1, &device_option.device, NULL, NULL, &clCreateContext_error);+ OPENCL_SUCCEED_FATAL(clCreateContext_error);++ cl_int clCreateCommandQueue_error;+ cl_command_queue queue =+ clCreateCommandQueue(ctx->ctx,+ device_option.device,+ ctx->cfg->profiling ? CL_QUEUE_PROFILING_ENABLE : 0,+ &clCreateCommandQueue_error);+ OPENCL_SUCCEED_FATAL(clCreateCommandQueue_error);++ setup_opencl_with_command_queue(ctx, queue, srcs, extra_build_opts, cache_fname);+}++int backend_context_setup(struct futhark_context* ctx) {+ ctx->lockstep_width = 0; // Real value set later.+ ctx->profiling_records_capacity = 200;+ ctx->profiling_records_used = 0;+ ctx->profiling_records =+ malloc(ctx->profiling_records_capacity *+ sizeof(struct profiling_record));+ ctx->failure_is_an_option = 0;+ ctx->total_runs = 0;+ ctx->total_runtime = 0;+ ctx->peak_mem_usage_device = 0;+ ctx->cur_mem_usage_device = 0;++ if (ctx->cfg->queue_set) {+ setup_opencl_with_command_queue(ctx, ctx->cfg->queue, opencl_program, ctx->cfg->build_opts, ctx->cfg->cache_fname);+ } else {+ setup_opencl(ctx, opencl_program, ctx->cfg->build_opts, ctx->cfg->cache_fname);+ }++ cl_int error;+ cl_int no_error = -1;+ ctx->global_failure =+ clCreateBuffer(ctx->ctx,+ CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,+ sizeof(cl_int), &no_error, &error);+ OPENCL_SUCCEED_OR_RETURN(error);++ // The +1 is to avoid zero-byte allocations.+ ctx->global_failure_args =+ clCreateBuffer(ctx->ctx,+ CL_MEM_READ_WRITE,+ sizeof(int64_t)*(max_failure_args+1), NULL, &error);+ OPENCL_SUCCEED_OR_RETURN(error);++ set_tuning_params(ctx);+ return 0;+}++void backend_context_teardown(struct futhark_context* ctx) {+ OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->global_failure));+ OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->global_failure_args));+ (void)opencl_tally_profiling_records(ctx);+ free(ctx->profiling_records);+ (void)opencl_free_all(ctx);+ (void)clReleaseProgram(ctx->clprogram);+ (void)clReleaseCommandQueue(ctx->queue);+ (void)clReleaseContext(ctx->ctx);+}++cl_command_queue futhark_context_get_command_queue(struct futhark_context* ctx) {+ return ctx->queue;+}++// End of backends/opencl.h
rts/c/context.h view
@@ -72,18 +72,75 @@ } } -static void context_setup(struct futhark_context *ctx) {+struct futhark_context_config* futhark_context_config_new(void) {+ struct futhark_context_config* cfg = malloc(sizeof(struct futhark_context_config));+ if (cfg == NULL) {+ return NULL;+ }+ cfg->in_use = 0;+ cfg->debugging = 0;+ cfg->profiling = 0;+ cfg->logging = 0;+ cfg->cache_fname = NULL;+ cfg->num_tuning_params = num_tuning_params;+ cfg->tuning_params = malloc(cfg->num_tuning_params * sizeof(int64_t));+ memcpy(cfg->tuning_params, tuning_param_defaults,+ cfg->num_tuning_params * sizeof(int64_t));+ cfg->tuning_param_names = tuning_param_names;+ cfg->tuning_param_vars = tuning_param_vars;+ cfg->tuning_param_classes = tuning_param_classes;+ backend_context_config_setup(cfg);+ return cfg;+}++void futhark_context_config_free(struct futhark_context_config* cfg) {+ assert(!cfg->in_use);+ backend_context_config_teardown(cfg);+ free(cfg->tuning_params);+ free(cfg);+}++struct futhark_context* futhark_context_new(struct futhark_context_config* cfg) {+ struct futhark_context* ctx = malloc(sizeof(struct futhark_context));+ if (ctx == NULL) {+ return NULL;+ }+ assert(!cfg->in_use);+ ctx->cfg = cfg;+ ctx->cfg->in_use = 1; create_lock(&ctx->error_lock); create_lock(&ctx->lock); free_list_init(&ctx->free_list);+ ctx->peak_mem_usage_default = 0;+ ctx->cur_mem_usage_default = 0;+ ctx->constants = malloc(sizeof(struct constants));+ ctx->detail_memory = cfg->debugging;+ ctx->debugging = cfg->debugging;+ ctx->logging = cfg->logging;+ ctx->profiling = cfg->profiling;+ ctx->profiling_paused = 0;+ ctx->error = NULL;+ ctx->log = stderr;+ if (backend_context_setup(ctx) == 0) {+ setup_program(ctx);+ init_constants(ctx);+ (void)futhark_context_clear_caches(ctx);+ (void)futhark_context_sync(ctx);+ }+ return ctx; } -static void context_teardown(struct futhark_context *ctx) {+void futhark_context_free(struct futhark_context* ctx) { free_constants(ctx);+ teardown_program(ctx);+ backend_context_teardown(ctx); free_all_in_free_list(ctx); free_list_destroy(&ctx->free_list);+ free(ctx->constants); free_lock(&ctx->lock); free_lock(&ctx->error_lock);+ ctx->cfg->in_use = 0;+ free(ctx); } // End of context.h
rts/c/context_prototypes.h view
@@ -1,20 +1,29 @@ // Start of context_prototypes.h //-// Prototypes for the functions in context.h that need to be-// available very early.+// Prototypes for the functions in context.h, or that will be called+// from those functions, that need to be available very early. struct futhark_context_config; struct futhark_context; static void set_error(struct futhark_context* ctx, char *error); -// These are called in context new/free functions and contain shared setup.-static void context_setup(struct futhark_context *ctx);-static void context_teardown(struct futhark_context *ctx);+// These are called in context/config new/free functions and contain+// shared setup. They are generated by the compiler itself.+static int init_constants(struct futhark_context*);+static int free_constants(struct futhark_context*);+static void setup_program(struct futhark_context* ctx);+static void teardown_program(struct futhark_context *ctx); // Allocate host memory. Must be freed with host_free(). static void host_alloc(struct futhark_context* ctx, size_t size, const char* tag, size_t* size_out, void** mem_out); // Allocate memory allocated with host_alloc(). static void host_free(struct futhark_context* ctx, size_t size, const char* tag, void* mem);++// Functions that must be defined by the backend.+static void backend_context_config_setup(struct futhark_context_config* cfg);+static void backend_context_config_teardown(struct futhark_context_config* cfg);+static int backend_context_setup(struct futhark_context *ctx);+static void backend_context_teardown(struct futhark_context *ctx); // End of of context_prototypes.h
− rts/c/cuda.h
@@ -1,766 +0,0 @@-// Start of cuda.h.--#define CUDA_SUCCEED_FATAL(x) cuda_api_succeed_fatal(x, #x, __FILE__, __LINE__)-#define CUDA_SUCCEED_NONFATAL(x) cuda_api_succeed_nonfatal(x, #x, __FILE__, __LINE__)-#define NVRTC_SUCCEED_FATAL(x) nvrtc_api_succeed_fatal(x, #x, __FILE__, __LINE__)-#define NVRTC_SUCCEED_NONFATAL(x) nvrtc_api_succeed_nonfatal(x, #x, __FILE__, __LINE__)-// Take care not to override an existing error.-#define CUDA_SUCCEED_OR_RETURN(e) { \- char *serror = CUDA_SUCCEED_NONFATAL(e); \- if (serror) { \- if (!ctx->error) { \- ctx->error = serror; \- return bad; \- } else { \- free(serror); \- } \- } \- }--// CUDA_SUCCEED_OR_RETURN returns the value of the variable 'bad' in-// scope. By default, it will be this one. Create a local variable-// of some other type if needed. This is a bit of a hack, but it-// saves effort in the code generator.-static const int bad = 1;--static inline void cuda_api_succeed_fatal(CUresult res, const char *call,- const char *file, int line) {- if (res != CUDA_SUCCESS) {- const char *err_str;- cuGetErrorString(res, &err_str);- if (err_str == NULL) { err_str = "Unknown"; }- futhark_panic(-1, "%s:%d: CUDA call\n %s\nfailed with error code %d (%s)\n",- file, line, call, res, err_str);- }-}--static char* cuda_api_succeed_nonfatal(CUresult res, const char *call,- const char *file, int line) {- if (res != CUDA_SUCCESS) {- const char *err_str;- cuGetErrorString(res, &err_str);- if (err_str == NULL) { err_str = "Unknown"; }- return msgprintf("%s:%d: CUDA call\n %s\nfailed with error code %d (%s)\n",- file, line, call, res, err_str);- } else {- return NULL;- }-}--static inline void nvrtc_api_succeed_fatal(nvrtcResult res, const char *call,- const char *file, int line) {- if (res != NVRTC_SUCCESS) {- const char *err_str = nvrtcGetErrorString(res);- futhark_panic(-1, "%s:%d: NVRTC call\n %s\nfailed with error code %d (%s)\n",- file, line, call, res, err_str);- }-}--static char* nvrtc_api_succeed_nonfatal(nvrtcResult res, const char *call,- const char *file, int line) {- if (res != NVRTC_SUCCESS) {- const char *err_str = nvrtcGetErrorString(res);- return msgprintf("%s:%d: NVRTC call\n %s\nfailed with error code %d (%s)\n",- file, line, call, res, err_str);- } else {- return NULL;- }-}--struct cuda_config {- int debugging;- int logging;- const char *preferred_device;- int preferred_device_num;-- const char *dump_program_to;- const char *load_program_from;-- const char *dump_ptx_to;- const char *load_ptx_from;-- size_t default_block_size;- size_t default_grid_size;- size_t default_tile_size;- size_t default_reg_tile_size;- size_t default_threshold;-- int default_block_size_changed;- int default_grid_size_changed;- int default_tile_size_changed;-- int num_sizes;- const char **size_names;- const char **size_vars;- int64_t *size_values;- const char **size_classes;-};--static void cuda_config_init(struct cuda_config *cfg,- int num_sizes,- const char *size_names[],- const char *size_vars[],- int64_t *size_values,- const char *size_classes[]) {- cfg->debugging = 0;- cfg->logging = 0;- cfg->preferred_device_num = 0;- cfg->preferred_device = "";- cfg->dump_program_to = NULL;- cfg->load_program_from = NULL;-- cfg->dump_ptx_to = NULL;- cfg->load_ptx_from = NULL;-- cfg->default_block_size = 256;- cfg->default_grid_size = 0; // Set properly later.- cfg->default_tile_size = 32;- cfg->default_reg_tile_size = 2;- cfg->default_threshold = 32*1024;-- cfg->default_block_size_changed = 0;- cfg->default_grid_size_changed = 0;- cfg->default_tile_size_changed = 0;-- cfg->num_sizes = num_sizes;- cfg->size_names = size_names;- cfg->size_vars = size_vars;- cfg->size_values = size_values;- cfg->size_classes = size_classes;-}--// A record of something that happened.-struct profiling_record {- cudaEvent_t *events; // Points to two events.- int *runs;- int64_t *runtime;-};--struct cuda_context {- CUdevice dev;- CUcontext cu_ctx;- CUmodule module;-- struct cuda_config cfg;-- struct free_list free_list;-- size_t max_block_size;- size_t max_grid_size;- size_t max_tile_size;- size_t max_threshold;- size_t max_shared_memory;- size_t max_bespoke;-- size_t lockstep_width;-- struct profiling_record *profiling_records;- int profiling_records_capacity;- int profiling_records_used;-};--#define CU_DEV_ATTR(x) (CU_DEVICE_ATTRIBUTE_##x)-#define device_query(dev,attrib) _device_query(dev, CU_DEV_ATTR(attrib))-static int _device_query(CUdevice dev, CUdevice_attribute attrib) {- int val;- CUDA_SUCCEED_FATAL(cuDeviceGetAttribute(&val, attrib, dev));- return val;-}--#define CU_FUN_ATTR(x) (CU_FUNC_ATTRIBUTE_##x)-#define function_query(fn,attrib) _function_query(dev, CU_FUN_ATTR(attrib))-static int _function_query(CUfunction dev, CUfunction_attribute attrib) {- int val;- CUDA_SUCCEED_FATAL(cuFuncGetAttribute(&val, attrib, dev));- return val;-}--static void set_preferred_device(struct cuda_config *cfg, const char *s) {- int x = 0;- if (*s == '#') {- s++;- while (isdigit(*s)) {- x = x * 10 + (*s++)-'0';- }- // Skip trailing spaces.- while (isspace(*s)) {- s++;- }- }- cfg->preferred_device = s;- cfg->preferred_device_num = x;-}--static int cuda_device_setup(struct cuda_context *ctx) {- char name[256];- int count, chosen = -1, best_cc = -1;- int cc_major_best, cc_minor_best;- int cc_major, cc_minor;- CUdevice dev;-- CUDA_SUCCEED_FATAL(cuDeviceGetCount(&count));- if (count == 0) { return 1; }-- int num_device_matches = 0;-- // XXX: Current device selection policy is to choose the device with the- // highest compute capability (if no preferred device is set).- // This should maybe be changed, since greater compute capability is not- // necessarily an indicator of better performance.- for (int i = 0; i < count; i++) {- CUDA_SUCCEED_FATAL(cuDeviceGet(&dev, i));-- cc_major = device_query(dev, COMPUTE_CAPABILITY_MAJOR);- cc_minor = device_query(dev, COMPUTE_CAPABILITY_MINOR);-- CUDA_SUCCEED_FATAL(cuDeviceGetName(name, sizeof(name) - 1, dev));- name[sizeof(name) - 1] = 0;-- if (ctx->cfg.logging) {- fprintf(stderr, "Device #%d: name=\"%s\", compute capability=%d.%d\n",- i, name, cc_major, cc_minor);- }-- if (device_query(dev, COMPUTE_MODE) == CU_COMPUTEMODE_PROHIBITED) {- if (ctx->cfg.logging) {- fprintf(stderr, "Device #%d is compute-prohibited, ignoring\n", i);- }- continue;- }-- if (best_cc == -1 || cc_major > cc_major_best ||- (cc_major == cc_major_best && cc_minor > cc_minor_best)) {- best_cc = i;- cc_major_best = cc_major;- cc_minor_best = cc_minor;- }-- if (strstr(name, ctx->cfg.preferred_device) != NULL &&- num_device_matches++ == ctx->cfg.preferred_device_num) {- chosen = i;- break;- }- }-- if (chosen == -1) { chosen = best_cc; }- if (chosen == -1) { return 1; }-- if (ctx->cfg.logging) {- fprintf(stderr, "Using device #%d\n", chosen);- }-- CUDA_SUCCEED_FATAL(cuDeviceGet(&ctx->dev, chosen));- return 0;-}--static char *concat_fragments(const char *src_fragments[]) {- size_t src_len = 0;- const char **p;-- for (p = src_fragments; *p; p++) {- src_len += strlen(*p);- }-- char *src = (char*) malloc(src_len + 1);- size_t n = 0;- for (p = src_fragments; *p; p++) {- strcpy(src + n, *p);- n += strlen(*p);- }-- return src;-}--static const char *cuda_nvrtc_get_arch(CUdevice dev) {- struct {- int major;- int minor;- const char *arch_str;- } static const x[] = {- { 3, 0, "compute_30" },- { 3, 2, "compute_32" },- { 3, 5, "compute_35" },- { 3, 7, "compute_37" },- { 5, 0, "compute_50" },- { 5, 2, "compute_52" },- { 5, 3, "compute_53" },- { 6, 0, "compute_60" },- { 6, 1, "compute_61" },- { 6, 2, "compute_62" },- { 7, 0, "compute_70" },- { 7, 2, "compute_72" },- { 7, 5, "compute_75" },- { 8, 0, "compute_80" },- { 8, 6, "compute_80" },- { 8, 7, "compute_80" }- };-- int major = device_query(dev, COMPUTE_CAPABILITY_MAJOR);- int minor = device_query(dev, COMPUTE_CAPABILITY_MINOR);-- int chosen = -1;- for (int i = 0; i < sizeof(x)/sizeof(x[0]); i++) {- if (x[i].major < major || (x[i].major == major && x[i].minor <= minor)) {- chosen = i;- } else {- break;- }- }-- if (chosen == -1) {- futhark_panic(-1, "Unsupported compute capability %d.%d\n", major, minor);- }-- if (x[chosen].major != major || x[chosen].minor != minor) {- fprintf(stderr,- "Warning: device compute capability is %d.%d, but newest supported by Futhark is %d.%d.\n",- major, minor, x[chosen].major, x[chosen].minor);- }-- return x[chosen].arch_str;-}--static void cuda_nvrtc_mk_build_options(struct cuda_context *ctx, const char *extra_opts[],- char*** opts_out, size_t *n_opts) {- int arch_set = 0, num_extra_opts;-- // nvrtc cannot handle multiple -arch options. Hence, if one of the- // extra_opts is -arch, we have to be careful not to do our usual- // automatic generation.- for (num_extra_opts = 0; extra_opts[num_extra_opts] != NULL; num_extra_opts++) {- if (strstr(extra_opts[num_extra_opts], "-arch")- == extra_opts[num_extra_opts] ||- strstr(extra_opts[num_extra_opts], "--gpu-architecture")- == extra_opts[num_extra_opts]) {- arch_set = 1;- }- }-- size_t i = 0, n_opts_alloc = 20 + num_extra_opts + ctx->cfg.num_sizes;- char **opts = (char**) malloc(n_opts_alloc * sizeof(char *));- if (!arch_set) {- opts[i++] = strdup("-arch");- opts[i++] = strdup(cuda_nvrtc_get_arch(ctx->dev));- }- opts[i++] = strdup("-default-device");- if (ctx->cfg.debugging) {- opts[i++] = strdup("-G");- opts[i++] = strdup("-lineinfo");- } else {- opts[i++] = strdup("--disable-warnings");- }- opts[i++] = msgprintf("-D%s=%d",- "max_group_size",- (int)ctx->max_block_size);- for (size_t j = 0; j < ctx->cfg.num_sizes; j++) {- opts[i++] = msgprintf("-D%s=%zu", ctx->cfg.size_vars[j],- ctx->cfg.size_values[j]);- }- opts[i++] = msgprintf("-DLOCKSTEP_WIDTH=%zu", ctx->lockstep_width);- opts[i++] = msgprintf("-DMAX_THREADS_PER_BLOCK=%zu", ctx->max_block_size);-- // Time for the best lines of the code in the entire compiler.- if (getenv("CUDA_HOME") != NULL) {- opts[i++] = msgprintf("-I%s/include", getenv("CUDA_HOME"));- }- if (getenv("CUDA_ROOT") != NULL) {- opts[i++] = msgprintf("-I%s/include", getenv("CUDA_ROOT"));- }- if (getenv("CUDA_PATH") != NULL) {- opts[i++] = msgprintf("-I%s/include", getenv("CUDA_PATH"));- }- opts[i++] = msgprintf("-I/usr/local/cuda/include");- opts[i++] = msgprintf("-I/usr/include");-- for (int j = 0; extra_opts[j] != NULL; j++) {- opts[i++] = strdup(extra_opts[j]);- }-- *n_opts = i;- *opts_out = opts;-}--static char* cuda_nvrtc_build(struct cuda_context *ctx, const char *src,- const char *opts[], size_t n_opts,- char **ptx) {- nvrtcProgram prog;- char *problem = NULL;-- problem = NVRTC_SUCCEED_NONFATAL(nvrtcCreateProgram(&prog, src, "futhark-cuda", 0, NULL, NULL));-- if (problem) {- return problem;- }-- nvrtcResult res = nvrtcCompileProgram(prog, n_opts, opts);- if (res != NVRTC_SUCCESS) {- size_t log_size;- if (nvrtcGetProgramLogSize(prog, &log_size) == NVRTC_SUCCESS) {- char *log = (char*) malloc(log_size);- if (nvrtcGetProgramLog(prog, log) == NVRTC_SUCCESS) {- problem = msgprintf("NVRTC compilation failed.\n\n%s\n", log);- } else {- problem = msgprintf("Could not retrieve compilation log\n");- }- free(log);- }- return problem;- }-- size_t ptx_size;- NVRTC_SUCCEED_FATAL(nvrtcGetPTXSize(prog, &ptx_size));- *ptx = (char*) malloc(ptx_size);- NVRTC_SUCCEED_FATAL(nvrtcGetPTX(prog, *ptx));-- NVRTC_SUCCEED_FATAL(nvrtcDestroyProgram(&prog));-- return NULL;-}--static void cuda_load_ptx_from_cache(struct cuda_context *ctx, const char *src,- const char *opts[], size_t n_opts,- struct cache_hash *h, const char *cache_fname,- char **ptx) {- if (ctx->cfg.logging) {- fprintf(stderr, "Restoring cache from from %s...\n", cache_fname);- }- cache_hash_init(h);- for (size_t i = 0; i < n_opts; i++) {- cache_hash(h, opts[i], strlen(opts[i]));- }- cache_hash(h, src, strlen(src));- size_t ptxsize;- errno = 0;- if (cache_restore(cache_fname, h, (unsigned char**)ptx, &ptxsize) != 0) {- if (ctx->cfg.logging) {- fprintf(stderr, "Failed to restore cache (errno: %s)\n", strerror(errno));- }- }-}--static void cuda_size_setup(struct cuda_context *ctx)-{- if (ctx->cfg.default_block_size > ctx->max_block_size) {- if (ctx->cfg.default_block_size_changed) {- fprintf(stderr,- "Note: Device limits default block size to %zu (down from %zu).\n",- ctx->max_block_size, ctx->cfg.default_block_size);- }- ctx->cfg.default_block_size = ctx->max_block_size;- }- if (ctx->cfg.default_grid_size > ctx->max_grid_size) {- if (ctx->cfg.default_grid_size_changed) {- fprintf(stderr,- "Note: Device limits default grid size to %zu (down from %zu).\n",- ctx->max_grid_size, ctx->cfg.default_grid_size);- }- ctx->cfg.default_grid_size = ctx->max_grid_size;- }- if (ctx->cfg.default_tile_size > ctx->max_tile_size) {- if (ctx->cfg.default_tile_size_changed) {- fprintf(stderr,- "Note: Device limits default tile size to %zu (down from %zu).\n",- ctx->max_tile_size, ctx->cfg.default_tile_size);- }- ctx->cfg.default_tile_size = ctx->max_tile_size;- }-- if (!ctx->cfg.default_grid_size_changed) {- ctx->cfg.default_grid_size =- (device_query(ctx->dev, MULTIPROCESSOR_COUNT) *- device_query(ctx->dev, MAX_THREADS_PER_MULTIPROCESSOR))- / ctx->cfg.default_block_size;- }-- for (int i = 0; i < ctx->cfg.num_sizes; i++) {- const char *size_class = ctx->cfg.size_classes[i];- int64_t *size_value = &ctx->cfg.size_values[i];- const char* size_name = ctx->cfg.size_names[i];- int64_t max_value = 0, default_value = 0;-- if (strstr(size_class, "group_size") == size_class) {- max_value = ctx->max_block_size;- default_value = ctx->cfg.default_block_size;- } else if (strstr(size_class, "num_groups") == size_class) {- max_value = ctx->max_grid_size;- default_value = ctx->cfg.default_grid_size;- // XXX: as a quick and dirty hack, use twice as many threads for- // histograms by default. We really should just be smarter- // about sizes somehow.- if (strstr(size_name, ".seghist_") != NULL) {- default_value *= 2;- }- } else if (strstr(size_class, "tile_size") == size_class) {- max_value = ctx->max_tile_size;- default_value = ctx->cfg.default_tile_size;- } else if (strstr(size_class, "reg_tile_size") == size_class) {- max_value = 0; // No limit.- default_value = ctx->cfg.default_reg_tile_size;- } else if (strstr(size_class, "threshold") == size_class) {- // Threshold can be as large as it takes.- default_value = ctx->cfg.default_threshold;- } else {- // Bespoke sizes have no limit or default.- }-- if (*size_value == 0) {- *size_value = default_value;- } else if (max_value > 0 && *size_value > max_value) {- fprintf(stderr, "Note: Device limits %s to %zu (down from %zu)\n",- size_name, max_value, *size_value);- *size_value = max_value;- }- }-}--static char* cuda_module_setup(struct cuda_context *ctx,- const char *src_fragments[],- const char *extra_opts[],- const char* cache_fname) {- char *ptx = NULL, *src = NULL;-- if (ctx->cfg.load_program_from == NULL) {- src = concat_fragments(src_fragments);- } else {- src = slurp_file(ctx->cfg.load_program_from, NULL);- }-- if (ctx->cfg.load_ptx_from) {- if (ctx->cfg.load_program_from != NULL) {- fprintf(stderr,- "WARNING: Using PTX from %s instead of C code from %s\n",- ctx->cfg.load_ptx_from, ctx->cfg.load_program_from);- }- ptx = slurp_file(ctx->cfg.load_ptx_from, NULL);- }-- if (ctx->cfg.dump_program_to != NULL) {- dump_file(ctx->cfg.dump_program_to, src, strlen(src));- }-- char **opts;- size_t n_opts;- cuda_nvrtc_mk_build_options(ctx, extra_opts, &opts, &n_opts);-- if (ctx->cfg.logging) {- fprintf(stderr, "NVRTC compile options:\n");- for (size_t j = 0; j < n_opts; j++) {- fprintf(stderr, "\t%s\n", opts[j]);- }- fprintf(stderr, "\n");- }-- struct cache_hash h;- int loaded_ptx_from_cache = 0;- if (cache_fname != NULL) {- cuda_load_ptx_from_cache(ctx, src, (const char**)opts, n_opts, &h, cache_fname, &ptx);-- if (ptx != NULL) {- if (ctx->cfg.logging) {- fprintf(stderr, "Restored PTX from cache; now loading module...\n");- }- if (cuModuleLoadData(&ctx->module, ptx) == CUDA_SUCCESS) {- if (ctx->cfg.logging) {- fprintf(stderr, "Success!\n");- }- loaded_ptx_from_cache = 1;- } else {- if (ctx->cfg.logging) {- fprintf(stderr, "Failed!\n");- }- free(ptx);- ptx = NULL;- }- }- }-- if (ptx == NULL) {- char* problem = cuda_nvrtc_build(ctx, src, (const char**)opts, n_opts, &ptx);- if (problem != NULL) {- free(src);- return problem;- }- }-- if (ctx->cfg.dump_ptx_to != NULL) {- dump_file(ctx->cfg.dump_ptx_to, ptx, strlen(ptx));- }-- if (!loaded_ptx_from_cache) {- CUDA_SUCCEED_FATAL(cuModuleLoadData(&ctx->module, ptx));- }-- if (cache_fname != NULL && !loaded_ptx_from_cache) {- if (ctx->cfg.logging) {- fprintf(stderr, "Caching PTX in %s...\n", cache_fname);- }- errno = 0;- if (cache_store(cache_fname, &h, (const unsigned char*)ptx, strlen(ptx)) != 0) {- fprintf(stderr, "Failed to cache PTX: %s\n", strerror(errno));- }- }-- for (size_t i = 0; i < n_opts; i++) {- free((char *)opts[i]);- }- free(opts);-- free(ptx);- if (src != NULL) {- free(src);- }-- return NULL;-}--static char* cuda_setup(struct cuda_context *ctx, const char *src_fragments[],- const char *extra_opts[], const char* cache_fname) {- CUDA_SUCCEED_FATAL(cuInit(0));-- if (cuda_device_setup(ctx) != 0) {- futhark_panic(-1, "No suitable CUDA device found.\n");- }- CUDA_SUCCEED_FATAL(cuCtxCreate(&ctx->cu_ctx, 0, ctx->dev));-- free_list_init(&ctx->free_list);-- ctx->max_shared_memory = device_query(ctx->dev, MAX_SHARED_MEMORY_PER_BLOCK);- ctx->max_block_size = device_query(ctx->dev, MAX_THREADS_PER_BLOCK);- ctx->max_grid_size = device_query(ctx->dev, MAX_GRID_DIM_X);- ctx->max_tile_size = sqrt(ctx->max_block_size);- ctx->max_threshold = 0;- ctx->max_bespoke = 0;- ctx->lockstep_width = device_query(ctx->dev, WARP_SIZE);-- cuda_size_setup(ctx);- return cuda_module_setup(ctx, src_fragments, extra_opts, cache_fname);-}--// Count up the runtime all the profiling_records that occured during execution.-// Also clears the buffer of profiling_records.-static cudaError_t cuda_tally_profiling_records(struct cuda_context *ctx) {- cudaError_t err;- for (int i = 0; i < ctx->profiling_records_used; i++) {- struct profiling_record record = ctx->profiling_records[i];-- float ms;- if ((err = cudaEventElapsedTime(&ms, record.events[0], record.events[1])) != cudaSuccess) {- return err;- }-- // CUDA provides milisecond resolution, but we want microseconds.- *record.runs += 1;- *record.runtime += ms*1000;-- if ((err = cudaEventDestroy(record.events[0])) != cudaSuccess) {- return err;- }- if ((err = cudaEventDestroy(record.events[1])) != cudaSuccess) {- return err;- }-- free(record.events);- }-- ctx->profiling_records_used = 0;-- return cudaSuccess;-}--// Returns pointer to two events.-static cudaEvent_t* cuda_get_events(struct cuda_context *ctx, int *runs, int64_t *runtime) {- if (ctx->profiling_records_used == ctx->profiling_records_capacity) {- ctx->profiling_records_capacity *= 2;- ctx->profiling_records =- realloc(ctx->profiling_records,- ctx->profiling_records_capacity *- sizeof(struct profiling_record));- }- cudaEvent_t *events = calloc(2, sizeof(cudaEvent_t));- cudaEventCreate(&events[0]);- cudaEventCreate(&events[1]);- ctx->profiling_records[ctx->profiling_records_used].events = events;- ctx->profiling_records[ctx->profiling_records_used].runs = runs;- ctx->profiling_records[ctx->profiling_records_used].runtime = runtime;- ctx->profiling_records_used++;- return events;-}--static CUresult cuda_free_all(struct cuda_context *ctx);--static void cuda_cleanup(struct cuda_context *ctx) {- CUDA_SUCCEED_FATAL(cuda_free_all(ctx));- (void)cuda_tally_profiling_records(ctx);- free(ctx->profiling_records);- CUDA_SUCCEED_FATAL(cuModuleUnload(ctx->module));- CUDA_SUCCEED_FATAL(cuCtxDestroy(ctx->cu_ctx));-}--static CUresult cuda_alloc(struct cuda_context *ctx, FILE *log,- size_t min_size, const char *tag,- CUdeviceptr *mem_out, size_t *size_out) {- if (min_size < sizeof(int)) {- min_size = sizeof(int);- }-- if (free_list_find(&ctx->free_list, min_size, tag, size_out, (fl_mem*)mem_out) == 0) {- if (*size_out >= min_size) {- if (ctx->cfg.debugging) {- fprintf(log, "No need to allocate: Found a block in the free list.\n");- }- return CUDA_SUCCESS;- } else {- if (ctx->cfg.debugging) {- fprintf(log, "Found a free block, but it was too small.\n");- }-- CUresult res = cuMemFree(*mem_out);- if (res != CUDA_SUCCESS) {- return res;- }- }- }-- *size_out = min_size;-- if (ctx->cfg.debugging) {- fprintf(log, "Actually allocating the desired block.\n");- }-- CUresult res = cuMemAlloc(mem_out, min_size);- while (res == CUDA_ERROR_OUT_OF_MEMORY) {- CUdeviceptr mem;- if (free_list_first(&ctx->free_list, (fl_mem*)&mem) == 0) {- res = cuMemFree(mem);- if (res != CUDA_SUCCESS) {- return res;- }- } else {- break;- }- res = cuMemAlloc(mem_out, min_size);- }-- return res;-}--static CUresult cuda_free(struct cuda_context *ctx,- CUdeviceptr mem, size_t size, const char *tag) {- free_list_insert(&ctx->free_list, size, (fl_mem)mem, tag);- return CUDA_SUCCESS;-}--static CUresult cuda_free_all(struct cuda_context *ctx) {- CUdeviceptr mem;- free_list_pack(&ctx->free_list);- while (free_list_first(&ctx->free_list, (fl_mem*)&mem) == 0) {- CUresult res = cuMemFree(mem);- if (res != CUDA_SUCCESS) {- return res;- }- }-- return CUDA_SUCCESS;-}--// End of cuda.h.
− rts/c/opencl.h
@@ -1,1066 +0,0 @@-// Start of opencl.h.--#define OPENCL_SUCCEED_FATAL(e) opencl_succeed_fatal(e, #e, __FILE__, __LINE__)-#define OPENCL_SUCCEED_NONFATAL(e) opencl_succeed_nonfatal(e, #e, __FILE__, __LINE__)-// Take care not to override an existing error.-#define OPENCL_SUCCEED_OR_RETURN(e) { \- char *serror = OPENCL_SUCCEED_NONFATAL(e); \- if (serror) { \- if (!ctx->error) { \- ctx->error = serror; \- return bad; \- } else { \- free(serror); \- } \- } \- }--// OPENCL_SUCCEED_OR_RETURN returns the value of the variable 'bad' in-// scope. By default, it will be this one. Create a local variable-// of some other type if needed. This is a bit of a hack, but it-// saves effort in the code generator.-static const int bad = 1;--struct opencl_config {- int debugging;- int profiling;- int logging;- int preferred_device_num;- const char *preferred_platform;- const char *preferred_device;- int ignore_blacklist;-- const char* dump_program_to;- const char* load_program_from;- const char* dump_binary_to;- const char* load_binary_from;-- size_t default_group_size;- size_t default_num_groups;- size_t default_tile_size;- size_t default_reg_tile_size;- size_t default_threshold;-- int default_group_size_changed;- int default_tile_size_changed;-- int num_sizes;- const char **size_names;- const char **size_vars;- int64_t *size_values;- const char **size_classes;-};--static void opencl_config_init(struct opencl_config *cfg,- int num_sizes,- const char *size_names[],- const char *size_vars[],- int64_t *size_values,- const char *size_classes[]) {- cfg->debugging = 0;- cfg->logging = 0;- cfg->profiling = 0;- cfg->preferred_device_num = 0;- cfg->preferred_platform = "";- cfg->preferred_device = "";- cfg->ignore_blacklist = 0;- cfg->dump_program_to = NULL;- cfg->load_program_from = NULL;- cfg->dump_binary_to = NULL;- cfg->load_binary_from = NULL;-- // The following are dummy sizes that mean the concrete defaults- // will be set during initialisation via hardware-inspection-based- // heuristics.- cfg->default_group_size = 0;- cfg->default_num_groups = 0;- cfg->default_tile_size = 0;- cfg->default_reg_tile_size = 0;- cfg->default_threshold = 0;-- cfg->default_group_size_changed = 0;- cfg->default_tile_size_changed = 0;-- cfg->num_sizes = num_sizes;- cfg->size_names = size_names;- cfg->size_vars = size_vars;- cfg->size_values = size_values;- cfg->size_classes = size_classes;-}--// A record of something that happened.-struct profiling_record {- cl_event *event;- int *runs;- int64_t *runtime;-};--struct opencl_context {- cl_device_id device;- cl_context ctx;- cl_command_queue queue;-- struct opencl_config cfg;-- struct free_list free_list;-- size_t max_group_size;- size_t max_num_groups;- size_t max_tile_size;- size_t max_threshold;- size_t max_local_memory;-- size_t lockstep_width;-- struct profiling_record *profiling_records;- int profiling_records_capacity;- int profiling_records_used;-};--struct opencl_device_option {- cl_platform_id platform;- cl_device_id device;- cl_device_type device_type;- char *platform_name;- char *device_name;-};--// This function must be defined by the user. It is invoked by-// setup_opencl() after the platform and device has been found, but-// before the program is loaded. Its intended use is to tune-// constants based on the selected platform and device.-static void post_opencl_setup(struct opencl_context*, struct opencl_device_option*);--static char *strclone(const char *str) {- size_t size = strlen(str) + 1;- char *copy = (char*) malloc(size);- if (copy == NULL) {- return NULL;- }-- memcpy(copy, str, size);- return copy;-}--static const char* opencl_error_string(cl_int err)-{- switch (err) {- case CL_SUCCESS: return "Success!";- case CL_DEVICE_NOT_FOUND: return "Device not found.";- case CL_DEVICE_NOT_AVAILABLE: return "Device not available";- case CL_COMPILER_NOT_AVAILABLE: return "Compiler not available";- case CL_MEM_OBJECT_ALLOCATION_FAILURE: return "Memory object allocation failure";- case CL_OUT_OF_RESOURCES: return "Out of resources";- case CL_OUT_OF_HOST_MEMORY: return "Out of host memory";- case CL_PROFILING_INFO_NOT_AVAILABLE: return "Profiling information not available";- case CL_MEM_COPY_OVERLAP: return "Memory copy overlap";- case CL_IMAGE_FORMAT_MISMATCH: return "Image format mismatch";- case CL_IMAGE_FORMAT_NOT_SUPPORTED: return "Image format not supported";- case CL_BUILD_PROGRAM_FAILURE: return "Program build failure";- case CL_MAP_FAILURE: return "Map failure";- case CL_INVALID_VALUE: return "Invalid value";- case CL_INVALID_DEVICE_TYPE: return "Invalid device type";- case CL_INVALID_PLATFORM: return "Invalid platform";- case CL_INVALID_DEVICE: return "Invalid device";- case CL_INVALID_CONTEXT: return "Invalid context";- case CL_INVALID_QUEUE_PROPERTIES: return "Invalid queue properties";- case CL_INVALID_COMMAND_QUEUE: return "Invalid command queue";- case CL_INVALID_HOST_PTR: return "Invalid host pointer";- case CL_INVALID_MEM_OBJECT: return "Invalid memory object";- case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: return "Invalid image format descriptor";- case CL_INVALID_IMAGE_SIZE: return "Invalid image size";- case CL_INVALID_SAMPLER: return "Invalid sampler";- case CL_INVALID_BINARY: return "Invalid binary";- case CL_INVALID_BUILD_OPTIONS: return "Invalid build options";- case CL_INVALID_PROGRAM: return "Invalid program";- case CL_INVALID_PROGRAM_EXECUTABLE: return "Invalid program executable";- case CL_INVALID_KERNEL_NAME: return "Invalid kernel name";- case CL_INVALID_KERNEL_DEFINITION: return "Invalid kernel definition";- case CL_INVALID_KERNEL: return "Invalid kernel";- case CL_INVALID_ARG_INDEX: return "Invalid argument index";- case CL_INVALID_ARG_VALUE: return "Invalid argument value";- case CL_INVALID_ARG_SIZE: return "Invalid argument size";- case CL_INVALID_KERNEL_ARGS: return "Invalid kernel arguments";- case CL_INVALID_WORK_DIMENSION: return "Invalid work dimension";- case CL_INVALID_WORK_GROUP_SIZE: return "Invalid work group size";- case CL_INVALID_WORK_ITEM_SIZE: return "Invalid work item size";- case CL_INVALID_GLOBAL_OFFSET: return "Invalid global offset";- case CL_INVALID_EVENT_WAIT_LIST: return "Invalid event wait list";- case CL_INVALID_EVENT: return "Invalid event";- case CL_INVALID_OPERATION: return "Invalid operation";- case CL_INVALID_GL_OBJECT: return "Invalid OpenGL object";- case CL_INVALID_BUFFER_SIZE: return "Invalid buffer size";- case CL_INVALID_MIP_LEVEL: return "Invalid mip-map level";- default: return "Unknown";- }-}--static void opencl_succeed_fatal(cl_int ret,- const char *call,- const char *file,- int line) {- if (ret != CL_SUCCESS) {- futhark_panic(-1, "%s:%d: OpenCL call\n %s\nfailed with error code %d (%s)\n",- file, line, call, ret, opencl_error_string(ret));- }-}--static char* opencl_succeed_nonfatal(cl_int ret,- const char *call,- const char *file,- int line) {- if (ret != CL_SUCCESS) {- return msgprintf("%s:%d: OpenCL call\n %s\nfailed with error code %d (%s)\n",- file, line, call, ret, opencl_error_string(ret));- } else {- return NULL;- }-}--static void set_preferred_platform(struct opencl_config *cfg, const char *s) {- cfg->preferred_platform = s;- cfg->ignore_blacklist = 1;-}--static void set_preferred_device(struct opencl_config *cfg, const char *s) {- int x = 0;- if (*s == '#') {- s++;- while (isdigit(*s)) {- x = x * 10 + (*s++)-'0';- }- // Skip trailing spaces.- while (isspace(*s)) {- s++;- }- }- cfg->preferred_device = s;- cfg->preferred_device_num = x;- cfg->ignore_blacklist = 1;-}--static char* opencl_platform_info(cl_platform_id platform,- cl_platform_info param) {- size_t req_bytes;- char *info;-- OPENCL_SUCCEED_FATAL(clGetPlatformInfo(platform, param, 0, NULL, &req_bytes));-- info = (char*) malloc(req_bytes);-- OPENCL_SUCCEED_FATAL(clGetPlatformInfo(platform, param, req_bytes, info, NULL));-- return info;-}--static char* opencl_device_info(cl_device_id device,- cl_device_info param) {- size_t req_bytes;- char *info;-- OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device, param, 0, NULL, &req_bytes));-- info = (char*) malloc(req_bytes);-- OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device, param, req_bytes, info, NULL));-- return info;-}--static void opencl_all_device_options(struct opencl_device_option **devices_out,- size_t *num_devices_out) {- size_t num_devices = 0, num_devices_added = 0;-- cl_platform_id *all_platforms;- cl_uint *platform_num_devices;-- cl_uint num_platforms;-- // Find the number of platforms.- OPENCL_SUCCEED_FATAL(clGetPlatformIDs(0, NULL, &num_platforms));-- // Make room for them.- all_platforms = calloc(num_platforms, sizeof(cl_platform_id));- platform_num_devices = calloc(num_platforms, sizeof(cl_uint));-- // Fetch all the platforms.- OPENCL_SUCCEED_FATAL(clGetPlatformIDs(num_platforms, all_platforms, NULL));-- // Count the number of devices for each platform, as well as the- // total number of devices.- for (cl_uint i = 0; i < num_platforms; i++) {- if (clGetDeviceIDs(all_platforms[i], CL_DEVICE_TYPE_ALL,- 0, NULL, &platform_num_devices[i]) == CL_SUCCESS) {- num_devices += platform_num_devices[i];- } else {- platform_num_devices[i] = 0;- }- }-- // Make room for all the device options.- struct opencl_device_option *devices =- calloc(num_devices, sizeof(struct opencl_device_option));-- // Loop through the platforms, getting information about their devices.- for (cl_uint i = 0; i < num_platforms; i++) {- cl_platform_id platform = all_platforms[i];- cl_uint num_platform_devices = platform_num_devices[i];-- if (num_platform_devices == 0) {- continue;- }-- char *platform_name = opencl_platform_info(platform, CL_PLATFORM_NAME);- cl_device_id *platform_devices =- calloc(num_platform_devices, sizeof(cl_device_id));-- // Fetch all the devices.- OPENCL_SUCCEED_FATAL(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL,- num_platform_devices, platform_devices, NULL));-- // Loop through the devices, adding them to the devices array.- for (cl_uint i = 0; i < num_platform_devices; i++) {- char *device_name = opencl_device_info(platform_devices[i], CL_DEVICE_NAME);- devices[num_devices_added].platform = platform;- devices[num_devices_added].device = platform_devices[i];- OPENCL_SUCCEED_FATAL(clGetDeviceInfo(platform_devices[i], CL_DEVICE_TYPE,- sizeof(cl_device_type),- &devices[num_devices_added].device_type,- NULL));- // We don't want the structs to share memory, so copy the platform name.- // Each device name is already unique.- devices[num_devices_added].platform_name = strclone(platform_name);- devices[num_devices_added].device_name = device_name;- num_devices_added++;- }- free(platform_devices);- free(platform_name);- }- free(all_platforms);- free(platform_num_devices);-- *devices_out = devices;- *num_devices_out = num_devices;-}--// Returns 0 on success.-static int list_devices(void) {- struct opencl_device_option *devices;- size_t num_devices;-- opencl_all_device_options(&devices, &num_devices);-- const char *cur_platform = "";- for (size_t i = 0; i < num_devices; i++) {- struct opencl_device_option device = devices[i];- if (strcmp(cur_platform, device.platform_name) != 0) {- printf("Platform: %s\n", device.platform_name);- cur_platform = device.platform_name;- }- printf("[%d]: %s\n", (int)i, device.device_name);- }-- // Free all the platform and device names.- for (size_t j = 0; j < num_devices; j++) {- free(devices[j].platform_name);- free(devices[j].device_name);- }- free(devices);-- return 0;-}--// Returns 0 on success.-static int select_device_interactively(struct opencl_config *cfg) {- struct opencl_device_option *devices;- size_t num_devices;- int ret = 1;-- opencl_all_device_options(&devices, &num_devices);-- printf("Choose OpenCL device:\n");- const char *cur_platform = "";- for (size_t i = 0; i < num_devices; i++) {- struct opencl_device_option device = devices[i];- if (strcmp(cur_platform, device.platform_name) != 0) {- printf("Platform: %s\n", device.platform_name);- cur_platform = device.platform_name;- }- printf("[%d] %s\n", (int)i, device.device_name);- }-- int selection;- printf("Choice: ");- if (scanf("%d", &selection) == 1) {- ret = 0;- cfg->preferred_platform = "";- cfg->preferred_device = "";- cfg->preferred_device_num = selection;- cfg->ignore_blacklist = 1;- }-- // Free all the platform and device names.- for (size_t j = 0; j < num_devices; j++) {- free(devices[j].platform_name);- free(devices[j].device_name);- }- free(devices);-- return ret;-}--static int is_blacklisted(const char *platform_name, const char *device_name,- const struct opencl_config *cfg) {- if (strcmp(cfg->preferred_platform, "") != 0 ||- strcmp(cfg->preferred_device, "") != 0) {- return 0;- } else if (strstr(platform_name, "Apple") != NULL &&- strstr(device_name, "Intel(R) Core(TM)") != NULL) {- return 1;- } else {- return 0;- }-}--static struct opencl_device_option get_preferred_device(const struct opencl_config *cfg) {- struct opencl_device_option *devices;- size_t num_devices;-- opencl_all_device_options(&devices, &num_devices);-- int num_device_matches = 0;-- for (size_t i = 0; i < num_devices; i++) {- struct opencl_device_option device = devices[i];- if (strstr(device.platform_name, cfg->preferred_platform) != NULL &&- strstr(device.device_name, cfg->preferred_device) != NULL &&- (cfg->ignore_blacklist ||- !is_blacklisted(device.platform_name, device.device_name, cfg)) &&- num_device_matches++ == cfg->preferred_device_num) {- // Free all the platform and device names, except the ones we have chosen.- for (size_t j = 0; j < num_devices; j++) {- if (j != i) {- free(devices[j].platform_name);- free(devices[j].device_name);- }- }- free(devices);- return device;- }- }-- futhark_panic(1, "Could not find acceptable OpenCL device.\n");- exit(1); // Never reached-}--static void describe_device_option(struct opencl_device_option device) {- fprintf(stderr, "Using platform: %s\n", device.platform_name);- fprintf(stderr, "Using device: %s\n", device.device_name);-}--static cl_build_status build_opencl_program(cl_program program, cl_device_id device, const char* options) {- cl_int clBuildProgram_error = clBuildProgram(program, 1, &device, options, NULL, NULL);-- // Avoid termination due to CL_BUILD_PROGRAM_FAILURE- if (clBuildProgram_error != CL_SUCCESS &&- clBuildProgram_error != CL_BUILD_PROGRAM_FAILURE) {- OPENCL_SUCCEED_FATAL(clBuildProgram_error);- }-- cl_build_status build_status;- OPENCL_SUCCEED_FATAL(clGetProgramBuildInfo(program,- device,- CL_PROGRAM_BUILD_STATUS,- sizeof(cl_build_status),- &build_status,- NULL));-- if (build_status != CL_SUCCESS) {- char *build_log;- size_t ret_val_size;- OPENCL_SUCCEED_FATAL(clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size));-- build_log = (char*) malloc(ret_val_size+1);- OPENCL_SUCCEED_FATAL(clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL));-- // The spec technically does not say whether the build log is zero-terminated, so let's be careful.- build_log[ret_val_size] = '\0';-- fprintf(stderr, "Build log:\n%s\n", build_log);-- free(build_log);- }-- return build_status;-}--// Fields in a bitmask indicating which types we must be sure are-// available.-enum opencl_required_type { OPENCL_F64 = 1 };--static char* mk_compile_opts(struct opencl_context *ctx,- const char *extra_build_opts[],- struct opencl_device_option device_option) {- int compile_opts_size = 1024;-- for (int i = 0; i < ctx->cfg.num_sizes; i++) {- compile_opts_size += strlen(ctx->cfg.size_names[i]) + 20;- }-- for (int i = 0; extra_build_opts[i] != NULL; i++) {- compile_opts_size += strlen(extra_build_opts[i] + 1);- }-- char *compile_opts = (char*) malloc(compile_opts_size);-- int w = snprintf(compile_opts, compile_opts_size,- "-DLOCKSTEP_WIDTH=%d ",- (int)ctx->lockstep_width);-- w += snprintf(compile_opts+w, compile_opts_size-w,- "-D%s=%d ",- "max_group_size",- (int)ctx->max_group_size);-- for (int i = 0; i < ctx->cfg.num_sizes; i++) {- w += snprintf(compile_opts+w, compile_opts_size-w,- "-D%s=%d ",- ctx->cfg.size_vars[i],- (int)ctx->cfg.size_values[i]);- }-- for (int i = 0; extra_build_opts[i] != NULL; i++) {- w += snprintf(compile_opts+w, compile_opts_size-w,- "%s ", extra_build_opts[i]);- }-- // Oclgrind claims to support cl_khr_fp16, but this is not actually- // the case.- if (strcmp(device_option.platform_name, "Oclgrind") == 0) {- w += snprintf(compile_opts+w, compile_opts_size-w, "-DEMULATE_F16 ");- }-- return compile_opts;-}--// We take as input several strings representing the program, because-// C does not guarantee that the compiler supports particularly large-// literals. Notably, Visual C has a limit of 2048 characters. The-// array must be NULL-terminated.-static cl_program setup_opencl_with_command_queue(struct opencl_context *ctx,- cl_command_queue queue,- const char *srcs[],- int required_types,- const char *extra_build_opts[],- const char* cache_fname) {- int error;-- free_list_init(&ctx->free_list);- ctx->queue = queue;-- OPENCL_SUCCEED_FATAL(clGetCommandQueueInfo(ctx->queue, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx->ctx, NULL));-- // Fill out the device info. This is redundant work if we are- // called from setup_opencl() (which is the common case), but I- // doubt it matters much.- struct opencl_device_option device_option;- OPENCL_SUCCEED_FATAL(clGetCommandQueueInfo(ctx->queue, CL_QUEUE_DEVICE,- sizeof(cl_device_id),- &device_option.device,- NULL));- OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_PLATFORM,- sizeof(cl_platform_id),- &device_option.platform,- NULL));- OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_TYPE,- sizeof(cl_device_type),- &device_option.device_type,- NULL));- device_option.platform_name = opencl_platform_info(device_option.platform, CL_PLATFORM_NAME);- device_option.device_name = opencl_device_info(device_option.device, CL_DEVICE_NAME);-- ctx->device = device_option.device;-- if (required_types & OPENCL_F64) {- cl_uint supported;- OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE,- sizeof(cl_uint), &supported, NULL));- if (!supported) {- futhark_panic(1, "Program uses double-precision floats, but this is not supported on the chosen device: %s\n",- device_option.device_name);- }- }-- size_t max_group_size;- OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_MAX_WORK_GROUP_SIZE,- sizeof(size_t), &max_group_size, NULL));-- size_t max_tile_size = sqrt(max_group_size);-- cl_ulong max_local_memory;- OPENCL_SUCCEED_FATAL(clGetDeviceInfo(device_option.device, CL_DEVICE_LOCAL_MEM_SIZE,- sizeof(size_t), &max_local_memory, NULL));-- // Futhark reserves 4 bytes for bookkeeping information.- max_local_memory -= 4;-- // The OpenCL implementation may reserve some local memory bytes for- // various purposes. In principle, we should use- // clGetKernelWorkGroupInfo() to figure out for each kernel how much- // is actually available, but our current code generator design- // makes this infeasible. Instead, we have this nasty hack where we- // arbitrarily subtract some bytes, based on empirical measurements- // (but which might be arbitrarily wrong). Fortunately, we rarely- // try to really push the local memory usage.- if (strstr(device_option.platform_name, "NVIDIA CUDA") != NULL) {- max_local_memory -= 12;- } else if (strstr(device_option.platform_name, "AMD") != NULL) {- max_local_memory -= 16;- }-- // Make sure this function is defined.- post_opencl_setup(ctx, &device_option);-- if (max_group_size < ctx->cfg.default_group_size) {- if (ctx->cfg.default_group_size_changed) {- fprintf(stderr, "Note: Device limits default group size to %zu (down from %zu).\n",- max_group_size, ctx->cfg.default_group_size);- }- ctx->cfg.default_group_size = max_group_size;- }-- if (max_tile_size < ctx->cfg.default_tile_size) {- if (ctx->cfg.default_tile_size_changed) {- fprintf(stderr, "Note: Device limits default tile size to %zu (down from %zu).\n",- max_tile_size, ctx->cfg.default_tile_size);- }- ctx->cfg.default_tile_size = max_tile_size;- }-- ctx->max_group_size = max_group_size;- ctx->max_tile_size = max_tile_size; // No limit.- ctx->max_threshold = ctx->max_num_groups = 0; // No limit.- ctx->max_local_memory = max_local_memory;-- // Now we go through all the sizes, clamp them to the valid range,- // or set them to the default.- for (int i = 0; i < ctx->cfg.num_sizes; i++) {- const char *size_class = ctx->cfg.size_classes[i];- int64_t *size_value = &ctx->cfg.size_values[i];- const char* size_name = ctx->cfg.size_names[i];- int64_t max_value = 0, default_value = 0;-- if (strstr(size_class, "group_size") == size_class) {- max_value = max_group_size;- default_value = ctx->cfg.default_group_size;- } else if (strstr(size_class, "num_groups") == size_class) {- max_value = max_group_size; // Futhark assumes this constraint.- default_value = ctx->cfg.default_num_groups;- // XXX: as a quick and dirty hack, use twice as many threads for- // histograms by default. We really should just be smarter- // about sizes somehow.- if (strstr(size_name, ".seghist_") != NULL) {- default_value *= 2;- }- } else if (strstr(size_class, "tile_size") == size_class) {- max_value = sqrt(max_group_size);- default_value = ctx->cfg.default_tile_size;- } else if (strstr(size_class, "reg_tile_size") == size_class) {- max_value = 0; // No limit.- default_value = ctx->cfg.default_reg_tile_size;- } else if (strstr(size_class, "threshold") == size_class) {- // Threshold can be as large as it takes.- default_value = ctx->cfg.default_threshold;- } else {- // Bespoke sizes have no limit or default.- }- if (*size_value == 0) {- *size_value = default_value;- } else if (max_value > 0 && *size_value > max_value) {- fprintf(stderr, "Note: Device limits %s to %d (down from %d)\n",- size_name, (int)max_value, (int)*size_value);- *size_value = max_value;- }- }-- if (ctx->lockstep_width == 0) {- ctx->lockstep_width = 1;- }-- if (ctx->cfg.logging) {- fprintf(stderr, "Lockstep width: %d\n", (int)ctx->lockstep_width);- fprintf(stderr, "Default group size: %d\n", (int)ctx->cfg.default_group_size);- fprintf(stderr, "Default number of groups: %d\n", (int)ctx->cfg.default_num_groups);- }-- char *compile_opts = mk_compile_opts(ctx, extra_build_opts, device_option);-- if (ctx->cfg.logging) {- fprintf(stderr, "OpenCL compiler options: %s\n", compile_opts);- }-- char *fut_opencl_src = NULL;- cl_program prog;- error = CL_SUCCESS;-- struct cache_hash h;-- int loaded_from_cache = 0;- if (ctx->cfg.load_binary_from == NULL) {- size_t src_size = 0;-- // Maybe we have to read OpenCL source from somewhere else (used for debugging).- if (ctx->cfg.load_program_from != NULL) {- fut_opencl_src = slurp_file(ctx->cfg.load_program_from, NULL);- assert(fut_opencl_src != NULL);- } else {- // Construct the OpenCL source concatenating all the fragments.- for (const char **src = srcs; src && *src; src++) {- src_size += strlen(*src);- }-- fut_opencl_src = (char*) malloc(src_size + 1);-- size_t n, i;- for (i = 0, n = 0; srcs && srcs[i]; i++) {- strncpy(fut_opencl_src+n, srcs[i], src_size-n);- n += strlen(srcs[i]);- }- fut_opencl_src[src_size] = 0;- }-- if (ctx->cfg.dump_program_to != NULL) {- if (ctx->cfg.logging) {- fprintf(stderr, "Dumping OpenCL source to %s...\n", ctx->cfg.dump_program_to);- }-- dump_file(ctx->cfg.dump_program_to, fut_opencl_src, strlen(fut_opencl_src));- }-- if (cache_fname != NULL) {- if (ctx->cfg.logging) {- fprintf(stderr, "Restoring cache from from %s...\n", cache_fname);- }- cache_hash_init(&h);- cache_hash(&h, fut_opencl_src, strlen(fut_opencl_src));- cache_hash(&h, compile_opts, strlen(compile_opts));-- unsigned char *buf;- size_t bufsize;- errno = 0;- if (cache_restore(cache_fname, &h, &buf, &bufsize) != 0) {- if (ctx->cfg.logging) {- fprintf(stderr, "Failed to restore cache (errno: %s)\n", strerror(errno));- }- } else {- if (ctx->cfg.logging) {- fprintf(stderr, "Cache restored; loading OpenCL binary...\n");- }-- cl_int status = 0;- prog = clCreateProgramWithBinary(ctx->ctx, 1, &device_option.device,- &bufsize, (const unsigned char**)&buf,- &status, &error);- if (status == CL_SUCCESS) {- loaded_from_cache = 1;- if (ctx->cfg.logging) {- fprintf(stderr, "Loading succeeded.\n");- }- } else {- if (ctx->cfg.logging) {- fprintf(stderr, "Loading failed.\n");- }- }- }- }-- if (!loaded_from_cache) {- if (ctx->cfg.logging) {- fprintf(stderr, "Creating OpenCL program...\n");- }-- const char* src_ptr[] = {fut_opencl_src};- prog = clCreateProgramWithSource(ctx->ctx, 1, src_ptr, &src_size, &error);- OPENCL_SUCCEED_FATAL(error);- }- } else {- if (ctx->cfg.logging) {- fprintf(stderr, "Loading OpenCL binary from %s...\n", ctx->cfg.load_binary_from);- }- size_t binary_size;- unsigned char *fut_opencl_bin =- (unsigned char*) slurp_file(ctx->cfg.load_binary_from, &binary_size);- assert(fut_opencl_bin != NULL);- const unsigned char *binaries[1] = { fut_opencl_bin };- cl_int status = 0;-- prog = clCreateProgramWithBinary(ctx->ctx, 1, &device_option.device,- &binary_size, binaries,- &status, &error);-- OPENCL_SUCCEED_FATAL(status);- OPENCL_SUCCEED_FATAL(error);- }-- if (ctx->cfg.logging) {- fprintf(stderr, "Building OpenCL program...\n");- }- OPENCL_SUCCEED_FATAL(build_opencl_program(prog, device_option.device, compile_opts));-- free(compile_opts);- free(fut_opencl_src);-- size_t binary_size = 0;- unsigned char *binary = NULL;- int store_in_cache = cache_fname != NULL && !loaded_from_cache;- if (store_in_cache || ctx->cfg.dump_binary_to != NULL) {- OPENCL_SUCCEED_FATAL(clGetProgramInfo(prog, CL_PROGRAM_BINARY_SIZES,- sizeof(size_t), &binary_size, NULL));- binary = (unsigned char*) malloc(binary_size);- OPENCL_SUCCEED_FATAL(clGetProgramInfo(prog, CL_PROGRAM_BINARIES,- sizeof(unsigned char*), &binary, NULL));- }-- if (store_in_cache) {- if (ctx->cfg.logging) {- fprintf(stderr, "Caching OpenCL binary in %s...\n", cache_fname);- }- if (cache_store(cache_fname, &h, binary, binary_size) != 0) {- printf("Failed to cache binary: %s\n", strerror(errno));- }- }-- if (ctx->cfg.dump_binary_to != NULL) {- if (ctx->cfg.logging) {- fprintf(stderr, "Dumping OpenCL binary to %s...\n", ctx->cfg.dump_binary_to);- }- dump_file(ctx->cfg.dump_binary_to, binary, binary_size);- }-- return prog;-}--static cl_program setup_opencl(struct opencl_context *ctx,- const char *srcs[],- int required_types,- const char *extra_build_opts[],- const char* cache_fname) {-- ctx->lockstep_width = 0; // Real value set later.-- struct opencl_device_option device_option = get_preferred_device(&ctx->cfg);-- if (ctx->cfg.logging) {- describe_device_option(device_option);- }-- // Note that NVIDIA's OpenCL requires the platform property- cl_context_properties properties[] = {- CL_CONTEXT_PLATFORM,- (cl_context_properties)device_option.platform,- 0- };-- cl_int clCreateContext_error;- ctx->ctx = clCreateContext(properties, 1, &device_option.device, NULL, NULL, &clCreateContext_error);- OPENCL_SUCCEED_FATAL(clCreateContext_error);-- cl_int clCreateCommandQueue_error;- cl_command_queue queue =- clCreateCommandQueue(ctx->ctx,- device_option.device,- ctx->cfg.profiling ? CL_QUEUE_PROFILING_ENABLE : 0,- &clCreateCommandQueue_error);- OPENCL_SUCCEED_FATAL(clCreateCommandQueue_error);-- return setup_opencl_with_command_queue(ctx, queue, srcs, required_types, extra_build_opts,- cache_fname);-}--// Count up the runtime all the profiling_records that occured during execution.-// Also clears the buffer of profiling_records.-static cl_int opencl_tally_profiling_records(struct opencl_context *ctx) {- cl_int err;- for (int i = 0; i < ctx->profiling_records_used; i++) {- struct profiling_record record = ctx->profiling_records[i];-- cl_ulong start_t, end_t;-- if ((err = clGetEventProfilingInfo(*record.event,- CL_PROFILING_COMMAND_START,- sizeof(start_t),- &start_t,- NULL)) != CL_SUCCESS) {- return err;- }-- if ((err = clGetEventProfilingInfo(*record.event,- CL_PROFILING_COMMAND_END,- sizeof(end_t),- &end_t,- NULL)) != CL_SUCCESS) {- return err;- }-- // OpenCL provides nanosecond resolution, but we want- // microseconds.- *record.runs += 1;- *record.runtime += (end_t - start_t)/1000;-- if ((err = clReleaseEvent(*record.event)) != CL_SUCCESS) {- return err;- }- free(record.event);- }-- ctx->profiling_records_used = 0;-- return CL_SUCCESS;-}--// If profiling, produce an event associated with a profiling record.-static cl_event* opencl_get_event(struct opencl_context *ctx, int *runs, int64_t *runtime) {- if (ctx->profiling_records_used == ctx->profiling_records_capacity) {- ctx->profiling_records_capacity *= 2;- ctx->profiling_records =- realloc(ctx->profiling_records,- ctx->profiling_records_capacity *- sizeof(struct profiling_record));- }- cl_event *event = malloc(sizeof(cl_event));- ctx->profiling_records[ctx->profiling_records_used].event = event;- ctx->profiling_records[ctx->profiling_records_used].runs = runs;- ctx->profiling_records[ctx->profiling_records_used].runtime = runtime;- ctx->profiling_records_used++;- return event;-}--// Allocate memory from driver. The problem is that OpenCL may perform-// lazy allocation, so we cannot know whether an allocation succeeded-// until the first time we try to use it. Hence we immediately-// perform a write to see if the allocation succeeded. This is slow,-// but the assumption is that this operation will be rare (most things-// will go through the free list).-static int opencl_alloc_actual(struct opencl_context *ctx, size_t size, cl_mem *mem_out) {- int error;- *mem_out = clCreateBuffer(ctx->ctx, CL_MEM_READ_WRITE, size, NULL, &error);-- if (error != CL_SUCCESS) {- return error;- }-- int x = 2;- error = clEnqueueWriteBuffer(ctx->queue, *mem_out,- CL_TRUE,- 0, sizeof(x), &x,- 0, NULL, NULL);-- // No need to wait for completion here. clWaitForEvents() cannot- // return mem object allocation failures. This implies that the- // buffer is faulted onto the device on enqueue. (Observation by- // Andreas Kloeckner.)-- return error;-}--static int opencl_alloc(struct opencl_context *ctx, FILE *log,- size_t min_size, const char *tag,- cl_mem *mem_out, size_t *size_out) {- (void)tag;- if (min_size < sizeof(int)) {- min_size = sizeof(int);- }-- cl_mem* memptr;- if (free_list_find(&ctx->free_list, min_size, tag, size_out, (fl_mem*)&memptr) == 0) {- // Successfully found a free block. Is it big enough?- if (*size_out >= min_size) {- if (ctx->cfg.debugging) {- fprintf(log, "No need to allocate: Found a block in the free list.\n");- }- *mem_out = *memptr;- free(memptr);- return CL_SUCCESS;- } else {- if (ctx->cfg.debugging) {- fprintf(log, "Found a free block, but it was too small.\n");- }- int error = clReleaseMemObject(*memptr);- free(*memptr);- if (error != CL_SUCCESS) {- return error;- }- }- }-- *size_out = min_size;-- // We have to allocate a new block from the driver. If the- // allocation does not succeed, then we might be in an out-of-memory- // situation. We now start freeing things from the free list until- // we think we have freed enough that the allocation will succeed.- // Since we don't know how far the allocation is from fitting, we- // have to check after every deallocation. This might be pretty- // expensive. Let's hope that this case is hit rarely.-- if (ctx->cfg.debugging) {- fprintf(log, "Actually allocating the desired block.\n");- }-- int error = opencl_alloc_actual(ctx, min_size, mem_out);-- while (error == CL_MEM_OBJECT_ALLOCATION_FAILURE) {- if (ctx->cfg.debugging) {- fprintf(log, "Out of OpenCL memory: releasing entry from the free list...\n");- }- cl_mem* memptr;- if (free_list_first(&ctx->free_list, (fl_mem*)&memptr) == 0) {- cl_mem mem = *memptr;- free(memptr);- error = clReleaseMemObject(mem);- if (error != CL_SUCCESS) {- return error;- }- } else {- break;- }- error = opencl_alloc_actual(ctx, min_size, mem_out);- }-- return error;-}--static int opencl_free(struct opencl_context *ctx,- cl_mem mem, size_t size, const char *tag) {- cl_mem* memptr = malloc(sizeof(cl_mem));- *memptr = mem;- free_list_insert(&ctx->free_list, size, (fl_mem)memptr, tag);- return CL_SUCCESS;-}--static int opencl_free_all(struct opencl_context *ctx) {- free_list_pack(&ctx->free_list);- cl_mem* memptr;- while (free_list_first(&ctx->free_list, (fl_mem*)&memptr) == 0) {- cl_mem mem = *memptr;- free(memptr);- int error = clReleaseMemObject(mem);- if (error != CL_SUCCESS) {- return error;- }- }-- return CL_SUCCESS;-}--// Free everything that belongs to 'ctx', but do not free 'ctx'-// itself.-static void teardown_opencl(struct opencl_context *ctx) {- (void)opencl_tally_profiling_records(ctx);- free(ctx->profiling_records);- (void)opencl_free_all(ctx);- (void)clReleaseCommandQueue(ctx->queue);- (void)clReleaseContext(ctx->ctx);-}--// End of opencl.h.
rts/c/scalar.h view
@@ -1774,6 +1774,10 @@ return log10(x); } +static inline float futrts_log1p_32(float x) {+ return log1p(x);+}+ static inline float futrts_sqrt32(float x) { return sqrt(x); }@@ -1904,6 +1908,13 @@ return futrts_log32(x) / log(10.0f); } +static inline float futrts_log1p_32(float x) {+ if(x == -1.0f || (futrts_isinf32(x) && x > 0.0f)) return x / 0.0f;+ float y = 1.0f + x;+ float z = y - 1.0f;+ return log(y) - (z-x)/y;+}+ static inline float futrts_sqrt32(float x) { return sqrt(x); }@@ -2106,6 +2117,10 @@ return log10f(x); } +static inline float futrts_log1p_32(float x) {+ return log1pf(x);+}+ static inline float futrts_sqrt32(float x) { return sqrtf(x); }@@ -2357,6 +2372,13 @@ return futrts_log64(x)/log(10.0d); } +static inline double futrts_log1p_64(double x) {+ if(x == -1.0d || (futrts_isinf64(x) && x > 0.0d)) return x / 0.0d;+ double y = 1.0d + x;+ double z = y - 1.0d;+ return log(y) - (z-x)/y;+}+ static inline double futrts_sqrt64(double x) { return sqrt(x); }@@ -2722,6 +2744,10 @@ static inline double futrts_log10_64(double x) { return log10(x);+}++static inline double futrts_log1p_64(double x) {+ return log1p(x); } static inline double futrts_sqrt64(double x) {
rts/c/scalar_f16.h view
@@ -217,6 +217,10 @@ return log10(x); } +static inline f16 futrts_log1p_16(f16 x) {+ return log1p(x);+}+ static inline f16 futrts_sqrt16(f16 x) { return sqrt(x); }@@ -346,6 +350,13 @@ return futrts_log16(x) / log(10.0f16); } +static inline f16 futrts_log1p_16(f16 x) {+ if(x == -1.0f16 || (futrts_isinf16(x) && x > 0.0f16)) return x / 0.0f16;+ f16 y = 1.0f16 + x;+ f16 z = y - 1.0f16;+ return log(y) - (z-x)/y;+}+ static inline f16 futrts_sqrt16(f16 x) { return (float16)sqrt((float)x); }@@ -497,6 +508,10 @@ return hlog10(x); } +static inline f16 futrts_log1p_16(f16 x) {+ return (f16)log1pf((float)x);+}+ static inline f16 futrts_sqrt16(f16 x) { return hsqrt(x); }@@ -693,6 +708,10 @@ static inline f16 futrts_log10_16(f16 x) { return futrts_log10_32(x);+}++static inline f16 futrts_log1p_16(f16 x) {+ return futrts_log1p_32(x); } static inline f16 futrts_sqrt16(f16 x) {
rts/c/server.h view
@@ -373,43 +373,49 @@ if (f == NULL) { failure(); printf("Failed to open %s: %s\n", fname, strerror(errno));- } else {- int values = 0;- for (int i = 1; arg_exists(args, i); i+=2, values++) {- const char *vname = get_arg(args, i);- const char *type = get_arg(args, i+1);+ return;+ } - const struct type *t = get_type(s, type);- struct variable *v = create_variable(s, vname, t);+ int bad = 0;+ int values = 0;+ for (int i = 1; arg_exists(args, i); i+=2, values++) {+ const char *vname = get_arg(args, i);+ const char *type = get_arg(args, i+1); - if (v == NULL) {- failure();- printf("Variable already exists: %s\n", vname);- return;- }+ const struct type *t = get_type(s, type);+ struct variable *v = create_variable(s, vname, t); - errno = 0;- if (t->restore(t->aux, f, s->ctx, value_ptr(&v->value)) != 0) {- failure();- printf("Failed to restore variable %s.\n"- "Possibly malformed data in %s (errno: %s)\n",- vname, fname, strerror(errno));- drop_variable(v);- break;- }+ if (v == NULL) {+ bad = 1;+ failure();+ printf("Variable already exists: %s\n", vname);+ break; } - if (end_of_input(f) != 0) {+ errno = 0;+ if (t->restore(t->aux, f, s->ctx, value_ptr(&v->value)) != 0) {+ bad = 1; failure();- printf("Expected EOF after reading %d values from %s\n",- values, fname);+ printf("Failed to restore variable %s.\n"+ "Possibly malformed data in %s (errno: %s)\n",+ vname, fname, strerror(errno));+ drop_variable(v);+ break; }+ } - fclose(f);+ if (!bad && end_of_input(f) != 0) {+ failure();+ printf("Expected EOF after reading %d values from %s\n",+ values, fname); } - int err = futhark_context_sync(s->ctx);- error_check(s, err);+ fclose(f);++ if (!bad) {+ int err = futhark_context_sync(s->ctx);+ error_check(s, err);+ } } void cmd_store(struct server_state *s, const char *args[]) {
rts/c/uniform.h view
@@ -931,6 +931,13 @@ return futrts_log32(x) / log(10.0f); } +static inline uniform float futrts_log1p_32(uniform float x) {+ if(x == -1.0f || (futrts_isinf32(x) && x > 0.0f)) return x / 0.0f;+ uniform float y = 1.0f + x;+ uniform float z = y - 1.0f;+ return log(y) - (z-x)/y;+}+ static inline uniform float futrts_sqrt32(uniform float x) { return sqrt(x); }@@ -1189,6 +1196,13 @@ return futrts_log64(x)/log(10.0d); } +static inline uniform double futrts_log1p_64(uniform double x) {+ if(x == -1.0d || (futrts_isinf64(x) && x > 0.0d)) return x / 0.0d;+ uniform double y = 1.0d + x;+ uniform double z = y - 1.0d;+ return log(y) - (z-x)/y;+}+ static inline uniform double futrts_sqrt64(uniform double x) { return sqrt(x); }@@ -1559,6 +1573,13 @@ static inline uniform f16 futrts_log10_16(uniform f16 x) { return futrts_log16(x) / log(10.0f16);+}++static inline uniform f16 futrts_log1p_16(uniform f16 x) {+ if(x == -1.0f16 || (futrts_isinf16(x) && x > 0.0f16)) return x / 0.0f16;+ uniform f16 y = 1.0f16 + x;+ uniform f16 z = y - 1.0f16;+ return log(y) - (z-x)/y; } static inline uniform f16 futrts_sqrt16(uniform f16 x) {
rts/c/util.h view
@@ -14,6 +14,7 @@ struct str_builder; static void str_builder_init(struct str_builder *b); static void str_builder(struct str_builder *b, const char *s, ...);+static char *strclone(const char *str); static void futhark_panic(int eval, const char *fmt, ...) { va_list ap;@@ -133,6 +134,18 @@ va_start(vl, s); // Must re-init. vsnprintf(b->str+b->used, b->capacity-b->used, s, vl); b->used += needed;+}+++static char *strclone(const char *str) {+ size_t size = strlen(str) + 1;+ char *copy = (char*) malloc(size);+ if (copy == NULL) {+ return NULL;+ }++ memcpy(copy, str, size);+ return copy; } // End of util.h.
rts/javascript/server.js view
@@ -59,7 +59,7 @@ _cmd_inputs(args) { var entry = this._get_arg(args, 0);- var inputs = this._get_entry_point(entry)[0];+ var inputs = this._get_entry_point(entry)[1]; for (var i = 0; i < inputs.length; i++) { console.log(inputs[i]); }@@ -67,7 +67,7 @@ _cmd_outputs(args) { var entry = this._get_arg(args, 0);- var outputs = this._get_entry_point(entry)[1];+ var outputs = this._get_entry_point(entry)[2]; for (var i = 0; i < outputs.length; i++) { console.log(outputs[i]); }@@ -99,8 +99,8 @@ _cmd_call(args) { var entry = this._get_entry_point(this._get_arg(args, 0));- var num_ins = entry[0].length;- var num_outs = entry[1].length;+ var num_ins = entry[1].length;+ var num_outs = entry[2].length; var expected_len = 1 + num_outs + num_ins if (args.length != expected_len) {@@ -121,13 +121,13 @@ } // Call entry point function from string name var bef = performance.now()*1000;- var vals = this.ctx[args[0]].apply(this.ctx, ins);+ var vals = this.ctx[entry[0]].apply(this.ctx, ins); var aft = performance.now()*1000; if (num_outs == 1) {- this._set_var(out_vnames[0], vals, entry[1][0]);+ this._set_var(out_vnames[0], vals, entry[2][0]); } else { for (var i = 0; i < out_vnames.length; i++) {- this._set_var(out_vnames[i], vals[i], entry[1][i]);+ this._set_var(out_vnames[i], vals[i], entry[2][i]); } } console.log("runtime: " + Math.round(aft-bef));
rts/python/scalar.py view
@@ -436,6 +436,9 @@ def futhark_log10_64(x): return np.float64(np.log10(x)) +def futhark_log1p_64(x):+ return np.float64(np.log1p(x))+ def futhark_sqrt64(x): return np.sqrt(x) @@ -534,6 +537,9 @@ def futhark_log10_32(x): return np.float32(np.log10(x)) +def futhark_log1p_32(x):+ return np.float32(np.log1p(x))+ def futhark_sqrt32(x): return np.float32(np.sqrt(x)) @@ -631,6 +637,9 @@ def futhark_log10_16(x): return np.float16(np.log10(x))++def futhark_log1p_16(x):+ return np.float16(np.log1p(x)) def futhark_sqrt16(x): return np.float16(np.sqrt(x))
rts/python/server.py view
@@ -39,12 +39,12 @@ def _cmd_inputs(self, args): entry = self._get_arg(args, 0)- for t in self._get_entry_point(entry)[0]:+ for t in self._get_entry_point(entry)[1]: print(t) def _cmd_outputs(self, args): entry = self._get_arg(args, 0)- for t in self._get_entry_point(entry)[1]:+ for t in self._get_entry_point(entry)[2]: print(t) def _cmd_dummy(self, args):@@ -65,8 +65,9 @@ def _cmd_call(self, args): entry = self._get_entry_point(self._get_arg(args, 0))- num_ins = len(entry[0])- num_outs = len(entry[1])+ entry_fname = entry[0]+ num_ins = len(entry[1])+ num_outs = len(entry[2]) exp_len = 1 + num_outs + num_ins if len(args) != exp_len:@@ -81,7 +82,7 @@ ins = [ self._get_var(in_vname) for in_vname in in_vnames ] try:- (runtime, vals) = getattr(self._ctx, args[0])(*ins)+ (runtime, vals) = getattr(self._ctx, entry_fname)(*ins) except Exception as e: raise self.Failure(str(e)) @@ -175,7 +176,11 @@ } def _process_line(self, line):- words = shlex.split(line)+ lex = shlex.shlex(line)+ lex.quotes = '"'+ lex.whitespace_split = True+ lex.commenters = ''+ words = list(lex) if words == []: raise self.Failure('Empty line') else:
src/Futhark/AD/Derivatives.hs view
@@ -183,6 +183,12 @@ Just [untyped $ 1 / (isF32 x * log 2)] pdBuiltin "log2_64" [x] = Just [untyped $ 1 / (isF64 x * log 2)]+pdBuiltin "log1p_16" [x] =+ Just [untyped $ 1 / (isF16 x + 1)]+pdBuiltin "log1p_32" [x] =+ Just [untyped $ 1 / (isF32 x + 1)]+pdBuiltin "log1p_64" [x] =+ Just [untyped $ 1 / (isF64 x + 1)] pdBuiltin "exp16" [x] = Just [untyped $ exp (isF16 x)] pdBuiltin "exp32" [x] =
src/Futhark/AD/Fwd.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-} module Futhark.AD.Fwd (fwdJVP) where @@ -7,7 +6,6 @@ import Control.Monad.RWS.Strict import Control.Monad.State.Strict import Data.Bifunctor (second)-import Data.Kind qualified import Data.List (transpose) import Data.List.NonEmpty (NonEmpty (..)) import Data.Map qualified as M@@ -90,15 +88,11 @@ modify $ \env -> env {stateTans = M.insert v v' (stateTans env)} class TanBuilder a where- type Bundled a :: Data.Kind.Type- type Bundled a = [a] newTan :: a -> ADM a- bundleNew :: a -> ADM (Bundled a)+ bundleNew :: a -> ADM [a] -instance (Monoid (Bundled a), TanBuilder a) => TanBuilder [a] where- type Bundled [a] = Bundled a- newTan = mapM newTan- bundleNew = fmap mconcat . mapM bundleNew+bundleNewList :: TanBuilder a => [a] -> ADM [a]+bundleNewList = fmap mconcat . mapM bundleNew instance TanBuilder (PatElem (TypeBase s u)) where newTan (PatElem p t)@@ -117,11 +111,12 @@ then pure [pe'] else pure [pe, pe'] -instance TanBuilder (Pat (TypeBase s u)) where- type Bundled (Pat (TypeBase s u)) = Pat (TypeBase s u)- newTan (Pat pes) = Pat <$> newTan pes- bundleNew (Pat pes) = Pat <$> bundleNew pes+newTanPat :: TanBuilder (PatElem t) => Pat t -> ADM (Pat t)+newTanPat (Pat pes) = Pat <$> mapM newTan pes +bundleNewPat :: TanBuilder (PatElem t) => Pat t -> ADM (Pat t)+bundleNewPat (Pat pes) = Pat <$> bundleNewList pes+ instance TanBuilder (Param (TypeBase s u)) where newTan (Param _ p t) = do PatElem p' t' <- newTan $ PatElem p t@@ -142,10 +137,8 @@ pure $ zip b [x, x_tan] class Tangent a where- type BundledTan a :: Data.Kind.Type- type BundledTan a = [a] tangent :: a -> ADM a- bundleTan :: a -> ADM (BundledTan a)+ bundleTan :: a -> ADM [a] instance Tangent (TypeBase s u) where tangent = tanType@@ -157,10 +150,8 @@ t' <- tangent t pure [t, t'] -instance (Monoid (BundledTan a), Tangent a) => Tangent [a] where- type BundledTan [a] = BundledTan a- tangent = mapM tangent- bundleTan = (mconcat <$>) . mapM bundleTan+bundleTangents :: Tangent a => [a] -> ADM [a]+bundleTangents = (mconcat <$>) . mapM bundleTan instance Tangent VName where tangent v = do@@ -192,7 +183,7 @@ basicFwd :: Pat Type -> StmAux () -> BasicOp -> ADM () basicFwd pat aux op = do- pat_tan <- newTan pat+ pat_tan <- newTanPat pat case op of SubExp se -> do se_tan <- tangent se@@ -201,7 +192,7 @@ se_tan <- tangent se addStm $ Let pat_tan aux $ BasicOp $ Opaque opaqueop se_tan ArrayLit ses t -> do- ses_tan <- tangent ses+ ses_tan <- mapM tangent ses addStm $ Let pat_tan aux $ BasicOp $ ArrayLit ses_tan t UnOp unop x -> do let t = unOpType unop@@ -233,7 +224,7 @@ addStm $ Let pat_tan aux $ BasicOp $ Update safety arr_tan slice se_tan Concat d (arr :| arrs) w -> do arr_tan <- tangent arr- arrs_tans <- tangent arrs+ arrs_tans <- mapM tangent arrs addStm $ Let pat_tan aux $ BasicOp $ Concat d (arr_tan :| arrs_tans) w Copy arr -> do arr_tan <- tangent arr@@ -261,11 +252,11 @@ fwdLambda :: Lambda SOACS -> ADM (Lambda SOACS) fwdLambda l@(Lambda params body ret) =- Lambda <$> bundleNew params <*> inScopeOf l (fwdBody body) <*> bundleTan ret+ Lambda <$> bundleNewList params <*> inScopeOf l (fwdBody body) <*> bundleTangents ret fwdStreamLambda :: Lambda SOACS -> ADM (Lambda SOACS) fwdStreamLambda l@(Lambda params body ret) =- Lambda <$> ((take 1 params ++) <$> bundleNew (drop 1 params)) <*> inScopeOf l (fwdBody body) <*> bundleTan ret+ Lambda <$> ((take 1 params ++) <$> bundleNewList (drop 1 params)) <*> inScopeOf l (fwdBody body) <*> bundleTangents ret interleave :: [a] -> [a] -> [a] interleave xs ys = concat $ transpose [xs, ys]@@ -280,8 +271,8 @@ fwdSOAC :: Pat Type -> StmAux () -> SOAC SOACS -> ADM () fwdSOAC pat aux (Screma size xs (ScremaForm scs reds f)) = do- pat' <- bundleNew pat- xs' <- bundleTan xs+ pat' <- bundleNewPat pat+ xs' <- bundleTangents xs scs' <- mapM fwdScan scs reds' <- mapM fwdRed reds f' <- fwdLambda f@@ -307,34 +298,34 @@ redNeutral = redNeutral red `interleave` map Var neutral_tans } fwdSOAC pat aux (Stream size xs nes lam) = do- pat' <- bundleNew pat+ pat' <- bundleNewPat pat lam' <- fwdStreamLambda lam- xs' <- bundleTan xs+ xs' <- bundleTangents xs nes_tan <- mapM (fmap Var . zeroFromSubExp) nes let nes' = interleave nes nes_tan addStm $ Let pat' aux $ Op $ Stream size xs' nes' lam' fwdSOAC pat aux (Hist w arrs ops bucket_fun) = do- pat' <- bundleNew pat+ pat' <- bundleNewPat pat ops' <- mapM fwdHist ops bucket_fun' <- fwdHistBucket bucket_fun- arrs' <- bundleTan arrs+ arrs' <- bundleTangents arrs addStm $ Let pat' aux $ Op $ Hist w arrs' ops' bucket_fun' where n_indices = sum $ map (shapeRank . histShape) ops fwdBodyHist (Body _ stms res) = buildBody_ $ do mapM_ fwdStm stms let (res_is, res_vs) = splitAt n_indices res- (res_is ++) <$> bundleTan res_vs+ (res_is ++) <$> bundleTangents res_vs fwdHistBucket l@(Lambda params body ret) = let (r_is, r_vs) = splitAt n_indices ret in Lambda- <$> bundleNew params+ <$> bundleNewList params <*> inScopeOf l (fwdBodyHist body)- <*> ((r_is ++) <$> bundleTan r_vs)+ <*> ((r_is ++) <$> bundleTangents r_vs) fwdHist :: HistOp SOACS -> ADM (HistOp SOACS) fwdHist (HistOp shape rf dest nes op) = do- dest' <- bundleTan dest+ dest' <- bundleTangents dest nes_tan <- mapM (fmap Var . zeroFromSubExp) nes op' <- fwdLambda op pure $@@ -347,8 +338,8 @@ } fwdSOAC (Pat pes) aux (Scatter w ivs lam as) = do as_tan <- mapM (\(s, n, a) -> do a_tan <- tangent a; pure (s, n, a_tan)) as- pes_tan <- newTan pes- ivs' <- bundleTan ivs+ pes_tan <- mapM newTan pes+ ivs' <- bundleTangents ivs let (as_ws, as_ns, _as_vs) = unzip3 as n_indices = sum $ zipWith (*) as_ns $ map length as_ws lam' <- fwdScatterLambda n_indices lam@@ -357,8 +348,8 @@ where fwdScatterLambda :: Int -> Lambda SOACS -> ADM (Lambda SOACS) fwdScatterLambda n_indices (Lambda params body ret) = do- params' <- bundleNew params- ret_tan <- tangent $ drop n_indices ret+ params' <- bundleNewList params+ ret_tan <- mapM tangent $ drop n_indices ret body' <- fwdBodyScatter n_indices body let indices = concat $ replicate 2 $ take n_indices ret ret' = indices ++ drop n_indices ret ++ ret_tan@@ -367,7 +358,7 @@ fwdBodyScatter n_indices (Body _ stms res) = do (res_tan, stms') <- collectStms $ do mapM_ fwdStm stms- tangent $ drop n_indices res+ mapM tangent $ drop n_indices res let indices = concat $ replicate 2 $ take n_indices res res' = indices ++ drop n_indices res ++ res_tan pure $ mkBody stms' res'@@ -378,8 +369,8 @@ fwdStm :: Stm SOACS -> ADM () fwdStm (Let pat aux (BasicOp (UpdateAcc acc i x))) = do- pat' <- bundleNew pat- x' <- bundleTan x+ pat' <- bundleNewPat pat+ x' <- bundleTangents x acc_tan <- tangent acc addStm $ Let pat' aux $ BasicOp $ UpdateAcc acc_tan i x' fwdStm stm@(Let pat aux (BasicOp e)) = do@@ -392,7 +383,7 @@ addStm stm arg_tans <- zipWith primExpFromSubExp argts <$> mapM (tangent . fst) args- pat_tan <- newTan pat+ pat_tan <- newTanPat pat let arg_pes = zipWith primExpFromSubExp argts (map fst args) case pdBuiltin f arg_pes of Nothing ->@@ -414,27 +405,27 @@ fwdStm (Let pat aux (Match ses cases defbody (MatchDec ret ifsort))) = do cases' <- slocal' $ mapM (traverse fwdBody) cases defbody' <- slocal' $ fwdBody defbody- pat' <- bundleNew pat- ret' <- bundleTan ret+ pat' <- bundleNewPat pat+ ret' <- bundleTangents ret addStm $ Let pat' aux $ Match ses cases' defbody' $ MatchDec ret' ifsort fwdStm (Let pat aux (DoLoop val_pats loop@(WhileLoop v) body)) = do- val_pats' <- bundleNew val_pats- pat' <- bundleNew pat+ val_pats' <- bundleNewList val_pats+ pat' <- bundleNewPat pat body' <- localScope (scopeOfFParams (map fst val_pats) <> scopeOf loop) . slocal' $ fwdBody body addStm $ Let pat' aux $ DoLoop val_pats' (WhileLoop v) body' fwdStm (Let pat aux (DoLoop val_pats loop@(ForLoop i it bound loop_vars) body)) = do- pat' <- bundleNew pat- val_pats' <- bundleNew val_pats- loop_vars' <- bundleNew loop_vars+ pat' <- bundleNewPat pat+ val_pats' <- bundleNewList val_pats+ loop_vars' <- bundleNewList loop_vars body' <- localScope (scopeOfFParams (map fst val_pats) <> scopeOf loop) . slocal' $ fwdBody body addStm $ Let pat' aux $ DoLoop val_pats' (ForLoop i it bound loop_vars') body' fwdStm (Let pat aux (WithAcc inputs lam)) = do inputs' <- forM inputs $ \(shape, arrs, op) -> do- arrs_tan <- tangent arrs+ arrs_tan <- mapM tangent arrs op' <- case op of Nothing -> pure Nothing Just (op_lam, nes) -> do@@ -445,7 +436,7 @@ let op_lam'' = Lambda (removeIndexTans (shapeRank shape) ps) body ret pure $ Just (op_lam'', interleave nes nes_tan) pure (shape, arrs <> arrs_tan, op')- pat' <- bundleNew pat+ pat' <- bundleNewPat pat lam' <- fwdLambda lam addStm $ Let pat' aux $ WithAcc inputs' lam' where@@ -459,17 +450,17 @@ fwdBody :: Body SOACS -> ADM (Body SOACS) fwdBody (Body _ stms res) = buildBody_ $ do mapM_ fwdStm stms- bundleTan res+ bundleTangents res fwdBodyTansLast :: Body SOACS -> ADM (Body SOACS) fwdBodyTansLast (Body _ stms res) = buildBody_ $ do mapM_ fwdStm stms- (res <>) <$> tangent res+ (res <>) <$> mapM tangent res fwdJVP :: MonadFreshNames m => Scope SOACS -> Lambda SOACS -> m (Lambda SOACS) fwdJVP scope l@(Lambda params body ret) = runADM . localScope scope . inScopeOf l $ do- params_tan <- newTan params+ params_tan <- mapM newTan params body_tan <- fwdBodyTansLast body- ret_tan <- tangent ret+ ret_tan <- mapM tangent ret pure $ Lambda (params ++ params_tan) body_tan (ret <> ret_tan)
src/Futhark/Actions.hs view
@@ -4,7 +4,6 @@ ( printAction, printAliasesAction, printLastUseGPU,- printLastUseGPUSS, printFusionGraph, printInterferenceGPU, printMemAliasGPU,@@ -55,10 +54,8 @@ import Futhark.IR import Futhark.IR.GPUMem (GPUMem) import Futhark.IR.MCMem (MCMem)-import Futhark.IR.Prop.Aliases import Futhark.IR.SOACS (SOACS) import Futhark.IR.SeqMem (SeqMem)-import Futhark.Optimise.ArrayShortCircuiting.LastUse qualified as LastUseSS import Futhark.Optimise.Fusion.GraphRep qualified import Futhark.Util (runProgramWithExitCode, unixEnvironment) import Futhark.Version (versionString)@@ -77,7 +74,7 @@ } -- | Print the result to stdout, alias annotations.-printAliasesAction :: (ASTRep rep, CanBeAliased (Op rep)) => Action rep+printAliasesAction :: AliasableRep rep => Action rep printAliasesAction = Action { actionName = "Prettyprint",@@ -91,21 +88,12 @@ Action { actionName = "print last use gpu", actionDescription = "Print last use information on gpu.",- actionProcedure = liftIO . putStrLn . prettyString . M.toList . LastUse.analyseGPUMem- }---- | Print last use information to stdout.-printLastUseGPUSS :: Action GPUMem-printLastUseGPUSS =- Action- { actionName = "print last use ss gpu",- actionDescription = "Print last use ss information on gpu.", actionProcedure = liftIO . putStrLn . prettyString . bimap M.toList (M.toList . fmap M.toList)- . LastUseSS.lastUseGPUMem+ . LastUse.lastUseGPUMem . aliasAnalysis }
src/Futhark/Analysis/Alias.hs view
@@ -10,10 +10,12 @@ -- the building blocks do). module Futhark.Analysis.Alias ( aliasAnalysis,+ AliasableRep, -- * Ad-hoc utilities analyseFun, analyseStms,+ analyseStm, analyseExp, analyseBody, analyseLambda,@@ -26,7 +28,7 @@ -- | Perform alias analysis on a Futhark program. aliasAnalysis ::- (ASTRep rep, CanBeAliased (Op rep)) =>+ AliasableRep rep => Prog rep -> Prog (Aliases rep) aliasAnalysis prog =@@ -37,7 +39,7 @@ -- | Perform alias analysis on function. analyseFun ::- (ASTRep rep, CanBeAliased (Op rep)) =>+ AliasableRep rep => FunDef rep -> FunDef (Aliases rep) analyseFun (FunDef entry attrs fname restype params body) =@@ -47,9 +49,7 @@ -- | Perform alias analysis on Body. analyseBody ::- ( ASTRep rep,- CanBeAliased (Op rep)- ) =>+ AliasableRep rep => AliasTable -> Body rep -> Body (Aliases rep)@@ -59,20 +59,26 @@ -- | Perform alias analysis on statements. analyseStms ::- (ASTRep rep, CanBeAliased (Op rep)) =>+ AliasableRep rep => AliasTable -> Stms rep -> (Stms (Aliases rep), AliasesAndConsumed) analyseStms orig_aliases =- foldl' f (mempty, (orig_aliases, mempty)) . stmsToList+ withoutBound . foldl' f (mempty, (orig_aliases, mempty)) . stmsToList where+ withoutBound (stms, (aliases, consumed)) =+ let bound = foldMap (namesFromList . patNames . stmPat) stms+ consumed' = consumed `namesSubtract` bound+ in (stms, (aliases, consumed'))+ f (stms, aliases) stm = let stm' = analyseStm (fst aliases) stm atable' = trackAliases aliases stm' in (stms <> oneStm stm', atable') +-- | Perform alias analysis on statement. analyseStm ::- (ASTRep rep, CanBeAliased (Op rep)) =>+ AliasableRep rep => AliasTable -> Stm rep -> Stm (Aliases rep)@@ -84,7 +90,7 @@ -- | Perform alias analysis on expression. analyseExp ::- (ASTRep rep, CanBeAliased (Op rep)) =>+ AliasableRep rep => AliasTable -> Exp rep -> Exp (Aliases rep)@@ -124,7 +130,7 @@ -- | Perform alias analysis on lambda. analyseLambda ::- (ASTRep rep, CanBeAliased (Op rep)) =>+ AliasableRep rep => AliasTable -> Lambda rep -> Lambda (Aliases rep)
src/Futhark/Analysis/HORep/SOAC.hs view
@@ -66,6 +66,7 @@ ViewL (..), ArrayTransform (..), transformFromExp,+ transformToExp, soacToStream, ) where@@ -233,6 +234,22 @@ Just (v, Replicate cs shape) transformFromExp _ _ = Nothing +-- | Turn an array transform on an array back into an expression.+transformToExp :: (Monad m, HasScope rep m) => ArrayTransform -> VName -> m (Certs, Exp rep)+transformToExp (Replicate cs n) ia =+ pure (cs, BasicOp $ Futhark.Replicate n (Var ia))+transformToExp (Rearrange cs perm) ia = do+ r <- arrayRank <$> lookupType ia+ pure (cs, BasicOp $ Futhark.Rearrange (perm ++ [length perm .. r - 1]) ia)+transformToExp (Reshape cs k shape) ia = do+ pure (cs, BasicOp $ Futhark.Reshape k shape ia)+transformToExp (ReshapeOuter cs k shape) ia = do+ shape' <- reshapeOuter shape 1 . arrayShape <$> lookupType ia+ pure (cs, BasicOp $ Futhark.Reshape k shape' ia)+transformToExp (ReshapeInner cs k shape) ia = do+ shape' <- reshapeInner shape 1 . arrayShape <$> lookupType ia+ pure (cs, BasicOp $ Futhark.Reshape k shape' ia)+ -- | One array input to a SOAC - a SOAC may have multiple inputs, but -- all are of this form. Only the array inputs are expressed with -- this type; other arguments, such as initial accumulator values, are@@ -285,24 +302,16 @@ addInitialTransforms ts (Input ots a t) = Input (ts <> ots) a t applyTransform :: MonadBuilder m => ArrayTransform -> VName -> m VName-applyTransform (Replicate cs n) ia =- certifying cs . letExp "repeat" . BasicOp $- Futhark.Replicate n (Var ia)-applyTransform (Rearrange cs perm) ia = do- r <- arrayRank <$> lookupType ia- certifying cs . letExp "rearrange" . BasicOp $- Futhark.Rearrange (perm ++ [length perm .. r - 1]) ia-applyTransform (Reshape cs k shape) ia =- certifying cs . letExp "reshape" . BasicOp $- Futhark.Reshape k shape ia-applyTransform (ReshapeOuter cs k shape) ia = do- shape' <- reshapeOuter shape 1 . arrayShape <$> lookupType ia- certifying cs . letExp "reshape_outer" . BasicOp $- Futhark.Reshape k shape' ia-applyTransform (ReshapeInner cs k shape) ia = do- shape' <- reshapeInner shape 1 . arrayShape <$> lookupType ia- certifying cs . letExp "reshape_inner" . BasicOp $- Futhark.Reshape k shape' ia+applyTransform tr ia = do+ (cs, e) <- transformToExp tr ia+ certifying cs $ letExp s e+ where+ s = case tr of+ Replicate {} -> "replicate"+ Rearrange {} -> "rearrange"+ Reshape {} -> "reshape"+ ReshapeOuter {} -> "reshape_outer"+ ReshapeInner {} -> "reshape_inner" applyTransforms :: MonadBuilder m => ArrayTransforms -> VName -> m VName applyTransforms (ArrayTransforms ts) a = foldlM (flip applyTransform) a ts
src/Futhark/Analysis/Interference.hs view
@@ -12,7 +12,8 @@ import Data.Maybe (catMaybes, fromMaybe, mapMaybe) import Data.Set (Set) import Data.Set qualified as S-import Futhark.Analysis.LastUse (LastUseMap)+import Futhark.Analysis.Alias qualified as AnlAls+import Futhark.Analysis.LastUse (LUTabFun) import Futhark.Analysis.LastUse qualified as LastUse import Futhark.Analysis.MemAlias qualified as MemAlias import Futhark.IR.GPUMem@@ -39,7 +40,7 @@ analyseStm :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> Stm GPUMem -> m (InUse, LastUsed, Graph VName)@@ -103,7 +104,7 @@ analyseExp :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> Exp GPUMem -> m (InUse, LastUsed, Graph VName)@@ -122,7 +123,7 @@ analyseKernelBody :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> KernelBody GPUMem -> m (InUse, LastUsed, Graph VName)@@ -130,7 +131,7 @@ analyseBody :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> Body GPUMem -> m (InUse, LastUsed, Graph VName)@@ -138,7 +139,7 @@ analyseStms :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> Stms GPUMem -> m (InUse, LastUsed, Graph VName)@@ -151,7 +152,7 @@ analyseSegOp :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> SegOp lvl GPUMem -> m (InUse, LastUsed, Graph VName)@@ -168,7 +169,7 @@ segWithBinOps :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> [SegBinOp GPUMem] -> KernelBody GPUMem ->@@ -184,7 +185,7 @@ analyseSegBinOp :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> SegBinOp GPUMem -> m (InUse, LastUsed, Graph VName)@@ -193,7 +194,7 @@ analyseHistOp :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> HistOp GPUMem -> m (InUse, LastUsed, Graph VName)@@ -202,7 +203,7 @@ analyseLambda :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> InUse -> Lambda GPUMem -> m (InUse, LastUsed, Graph VName)@@ -213,14 +214,14 @@ analyseProgGPU prog = onConsts (progConsts prog) <> foldMap onFun (progFuns prog) where (consts_aliases, funs_aliases) = MemAlias.analyzeGPUMem prog- lumap = LastUse.analyseGPUMem prog+ (lumap_consts, lumap) = LastUse.lastUseGPUMem $ AnlAls.aliasAnalysis prog onFun f = applyAliases (fromMaybe mempty $ M.lookup (funDefName f) funs_aliases) $- runReader (analyseGPU lumap $ bodyStms $ funDefBody f) $+ runReader (analyseGPU (lumap M.! funDefName f) $ bodyStms $ funDefBody f) $ scopeOf f onConsts stms = applyAliases consts_aliases $- runReader (analyseGPU lumap stms) (mempty :: Scope GPUMem)+ runReader (analyseGPU lumap_consts stms) (mempty :: Scope GPUMem) applyAliases :: MemAlias.MemAliases -> Graph VName -> Graph VName applyAliases aliases =@@ -237,7 +238,7 @@ -- within, and the resulting graph. analyseGPU :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> Stms GPUMem -> m (Graph VName) analyseGPU lumap stms = do@@ -304,7 +305,7 @@ analyseGPU' :: LocalScope GPUMem m =>- LastUseMap ->+ LUTabFun -> Stms GPUMem -> m (InUse, LastUsed, Graph VName) analyseGPU' lumap stms =
src/Futhark/Analysis/LastUse.hs view
@@ -1,240 +1,445 @@ {-# LANGUAGE TypeFamilies #-} --- | Provides last-use analysis for Futhark programs.+-- | Last use analysis for array short circuiting+--+-- Last-Use analysis of a Futhark program in aliased explicit-memory lore form.+-- Takes as input such a program or a function and produces a 'M.Map VName+-- Names', in which the key identified the let stmt, and the list argument+-- identifies the variables that were lastly used in that stmt. Note that the+-- results of a body do not have a last use, and neither do a function+-- parameters if it happens to not be used inside function's body. Such cases+-- are supposed to be treated separately. module Futhark.Analysis.LastUse- ( LastUseMap,- LastUse,- Used,- analyseGPUMem,- analyseSeqMem,+ ( lastUseSeqMem,+ lastUseGPUMem,+ lastUseMCMem,+ LUTabFun,+ LUTabProg, ) where import Control.Monad.Reader-import Data.Bifunctor (bimap, first)+import Control.Monad.State.Strict+import Data.Bifunctor (bimap) import Data.Function ((&))-import Data.Map (Map)-import Data.Map qualified as M-import Data.Tuple-import Futhark.Analysis.Alias (aliasAnalysis)+import Data.Map.Strict qualified as M+import Data.Maybe+import Data.Sequence (Seq (..)) import Futhark.IR.Aliases import Futhark.IR.GPUMem+import Futhark.IR.GPUMem qualified as GPU+import Futhark.IR.MCMem+import Futhark.IR.MCMem qualified as MC import Futhark.IR.SeqMem+import Futhark.Optimise.ArrayShortCircuiting.DataStructs+import Futhark.Util --- | 'LastUseMap' tells which names were last used in a given statement.--- Statements are uniquely identified by the 'VName' of the first value--- parameter in the statement pattern. 'Names' is the set of names last used.-type LastUseMap = Map VName Names+-- | Maps a name indentifying a Stm to the last uses in that Stm.+type LUTabFun = M.Map VName Names --- | 'LastUse' is a mapping from a 'VName' to the statement identifying it's--- last use. 'LastUseMap' is the inverse of 'LastUse'.-type LastUse = Map VName VName+-- | LU-table for the constants, and for each function.+type LUTabProg = (LUTabFun, M.Map Name LUTabFun) --- | 'Used' is the set of 'VName' that were used somewhere in a--- statement, body or otherwise.-type Used = Names+type LastUseOp rep = Op (Aliases rep) -> Names -> LastUseM rep (LUTabFun, Names, Names) -type LastUseOp rep =- VName -> (LastUse, Used) -> Op (Aliases rep) -> LastUseM rep+-- | 'LastUseReader' allows us to abstract over representations by supplying the+-- 'onOp' function.+data LastUseReader rep = LastUseReader+ { onOp :: LastUseOp rep,+ scope :: Scope (Aliases rep)+ } -newtype Env rep = Env {envLastUseOp :: LastUseOp rep}+-- | Maps a variable or memory block to its aliases.+type AliasTab = M.Map VName Names -type LastUseM rep = Reader (Env rep) (LastUse, Used)+newtype LastUseM rep a = LastUseM (StateT AliasTab (Reader (LastUseReader rep)) a)+ deriving+ ( Monad,+ Functor,+ Applicative,+ MonadReader (LastUseReader rep),+ MonadState AliasTab+ ) -analyseGPUMem :: Prog GPUMem -> LastUseMap-analyseGPUMem = analyseProg analyseGPUOp+instance RepTypes (Aliases rep) => HasScope (Aliases rep) (LastUseM rep) where+ askScope = asks scope -analyseSeqMem :: Prog SeqMem -> LastUseMap-analyseSeqMem = analyseProg analyseSeqOp+instance RepTypes (Aliases rep) => LocalScope (Aliases rep) (LastUseM rep) where+ localScope sc (LastUseM m) = LastUseM $ do+ local (\rd -> rd {scope = scope rd <> sc}) m -analyseGPUOp :: LastUseOp GPUMem-analyseGPUOp pat_name (lumap, used) (Alloc se sp) = do- let nms = (freeIn se <> freeIn sp) `namesSubtract` used- pure (insertNames pat_name nms lumap, used <> nms)-analyseGPUOp pat_name (lumap, used) (Inner (SizeOp sop)) = do- let nms = freeIn sop `namesSubtract` used- pure (insertNames pat_name nms lumap, used <> nms)-analyseGPUOp _ (lumap, used) (Inner (OtherOp ())) =- pure (lumap, used)-analyseGPUOp pat_name (lumap, used) (Inner (SegOp (SegMap lvl _ tps body))) = do- (lumap', used') <- analyseKernelBody (lumap, used) body- let nms = (freeIn lvl <> freeIn tps) `namesSubtract` used'- pure (insertNames pat_name nms lumap', used' <> nms)-analyseGPUOp pat_name (lumap, used) (Inner (SegOp (SegRed lvl _ binops tps body))) =- segOpHelper pat_name lumap used lvl binops tps body-analyseGPUOp pat_name (lumap, used) (Inner (SegOp (SegScan lvl _ binops tps body))) =- segOpHelper pat_name lumap used lvl binops tps body-analyseGPUOp pat_name (lumap, used) (Inner (SegOp (SegHist lvl _ binops tps body))) = do- (lumap', used') <- foldM analyseHistOp (lumap, used) $ reverse binops- (lumap'', used'') <- analyseKernelBody (lumap', used') body- let nms = (freeIn lvl <> freeIn tps) `namesSubtract` used''- pure (insertNames pat_name nms lumap'', used'' <> nms)-analyseGPUOp pat_name (lumap, used) (Inner (GPUBody ts body)) = do- (lumap', used') <- analyseBody lumap used body- let nms = freeIn ts- pure (insertNames pat_name nms lumap', used' <> nms)+type Constraints rep =+ ( LocalScope (Aliases rep) (LastUseM rep),+ HasMemBlock (Aliases rep),+ AliasableRep rep+ ) -segOpHelper ::- (FreeIn (OpWithAliases (Op rep)), ASTRep rep) =>- VName ->- LastUse ->- Used ->- SegLevel ->- [SegBinOp (Aliases rep)] ->- [Type] ->+runLastUseM :: LastUseOp rep -> LastUseM rep a -> a+runLastUseM onOp (LastUseM m) =+ runReader (evalStateT m mempty) (LastUseReader onOp mempty)++aliasLookup :: VName -> LastUseM rep Names+aliasLookup vname =+ gets $ fromMaybe mempty . M.lookup vname++lastUseProg ::+ Constraints rep =>+ Prog (Aliases rep) ->+ LastUseM rep LUTabProg+lastUseProg prog =+ let bound_in_consts =+ progConsts prog+ & concatMap (patNames . stmPat)+ & namesFromList+ consts = progConsts prog+ funs = progFuns prog+ in inScopeOf consts $ do+ (consts_lu, _) <- lastUseStms consts mempty mempty+ lus <- mapM (lastUseFun bound_in_consts) funs+ pure (consts_lu, M.fromList $ zip (map funDefName funs) lus)++lastUseFun ::+ Constraints rep =>+ Names ->+ FunDef (Aliases rep) ->+ LastUseM rep LUTabFun+lastUseFun bound_in_consts f =+ inScopeOf f $ fst <$> lastUseBody (funDefBody f) (mempty, bound_in_consts)++-- | Perform last-use analysis on a 'Prog' in 'SeqMem'+lastUseSeqMem :: Prog (Aliases SeqMem) -> LUTabProg+lastUseSeqMem = runLastUseM lastUseSeqOp . lastUseProg++-- | Perform last-use analysis on a 'Prog' in 'GPUMem'+lastUseGPUMem :: Prog (Aliases GPUMem) -> LUTabProg+lastUseGPUMem = runLastUseM (lastUseMemOp lastUseGPUOp) . lastUseProg++-- | Perform last-use analysis on a 'Prog' in 'MCMem'+lastUseMCMem :: Prog (Aliases MCMem) -> LUTabProg+lastUseMCMem = runLastUseM (lastUseMemOp lastUseMCOp) . lastUseProg++-- | Performing the last-use analysis on a body.+--+-- The implementation consists of a bottom-up traversal of the body's statements+-- in which the the variables lastly used in a statement are computed as the+-- difference between the free-variables in that stmt and the set of variables+-- known to be used after that statement.+lastUseBody ::+ Constraints rep =>+ -- | The body of statements+ Body (Aliases rep) ->+ -- | The current last-use table, tupled with the known set of already used names+ (LUTabFun, Names) ->+ -- | The result is:+ -- (i) an updated last-use table,+ -- (ii) an updated set of used names (including the binding).+ LastUseM rep (LUTabFun, Names)+lastUseBody bdy@(Body _ stms result) (lutab, used_nms) =+ -- perform analysis bottom-up in bindings: results are known to be used,+ -- hence they are added to the used_nms set.+ inScopeOf stms $ do+ (lutab', _) <-+ lastUseStms stms (lutab, used_nms) $+ namesToList $+ freeIn $+ map resSubExp result+ -- Clean up the used names by recomputing the aliasing transitive-closure+ -- of the free names in body based on the current alias table @alstab@.+ used_in_body <- aliasTransitiveClosure $ freeIn bdy+ pure (lutab', used_nms <> used_in_body)++-- | Performing the last-use analysis on a body.+--+-- The implementation consists of a bottom-up traversal of the body's statements+-- in which the the variables lastly used in a statement are computed as the+-- difference between the free-variables in that stmt and the set of variables+-- known to be used after that statement.+lastUseKernelBody ::+ Constraints rep =>+ -- | The body of statements KernelBody (Aliases rep) ->- LastUseM rep-segOpHelper pat_name lumap used lvl binops tps body = do- (lumap', used') <- foldM analyseSegBinOp (lumap, used) $ reverse binops- (lumap'', used'') <- analyseKernelBody (lumap', used') body- let nms = (freeIn lvl <> freeIn tps) `namesSubtract` used''- pure (insertNames pat_name nms lumap'', used'' <> nms)+ -- | The current last-use table, tupled with the known set of already used names+ (LUTabFun, Names) ->+ -- | The result is:+ -- (i) an updated last-use table,+ -- (ii) an updated set of used names (including the binding).+ LastUseM rep (LUTabFun, Names)+lastUseKernelBody bdy@(KernelBody _ stms result) (lutab, used_nms) =+ inScopeOf stms $ do+ -- perform analysis bottom-up in bindings: results are known to be used,+ -- hence they are added to the used_nms set.+ (lutab', _) <-+ lastUseStms stms (lutab, used_nms) $ namesToList $ freeIn result+ -- Clean up the used names by recomputing the aliasing transitive-closure+ -- of the free names in body based on the current alias table @alstab@.+ used_in_body <- aliasTransitiveClosure $ freeIn bdy+ pure (lutab', used_nms <> used_in_body) -analyseSeqOp :: LastUseOp SeqMem-analyseSeqOp pat_name (lumap, used) (Alloc se sp) = do- let nms = (freeIn se <> freeIn sp) `namesSubtract` used- pure (insertNames pat_name nms lumap, used <> nms)-analyseSeqOp _ (lumap, used) (Inner ()) =- pure (lumap, used)+lastUseStms ::+ Constraints rep =>+ Stms (Aliases rep) ->+ (LUTabFun, Names) ->+ [VName] ->+ LastUseM rep (LUTabFun, Names)+lastUseStms Empty (lutab, nms) res_nms = do+ aliases <- concatMapM aliasLookup res_nms+ pure (lutab, nms <> aliases <> namesFromList res_nms)+lastUseStms (stm@(Let pat _ e) :<| stms) (lutab, nms) res_nms =+ inScopeOf stm $ do+ let extra_alias = case e of+ BasicOp (Update _ old _ _) -> oneName old+ BasicOp (FlatUpdate old _ _) -> oneName old+ _ -> mempty+ -- We build up aliases top-down+ updateAliasing extra_alias pat+ -- But compute last use bottom-up+ (lutab', nms') <- lastUseStms stms (lutab, nms) res_nms+ (lutab'', nms'') <- lastUseStm stm (lutab', nms')+ pure (lutab'', nms'') --- | Analyses a program to return a last-use map, mapping each simple statement--- in the program to the values that were last used within that statement, and--- the set of all `VName` that were used inside.-analyseProg :: (CanBeAliased (Op rep), Mem rep inner) => LastUseOp rep -> Prog rep -> LastUseMap-analyseProg onOp prog =- runReader helper (Env onOp)- where- helper = do- let bound_in_consts =- progConsts prog- & concatMap (patNames . stmPat)- & namesFromList- prog_alias = aliasAnalysis prog- consts = progConsts prog_alias- funs = progFuns prog_alias- (consts_lu, _) <- analyseStms mempty mempty consts- (lus, _) <- mconcat <$> mapM (analyseFun mempty bound_in_consts) funs- pure $ flipMap $ consts_lu <> lus+lastUseStm ::+ Constraints rep =>+ Stm (Aliases rep) ->+ (LUTabFun, Names) ->+ LastUseM rep (LUTabFun, Names)+lastUseStm (Let pat _ e) (lutab, used_nms) = do+ -- analyse the expression and get the+ -- (i) a new last-use table (in case the @e@ contains bodies of stmts)+ -- (ii) the set of variables lastly used in the current binding.+ -- (iii) aliased transitive-closure of used names, and+ (lutab', last_uses, used_nms') <- lastUseExp e used_nms+ sc <- asks scope+ let lu_mems =+ namesToList last_uses+ & mapMaybe (`getScopeMemInfo` sc)+ & map memName+ & namesFromList+ & flip namesSubtract used_nms -analyseFun :: (FreeIn (OpWithAliases (Op rep)), ASTRep rep) => LastUse -> Used -> FunDef (Aliases rep) -> LastUseM rep-analyseFun lumap used fun = do- (lumap', used') <- analyseBody lumap used $ funDefBody fun- pure (lumap', used' <> freeIn (funDefParams fun))+ -- filter-out the binded names from the set of used variables,+ -- since they go out of scope, and update the last-use table.+ let patnms = patNames pat+ used_nms'' = used_nms' `namesSubtract` namesFromList patnms+ lutab'' =+ M.union lutab' $ M.insert (head patnms) (last_uses <> lu_mems) lutab+ pure (lutab'', used_nms'') -analyseStms :: (FreeIn (OpWithAliases (Op rep)), ASTRep rep) => LastUse -> Used -> Stms (Aliases rep) -> LastUseM rep-analyseStms lumap used stms = foldM analyseStm (lumap, used) $ reverse $ stmsToList stms+-------------------------------- -analyseStm :: (FreeIn (OpWithAliases (Op rep)), ASTRep rep) => (LastUse, Used) -> Stm (Aliases rep) -> LastUseM rep-analyseStm (lumap0, used0) (Let pat _ e) = do- let (lumap', used') = patElems pat & foldl helper (lumap0, used0)- analyseExp (lumap', used') e+-- | Last-Use Analysis for an expression.+lastUseExp ::+ Constraints rep =>+ -- | The expression to analyse+ Exp (Aliases rep) ->+ -- | The set of used names "after" this expression+ Names ->+ -- | Result:+ -- 1. an extra LUTab recording the last use for expression's inner bodies,+ -- 2. the set of last-used vars in the expression at this level,+ -- 3. the updated used names, now including expression's free vars.+ LastUseM rep (LUTabFun, Names, Names)+lastUseExp (Match _ cases body _) used_nms = do+ -- For an if-then-else, we duplicate the last use at each body level, meaning+ -- we record the last use of the outer statement, and also the last use in the+ -- statement in the inner bodies. We can safely ignore the if-condition as it is+ -- a boolean scalar.+ (lutab_cases, used_cases) <-+ bimap mconcat mconcat . unzip+ <$> mapM (flip lastUseBody (M.empty, used_nms) . caseBody) cases+ (lutab', body_used_nms) <- lastUseBody body (M.empty, used_nms)+ let free_in_body = freeIn body+ let free_in_cases = freeIn cases+ let used_nms' = used_cases <> body_used_nms+ (_, last_used_arrs) <- lastUsedInNames used_nms $ free_in_body <> free_in_cases+ pure (lutab_cases <> lutab', last_used_arrs, used_nms')+lastUseExp (DoLoop var_ses lf body) used_nms0 = inScopeOf lf $ do+ free_in_body <- aliasTransitiveClosure $ freeIn body+ -- compute the aliasing transitive closure of initializers that are not last-uses+ var_inis <- catMaybes <$> mapM (initHelper (free_in_body <> used_nms0)) var_ses+ let -- To record last-uses inside the loop body, we call 'lastUseBody' with used-names+ -- being: (free_in_body - loop-variants-a) + used_nms0. As such we disable cases b)+ -- and c) to produce loop-variant last uses inside the loop, and also we prevent+ -- the free-loop-variables to having last uses inside the loop.+ free_in_body' = free_in_body `namesSubtract` namesFromList (map fst var_inis)+ used_nms = used_nms0 <> free_in_body' <> freeIn (bodyResult body)+ (body_lutab, _) <- lastUseBody body (mempty, used_nms)++ -- add var_inis_a to the body_lutab, i.e., record the last-use of+ -- initializer in the corresponding loop variant.+ let lutab_res = body_lutab <> M.fromList var_inis++ -- the result used names are:+ fpar_nms = namesFromList $ map (identName . paramIdent . fst) var_ses+ used_nms' = (free_in_body <> freeIn (map snd var_ses)) `namesSubtract` fpar_nms+ used_nms_res = used_nms0 <> used_nms' <> freeIn (bodyResult body)++ -- the last-uses at loop-statement level are the loop free variables that+ -- do not belong to @used_nms0@; this includes the initializers of b), @lu_ini_b@+ lu_arrs = used_nms' `namesSubtract` used_nms0+ pure (lutab_res, lu_arrs, used_nms_res) where- helper (lumap_acc, used_acc) (PatElem name (aliases, _)) =- -- Any aliases of `name` should have the same last-use as `name`- ( case M.lookup name lumap_acc of- Just name' ->- insertNames name' (unAliases aliases) lumap_acc- Nothing -> lumap_acc,- used_acc <> unAliases aliases- )+ initHelper free_and_used (fp, se) = do+ names <- aliasTransitiveClosure $ maybe mempty oneName $ subExpVar se+ if names `namesIntersect` free_and_used+ then pure Nothing+ else pure $ Just (identName $ paramIdent fp, names)+lastUseExp (Op op) used_nms = do+ on_op <- reader onOp+ on_op op used_nms+lastUseExp e used_nms = do+ let free_in_e = freeIn e+ (used_nms', lu_vars) <- lastUsedInNames used_nms free_in_e+ pure (M.empty, lu_vars, used_nms') - addAliasesFromBodyRes (lumap_acc, used_acc) (PatElem {}, Constant _) = (lumap_acc, used_acc)- addAliasesFromBodyRes (lumap_acc, used_acc) (PatElem name _, Var body_res) =- -- Any aliases of `name` should have the same last-use as `name`- ( case M.lookup name lumap_acc of- Just name' ->- insertNames name' (oneName body_res) lumap_acc- Nothing -> lumap_acc,- used_acc <> oneName body_res- )+lastUseMemOp ::+ (inner (Aliases rep) -> Names -> LastUseM rep (LUTabFun, Names, Names)) ->+ MemOp inner (Aliases rep) ->+ Names ->+ LastUseM rep (LUTabFun, Names, Names)+lastUseMemOp _ (Alloc se sp) used_nms = do+ let free_in_e = freeIn se <> freeIn sp+ (used_nms', lu_vars) <- lastUsedInNames used_nms free_in_e+ pure (M.empty, lu_vars, used_nms')+lastUseMemOp onInner (Inner op) used_nms = onInner op used_nms - pat_name = patElemName $ head $ patElems pat+lastUseSegOp ::+ Constraints rep =>+ SegOp lvl (Aliases rep) ->+ Names ->+ LastUseM rep (LUTabFun, Names, Names)+lastUseSegOp (SegMap _ _ tps kbody) used_nms = do+ (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn tps+ (body_lutab, used_nms'') <- lastUseKernelBody kbody (mempty, used_nms')+ pure (body_lutab, lu_vars, used_nms' <> used_nms'')+lastUseSegOp (SegRed _ _ sbos tps kbody) used_nms = do+ (lutab_sbo, lu_vars_sbo, used_nms_sbo) <- lastUseSegBinOp sbos used_nms+ (used_nms', lu_vars) <- lastUsedInNames used_nms_sbo $ freeIn tps+ (body_lutab, used_nms'') <- lastUseKernelBody kbody (mempty, used_nms')+ pure (M.union lutab_sbo body_lutab, lu_vars <> lu_vars_sbo, used_nms_sbo <> used_nms' <> used_nms'')+lastUseSegOp (SegScan _ _ sbos tps kbody) used_nms = do+ (lutab_sbo, lu_vars_sbo, used_nms_sbo) <- lastUseSegBinOp sbos used_nms+ (used_nms', lu_vars) <- lastUsedInNames used_nms_sbo $ freeIn tps+ (body_lutab, used_nms'') <- lastUseKernelBody kbody (mempty, used_nms')+ pure (M.union lutab_sbo body_lutab, lu_vars <> lu_vars_sbo, used_nms_sbo <> used_nms' <> used_nms'')+lastUseSegOp (SegHist _ _ hos tps kbody) used_nms = do+ (lutab_sbo, lu_vars_sbo, used_nms_sbo) <- lastUseHistOp hos used_nms+ (used_nms', lu_vars) <- lastUsedInNames used_nms_sbo $ freeIn tps+ (body_lutab, used_nms'') <- lastUseKernelBody kbody (mempty, used_nms')+ pure (M.union lutab_sbo body_lutab, lu_vars <> lu_vars_sbo, used_nms_sbo <> used_nms' <> used_nms'') - analyseExp (lumap, used) (BasicOp _) = do- let nms = freeIn e `namesSubtract` used- pure (insertNames pat_name nms lumap, used <> nms)- analyseExp (lumap, used) (Apply _ args _ _) = do- let nms = freeIn $ map fst args- pure (insertNames pat_name nms lumap, used <> nms)- analyseExp (lumap, used) (Match ses cases defbody dec) = do- (lumap_cases, used_cases) <-- bimap mconcat mconcat . unzip- <$> mapM (analyseBody lumap used . caseBody) cases- (lumap_defbody, used_defbody) <- analyseBody lumap used defbody- let (lumap', used') =- (lumap_defbody <> lumap_cases, used_cases <> used_defbody)- & flip (foldl addAliasesFromBodyRes) (zip (patElems pat) (map resSubExp $ bodyResult defbody))- nms = (freeIn ses <> freeIn dec) `namesSubtract` used'- pure- ( insertNames pat_name nms lumap',- used' <> nms- )- analyseExp (lumap, used) (DoLoop merge form body) = do- let (lumap', used') =- zip (patElems pat) (map resSubExp $ bodyResult body)- & foldl addAliasesFromBodyRes (lumap, used)- (lumap'', used'') <- analyseBody lumap' used' body- let nms = (freeIn merge <> freeIn form) `namesSubtract` used''- pure (insertNames pat_name nms lumap'', used'' <> nms)- analyseExp (lumap, used) (Op op) = do- onOp <- asks envLastUseOp- onOp pat_name (lumap, used) op- analyseExp (lumap, used) (WithAcc _ l) =- analyseLambda (lumap, used) l+lastUseGPUOp :: HostOp NoOp (Aliases GPUMem) -> Names -> LastUseM GPUMem (LUTabFun, Names, Names)+lastUseGPUOp (GPU.OtherOp NoOp) used_nms =+ pure (mempty, mempty, used_nms)+lastUseGPUOp (SizeOp sop) used_nms = do+ (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn sop+ pure (mempty, lu_vars, used_nms')+lastUseGPUOp (GPUBody tps body) used_nms = do+ (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn tps+ (body_lutab, used_nms'') <- lastUseBody body (mempty, used_nms')+ pure (body_lutab, lu_vars, used_nms' <> used_nms'')+lastUseGPUOp (SegOp op) used_nms =+ lastUseSegOp op used_nms -analyseBody :: (FreeIn (OpWithAliases (Op rep)), ASTRep rep) => LastUse -> Used -> Body (Aliases rep) -> LastUseM rep-analyseBody lumap used (Body _ stms result) = do- let used' = used <> freeIn result- analyseStms lumap used' stms+lastUseMCOp :: MCOp NoOp (Aliases MCMem) -> Names -> LastUseM MCMem (LUTabFun, Names, Names)+lastUseMCOp (MC.OtherOp NoOp) used_nms =+ pure (mempty, mempty, used_nms)+lastUseMCOp (MC.ParOp par_op op) used_nms = do+ (lutab_par_op, lu_vars_par_op, used_names_par_op) <-+ maybe (pure mempty) (`lastUseSegOp` used_nms) par_op+ (lutab_op, lu_vars_op, used_names_op) <-+ lastUseSegOp op used_nms+ pure+ ( lutab_par_op <> lutab_op,+ lu_vars_par_op <> lu_vars_op,+ used_names_par_op <> used_names_op+ ) -analyseKernelBody ::- (FreeIn (OpWithAliases (Op rep)), ASTRep rep) =>- (LastUse, Used) ->- KernelBody (Aliases rep) ->- LastUseM rep-analyseKernelBody (lumap, used) (KernelBody _ stms result) =- let used' = used <> freeIn result- in analyseStms lumap used' stms+lastUseSegBinOp ::+ Constraints rep =>+ [SegBinOp (Aliases rep)] ->+ Names ->+ LastUseM rep (LUTabFun, Names, Names)+lastUseSegBinOp sbos used_nms = do+ (lutab, lu_vars, used_nms') <- unzip3 <$> mapM helper sbos+ pure (mconcat lutab, mconcat lu_vars, mconcat used_nms')+ where+ helper (SegBinOp _ l@(Lambda _ body _) neutral shp) = inScopeOf l $ do+ (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn neutral <> freeIn shp+ (body_lutab, used_nms'') <- lastUseBody body (mempty, used_nms')+ pure (body_lutab, lu_vars, used_nms'') -analyseSegBinOp ::- (FreeIn (OpWithAliases (Op rep)), ASTRep rep) =>- (LastUse, Used) ->- SegBinOp (Aliases rep) ->- LastUseM rep-analyseSegBinOp (lumap, used) (SegBinOp _ lambda neutral shp) = do- (lumap', used') <- analyseLambda (lumap, used) lambda- let nms = (freeIn neutral <> freeIn shp) `namesSubtract` used'- pure (lumap', used' <> nms)+lastUseHistOp ::+ Constraints rep =>+ [HistOp (Aliases rep)] ->+ Names ->+ LastUseM rep (LUTabFun, Names, Names)+lastUseHistOp hos used_nms = do+ (lutab, lu_vars, used_nms') <- unzip3 <$> mapM helper hos+ pure (mconcat lutab, mconcat lu_vars, mconcat used_nms')+ where+ helper (HistOp shp rf dest neutral shp' l@(Lambda _ body _)) = inScopeOf l $ do+ (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn shp <> freeIn rf <> freeIn dest <> freeIn neutral <> freeIn shp'+ (body_lutab, used_nms'') <- lastUseBody body (mempty, used_nms')+ pure (body_lutab, lu_vars, used_nms'') -analyseHistOp ::- (FreeIn (OpWithAliases (Op rep)), ASTRep rep) =>- (LastUse, Used) ->- HistOp (Aliases rep) ->- LastUseM rep-analyseHistOp (lumap, used) (HistOp width race dest neutral shp lambda) = do- (lumap', used') <- analyseLambda (lumap, used) lambda- let nms =- ( freeIn width- <> freeIn race- <> freeIn dest- <> freeIn neutral- <> freeIn shp- )- `namesSubtract` used'- pure (lumap', used' <> nms)+lastUseSeqOp :: Op (Aliases SeqMem) -> Names -> LastUseM SeqMem (LUTabFun, Names, Names)+lastUseSeqOp (Alloc se sp) used_nms = do+ let free_in_e = freeIn se <> freeIn sp+ (used_nms', lu_vars) <- lastUsedInNames used_nms free_in_e+ pure (mempty, lu_vars, used_nms')+lastUseSeqOp (Inner NoOp) used_nms = do+ pure (mempty, mempty, used_nms) -analyseLambda :: (FreeIn (OpWithAliases (Op rep)), ASTRep rep) => (LastUse, Used) -> Lambda (Aliases rep) -> LastUseM rep-analyseLambda (lumap, used) (Lambda params body ret) = do- (lumap', used') <- analyseBody lumap used body- let used'' = used' <> freeIn params <> freeIn ret- pure (lumap', used'')+------------------------------------------------------ -flipMap :: Map VName VName -> Map VName Names-flipMap m =- M.toList m- & fmap (swap . first oneName)- & foldr (uncurry $ M.insertWith (<>)) mempty+-- | Given already used names and newly encountered 'Names', return an updated+-- set used names and the set of names that were last used here.+--+-- For a given name @x@ in the new uses, if neither @x@ nor any of its aliases+-- are present in the set of used names, this is a last use of @x@.+lastUsedInNames ::+ -- | Used names+ Names ->+ -- | New uses+ Names ->+ LastUseM rep (Names, Names)+lastUsedInNames used_nms new_uses = do+ -- a use of an argument x is also a use of any variable in x alias set+ -- so we update the alias-based transitive-closure of used names.+ new_uses_with_aliases <- aliasTransitiveClosure new_uses+ -- if neither a variable x, nor any of its alias set have been used before (in+ -- the backward traversal), then it is a last use of both that variable and+ -- all other variables in its alias set+ last_uses <- filterM isLastUse $ namesToList new_uses+ last_uses' <- aliasTransitiveClosure $ namesFromList last_uses+ pure (used_nms <> new_uses_with_aliases, last_uses')+ where+ isLastUse x = do+ with_aliases <- aliasTransitiveClosure $ oneName x+ pure $ not $ with_aliases `namesIntersect` used_nms -insertNames :: VName -> Names -> LastUse -> LastUse-insertNames name names lumap =- foldr (flip (M.insertWith $ \_ x -> x) name) lumap $ namesToList names+-- | Compute the transitive closure of the aliases of a set of 'Names'.+aliasTransitiveClosure :: Names -> LastUseM rep Names+aliasTransitiveClosure args = do+ res <- foldl (<>) args <$> mapM aliasLookup (namesToList args)+ if res == args+ then pure res+ else aliasTransitiveClosure res++-- | For each 'PatElem' in the 'Pat', add its aliases to the 'AliasTab' in+-- 'LastUseM'. Additionally, 'Names' are added as aliases of all the 'PatElemT'.+updateAliasing ::+ AliasesOf dec =>+ -- | Extra names that all 'PatElem' should alias.+ Names ->+ -- | Pattern to process+ Pat dec ->+ LastUseM rep ()+updateAliasing extra_aliases =+ mapM_ update . patElems+ where+ update :: AliasesOf dec => PatElem dec -> LastUseM rep ()+ update (PatElem name dec) = do+ let aliases = aliasesOf dec+ aliases' <- aliasTransitiveClosure $ extra_aliases <> aliases+ modify $ M.insert name aliases'
src/Futhark/Analysis/MemAlias.hs view
@@ -64,7 +64,7 @@ type MemAliasesM inner a = Reader (Env inner) a -analyzeHostOp :: MemAliases -> HostOp GPUMem () -> MemAliasesM (HostOp GPUMem ()) MemAliases+analyzeHostOp :: MemAliases -> HostOp NoOp GPUMem -> MemAliasesM (HostOp NoOp GPUMem) MemAliases analyzeHostOp m (SegOp (SegMap _ _ _ kbody)) = analyzeStms (kernelBodyStms kbody) m analyzeHostOp m (SegOp (SegRed _ _ _ _ kbody)) =@@ -75,9 +75,13 @@ analyzeStms (kernelBodyStms kbody) m analyzeHostOp m SizeOp {} = pure m analyzeHostOp m GPUBody {} = pure m-analyzeHostOp m (OtherOp ()) = pure m+analyzeHostOp m (OtherOp NoOp) = pure m -analyzeStm :: (Mem rep inner, LetDec rep ~ LetDecMem) => MemAliases -> Stm rep -> MemAliasesM inner MemAliases+analyzeStm ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ MemAliases ->+ Stm rep ->+ MemAliasesM (inner rep) MemAliases analyzeStm m (Let (Pat [PatElem vname _]) _ (Op (Alloc _ _))) = pure $ m <> singleton vname mempty analyzeStm m (Let _ _ (Op (Inner inner))) = do@@ -110,11 +114,18 @@ filterFun m' (v, Var v') | v' `isIn` m' = Just (v, v') filterFun _ _ = Nothing -analyzeStms :: (Mem rep inner, LetDec rep ~ LetDecMem) => Stms rep -> MemAliases -> MemAliasesM inner MemAliases+analyzeStms ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ Stms rep ->+ MemAliases ->+ MemAliasesM (inner rep) MemAliases analyzeStms = flip $ foldM analyzeStm -analyzeFun :: (Mem rep inner, LetDec rep ~ LetDecMem) => FunDef rep -> MemAliasesM inner (Name, MemAliases)+analyzeFun ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ FunDef rep ->+ MemAliasesM (inner rep) (Name, MemAliases) analyzeFun f = funDefParams f & mapMaybe justMem@@ -144,7 +155,10 @@ analyzeGPUMem :: Prog GPUMem -> (MemAliases, M.Map Name MemAliases) analyzeGPUMem prog = completeBijection $ runReader (analyze prog) $ Env analyzeHostOp -analyze :: (Mem rep inner, LetDec rep ~ LetDecMem) => Prog rep -> MemAliasesM inner (MemAliases, M.Map Name MemAliases)+analyze ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ Prog rep ->+ MemAliasesM (inner rep) (MemAliases, M.Map Name MemAliases) analyze prog = (,) <$> (progConsts prog & flip analyzeStms mempty <&> fixPoint transitiveClosure)
src/Futhark/Analysis/Metrics.hs view
@@ -32,8 +32,8 @@ opMetrics Nothing = pure () opMetrics (Just x) = opMetrics x -instance OpMetrics () where- opMetrics () = pure ()+instance OpMetrics (NoOp rep) where+ opMetrics NoOp = pure () newtype CountMetrics = CountMetrics [([Text], Text)]
− src/Futhark/Analysis/Rephrase.hs
@@ -1,103 +0,0 @@--- | Facilities for changing the rep of some fragment, with no--- context. We call this "rephrasing", for no deep reason.-module Futhark.Analysis.Rephrase- ( rephraseProg,- rephraseFunDef,- rephraseExp,- rephraseBody,- rephraseStm,- rephraseLambda,- rephrasePat,- rephrasePatElem,- Rephraser (..),- )-where--import Futhark.IR---- | A collection of functions that together allow us to rephrase some--- IR fragment, in some monad @m@. If we let @m@ be the 'Maybe'--- monad, we can conveniently do rephrasing that might fail. This is--- useful if you want to see if some IR in e.g. the @Kernels@ rep--- actually uses any @Kernels@-specific operations.-data Rephraser m from to = Rephraser- { rephraseExpDec :: ExpDec from -> m (ExpDec to),- rephraseLetBoundDec :: LetDec from -> m (LetDec to),- rephraseFParamDec :: FParamInfo from -> m (FParamInfo to),- rephraseLParamDec :: LParamInfo from -> m (LParamInfo to),- rephraseBodyDec :: BodyDec from -> m (BodyDec to),- rephraseRetType :: RetType from -> m (RetType to),- rephraseBranchType :: BranchType from -> m (BranchType to),- rephraseOp :: Op from -> m (Op to)- }---- | Rephrase an entire program.-rephraseProg :: Monad m => Rephraser m from to -> Prog from -> m (Prog to)-rephraseProg rephraser prog = do- consts <- mapM (rephraseStm rephraser) (progConsts prog)- funs <- mapM (rephraseFunDef rephraser) (progFuns prog)- pure $ prog {progConsts = consts, progFuns = funs}---- | Rephrase a function definition.-rephraseFunDef :: Monad m => Rephraser m from to -> FunDef from -> m (FunDef to)-rephraseFunDef rephraser fundec = do- body' <- rephraseBody rephraser $ funDefBody fundec- params' <- mapM (rephraseParam $ rephraseFParamDec rephraser) $ funDefParams fundec- rettype' <- mapM (rephraseRetType rephraser) $ funDefRetType fundec- pure fundec {funDefBody = body', funDefParams = params', funDefRetType = rettype'}---- | Rephrase an expression.-rephraseExp :: Monad m => Rephraser m from to -> Exp from -> m (Exp to)-rephraseExp = mapExpM . mapper---- | Rephrase a statement.-rephraseStm :: Monad m => Rephraser m from to -> Stm from -> m (Stm to)-rephraseStm rephraser (Let pat (StmAux cs attrs dec) e) =- Let- <$> rephrasePat (rephraseLetBoundDec rephraser) pat- <*> (StmAux cs attrs <$> rephraseExpDec rephraser dec)- <*> rephraseExp rephraser e---- | Rephrase a pattern.-rephrasePat ::- Monad m =>- (from -> m to) ->- Pat from ->- m (Pat to)-rephrasePat = traverse---- | Rephrase a pattern element.-rephrasePatElem :: Monad m => (from -> m to) -> PatElem from -> m (PatElem to)-rephrasePatElem rephraser (PatElem ident from) =- PatElem ident <$> rephraser from---- | Rephrase a parameter.-rephraseParam :: Monad m => (from -> m to) -> Param from -> m (Param to)-rephraseParam rephraser (Param attrs name from) =- Param attrs name <$> rephraser from---- | Rephrase a body.-rephraseBody :: Monad m => Rephraser m from to -> Body from -> m (Body to)-rephraseBody rephraser (Body rep stms res) =- Body- <$> rephraseBodyDec rephraser rep- <*> (stmsFromList <$> mapM (rephraseStm rephraser) (stmsToList stms))- <*> pure res---- | Rephrase a lambda.-rephraseLambda :: Monad m => Rephraser m from to -> Lambda from -> m (Lambda to)-rephraseLambda rephraser lam = do- body' <- rephraseBody rephraser $ lambdaBody lam- params' <- mapM (rephraseParam $ rephraseLParamDec rephraser) $ lambdaParams lam- pure lam {lambdaBody = body', lambdaParams = params'}--mapper :: Monad m => Rephraser m from to -> Mapper from to m-mapper rephraser =- identityMapper- { mapOnBody = const $ rephraseBody rephraser,- mapOnRetType = rephraseRetType rephraser,- mapOnBranchType = rephraseBranchType rephraser,- mapOnFParam = rephraseParam (rephraseFParamDec rephraser),- mapOnLParam = rephraseParam (rephraseLParamDec rephraser),- mapOnOp = rephraseOp rephraser- }
src/Futhark/Analysis/SymbolTable.hs view
@@ -30,6 +30,7 @@ lookupLoopParam, aliases, available,+ subExpAvailable, consume, index, index',@@ -281,6 +282,11 @@ available :: VName -> SymbolTable rep -> Bool available name = maybe False (not . entryConsumed) . M.lookup name . bindings +-- | Constant or 'available'+subExpAvailable :: SubExp -> SymbolTable rep -> Bool+subExpAvailable (Var name) = available name+subExpAvailable Constant {} = const True+ index :: ASTRep rep => VName ->@@ -323,7 +329,7 @@ Maybe Indexed indexOp _ _ _ _ = Nothing -instance IndexOp ()+instance IndexOp (NoOp rep) indexExp :: (IndexOp (Op rep), ASTRep rep) =>@@ -390,7 +396,7 @@ } bindingEntries ::- (ASTRep rep, Aliases.Aliased rep, IndexOp (Op rep)) =>+ (Aliases.Aliased rep, IndexOp (Op rep)) => Stm rep -> SymbolTable rep -> [LetBoundEntry rep]@@ -436,7 +442,7 @@ add vtable' (name, entry) = insertEntry name entry vtable' insertStm ::- (ASTRep rep, IndexOp (Op rep), Aliases.Aliased rep) =>+ (IndexOp (Op rep), Aliases.Aliased rep) => Stm rep -> SymbolTable rep -> SymbolTable rep@@ -475,7 +481,7 @@ update' e = e insertStms ::- (ASTRep rep, IndexOp (Op rep), Aliases.Aliased rep) =>+ (IndexOp (Op rep), Aliases.Aliased rep) => Stms rep -> SymbolTable rep -> SymbolTable rep
src/Futhark/Analysis/UsageTable.hs view
@@ -153,7 +153,7 @@ -- | Produce a usage table reflecting the use of the free variables in -- a single statement.-usageInStm :: (ASTRep rep, Aliased rep) => Stm rep -> UsageTable+usageInStm :: Aliased rep => Stm rep -> UsageTable usageInStm (Let pat rep e) = mconcat [ usageInPat pat `without` patNames pat,
src/Futhark/Bench.hs view
@@ -54,7 +54,7 @@ -- | The results for a single named dataset is either an error message, or -- runtime measurements, the number of bytes used, and the stderr that was -- produced.-data DataResult = DataResult String (Either T.Text Result)+data DataResult = DataResult T.Text (Either T.Text Result) deriving (Eq, Show) -- | The results for all datasets for some benchmark program.@@ -88,16 +88,16 @@ DataResults <$> mapM datasetResult (JSON.toList o) where datasetResult (k, v) =- DataResult (JSON.toString k)+ DataResult (JSON.toText k) <$> ((Right <$> success v) <|> (Left <$> JSON.parseJSON v)) success = JSON.withObject "result" $ \o -> Result <$> o JSON..: "runtimes" <*> o JSON..: "bytes" <*> o JSON..:? "stderr" dataResultJSON :: DataResult -> (JSON.Key, JSON.Value) dataResultJSON (DataResult desc (Left err)) =- (JSON.fromString desc, JSON.toJSON err)+ (JSON.fromText desc, JSON.toJSON err) dataResultJSON (DataResult desc (Right (Result runtimes bytes progerr_opt))) =- ( JSON.fromString desc,+ ( JSON.fromText desc, JSON.object $ [ ("runtimes", JSON.toJSON $ map runMicroseconds runtimes), ("bytes", JSON.toJSON bytes)
src/Futhark/CLI/Autotune.hs view
@@ -4,11 +4,12 @@ import Control.Monad import Data.ByteString.Char8 qualified as SBS import Data.Function (on)-import Data.List (elemIndex, intersect, isPrefixOf, minimumBy, sort, sortOn)+import Data.List (elemIndex, intersect, minimumBy, sort, sortOn) import Data.Map qualified as M import Data.Maybe import Data.Set qualified as S import Data.Text qualified as T+import Data.Text.IO qualified as T import Data.Tree import Futhark.Bench import Futhark.Server@@ -73,26 +74,26 @@ runResultAction = const $ pure () } -type Path = [(String, Int)]+type Path = [(T.Text, Int)] -regexGroups :: Regex -> String -> Maybe [String]+regexGroups :: Regex -> T.Text -> Maybe [T.Text] regexGroups regex s = do (_, _, _, groups) <-- matchM regex s :: Maybe (String, String, String, [String])+ matchM regex s :: Maybe (T.Text, T.Text, T.Text, [T.Text]) Just groups -comparisons :: String -> [(String, Int)]-comparisons = mapMaybe isComparison . lines+comparisons :: T.Text -> [(T.Text, Int)]+comparisons = mapMaybe isComparison . T.lines where regex = makeRegex ("Compared ([^ ]+) <= (-?[0-9]+)" :: String) isComparison l = do [thresh, val] <- regexGroups regex l- val' <- readMaybe val+ val' <- readMaybe $ T.unpack val pure (thresh, val') -type RunDataset = Server -> Int -> Path -> IO (Either String ([(String, Int)], Int))+type RunDataset = Server -> Int -> Path -> IO (Either String ([(T.Text, Int)], Int)) -type DatasetName = String+type DatasetName = T.Text serverOptions :: AutotuneOptions -> [String] serverOptions opts =@@ -101,10 +102,10 @@ : "-L" : optExtraOptions opts -setTuningParam :: Server -> String -> Int -> IO ()+setTuningParam :: Server -> T.Text -> Int -> IO () setTuningParam server name val = either (error . T.unpack . T.unlines . failureMsg) (const $ pure ())- =<< cmdSetTuningParam server (T.pack name) (showText val)+ =<< cmdSetTuningParam server name (showText val) setTuningParams :: Server -> Path -> IO () setTuningParams server = mapM_ (uncurry $ setTuningParam server)@@ -165,9 +166,9 @@ pure (dataset, do_run, iosEntryPoint ios) where run server entry_point trun expected timeout path = do- let bestRuntime :: ([RunResult], T.Text) -> ([(String, Int)], Int)+ let bestRuntime :: ([RunResult], T.Text) -> ([(T.Text, Int)], Int) bestRuntime (runres, errout) =- ( comparisons (T.unpack errout),+ ( comparisons errout, minimum $ map runMicroseconds runres ) @@ -196,14 +197,14 @@ --- Benchmarking a program -data DatasetResult = DatasetResult [(String, Int)] Double+data DatasetResult = DatasetResult [(T.Text, Int)] Double deriving (Show) --- Finding initial comparisons. --- Extracting threshold hierarchy. -type ThresholdForest = Forest (String, Bool)+type ThresholdForest = Forest (T.Text, Bool) thresholdMin, thresholdMax :: Int thresholdMin = 1@@ -212,7 +213,7 @@ -- | Depth-first list of thresholds to tune in order, and a -- corresponding assignment of ancestor thresholds to ensure that they -- are used.-tuningPaths :: ThresholdForest -> [(String, Path)]+tuningPaths :: ThresholdForest -> [(T.Text, Path)] tuningPaths = concatMap (treePaths []) where treePaths ancestors (Node (v, _) children) =@@ -227,7 +228,7 @@ thresholdForest :: FilePath -> IO ThresholdForest thresholdForest prog = do thresholds <-- getThresholds+ getThresholds . T.pack <$> readProcess ("." </> dropExtension prog) ["--print-params"] "" let root (v, _) = ((v, False), []) pure $@@ -235,22 +236,22 @@ map root $ filter (null . snd) thresholds where- getThresholds = mapMaybe findThreshold . lines- regex = makeRegex ("(.*) \\(threshold\\(([^ ]+,)(.*)\\)\\)" :: String)+ getThresholds = mapMaybe findThreshold . T.lines+ regex = makeRegex ("(.*) \\(threshold\\(([^ ]+,)(.*)\\)\\)" :: T.Text) - findThreshold :: String -> Maybe (String, [(String, Bool)])+ findThreshold :: T.Text -> Maybe (T.Text, [(T.Text, Bool)]) findThreshold l = do [grp1, _, grp2] <- regexGroups regex l pure ( grp1,- filter (not . null . fst)+ filter (not . T.null . fst) $ map ( \x ->- if "!" `isPrefixOf` x- then (drop 1 x, False)+ if "!" `T.isPrefixOf` x+ then (T.drop 1 x, False) else (x, True) )- $ words grp2+ $ T.words grp2 ) unfold thresholds ((parent, parent_cmp), ancestors) =@@ -276,7 +277,7 @@ Server -> [(DatasetName, RunDataset, T.Text)] -> (Path, M.Map DatasetName Int) ->- (String, Path) ->+ (T.Text, Path) -> IO (Path, M.Map DatasetName Int) tuneThreshold opts server datasets (already_tuned, best_runtimes0) (v, _v_path) = do (tune_result, best_runtimes) <-@@ -287,21 +288,24 @@ Just (_, threshold) -> pure ((v, threshold) : already_tuned, best_runtimes) where- tuneDataset :: (Maybe (Int, Int), M.Map DatasetName Int) -> (DatasetName, RunDataset, T.Text) -> IO (Maybe (Int, Int), M.Map DatasetName Int)+ tuneDataset ::+ (Maybe (Int, Int), M.Map DatasetName Int) ->+ (DatasetName, RunDataset, T.Text) ->+ IO (Maybe (Int, Int), M.Map DatasetName Int) tuneDataset (thresholds, best_runtimes) (dataset_name, run, entry_point) =- if not $ isPrefixOf (T.unpack entry_point ++ ".") v+ if not $ T.isPrefixOf (entry_point <> ".") v then do when (optVerbose opts > 0) $- putStrLn $- unwords [v, "is irrelevant for", T.unpack entry_point]+ T.putStrLn $+ T.unwords [v, "is irrelevant for", entry_point] pure (thresholds, best_runtimes) else do- putStrLn $- unwords+ T.putStrLn $+ T.unwords [ "Tuning", v, "on entry point",- T.unpack entry_point,+ entry_point, "and dataset", dataset_name ]@@ -351,16 +355,16 @@ case dataset_name `M.lookup` best_runtimes of Just rt | fromIntegral rt * epsilon < fromIntegral best_t -> do- putStrLn $- unwords+ T.putStrLn $+ T.unwords [ "WARNING! Possible non-monotonicity detected. Previous best run-time for dataset", dataset_name, " was",- show rt,+ showText rt, "but after tuning threshold", v, "it is",- show best_t+ showText best_t ] pure best_runtimes _ ->@@ -374,7 +378,7 @@ -- We wish to let datasets run for the untuned time + 20% + 1 second. timeout elapsed = ceiling (fromIntegral elapsed * 1.2 :: Double) + 1 - candidateEPar :: (Int, Int) -> (String, Int) -> Bool+ candidateEPar :: (Int, Int) -> (T.Text, Int) -> Bool candidateEPar (tMin, tMax) (threshold, ePar) = ePar > tMin && ePar < tMax && threshold == v @@ -451,17 +455,17 @@ runAutotuner opts prog = do best <- tune opts prog - let tuning = unlines $ do+ let tuning = T.unlines $ do (s, n) <- sortOn fst best- pure $ s ++ "=" ++ show n+ pure $ s <> "=" <> showText n case optTuning opts of Nothing -> pure () Just suffix -> do- writeFile (prog <.> suffix) tuning+ T.writeFile (prog <.> suffix) tuning putStrLn $ "Wrote " ++ prog <.> suffix - putStrLn $ "Result of autotuning:\n" ++ tuning+ T.putStrLn $ "Result of autotuning:\n" <> tuning commandLineOptions :: [FunOptDescr AutotuneOptions] commandLineOptions =
src/Futhark/CLI/Bench.hs view
@@ -242,7 +242,8 @@ relevant = maybe (const True) (==) (optEntryPoint opts) . T.unpack . iosEntryPoint - pad_to = foldl max 0 $ concatMap (map (length . atMostChars maxDatasetNameLength . runDescription) . iosTestRuns) cases+ len = T.length . atMostChars maxDatasetNameLength . runDescription+ pad_to = foldl max 0 $ concatMap (map len . iosTestRuns) cases runOptions :: ((Int, Maybe Double) -> IO ()) -> BenchOptions -> RunOptions runOptions f opts =@@ -256,8 +257,8 @@ runResultAction = f } -descString :: String -> Int -> String-descString desc pad_to = desc ++ ": " ++ replicate (pad_to - length desc) ' '+descText :: T.Text -> Int -> T.Text+descText desc pad_to = desc <> ": " <> T.replicate (pad_to - T.length desc) " " progress :: Double -> T.Text progress elapsed =@@ -290,17 +291,17 @@ data BenchPhase = Initial | Convergence -mkProgressPrompt :: BenchOptions -> Int -> String -> UTCTime -> IO ((Maybe Int, Maybe Double) -> IO ())+mkProgressPrompt :: BenchOptions -> Int -> T.Text -> UTCTime -> IO ((Maybe Int, Maybe Double) -> IO ()) mkProgressPrompt opts pad_to dataset_desc start_time | fancyTerminal = do count <- newIORef (0, 0) phase_var <- newIORef Initial spin_count <- newIORef 0 pure $ \(us, rse) -> do- putStr "\r" -- Go to start of line.+ T.putStr "\r" -- Go to start of line. let p s = T.putStr $- T.pack (descString (atMostChars maxDatasetNameLength dataset_desc) pad_to) <> s+ descText (atMostChars maxDatasetNameLength dataset_desc) pad_to <> s (us_sum, i) <- readIORef count @@ -343,7 +344,7 @@ putStr " " -- Just to move the cursor away from the progress bar. hFlush stdout | otherwise = do- putStr $ descString dataset_desc pad_to+ T.putStr $ descText dataset_desc pad_to hFlush stdout pure $ const $ pure () where@@ -390,8 +391,8 @@ when fancyTerminal $ do clearLine- putStr "\r"- putStr $ descString (atMostChars maxDatasetNameLength dataset_desc) pad_to+ T.putStr "\r"+ T.putStr $ descText (atMostChars maxDatasetNameLength dataset_desc) pad_to case res of Left err -> liftIO $ do
+ src/Futhark/CLI/Benchcmp.hs view
@@ -0,0 +1,327 @@+-- | @futhark benchcmp@+module Futhark.CLI.Benchcmp (main) where++import Control.Exception (catch)+import Data.Bifunctor (Bifunctor (bimap, first, second))+import Data.ByteString.Lazy.Char8 qualified as LBS+import Data.Either qualified as E+import Data.List qualified as L+import Data.Map qualified as M+import Data.Text qualified as T+import Data.Vector qualified as V+import Futhark.Bench+import Futhark.Util (showText)+import Futhark.Util.Options (mainWithOptions)+import Statistics.Sample qualified as S+import System.Console.ANSI (hSupportsANSI)+import System.IO (stdout)+import Text.Printf (printf)++-- | Record that summerizes a comparison between two benchmarks.+data SpeedUp = SpeedUp+ { -- | What factor the benchmark is improved by.+ speedup :: Double,+ -- | Memory usage.+ memoryUsage :: M.Map T.Text Double,+ -- | If the speedup was significant.+ significant :: Bool+ }+ deriving (Show)++-- | Terminal colors used when printing the comparisons. Some of these are not+-- colors ways of emphasising text.+data Colors = Colors+ { -- | The header color.+ header :: T.Text,+ -- | Okay color+ okblue :: T.Text,+ -- | A second okay color+ okgreen :: T.Text,+ -- | Warning color.+ warning :: T.Text,+ -- | When something fails.+ failing :: T.Text,+ -- | Default color.+ endc :: T.Text,+ -- | Bold text.+ bold :: T.Text,+ -- | Underline text.+ underline :: T.Text+ }++-- | Colors to use for a terminal device.+ttyColors :: Colors+ttyColors =+ Colors+ { header = "\ESC[95m",+ okblue = "\ESC[94m",+ okgreen = "\ESC[92m",+ warning = "\ESC[93m",+ failing = "\ESC[91m",+ endc = "\ESC[0m",+ bold = "\ESC[1m",+ underline = "\ESC[4m"+ }++-- | Colors to use for a non-terminal device.+nonTtyColors :: Colors+nonTtyColors =+ Colors+ { header = "",+ okblue = "",+ okgreen = "",+ warning = "",+ failing = "",+ endc = "",+ bold = "",+ underline = ""+ }++-- | Reads a file without throwing an error.+readFileSafely :: T.Text -> IO (Either T.Text LBS.ByteString)+readFileSafely filepath =+ (Right <$> LBS.readFile (T.unpack filepath)) `catch` couldNotRead+ where+ couldNotRead e = pure $ Left $ showText (e :: IOError)++-- | Converts DataResults to a Map with the text as a key.+toDataResultsMap :: [DataResult] -> M.Map T.Text (Either T.Text Result)+toDataResultsMap = M.fromList . fmap toTuple+ where+ toTuple (DataResult dataset dataResults) = (dataset, dataResults)++-- | Converts BenchResults to a Map with the file path as a key.+toBenchResultsMap ::+ [BenchResult] ->+ M.Map T.Text (M.Map T.Text (Either T.Text Result))+toBenchResultsMap = M.fromList . fmap toTuple+ where+ toTuple (BenchResult path dataResults) =+ (T.pack path, toDataResultsMap dataResults)++-- | Given a file path to a json file which has the form of a futhark benchmark+-- result, it will try to parse the file to a Map of Maps. The key+-- in the outer most dictionary is a file path the inner key is the dataset.+decodeFileBenchResultsMap ::+ T.Text ->+ IO (Either T.Text (M.Map T.Text (M.Map T.Text (Either T.Text Result))))+decodeFileBenchResultsMap path = do+ file <- readFileSafely path+ pure $ toBenchResultsMap <$> (file >>= (first T.pack . decodeBenchResults))++-- | Will return a text with an error saying there is a missing program in a+-- given result.+formatMissingProg :: T.Text -> T.Text -> T.Text -> T.Text+formatMissingProg = ((T.pack .) .) . printf "In %s but not %s: program %s"++-- | Will return a text with an error saying there is a missing dataset in a+-- given result.+formatMissingData :: T.Text -> T.Text -> T.Text -> T.Text -> T.Text+formatMissingData =+ (((T.pack .) .) .) . printf "In %s but not %s: program %s dataset %s"++-- | Will return texts that say there are a missing program.+formatManyMissingProg :: T.Text -> T.Text -> [T.Text] -> [T.Text]+formatManyMissingProg a_path b_path =+ zipWith3 formatMissingProg a_paths b_paths+ where+ a_paths = repeat a_path+ b_paths = repeat b_path++-- | Will return texts that say there are missing datasets for a program.+formatManyMissingData :: T.Text -> T.Text -> T.Text -> [T.Text] -> [T.Text]+formatManyMissingData prog a_path b_path =+ L.zipWith4 formatMissingData a_paths b_paths progs+ where+ a_paths = repeat a_path+ b_paths = repeat b_path+ progs = repeat prog++-- | Finds the keys two Maps does not have in common and returns a appropiate+-- error based on the functioned passed.+missingResults ::+ (T.Text -> T.Text -> [T.Text] -> [T.Text]) ->+ T.Text ->+ T.Text ->+ M.Map T.Text a ->+ M.Map T.Text b ->+ [T.Text]+missingResults toMissingMap a_path b_path a_results b_results = missing+ where+ a_keys = M.keys a_results+ b_keys = M.keys b_results+ a_missing = toMissingMap a_path b_path $ a_keys L.\\ b_keys+ b_missing = toMissingMap b_path a_path $ b_keys L.\\ a_keys+ missing = a_missing `L.union` b_missing++-- | Compares the memory usage of two results.+computeMemoryUsage ::+ M.Map T.Text Int ->+ M.Map T.Text Int ->+ M.Map T.Text Double+computeMemoryUsage a b = M.intersectionWith divide b $ M.filter (/= 0) a+ where+ divide x y = fromIntegral x / fromIntegral y++-- | Compares two results and thereby computes the Speed Up records.+compareResult :: Result -> Result -> SpeedUp+compareResult a b =+ SpeedUp+ { speedup = speedup',+ significant = significant',+ memoryUsage = memory_usage+ }+ where+ runResultToDouble :: RunResult -> Double+ runResultToDouble = fromIntegral . runMicroseconds+ toVector = V.fromList . (runResultToDouble <$>) . runResults+ a_memory_usage = memoryMap a+ b_memory_usage = memoryMap b+ a_run_results = toVector a+ b_run_results = toVector b+ a_std = S.stdDev a_run_results+ b_std = S.stdDev b_run_results+ a_mean = S.mean a_run_results+ b_mean = S.mean b_run_results+ diff = abs $ a_mean - b_mean+ speedup' = a_mean / b_mean+ significant' = diff > a_std / 2 + b_std / 2+ memory_usage = computeMemoryUsage a_memory_usage b_memory_usage++-- | Given two Maps containing datasets as keys and results as values, compare+-- the results and return the errors in a tuple.+compareDataResults ::+ T.Text ->+ T.Text ->+ T.Text ->+ M.Map T.Text (Either T.Text Result) ->+ M.Map T.Text (Either T.Text Result) ->+ (M.Map T.Text SpeedUp, ([T.Text], [T.Text]))+compareDataResults prog a_path b_path a_data b_data = result+ where+ formatMissing = formatManyMissingData prog+ partition = E.partitionEithers . fmap sequence . M.toList+ (a_errors, a_data') = second M.fromList $ partition a_data+ (b_errors, b_data') = second M.fromList $ partition b_data+ missing = missingResults formatMissing a_path b_path a_data' b_data'+ exists = M.intersectionWith compareResult a_data' b_data'+ errors = a_errors ++ b_errors+ result = (exists, (errors, missing))++-- | Given two Maps containing program file paths as keys and values as datasets+-- with results. Compare the results for each dataset in each program and+-- return the errors in a tuple.+compareBenchResults ::+ T.Text ->+ T.Text ->+ M.Map T.Text (M.Map T.Text (Either T.Text Result)) ->+ M.Map T.Text (M.Map T.Text (Either T.Text Result)) ->+ (M.Map T.Text (M.Map T.Text SpeedUp), ([T.Text], [T.Text]))+compareBenchResults a_path b_path a_bench b_bench = (exists, errors_missing)+ where+ missing = missingResults formatManyMissingProg a_path b_path a_bench b_bench+ result = M.intersectionWithKey auxiliary a_bench b_bench+ auxiliary prog = compareDataResults prog a_path b_path+ exists = M.filter (not . null) $ fst <$> result+ errors_missing' = bimap concat concat . unzip . M.elems $ snd <$> result+ errors_missing = second (missing ++) errors_missing'++-- | Formats memory usage such that it is human readable. If the memory usage+-- is not significant an empty text is returned.+memoryFormatter :: Colors -> T.Text -> Double -> T.Text+memoryFormatter colors key value+ | value < 0.99 = memoryFormat $ okgreen colors+ | value > 1.01 = memoryFormat $ failing colors+ | otherwise = ""+ where+ memoryFormat c = T.pack $ printf "%s%4.2fx@%s%s" c value key endc'+ endc' = endc colors++-- | Given a SpeedUp record the memory usage will be formatted to a colored+-- human readable text.+toMemoryText :: Colors -> SpeedUp -> T.Text+toMemoryText colors data_result+ | T.null memory_text = ""+ | otherwise = " (mem: " <> memory_text <> ")"+ where+ memory_text = M.foldrWithKey formatFolder "" memory+ memory = memoryUsage data_result+ formatFolder key value lst = lst <> memoryFormatter colors key value++-- | Given a text shorten it to a given length and add a suffix as the last+-- word.+shorten :: Int -> T.Text -> T.Text -> T.Text+shorten c end string+ | T.length string > c = (T.unwords . init $ T.words shortened) <> " " <> end+ | otherwise = string+ where+ end_len = T.length end+ (shortened, _) = T.splitAt (c - end_len) string++-- | Given a text add padding to the right of the text in form of spaces.+rightPadding :: Int -> T.Text -> T.Text+rightPadding c = T.pack . printf s+ where+ s = "%-" <> show c <> "s"++-- | Given a SpeedUp record print the SpeedUp in a human readable manner.+printSpeedUp :: Colors -> T.Text -> SpeedUp -> IO ()+printSpeedUp colors dataset data_result = do+ let color+ | significant data_result && speedup data_result > 1.01 = okgreen colors+ | significant data_result && speedup data_result < 0.99 = failing colors+ | otherwise = ""+ let short_dataset = rightPadding 64 . (<> ":") $ shorten 63 "[...]" dataset+ let memoryText = toMemoryText colors data_result+ let speedup' = speedup data_result+ let endc' = endc colors+ let format = " %s%s%10.2fx%s%s"+ putStrLn $ printf format short_dataset color speedup' endc' memoryText++-- | Given a Map of SpeedUp records where the key is the program, print the+-- SpeedUp in a human readable manner.+printProgSpeedUps :: Colors -> T.Text -> M.Map T.Text SpeedUp -> IO ()+printProgSpeedUps colors prog bench_result = do+ putStrLn ""+ putStrLn $ printf "%s%s%s%s" (header colors) (bold colors) prog (endc colors)+ mapM_ (uncurry (printSpeedUp colors)) $ M.toList bench_result++-- | Given a Map of programs with dataset speedups and relevant errors, print+-- the errors and print the speedups in a human readable manner.+printComparisons ::+ Colors ->+ M.Map T.Text (M.Map T.Text SpeedUp) ->+ ([T.Text], [T.Text]) ->+ IO ()+printComparisons colors speedups (errors, missing) = do+ mapM_ (putStrLn . T.unpack) $ L.sort missing+ mapM_ (putStrLn . T.unpack) $ L.sort errors+ mapM_ (uncurry (printProgSpeedUps colors)) $ M.toList speedups++-- | Run @futhark benchcmp@+main :: String -> [String] -> IO ()+main = mainWithOptions () [] "<file> <file>" f+ where+ f [a_path', b_path'] () = Just $ do+ let a_path = T.pack a_path'+ let b_path = T.pack b_path'+ a_either <- decodeFileBenchResultsMap a_path+ b_either <- decodeFileBenchResultsMap b_path++ isTty <- hSupportsANSI stdout++ let colors =+ if isTty+ then ttyColors+ else nonTtyColors++ let comparePrint =+ (uncurry (printComparisons colors) .)+ . compareBenchResults a_path b_path++ case (a_either, b_either) of+ (Left a, Left b) -> putStrLn . T.unpack $ (a <> "\n" <> b)+ (Left a, _) -> putStrLn . T.unpack $ a+ (_, Left b) -> putStrLn . T.unpack $ b+ (Right a, Right b) -> comparePrint a b+ f _ _ = Nothing
src/Futhark/CLI/Dataset.hs view
@@ -114,9 +114,9 @@ "Generate a random value of this type.", Option []- ["pretty"]+ ["text"] (NoArg $ Right $ \opts -> opts {format = Text})- "Output data in pretty format (must precede --generate).",+ "Output data in text format (default; must precede --generate).", Option "b" ["binary"]
src/Futhark/CLI/Dev.hs view
@@ -13,13 +13,13 @@ import Futhark.Analysis.Alias qualified as Alias import Futhark.Analysis.Metrics (OpMetrics) import Futhark.Compiler.CLI hiding (compilerMain)-import Futhark.IR (ASTRep, Op, Prog, prettyString)+import Futhark.IR (Op, Prog, prettyString)+import Futhark.IR.Aliases (AliasableRep) import Futhark.IR.GPU qualified as GPU import Futhark.IR.GPUMem qualified as GPUMem import Futhark.IR.MC qualified as MC import Futhark.IR.MCMem qualified as MCMem import Futhark.IR.Parse-import Futhark.IR.Prop.Aliases (CanBeAliased) import Futhark.IR.SOACS qualified as SOACS import Futhark.IR.Seq qualified as Seq import Futhark.IR.SeqMem qualified as SeqMem@@ -154,8 +154,7 @@ | SeqMemAction (BackendAction SeqMem.SeqMem) | PolyAction ( forall (rep :: Data.Kind.Type).- ( ASTRep rep,- (CanBeAliased (Op rep)),+ ( AliasableRep rep, (OpMetrics (Op rep)) ) => Action rep@@ -506,14 +505,6 @@ ( NoArg $ Right $ \opts -> opts {futharkAction = GPUMemAction $ \_ _ _ -> printLastUseGPU}- )- "Print last use information.",- Option- []- ["print-last-use-gpu-ss"]- ( NoArg $- Right $ \opts ->- opts {futharkAction = GPUMemAction $ \_ _ _ -> printLastUseGPUSS} ) "Print last use information ss.", Option
+ src/Futhark/CLI/Eval.hs view
@@ -0,0 +1,130 @@+module Futhark.CLI.Eval (main) where++import Control.Exception+import Control.Monad+import Control.Monad.Except+import Control.Monad.Free.Church+import Data.Map qualified as M+import Data.Maybe+import Data.Text qualified as T+import Data.Text.IO qualified as T+import Futhark.Compiler+import Futhark.MonadFreshNames+import Futhark.Pipeline+import Futhark.Util.Options+import Futhark.Util.Pretty+import Language.Futhark.Interpreter qualified as I+import Language.Futhark.Parser+import Language.Futhark.Semantic qualified as T+import Language.Futhark.TypeChecker qualified as I+import Language.Futhark.TypeChecker qualified as T+import System.Exit+import System.FilePath+import System.IO+import Prelude++main :: String -> [String] -> IO ()+main = mainWithOptions interpreterConfig options "options... <exprs...>" run+ where+ run [] _ = Nothing+ run exprs config = Just $ runExprs exprs config++runExprs :: [String] -> InterpreterConfig -> IO ()+runExprs exprs cfg = do+ let InterpreterConfig _ file = cfg+ maybe_new_state <- newFutharkiState cfg file+ (src, env, ctx) <- case maybe_new_state of+ Left _ -> do+ hPutStrLn stderr $ fromJust file <> ": file not found."+ exitWith $ ExitFailure 2+ Right s -> pure s+ mapM_ (runExpr src env ctx) exprs++-- Use parseExp, checkExp, then interpretExp.+runExpr :: VNameSource -> T.Env -> I.Ctx -> String -> IO ()+runExpr src env ctx str = do+ uexp <- case parseExp "" (T.pack str) of+ Left (SyntaxError _ serr) -> do+ T.hPutStrLn stderr serr+ exitWith $ ExitFailure 1+ Right e -> pure e+ fexp <- case T.checkExp [] src env uexp of+ (_, Left terr) -> do+ hPutDoc stderr $ I.prettyTypeError terr+ exitWith $ ExitFailure 1+ (_, Right (_, e)) -> pure e+ pval <- runInterpreterNoBreak $ I.interpretExp ctx fexp+ case pval of+ Left err -> do+ hPutDoc stderr $ I.prettyInterpreterError err+ exitWith $ ExitFailure 1+ Right val -> putDoc $ I.prettyValue val <> hardline++data InterpreterConfig = InterpreterConfig+ { interpreterPrintWarnings :: Bool,+ interpreterFile :: Maybe String+ }++interpreterConfig :: InterpreterConfig+interpreterConfig = InterpreterConfig True Nothing++options :: [FunOptDescr InterpreterConfig]+options =+ [ Option+ "f"+ ["file"]+ ( ReqArg+ ( \entry -> Right $ \config ->+ config {interpreterFile = Just entry}+ )+ "NAME"+ )+ "The file to load before evaluating expressions.",+ Option+ "w"+ ["no-warnings"]+ (NoArg $ Right $ \config -> config {interpreterPrintWarnings = False})+ "Do not print warnings."+ ]++newFutharkiState ::+ InterpreterConfig ->+ Maybe FilePath ->+ IO (Either (Doc AnsiStyle) (VNameSource, T.Env, I.Ctx))+newFutharkiState cfg maybe_file = runExceptT $ do+ (ws, imports, src) <-+ badOnLeft prettyCompilerError+ =<< liftIO+ ( runExceptT (readProgramFiles [] $ maybeToList maybe_file)+ `catch` \(err :: IOException) ->+ pure (externalErrorS (show err))+ )+ when (interpreterPrintWarnings cfg) $+ liftIO $+ hPutDoc stderr $+ prettyWarnings ws++ ictx <-+ foldM (\ctx -> badOnLeft I.prettyInterpreterError <=< runInterpreterNoBreak . I.interpretImport ctx) I.initialCtx $+ map (fmap fileProg) imports++ let (tenv, ienv) =+ let (iname, fm) = last imports+ in ( fileScope fm,+ ictx {I.ctxEnv = I.ctxImports ictx M.! iname}+ )++ pure (src, tenv, ienv)+ where+ badOnLeft :: (err -> err') -> Either err a -> ExceptT err' IO a+ badOnLeft _ (Right x) = pure x+ badOnLeft p (Left err) = throwError $ p err++runInterpreterNoBreak :: MonadIO m => F I.ExtOp a -> m (Either I.InterpreterError a)+runInterpreterNoBreak m = runF m (pure . Right) intOp+ where+ intOp (I.ExtOpError err) = pure $ Left err+ intOp (I.ExtOpTrace w v c) = do+ liftIO $ putDocLn $ pretty w <> ":" <+> align (unAnnotate v)+ c+ intOp (I.ExtOpBreak _ _ _ c) = c
src/Futhark/CLI/Literate.hs view
@@ -18,12 +18,12 @@ import Data.Text qualified as T import Data.Text.Encoding qualified as T import Data.Text.IO qualified as T+import Data.Text.Read qualified as T import Data.Vector.Storable qualified as SVec import Data.Vector.Storable.ByteString qualified as SVec import Data.Void import Data.Word (Word32, Word8) import Futhark.Data-import Futhark.Data.Reader import Futhark.Script import Futhark.Server import Futhark.Test@@ -597,18 +597,33 @@ void $ system "convert" [imgfile, "-type", "TrueColorAlpha", bmpfile] mempty loadBMP bmpfile -loadData :: FilePath -> ScriptM (Compound Value)-loadData datafile = do- contents <- liftIO $ LBS.readFile datafile- let maybe_vs = readValues contents- case maybe_vs of- Nothing ->- throwError $ "Failed to read data file " <> T.pack datafile- Just [v] ->- pure $ ValueAtom v- Just vs ->- pure $ ValueTuple $ map ValueAtom vs+loadPCM :: Int -> FilePath -> ScriptM (Compound Value)+loadPCM num_channels pcmfile = do+ contents <- liftIO $ LBS.readFile pcmfile+ let v = SVec.byteStringToVector $ LBS.toStrict contents+ channel_length = SVec.length v `div` num_channels+ shape =+ SVec.fromList+ [ fromIntegral num_channels,+ fromIntegral channel_length+ ]+ -- ffmpeg outputs audio data in column-major format. `backPermuter` computes the+ -- tranposed indexes for a backpermutation.+ backPermuter i = (i `mod` channel_length) * num_channels + i `div` channel_length+ perm = SVec.generate (SVec.length v) backPermuter+ pure $ ValueAtom $ F64Value shape $ SVec.backpermute v perm +loadAudio :: FilePath -> ScriptM (Compound Value)+loadAudio audiofile = do+ s <- system "ffprobe" [audiofile, "-show_entries", "stream=channels", "-select_streams", "a", "-of", "compact=p=0:nk=1", "-v", "0"] mempty+ case T.decimal s of+ Right (num_channels, _) -> do+ withTempDir $ \dir -> do+ let pcmfile = dir </> takeBaseName audiofile `replaceExtension` "pcm"+ void $ system "ffmpeg" ["-i", audiofile, "-c:a", "pcm_f64le", "-map", "0", "-f", "data", pcmfile] mempty+ loadPCM num_channels pcmfile+ _ -> throwError "$loadImg failed to detect the number of channels in the audio input"+ literateBuiltin :: EvalBuiltin ScriptM literateBuiltin "loadimg" vs = case vs of@@ -620,18 +635,18 @@ throwError $ "$loadimg does not accept arguments of types: " <> T.intercalate ", " (map (prettyText . fmap valueType) vs)-literateBuiltin "loaddata" vs =+literateBuiltin "loadaudio" vs = case vs of [ValueAtom v] | Just path <- getValue v -> do let path' = map (chr . fromIntegral) (path :: [Word8])- loadData path'+ loadAudio path' _ -> throwError $- "$loaddata does not accept arguments of types: "+ "$loadaudio does not accept arguments of types: " <> T.intercalate ", " (map (prettyText . fmap valueType) vs)-literateBuiltin f _ =- throwError $ "Unknown builtin function $" <> prettyText f+literateBuiltin f vs =+ scriptBuiltin "." f vs data Options = Options { scriptBackend :: String,
src/Futhark/CLI/Main.hs view
@@ -7,6 +7,7 @@ import Data.Text.IO qualified as T import Futhark.CLI.Autotune qualified as Autotune import Futhark.CLI.Bench qualified as Bench+import Futhark.CLI.Benchcmp qualified as Benchcmp import Futhark.CLI.C qualified as C import Futhark.CLI.CUDA qualified as CCUDA import Futhark.CLI.Check qualified as Check@@ -15,6 +16,7 @@ import Futhark.CLI.Defs qualified as Defs import Futhark.CLI.Dev qualified as Dev import Futhark.CLI.Doc qualified as Doc+import Futhark.CLI.Eval qualified as Eval import Futhark.CLI.LSP qualified as LSP import Futhark.CLI.Literate qualified as Literate import Futhark.CLI.Misc qualified as Misc@@ -47,6 +49,7 @@ sortOn fst [ ("dev", (Dev.main, "Run compiler passes directly.")),+ ("eval", (Eval.main, "Evaluate Futhark expressions passed in as arguments")), ("repl", (REPL.main, "Run interactive Read-Eval-Print-Loop.")), ("run", (Run.main, "Run a program through the (slow!) interpreter.")), ("c", (C.main, "Compile to sequential C.")),@@ -75,7 +78,8 @@ ("literate", (Literate.main, "Process a literate Futhark program.")), ("lsp", (LSP.main, "Run LSP server.")), ("thanks", (Misc.mainThanks, "Express gratitude.")),- ("tokens", (Misc.mainTokens, "Print tokens from Futhark file."))+ ("tokens", (Misc.mainTokens, "Print tokens from Futhark file.")),+ ("benchcmp", (Benchcmp.main, "Compare two Futhark benchmarks.")) ] msg :: String
src/Futhark/CLI/Misc.hs view
@@ -12,8 +12,9 @@ import Control.Monad.State import Data.ByteString.Lazy qualified as BS import Data.Function (on)-import Data.List (isInfixOf, nubBy)+import Data.List (nubBy) import Data.Loc (L (..), startPos)+import Data.Text qualified as T import Data.Text.IO qualified as T import Futhark.Compiler import Futhark.Test@@ -53,7 +54,7 @@ mainDataget :: String -> [String] -> IO () mainDataget = mainWithOptions () [] "program dataset" $ \args () -> case args of- [file, dataset] -> Just $ dataget file dataset+ [file, dataset] -> Just $ dataget file $ T.pack dataset _ -> Nothing where dataget prog dataset = do@@ -62,7 +63,7 @@ runs <- testSpecRuns <$> testSpecFromProgramOrDie prog let exact = filter ((dataset ==) . runDescription) runs- infixes = filter ((dataset `isInfixOf`) . runDescription) runs+ infixes = filter ((dataset `T.isInfixOf`) . runDescription) runs futhark <- FutharkExe <$> getExecutablePath @@ -70,13 +71,13 @@ if null exact then infixes else exact of [x] -> BS.putStr =<< getValuesBS futhark dir (runInput x) [] -> do- hPutStr stderr $ "No dataset '" ++ dataset ++ "'.\n"- hPutStr stderr "Available datasets:\n"- mapM_ (hPutStrLn stderr . (" " ++) . runDescription) runs+ T.hPutStr stderr $ "No dataset '" <> dataset <> "'.\n"+ T.hPutStr stderr "Available datasets:\n"+ mapM_ (T.hPutStrLn stderr . (" " <>) . runDescription) runs exitFailure runs' -> do- hPutStr stderr $ "Dataset '" ++ dataset ++ "' ambiguous:\n"- mapM_ (hPutStrLn stderr . (" " ++) . runDescription) runs'+ T.hPutStr stderr $ "Dataset '" <> dataset <> "' ambiguous:\n"+ mapM_ (T.hPutStrLn stderr . (" " <>) . runDescription) runs' exitFailure testSpecRuns = testActionRuns . testAction
src/Futhark/CLI/Pkg.hs view
@@ -1,12 +1,10 @@ -- | @futhark pkg@ module Futhark.CLI.Pkg (main) where -import Codec.Archive.Zip qualified as Zip import Control.Monad.IO.Class import Control.Monad.Reader import Control.Monad.State-import Data.ByteString.Lazy qualified as LBS-import Data.List (intercalate, isPrefixOf)+import Data.List (intercalate) import Data.Map qualified as M import Data.Maybe import Data.Monoid@@ -22,57 +20,17 @@ import System.Environment import System.Exit import System.FilePath-import System.FilePath.Posix qualified as Posix import System.IO+import System.IO.Temp (withSystemTempDirectory) import Prelude --- Installing packages -installInDir :: BuildList -> FilePath -> PkgM ()-installInDir (BuildList bl) dir = do- let putEntry from_dir pdir entry- -- The archive may contain all kinds of other stuff that we don't want.- | not (isInPkgDir from_dir $ Zip.eRelativePath entry)- || hasTrailingPathSeparator (Zip.eRelativePath entry) =- pure Nothing- | otherwise = do- -- Since we are writing to paths indicated in a zipfile we- -- downloaded from the wild Internet, we are going to be a- -- little bit paranoid. Specifically, we want to avoid- -- writing outside of the 'lib/' directory. We do this by- -- bailing out if the path contains any '..' components. We- -- have to use System.FilePath.Posix, because the zip library- -- claims to encode filepaths with '/' directory seperators no- -- matter the host OS.- when (".." `elem` Posix.splitPath (Zip.eRelativePath entry)) $- fail $- "Zip archive for "- <> pdir- <> " contains suspicious path: "- <> Zip.eRelativePath entry- let f = pdir </> makeRelative from_dir (Zip.eRelativePath entry)- createDirectoryIfMissing True $ takeDirectory f- LBS.writeFile f $ Zip.fromEntry entry- pure $ Just f-- isInPkgDir from_dir f =- Posix.splitPath from_dir `isPrefixOf` Posix.splitPath f-+installInDir :: CacheDir -> BuildList -> FilePath -> PkgM ()+installInDir cachedir (BuildList bl) dir = forM_ (M.toList bl) $ \(p, v) -> do- info <- lookupPackageRev p v- a <- downloadZipball info- m <- getManifest $ pkgRevGetManifest info-- -- Compute the directory in the zipball that should contain the- -- package files.- let noPkgDir =- fail $- "futhark.pkg for "- ++ T.unpack p- ++ "-"- ++ T.unpack (prettySemVer v)- ++ " does not define a package path."- from_dir <- maybe noPkgDir (pure . (pkgRevZipballDir info <>)) $ pkgDir m+ info <- lookupPackageRev cachedir p v+ (filedir, files) <- getFiles $ pkgGetFiles info -- The directory in the local file system that will contain the -- package files.@@ -83,17 +41,13 @@ -- have a way to recognise this situation, and not download the -- zipball in that case. liftIO $ removePathForcibly pdir- liftIO $ createDirectoryIfMissing True pdir - written <-- catMaybes <$> liftIO (mapM (putEntry from_dir pdir) $ Zip.zEntries a)-- when (null written) $- fail $- "Zip archive for package "- ++ T.unpack p- ++ " does not contain any files in "- ++ from_dir+ forM_ files $ \file -> do+ let from = filedir </> file+ to = pdir </> file+ liftIO $ createDirectoryIfMissing True $ takeDirectory to+ logMsg $ "Copying " <> from <> "\n" <> "to " <> to+ liftIO $ copyFile from to libDir, libNewDir, libOldDir :: FilePath (libDir, libNewDir, libOldDir) = ("lib", "lib~new", "lib~old")@@ -124,8 +78,8 @@ -- Since POSIX at least guarantees atomic renames, the only place this -- can fail is between steps 3, 4, and 5. In that case, at least the -- @lib~old@ will still exist and can be put back by the user.-installBuildList :: Maybe PkgPath -> BuildList -> PkgM ()-installBuildList p bl = do+installBuildList :: CacheDir -> Maybe PkgPath -> BuildList -> PkgM ()+installBuildList cachedir p bl = do libdir_exists <- liftIO $ doesDirectoryExist libDir -- 1@@ -134,7 +88,7 @@ createDirectoryIfMissing False libNewDir -- 2- installInDir bl libNewDir+ installInDir cachedir bl libNewDir -- 3 when libdir_exists $@@ -230,61 +184,65 @@ T.writeFile futharkPkg $ prettyPkgManifest m _ -> Nothing +withCacheDir :: (CacheDir -> IO a) -> IO a+withCacheDir f = withSystemTempDirectory "futhark-pkg" $ f . CacheDir+ doCheck :: String -> [String] -> IO () doCheck = cmdMain "check" $ \args cfg -> case args of- [] -> Just $- runPkgM cfg $ do- m <- getPkgManifest- bl <- solveDeps $ pkgRevDeps m+ [] -> Just . withCacheDir $ \cachedir -> runPkgM cfg $ do+ m <- getPkgManifest+ bl <- solveDeps cachedir $ pkgRevDeps m - liftIO $ T.putStrLn "Dependencies chosen:"- liftIO $ T.putStr $ prettyBuildList bl+ liftIO $ T.putStrLn "Dependencies chosen:"+ liftIO $ T.putStr $ prettyBuildList bl - case commented $ manifestPkgPath m of- Nothing -> pure ()- Just p -> do- let pdir = "lib" </> T.unpack p+ case commented $ manifestPkgPath m of+ Nothing -> pure ()+ Just p -> do+ let pdir = "lib" </> T.unpack p - pdir_exists <- liftIO $ doesDirectoryExist pdir+ pdir_exists <- liftIO $ doesDirectoryExist pdir - unless pdir_exists $- liftIO $ do- T.putStrLn $ "Problem: the directory " <> T.pack pdir <> " does not exist."- exitFailure+ unless pdir_exists $+ liftIO $ do+ T.putStrLn $ "Problem: the directory " <> T.pack pdir <> " does not exist."+ exitFailure - anything <-- liftIO $- any ((== ".fut") . takeExtension)- <$> directoryContents ("lib" </> T.unpack p)- unless anything $- liftIO $ do- T.putStrLn $ "Problem: the directory " <> T.pack pdir <> " does not contain any .fut files."- exitFailure+ anything <-+ liftIO $+ any ((== ".fut") . takeExtension)+ <$> directoryContents ("lib" </> T.unpack p)+ unless anything $+ liftIO $ do+ T.putStrLn $ "Problem: the directory " <> T.pack pdir <> " does not contain any .fut files."+ exitFailure _ -> Nothing doSync :: String -> [String] -> IO () doSync = cmdMain "" $ \args cfg -> case args of- [] -> Just $- runPkgM cfg $ do- m <- getPkgManifest- bl <- solveDeps $ pkgRevDeps m- installBuildList (commented $ manifestPkgPath m) bl+ [] -> Just . withCacheDir $ \cachedir -> runPkgM cfg $ do+ m <- getPkgManifest+ bl <- solveDeps cachedir $ pkgRevDeps m+ installBuildList cachedir (commented $ manifestPkgPath m) bl _ -> Nothing doAdd :: String -> [String] -> IO () doAdd = cmdMain "PKGPATH" $ \args cfg -> case args of- [p, v] | Right v' <- parseVersion $ T.pack v -> Just $ runPkgM cfg $ doAdd' (T.pack p) v'+ [p, v]+ | Right v' <- parseVersion $ T.pack v ->+ Just $ withCacheDir $ \cachedir ->+ runPkgM cfg $ doAdd' cachedir (T.pack p) v' [p] ->- Just $+ Just $ withCacheDir $ \cachedir -> runPkgM cfg $ -- Look up the newest revision of the package.- doAdd' (T.pack p) =<< lookupNewestRev (T.pack p)+ doAdd' cachedir (T.pack p) =<< lookupNewestRev cachedir (T.pack p) _ -> Nothing where- doAdd' p v = do+ doAdd' cachedir p v = do m <- getPkgManifest -- See if this package (and its dependencies) even exists. We@@ -292,11 +250,11 @@ -- in the manifest, plus this new one. The Monoid instance for -- PkgRevDeps is left-biased, so we are careful to use the new -- version for this package.- _ <- solveDeps $ PkgRevDeps (M.singleton p (v, Nothing)) <> pkgRevDeps m+ _ <- solveDeps cachedir $ PkgRevDeps (M.singleton p (v, Nothing)) <> pkgRevDeps m -- We either replace any existing occurence of package 'p', or -- we add a new one.- p_info <- lookupPackageRev p v+ p_info <- lookupPackageRev cachedir p v let hash = case (_svMajor v, _svMinor v, _svPatch v) of -- We do not perform hash-pinning for -- (0,0,0)-versions, because these already embed a@@ -372,19 +330,18 @@ doUpgrade :: String -> [String] -> IO () doUpgrade = cmdMain "" $ \args cfg -> case args of- [] -> Just $- runPkgM cfg $ do- m <- getPkgManifest- rs <- traverse (mapM (traverse upgrade)) $ manifestRequire m- putPkgManifest m {manifestRequire = rs}- if rs == manifestRequire m- then liftIO $ T.putStrLn "Nothing to upgrade."- else liftIO $ T.putStrLn "Remember to run 'futhark pkg sync'."+ [] -> Just . withCacheDir $ \cachedir -> runPkgM cfg $ do+ m <- getPkgManifest+ rs <- traverse (mapM (traverse (upgrade cachedir))) $ manifestRequire m+ putPkgManifest m {manifestRequire = rs}+ if rs == manifestRequire m+ then liftIO $ T.putStrLn "Nothing to upgrade."+ else liftIO $ T.putStrLn "Remember to run 'futhark pkg sync'." _ -> Nothing where- upgrade req = do- v <- lookupNewestRev $ requiredPkg req- h <- pkgRevCommit <$> lookupPackageRev (requiredPkg req) v+ upgrade cachedir req = do+ v <- lookupNewestRev cachedir $ requiredPkg req+ h <- pkgRevCommit <$> lookupPackageRev cachedir (requiredPkg req) v when (v /= requiredPkgRev req) $ liftIO $@@ -406,12 +363,13 @@ doVersions :: String -> [String] -> IO () doVersions = cmdMain "PKGPATH" $ \args cfg -> case args of- [p] -> Just $ runPkgM cfg $ doVersions' $ T.pack p+ [p] -> Just $ withCacheDir $ \cachedir ->+ runPkgM cfg $ doVersions' cachedir $ T.pack p _ -> Nothing where- doVersions' =+ doVersions' cachedir = mapM_ (liftIO . T.putStrLn . prettySemVer) . M.keys . pkgVersions- <=< lookupPackage+ <=< lookupPackage cachedir -- | Run @futhark pkg@. main :: String -> [String] -> IO ()@@ -453,12 +411,11 @@ _ -> do let bad _ () = Just $ do let k = maxinum (map (length . fst) commands) + 3- usageMsg $- T.unlines $- ["<command> ...:", "", "Commands:"]- ++ [ " " <> T.pack cmd <> T.pack (replicate (k - length cmd) ' ') <> desc- | (cmd, (_, desc)) <- commands- ]+ usageMsg . T.unlines $+ ["<command> ...:", "", "Commands:"]+ ++ [ " " <> T.pack cmd <> T.pack (replicate (k - length cmd) ' ') <> desc+ | (cmd, (_, desc)) <- commands+ ] mainWithOptions () [] usage bad prog args where
src/Futhark/CLI/REPL.hs view
@@ -30,7 +30,6 @@ import NeatInterpolation (text) import System.Console.Haskeline qualified as Haskeline import System.Directory-import System.FilePath import System.IO (stdout) import Text.Read (readMaybe) @@ -150,36 +149,24 @@ newFutharkiState :: Int -> LoadedProg -> Maybe FilePath -> IO (Either (Doc AnsiStyle) FutharkiState) newFutharkiState count prev_prog maybe_file = runExceptT $ do- (prog, tenv, ienv) <- case maybe_file of- Nothing -> do- -- Load the builtins through the type checker.- prog <-- badOnLeft prettyProgErrors =<< liftIO (reloadProg prev_prog [] M.empty)- -- Then into the interpreter.- ienv <-- foldM- (\ctx -> badOnLeft (pretty . show) <=< runInterpreter' . I.interpretImport ctx)- I.initialCtx- $ map (fmap fileProg) (lpImports prog)-- let (tenv, ienv') =- extendEnvs prog (T.initialEnv, ienv) ["/prelude/prelude"]-- pure (prog, tenv, ienv')- Just file -> do- prog <- badOnLeft prettyProgErrors =<< liftIO (reloadProg prev_prog [file] M.empty)- liftIO $ putDoc $ prettyWarnings $ lpWarnings prog-- ienv <-- foldM- (\ctx -> badOnLeft (pretty . show) <=< runInterpreter' . I.interpretImport ctx)- I.initialCtx- $ map (fmap fileProg) (lpImports prog)-- let (tenv, ienv') =- extendEnvs prog (T.initialEnv, ienv) ["/prelude/prelude", dropExtension file]+ let files = maybeToList maybe_file+ -- Put code through the type checker.+ prog <-+ badOnLeft prettyProgErrors+ =<< liftIO (reloadProg prev_prog files M.empty)+ liftIO $ putDoc $ prettyWarnings $ lpWarnings prog+ -- Then into the interpreter.+ ictx <-+ foldM+ (\ctx -> badOnLeft (pretty . show) <=< runInterpreterNoBreak . I.interpretImport ctx)+ I.initialCtx+ $ map (fmap fileProg) (lpImports prog) - pure (prog, tenv, ienv')+ let (tenv, ienv) =+ let (iname, fm) = last $ lpImports prog+ in ( fileScope fm,+ ictx {I.ctxEnv = I.ctxImports ictx M.! iname}+ ) pure FutharkiState@@ -267,7 +254,7 @@ Left e -> liftIO $ putDoc $ prettyProgErrors e Right prog -> do env <- gets futharkiEnv- let (tenv, ienv) = extendEnvs prog env (map fst $ decImports d)+ let (tenv, ienv) = extendEnvs prog env $ map fst $ decImports d imports = lpImports prog src = lpNameSource prog case T.checkDec imports src tenv cur_import d of@@ -371,8 +358,8 @@ c -runInterpreter' :: MonadIO m => F I.ExtOp a -> m (Either I.InterpreterError a)-runInterpreter' m = runF m (pure . Right) intOp+runInterpreterNoBreak :: MonadIO m => F I.ExtOp a -> m (Either I.InterpreterError a)+runInterpreterNoBreak m = runF m (pure . Right) intOp where intOp (I.ExtOpError err) = pure $ Left err intOp (I.ExtOpTrace w v c) = do
src/Futhark/CLI/Run.hs view
@@ -12,13 +12,11 @@ import Futhark.Compiler import Futhark.Data.Reader (readValues) import Futhark.Pipeline-import Futhark.Util (toPOSIX) import Futhark.Util.Options import Futhark.Util.Pretty (AnsiStyle, Doc, align, hPutDoc, hPutDocLn, pretty, unAnnotate, (<+>)) import Language.Futhark import Language.Futhark.Interpreter qualified as I import Language.Futhark.Semantic qualified as T-import Language.Futhark.TypeChecker qualified as T import System.Exit import System.FilePath import System.IO@@ -112,7 +110,7 @@ FilePath -> IO (Either (Doc AnsiStyle) (T.Env, I.Ctx)) newFutharkiState cfg file = runExceptT $ do- (ws, imports, src) <-+ (ws, imports, _src) <- badOnLeft prettyCompilerError =<< liftIO ( runExceptT (readProgramFile [] file)@@ -124,30 +122,20 @@ hPutDoc stderr $ prettyWarnings ws - let imp = T.mkInitialImport "."- ienv1 <-+ ictx <- foldM (\ctx -> badOnLeft I.prettyInterpreterError <=< runInterpreter' . I.interpretImport ctx) I.initialCtx $ map (fmap fileProg) imports- (tenv1, d1, src') <-- badOnLeft T.prettyTypeError . snd $- T.checkDec imports src T.initialEnv imp $- mkOpen "/prelude/prelude"- (tenv2, d2, _) <-- badOnLeft T.prettyTypeError . snd $- T.checkDec imports src' tenv1 imp $- mkOpen $- toPOSIX $- dropExtension file- ienv2 <- badOnLeft I.prettyInterpreterError =<< runInterpreter' (I.interpretDec ienv1 d1)- ienv3 <- badOnLeft I.prettyInterpreterError =<< runInterpreter' (I.interpretDec ienv2 d2)- pure (tenv2, ienv3)+ let (tenv, ienv) =+ let (iname, fm) = last imports+ in ( fileScope fm,+ ictx {I.ctxEnv = I.ctxImports ictx M.! iname}+ )++ pure (tenv, ienv) where badOnLeft :: (err -> err') -> Either err a -> ExceptT err' IO a badOnLeft _ (Right x) = pure x badOnLeft p (Left err) = throwError $ p err--mkOpen :: FilePath -> UncheckedDec-mkOpen f = OpenDec (ModImport f NoInfo mempty) mempty runInterpreter' :: MonadIO m => F I.ExtOp a -> m (Either I.InterpreterError a) runInterpreter' m = runF m (pure . Right) intOp
src/Futhark/CLI/Test.hs view
@@ -15,6 +15,7 @@ import Data.Map.Strict qualified as M import Data.Text qualified as T import Data.Text.Encoding qualified as T+import Data.Text.IO qualified as T import Futhark.Analysis.Metrics.Type import Futhark.Server import Futhark.Test@@ -215,7 +216,7 @@ let dir = takeDirectory program runInterpretedCase run@(TestRun _ inputValues _ index _) = unless (any (`elem` runTags run) ["compiled", "script"]) $- context ("Entry point: " <> entry <> "; dataset: " <> T.pack (runDescription run)) $ do+ context ("Entry point: " <> entry <> "; dataset: " <> runDescription run) $ do input <- T.unlines . map valueText <$> getValues (FutharkExe futhark) dir inputValues expectedResult' <- getExpectedResult (FutharkExe futhark) program entry run (code, output, err) <-@@ -325,7 +326,7 @@ "Entry point: " <> entry <> "; dataset: "- <> T.pack (runDescription run)+ <> runDescription run context1 case_ctx $ do expected <- getExpectedResult futhark program entry run@@ -491,9 +492,9 @@ putStatusTable ts clearLine w <- maybe 80 Terminal.width <$> Terminal.size- putStrLn $ atMostChars (w - length labelstr) running+ T.putStrLn $ atMostChars (w - T.length labelstr) running where- running = labelstr ++ (unwords . reverse . map testCaseProgram . testStatusRun) ts+ running = labelstr <> (T.unwords . reverse . map (T.pack . testCaseProgram) . testStatusRun) ts labelstr = "Now testing: " moveCursorToTableTop :: IO ()
src/Futhark/CodeGen/Backends/CCUDA.hs view
@@ -69,13 +69,12 @@ GC.opsAllocate = allocateCUDABuffer, GC.opsDeallocate = deallocateCUDABuffer, GC.opsCopy = copyCUDAMemory,- GC.opsStaticArray = staticCUDAArray, GC.opsMemoryType = cudaMemoryType, GC.opsCompiler = callKernel, GC.opsFatMemory = True, GC.opsCritical =- ( [C.citems|CUDA_SUCCEED_FATAL(cuCtxPushCurrent(ctx->cuda.cu_ctx));|],- [C.citems|CUDA_SUCCEED_FATAL(cuCtxPopCurrent(&ctx->cuda.cu_ctx));|]+ ( [C.citems|CUDA_SUCCEED_FATAL(cuCtxPushCurrent(ctx->cu_ctx));|],+ [C.citems|CUDA_SUCCEED_FATAL(cuCtxPopCurrent(&ctx->cu_ctx));|] ) } cuda_includes =@@ -199,7 +198,7 @@ allocateCUDABuffer mem size tag "device" = GC.stm [C.cstm|ctx->error =- CUDA_SUCCEED_NONFATAL(cuda_alloc(&ctx->cuda, ctx->log,+ CUDA_SUCCEED_NONFATAL(cuda_alloc(ctx, ctx->log, (size_t)$exp:size, $exp:tag, &$exp:mem, (size_t*)&$exp:size));|] allocateCUDABuffer _ _ _ space =@@ -207,7 +206,7 @@ deallocateCUDABuffer :: GC.Deallocate OpenCL () deallocateCUDABuffer mem size tag "device" =- GC.stm [C.cstm|CUDA_SUCCEED_OR_RETURN(cuda_free(&ctx->cuda, $exp:mem, $exp:size, $exp:tag));|]+ GC.stm [C.cstm|CUDA_SUCCEED_OR_RETURN(cuda_free(ctx, $exp:mem, $exp:size, $exp:tag));|] deallocateCUDABuffer _ _ _ space = error $ "Cannot deallocate in '" ++ space ++ "' memory space." @@ -238,43 +237,6 @@ ++ show srcSpace ++ "'." -staticCUDAArray :: GC.StaticArray OpenCL ()-staticCUDAArray name "device" t vs = do- let ct = GC.primTypeToCType t- name_realtype <- newVName $ baseString name ++ "_realtype"- num_elems <- case vs of- ArrayValues vs' -> do- let vs'' = [[C.cinit|$exp:v|] | v <- vs']- GC.earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:(length vs'')] = {$inits:vs''};|]- pure $ length vs''- ArrayZeros n -> do- GC.earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:n];|]- pure n- -- Fake a memory block.- GC.contextFieldDyn- (C.toIdent name mempty)- [C.cty|struct memblock_device|]- Nothing- [C.cstm|cuMemFree(ctx->$id:name.mem);|]- -- During startup, copy the data to where we need it.- GC.atInit- [C.cstm|{- ctx->$id:name.references = NULL;- ctx->$id:name.size = 0;- CUDA_SUCCEED_FATAL(cuMemAlloc(&ctx->$id:name.mem,- ($int:num_elems > 0 ? $int:num_elems : 1)*sizeof($ty:ct)));- if ($int:num_elems > 0) {- CUDA_SUCCEED_FATAL(cuMemcpyHtoD(ctx->$id:name.mem, $id:name_realtype,- $int:num_elems*sizeof($ty:ct)));- }- }|]- GC.item [C.citem|struct memblock_device $id:name = ctx->$id:name;|]-staticCUDAArray _ space _ _ =- error $- "CUDA backend cannot create static array in '"- ++ space- ++ "' memory space"- cudaMemoryType :: GC.MemoryType OpenCL () cudaMemoryType "device" = pure [C.cty|typename CUdeviceptr|] cudaMemoryType space =@@ -284,7 +246,7 @@ kernelConstToExp (SizeConst key) = [C.cexp|*ctx->tuning_params.$id:key|] kernelConstToExp (SizeMaxConst size_class) =- [C.cexp|ctx->cuda.$id:field|]+ [C.cexp|ctx->$id:field|] where field = "max_" <> cudaSizeClass size_class cudaSizeClass SizeThreshold {} = "threshold"@@ -379,7 +341,7 @@ } $items:bef CUDA_SUCCEED_OR_RETURN(- cuLaunchKernel(ctx->$id:kernel_name,+ cuLaunchKernel(ctx->program->$id:kernel_name, grid[0], grid[1], grid[2], $exp:block_x, $exp:block_y, $exp:block_z, $exp:shared_tot, NULL,
src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs view
@@ -8,8 +8,8 @@ ) where +import Control.Monad import Data.Map qualified as M-import Data.Maybe import Data.Text qualified as T import Futhark.CodeGen.Backends.COpenCL.Boilerplate ( copyDevToDev,@@ -18,15 +18,16 @@ copyScalarFromDev, copyScalarToDev, costCentreReport,- failureSwitch,+ failureMsgFunction,+ generateTuningParams, kernelRuns, kernelRuntime, ) import Futhark.CodeGen.Backends.GenericC qualified as GC import Futhark.CodeGen.Backends.GenericC.Pretty import Futhark.CodeGen.ImpCode.OpenCL-import Futhark.CodeGen.RTS.C (cudaH)-import Futhark.Util (chunk, zEncodeText)+import Futhark.CodeGen.RTS.C (backendsCudaH)+import Futhark.Util (chunk) import Language.C.Quote.OpenCL qualified as C import Language.C.Syntax qualified as C @@ -39,9 +40,9 @@ ( [C.citems| typename cudaEvent_t *pevents = NULL; if (ctx->profiling && !ctx->profiling_paused) {- pevents = cuda_get_events(&ctx->cuda,- &ctx->$id:(kernelRuns name),- &ctx->$id:(kernelRuntime name));+ pevents = cuda_get_events(ctx,+ &ctx->program->$id:(kernelRuns name),+ &ctx->program->$id:(kernelRuntime name)); CUDA_SUCCEED_FATAL(cudaEventRecord(pevents[0], 0)); } |],@@ -52,6 +53,35 @@ |] ) +generateCUDADecls ::+ [Name] ->+ M.Map KernelName KernelSafety ->+ GC.CompilerM op s ()+generateCUDADecls cost_centres kernels = do+ let forCostCentre name = do+ GC.contextField+ (C.toIdent (kernelRuntime name) mempty)+ [C.cty|typename int64_t|]+ (Just [C.cexp|0|])+ GC.contextField+ (C.toIdent (kernelRuns name) mempty)+ [C.cty|int|]+ (Just [C.cexp|0|])++ forM_ (M.keys kernels) $ \name -> do+ GC.contextFieldDyn+ (C.toIdent name mempty)+ [C.cty|typename CUfunction|]+ [C.cstm|+ CUDA_SUCCEED_FATAL(cuModuleGetFunction(+ &ctx->program->$id:name,+ ctx->module,+ $string:(T.unpack (idText (C.toIdent name mempty)))));|]+ [C.cstm|{}|]+ forCostCentre name++ mapM_ forCostCentre cost_centres+ -- | Called after most code has been generated to generate the bulk of -- the boilerplate. generateBoilerplate ::@@ -63,414 +93,54 @@ [FailureMsg] -> GC.CompilerM OpenCL () () generateBoilerplate cuda_program cuda_prelude cost_centres kernels sizes failures = do+ let cuda_program_fragments =+ -- Some C compilers limit the size of literal strings, so+ -- chunk the entire program into small bits here, and+ -- concatenate it again at runtime.+ [[C.cinit|$string:s|] | s <- chunk 2000 $ T.unpack $ cuda_prelude <> cuda_program]+ program_fragments = cuda_program_fragments ++ [[C.cinit|NULL|]]+ let max_failure_args = foldl max 0 $ map (errorMsgNumArgs . failureError) failures+ generateTuningParams sizes mapM_ GC.earlyDecl- [C.cunit|- $esc:("#include <cuda.h>")- $esc:("#include <nvrtc.h>")- $esc:(T.unpack cudaH)- const char *cuda_program[] = {$inits:fragments, NULL};- |]-- generateSizeFuns sizes- cfg <- generateConfigFuns sizes- generateContextFuns cfg cost_centres kernels sizes failures-- GC.profileReport [C.citem|CUDA_SUCCEED_FATAL(cuda_tally_profiling_records(&ctx->cuda));|]- mapM_ GC.profileReport $ costCentreReport $ cost_centres ++ M.keys kernels- where- fragments =- [ [C.cinit|$string:s|]- | s <- chunk 2000 $ T.unpack $ cuda_prelude <> cuda_program- ]--generateSizeFuns :: M.Map Name SizeClass -> GC.CompilerM OpenCL () ()-generateSizeFuns sizes = do- let strinit s = [C.cinit|$string:(T.unpack s)|]- size_name_inits = map (strinit . prettyText) $ M.keys sizes- size_var_inits = map (strinit . zEncodeText . prettyText) $ M.keys sizes- size_class_inits = map (strinit . prettyText) $ M.elems sizes-- GC.earlyDecl [C.cedecl|static const char *tuning_param_names[] = { $inits:size_name_inits };|]- GC.earlyDecl [C.cedecl|static const char *tuning_param_vars[] = { $inits:size_var_inits };|]- GC.earlyDecl [C.cedecl|static const char *tuning_param_classes[] = { $inits:size_class_inits };|]--generateConfigFuns :: M.Map Name SizeClass -> GC.CompilerM OpenCL () T.Text-generateConfigFuns sizes = do- let size_decls = map (\k -> [C.csdecl|typename int64_t *$id:k;|]) $ M.keys sizes- num_sizes = M.size sizes- GC.earlyDecl [C.cedecl|struct tuning_params { $sdecls:size_decls };|]- cfg <- GC.publicDef "context_config" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:s;|],- [C.cedecl|struct $id:s {int in_use;- struct cuda_config cu_cfg;- int profiling;- typename int64_t tuning_params[$int:num_sizes];- int num_nvrtc_opts;- const char **nvrtc_opts;- const char *cache_fname;- };|]- )-- let size_value_inits = zipWith sizeInit [0 .. M.size sizes - 1] (M.elems sizes)- sizeInit i size = [C.cstm|cfg->tuning_params[$int:i] = $int:val;|]- where- val = fromMaybe 0 $ sizeDefault size- GC.publicDef_ "context_config_new" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:cfg* $id:s(void);|],- [C.cedecl|struct $id:cfg* $id:s(void) {- struct $id:cfg *cfg = (struct $id:cfg*) malloc(sizeof(struct $id:cfg));- if (cfg == NULL) {- return NULL;- }- cfg->in_use = 0;-- cfg->profiling = 0;- cfg->num_nvrtc_opts = 0;- cfg->nvrtc_opts = (const char**) malloc(sizeof(const char*));- cfg->nvrtc_opts[0] = NULL;- cfg->cache_fname = NULL;- $stms:size_value_inits- cuda_config_init(&cfg->cu_cfg, $int:num_sizes,- tuning_param_names, tuning_param_vars,- cfg->tuning_params, tuning_param_classes);- return cfg;- }|]- )-- GC.publicDef_ "context_config_free" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg) {- assert(!cfg->in_use);- free(cfg->nvrtc_opts);- free(cfg);- }|]- )-- GC.publicDef_ "context_config_add_nvrtc_option" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *opt);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *opt) {- cfg->nvrtc_opts[cfg->num_nvrtc_opts] = opt;- cfg->num_nvrtc_opts++;- cfg->nvrtc_opts = (const char**) realloc(cfg->nvrtc_opts, (cfg->num_nvrtc_opts+1) * sizeof(const char*));- cfg->nvrtc_opts[cfg->num_nvrtc_opts] = NULL;- }|]- )-- GC.publicDef_ "context_config_set_debugging" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {- cfg->cu_cfg.logging = cfg->cu_cfg.debugging = flag;- }|]- )-- GC.publicDef_ "context_config_set_profiling" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {- cfg->profiling = flag;- }|]- )-- GC.publicDef_ "context_config_set_logging" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {- cfg->cu_cfg.logging = flag;- }|]- )-- GC.publicDef_ "context_config_set_device" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *s);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *s) {- set_preferred_device(&cfg->cu_cfg, s);- }|]- )-- GC.publicDef_ "context_config_dump_program_to" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path) {- cfg->cu_cfg.dump_program_to = path;- }|]- )-- GC.publicDef_ "context_config_load_program_from" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path) {- cfg->cu_cfg.load_program_from = path;- }|]- )-- GC.publicDef_ "context_config_dump_ptx_to" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path) {- cfg->cu_cfg.dump_ptx_to = path;- }|]- )-- GC.publicDef_ "context_config_load_ptx_from" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path) {- cfg->cu_cfg.load_ptx_from = path;- }|]- )-- GC.publicDef_ "context_config_set_default_group_size" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int size);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int size) {- cfg->cu_cfg.default_block_size = size;- cfg->cu_cfg.default_block_size_changed = 1;- }|]- )-- GC.publicDef_ "context_config_set_default_num_groups" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int num);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int num) {- cfg->cu_cfg.default_grid_size = num;- cfg->cu_cfg.default_grid_size_changed = 1;- }|]- )-- GC.publicDef_ "context_config_set_default_tile_size" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int num);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int size) {- cfg->cu_cfg.default_tile_size = size;- cfg->cu_cfg.default_tile_size_changed = 1;- }|]- )-- GC.publicDef_ "context_config_set_default_reg_tile_size" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int num);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int size) {- cfg->cu_cfg.default_reg_tile_size = size;- }|]- )-- GC.publicDef_ "context_config_set_default_threshold" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int num);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int size) {- cfg->cu_cfg.default_threshold = size;- }|]- )-- GC.publicDef_ "context_config_set_tuning_param" GC.InitDecl $ \s ->- ( [C.cedecl|int $id:s(struct $id:cfg* cfg, const char *param_name, size_t new_value);|],- [C.cedecl|int $id:s(struct $id:cfg* cfg, const char *param_name, size_t new_value) {-- for (int i = 0; i < $int:num_sizes; i++) {- if (strcmp(param_name, tuning_param_names[i]) == 0) {- cfg->tuning_params[i] = new_value;- return 0;- }- }-- if (strcmp(param_name, "default_group_size") == 0) {- cfg->cu_cfg.default_block_size = new_value;- return 0;- }-- if (strcmp(param_name, "default_num_groups") == 0) {- cfg->cu_cfg.default_grid_size = new_value;- return 0;- }-- if (strcmp(param_name, "default_threshold") == 0) {- cfg->cu_cfg.default_threshold = new_value;- return 0;- }-- if (strcmp(param_name, "default_tile_size") == 0) {- cfg->cu_cfg.default_tile_size = new_value;- return 0;- }-- if (strcmp(param_name, "default_reg_tile_size") == 0) {- cfg->cu_cfg.default_reg_tile_size = new_value;- return 0;- }-- return 1;- }|]- )- pure cfg--generateContextFuns ::- T.Text ->- [Name] ->- M.Map KernelName KernelSafety ->- M.Map Name SizeClass ->- [FailureMsg] ->- GC.CompilerM OpenCL () ()-generateContextFuns cfg cost_centres kernels sizes failures = do- final_inits <- GC.contextFinalInits- (fields, init_fields, free_fields) <- GC.contextContents- let forCostCentre name =- [ ( [C.csdecl|typename int64_t $id:(kernelRuntime name);|],- [C.cstm|ctx->$id:(kernelRuntime name) = 0;|]- ),- ( [C.csdecl|int $id:(kernelRuns name);|],- [C.cstm|ctx->$id:(kernelRuns name) = 0;|]- )- ]-- forKernel name =- ( [C.csdecl|typename CUfunction $id:name;|],- [C.cstm|CUDA_SUCCEED_FATAL(cuModuleGetFunction(- &ctx->$id:name,- ctx->cuda.module,- $string:(T.unpack (idText (C.toIdent name mempty)))));|]- )- : forCostCentre name-- (kernel_fields, init_kernel_fields) =- unzip $- concatMap forKernel (M.keys kernels)- ++ concatMap forCostCentre cost_centres+ [C.cunit|static const int max_failure_args = $int:max_failure_args;+ static const char *cuda_program[] = {$inits:program_fragments, NULL};+ $esc:(T.unpack backendsCudaH)+ |]+ GC.earlyDecl $ failureMsgFunction failures - ctx <- GC.publicDef "context" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:s;|],- [C.cedecl|struct $id:s {- struct $id:cfg* cfg;- int detail_memory;- int debugging;- int profiling;- int profiling_paused;- int logging;- struct free_list free_list;- typename lock_t lock;- char *error;- typename lock_t error_lock;- typename FILE *log;- $sdecls:fields- $sdecls:kernel_fields- typename CUdeviceptr global_failure;- typename CUdeviceptr global_failure_args;- struct cuda_context cuda;- struct tuning_params tuning_params;- // True if a potentially failing kernel has been enqueued.- typename int32_t failure_is_an_option;+ generateCUDADecls cost_centres kernels - int total_runs;- long int total_runtime;- };|]- )+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_add_nvrtc_option(struct futhark_context_config *cfg, const char* opt);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_device(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_dump_program_to(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_load_program_from(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_dump_ptx_to(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_load_ptx_from(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_group_size(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_num_groups(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_tile_size(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_reg_tile_size(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_threshold(struct futhark_context_config *cfg, int size);|] let set_tuning_params = zipWith- (\i k -> [C.cstm|ctx->tuning_params.$id:k = &cfg->tuning_params[$int:i];|])+ (\i k -> [C.cstm|ctx->tuning_params.$id:k = &ctx->cfg->tuning_params[$int:i];|]) [(0 :: Int) ..] $ M.keys sizes- max_failure_args =- foldl max 0 $ map (errorMsgNumArgs . failureError) failures - GC.publicDef_ "context_new" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg);|],- [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg) {- assert(!cfg->in_use);- struct $id:ctx* ctx = (struct $id:ctx*) malloc(sizeof(struct $id:ctx));- if (ctx == NULL) {- return NULL;- }- ctx->cfg = cfg;- ctx->cfg->in_use = 1;- ctx->debugging = ctx->detail_memory = cfg->cu_cfg.debugging;- ctx->profiling = cfg->profiling;- ctx->profiling_paused = 0;- ctx->logging = cfg->cu_cfg.logging;- ctx->error = NULL;- context_setup(ctx);- ctx->log = stderr;- ctx->cuda.profiling_records_capacity = 200;- ctx->cuda.profiling_records_used = 0;- ctx->cuda.profiling_records =- malloc(ctx->cuda.profiling_records_capacity *- sizeof(struct profiling_record));-- ctx->cuda.cfg = cfg->cu_cfg;-- ctx->failure_is_an_option = 0;- ctx->total_runs = 0;- ctx->total_runtime = 0;- $stms:init_fields-- ctx->error = cuda_setup(&ctx->cuda, cuda_program, cfg->nvrtc_opts, cfg->cache_fname);-- if (ctx->error != NULL) {- futhark_panic(1, "%s\n", ctx->error);- }-- typename int32_t no_error = -1;- CUDA_SUCCEED_FATAL(cuMemAlloc(&ctx->global_failure, sizeof(no_error)));- CUDA_SUCCEED_FATAL(cuMemcpyHtoD(ctx->global_failure, &no_error, sizeof(no_error)));- // The +1 is to avoid zero-byte allocations.- CUDA_SUCCEED_FATAL(cuMemAlloc(&ctx->global_failure_args, sizeof(int64_t)*($int:max_failure_args+1)));-- $stms:init_kernel_fields-- $stms:final_inits- $stms:set_tuning_params-- init_constants(ctx);- // Clear the free list of any deallocations that occurred while initialising constants.- CUDA_SUCCEED_FATAL(cuda_free_all(&ctx->cuda));-- futhark_context_sync(ctx);-- return ctx;- }|]- )-- GC.publicDef_ "context_free" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:ctx* ctx);|],- [C.cedecl|void $id:s(struct $id:ctx* ctx) {- $stms:free_fields- context_teardown(ctx);- cuMemFree(ctx->global_failure);- cuMemFree(ctx->global_failure_args);- cuda_cleanup(&ctx->cuda);- ctx->cfg->in_use = 0;- free(ctx);- }|]- )-- GC.publicDef_ "context_sync" GC.MiscDecl $ \s ->- ( [C.cedecl|int $id:s(struct $id:ctx* ctx);|],- [C.cedecl|int $id:s(struct $id:ctx* ctx) {- CUDA_SUCCEED_OR_RETURN(cuCtxPushCurrent(ctx->cuda.cu_ctx));- CUDA_SUCCEED_OR_RETURN(cuCtxSynchronize());- if (ctx->failure_is_an_option) {- // Check for any delayed error.- typename int32_t failure_idx;- CUDA_SUCCEED_OR_RETURN(- cuMemcpyDtoH(&failure_idx,- ctx->global_failure,- sizeof(int32_t)));- ctx->failure_is_an_option = 0;-- if (failure_idx >= 0) {- // We have to clear global_failure so that the next entry point- // is not considered a failure from the start.- typename int32_t no_failure = -1;- CUDA_SUCCEED_OR_RETURN(- cuMemcpyHtoD(ctx->global_failure,- &no_failure,- sizeof(int32_t)));-- typename int64_t args[$int:max_failure_args+1];- CUDA_SUCCEED_OR_RETURN(- cuMemcpyDtoH(&args,- ctx->global_failure_args,- sizeof(args)));-- $stm:(failureSwitch failures)+ GC.earlyDecl+ [C.cedecl|static void set_tuning_params(struct futhark_context* ctx) {+ $stms:set_tuning_params+ }|] - return FUTHARK_PROGRAM_ERROR;- }- }- CUDA_SUCCEED_OR_RETURN(cuCtxPopCurrent(&ctx->cuda.cu_ctx));- return 0;- }|]- )+ GC.generateProgramStruct GC.onClear [C.citem|if (ctx->error == NULL) {- CUDA_SUCCEED_NONFATAL(cuda_free_all(&ctx->cuda));+ CUDA_SUCCEED_NONFATAL(cuda_free_all(ctx)); }|]++ GC.profileReport [C.citem|CUDA_SUCCEED_FATAL(cuda_tally_profiling_records(ctx));|]+ mapM_ GC.profileReport $ costCentreReport $ cost_centres ++ M.keys kernels+{-# NOINLINE generateBoilerplate #-}
src/Futhark/CodeGen/Backends/COpenCL.hs view
@@ -78,7 +78,6 @@ GC.opsAllocate = allocateOpenCLBuffer, GC.opsDeallocate = deallocateOpenCLBuffer, GC.opsCopy = copyOpenCLMemory,- GC.opsStaticArray = staticOpenCLArray, GC.opsMemoryType = openclMemoryType, GC.opsFatMemory = True }@@ -177,7 +176,7 @@ GC.stm [C.cstm|{$item:decl OPENCL_SUCCEED_OR_RETURN(- clEnqueueWriteBuffer(ctx->opencl.queue, $exp:mem, $exp:blocking,+ clEnqueueWriteBuffer(ctx->queue, $exp:mem, $exp:blocking, $exp:i * sizeof($ty:t), sizeof($ty:t), &$id:val', 0, NULL, $exp:(profilingEvent copyScalarToDev)));@@ -195,7 +194,7 @@ GC.decl [C.cdecl|$ty:t $id:val;|] GC.stm [C.cstm|OPENCL_SUCCEED_OR_RETURN(- clEnqueueReadBuffer(ctx->opencl.queue, $exp:mem,+ clEnqueueReadBuffer(ctx->queue, $exp:mem, ctx->failure_is_an_option ? CL_FALSE : CL_TRUE, $exp:i * sizeof($ty:t), sizeof($ty:t), &$id:val,@@ -212,7 +211,7 @@ allocateOpenCLBuffer mem size tag "device" = GC.stm [C.cstm|ctx->error =- OPENCL_SUCCEED_NONFATAL(opencl_alloc(&ctx->opencl, ctx->log,+ OPENCL_SUCCEED_NONFATAL(opencl_alloc(ctx, ctx->log, (size_t)$exp:size, $exp:tag, &$exp:mem, (size_t*)&$exp:size));|] allocateOpenCLBuffer _ _ _ space =@@ -220,7 +219,7 @@ deallocateOpenCLBuffer :: GC.Deallocate OpenCL () deallocateOpenCLBuffer mem size tag "device" =- GC.stm [C.cstm|OPENCL_SUCCEED_OR_RETURN(opencl_free(&ctx->opencl, $exp:mem, $exp:size, $exp:tag));|]+ GC.stm [C.cstm|OPENCL_SUCCEED_OR_RETURN(opencl_free(ctx, $exp:mem, $exp:size, $exp:tag));|] deallocateOpenCLBuffer _ _ _ space = error $ "Cannot deallocate in '" ++ space ++ "' space" @@ -238,7 +237,7 @@ if ($exp:nbytes > 0) { typename cl_bool sync_call = $exp:(syncArg b); OPENCL_SUCCEED_OR_RETURN(- clEnqueueReadBuffer(ctx->opencl.queue, $exp:srcmem,+ clEnqueueReadBuffer(ctx->queue, $exp:srcmem, ctx->failure_is_an_option ? CL_FALSE : sync_call, (size_t)$exp:srcidx, (size_t)$exp:nbytes, $exp:destmem + $exp:destidx,@@ -253,7 +252,7 @@ [C.cstm| if ($exp:nbytes > 0) { OPENCL_SUCCEED_OR_RETURN(- clEnqueueWriteBuffer(ctx->opencl.queue, $exp:destmem, $exp:(syncArg b),+ clEnqueueWriteBuffer(ctx->queue, $exp:destmem, $exp:(syncArg b), (size_t)$exp:destidx, (size_t)$exp:nbytes, $exp:srcmem + $exp:srcidx, 0, NULL, $exp:(profilingEvent copyDevToHost)));@@ -266,13 +265,13 @@ [C.cstm|{ if ($exp:nbytes > 0) { OPENCL_SUCCEED_OR_RETURN(- clEnqueueCopyBuffer(ctx->opencl.queue,+ clEnqueueCopyBuffer(ctx->queue, $exp:srcmem, $exp:destmem, (size_t)$exp:srcidx, (size_t)$exp:destidx, (size_t)$exp:nbytes, 0, NULL, $exp:(profilingEvent copyDevToDev))); if (ctx->debugging) {- OPENCL_SUCCEED_FATAL(clFinish(ctx->opencl.queue));+ OPENCL_SUCCEED_FATAL(clFinish(ctx->queue)); } } }|]@@ -286,52 +285,11 @@ openclMemoryType space = error $ "OpenCL backend does not support '" ++ space ++ "' memory space." -staticOpenCLArray :: GC.StaticArray OpenCL ()-staticOpenCLArray name "device" t vs = do- let ct = GC.primTypeToCType t- name_realtype <- newVName $ baseString name ++ "_realtype"- num_elems <- case vs of- ArrayValues vs' -> do- let vs'' = [[C.cinit|$exp:v|] | v <- vs']- GC.earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:(length vs'')] = {$inits:vs''};|]- pure $ length vs''- ArrayZeros n -> do- GC.earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:n];|]- pure n- -- Fake a memory block.- GC.contextFieldDyn- (C.toIdent name mempty)- [C.cty|struct memblock_device|]- Nothing- [C.cstm|OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->$id:name.mem));|]- -- During startup, copy the data to where we need it.- GC.atInit- [C.cstm|{- typename cl_int success;- ctx->$id:name.references = NULL;- ctx->$id:name.size = 0;- ctx->$id:name.mem =- clCreateBuffer(ctx->opencl.ctx, CL_MEM_READ_WRITE,- ($int:num_elems > 0 ? $int:num_elems : 1)*sizeof($ty:ct), NULL,- &success);- OPENCL_SUCCEED_OR_RETURN(success);- if ($int:num_elems > 0) {- OPENCL_SUCCEED_OR_RETURN(- clEnqueueWriteBuffer(ctx->opencl.queue, ctx->$id:name.mem, CL_TRUE,- 0, $int:num_elems*sizeof($ty:ct),- $id:name_realtype,- 0, NULL, NULL));- }- }|]- GC.item [C.citem|struct memblock_device $id:name = ctx->$id:name;|]-staticOpenCLArray _ space _ _ =- error $ "OpenCL backend cannot create static array in memory space '" ++ space ++ "'"- kernelConstToExp :: KernelConst -> C.Exp kernelConstToExp (SizeConst key) = [C.cexp|*ctx->tuning_params.$id:key|] kernelConstToExp (SizeMaxConst size_class) =- [C.cexp|ctx->opencl.$id:field|]+ [C.cexp|ctx->$id:field|] where field = "max_" <> prettyString size_class @@ -357,7 +315,7 @@ when (safety == SafetyFull) $ GC.stm [C.cstm|- OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->$id:name, 1,+ OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:name, 1, sizeof(ctx->failure_is_an_option), &ctx->failure_is_an_option)); |]@@ -385,19 +343,19 @@ _ -> GC.compileExpToName "kernel_arg" pt e GC.stm [C.cstm|- OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->$id:name, $int:i, sizeof($id:v), &$id:v));+ OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:name, $int:i, sizeof($id:v), &$id:v)); |] setKernelArg i (MemKArg v) = do v' <- GC.rawMem v GC.stm [C.cstm|- OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->$id:name, $int:i, sizeof($exp:v'), &$exp:v'));+ OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:name, $int:i, sizeof($exp:v'), &$exp:v')); |] setKernelArg i (SharedMemoryKArg num_bytes) = do num_bytes' <- GC.compileExp $ unCount num_bytes GC.stm [C.cstm|- OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->$id:name, $int:i, (size_t)$exp:num_bytes', NULL));+ OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:name, $int:i, (size_t)$exp:num_bytes', NULL)); |] localBytes cur (SharedMemoryKArg num_bytes) = do@@ -433,11 +391,11 @@ } typename cl_event *pevent = $exp:(profilingEvent kernel_name); OPENCL_SUCCEED_OR_RETURN(- clEnqueueNDRangeKernel(ctx->opencl.queue, ctx->$id:kernel_name, $int:kernel_rank, NULL,+ clEnqueueNDRangeKernel(ctx->queue, ctx->program->$id:kernel_name, $int:kernel_rank, NULL, $id:global_work_size, $id:local_work_size, 0, NULL, pevent)); if (ctx->debugging) {- OPENCL_SUCCEED_FATAL(clFinish(ctx->opencl.queue));+ OPENCL_SUCCEED_FATAL(clFinish(ctx->queue)); $id:time_end = get_wall_time(); long int $id:time_diff = $id:time_end - $id:time_start; fprintf(ctx->log, "kernel %s runtime: %ldus\n",
src/Futhark/CodeGen/Backends/COpenCL/Boilerplate.hs view
@@ -9,11 +9,12 @@ copyScalarToDev, copyScalarFromDev, commonOptions,- failureSwitch,+ failureMsgFunction, costCentreReport, kernelRuntime, kernelRuns, sizeLoggingCode,+ generateTuningParams, ) where @@ -26,7 +27,7 @@ import Futhark.CodeGen.Backends.GenericC.Pretty import Futhark.CodeGen.ImpCode.OpenCL import Futhark.CodeGen.OpenCL.Heuristics-import Futhark.CodeGen.RTS.C (openclH)+import Futhark.CodeGen.RTS.C (backendsOpenclH) import Futhark.Util (chunk, zEncodeText) import Futhark.Util.Pretty (prettyTextOneLine) import Language.C.Quote.OpenCL qualified as C@@ -35,8 +36,8 @@ errorMsgNumArgs :: ErrorMsg a -> Int errorMsgNumArgs = length . errorMsgArgTypes -failureSwitch :: [FailureMsg] -> C.Stm-failureSwitch failures =+failureMsgFunction :: [FailureMsg] -> C.Definition+failureMsgFunction failures = let printfEscape = let escapeChar '%' = "%%" escapeChar c = [c]@@ -47,10 +48,13 @@ onFailure i (FailureMsg emsg@(ErrorMsg parts) backtrace) = let msg = concatMap onPart parts ++ "\n" ++ printfEscape backtrace msgargs = [[C.cexp|args[$int:j]|] | j <- [0 .. errorMsgNumArgs emsg - 1]]- in [C.cstm|case $int:i: {ctx->error = msgprintf($string:msg, $args:msgargs); break;}|]+ in [C.cstm|case $int:i: {return msgprintf($string:msg, $args:msgargs); break;}|] failure_cases = zipWith onFailure [(0 :: Int) ..] failures- in [C.cstm|switch (failure_idx) { $stms:failure_cases }|]+ in [C.cedecl|static char* get_failure_msg(int failure_idx, typename int64_t args[]) {+ switch (failure_idx) { $stms:failure_cases }+ return strdup("Unknown error. This is a compiler bug.");+ }|] copyDevToDev, copyDevToHost, copyHostToDev, copyScalarToDev, copyScalarFromDev :: Name copyDevToDev = "copy_dev_to_dev"@@ -62,525 +66,34 @@ profilingEvent :: Name -> C.Exp profilingEvent name = [C.cexp|(ctx->profiling_paused || !ctx->profiling) ? NULL- : opencl_get_event(&ctx->opencl,- &ctx->$id:(kernelRuns name),- &ctx->$id:(kernelRuntime name))|]---- | Called after most code has been generated to generate the bulk of--- the boilerplate.-generateBoilerplate ::- T.Text ->- T.Text ->- [Name] ->- M.Map KernelName KernelSafety ->- [PrimType] ->- M.Map Name SizeClass ->- [FailureMsg] ->- GC.CompilerM OpenCL () ()-generateBoilerplate opencl_code opencl_prelude cost_centres kernels types sizes failures = do- final_inits <- GC.contextFinalInits-- let (ctx_opencl_fields, ctx_opencl_inits, top_decls, later_top_decls) =- openClDecls cost_centres kernels (opencl_prelude <> opencl_code)-- mapM_ GC.earlyDecl top_decls+ : opencl_get_event(ctx,+ &ctx->program->$id:(kernelRuns name),+ &ctx->program->$id:(kernelRuntime name))|] +generateTuningParams :: M.Map Name SizeClass -> GC.CompilerM op a ()+generateTuningParams sizes = do let strinit s = [C.cinit|$string:(T.unpack s)|]+ intinit x = [C.cinit|$int:x|] size_name_inits = map (strinit . prettyText) $ M.keys sizes size_var_inits = map (strinit . zEncodeText . prettyText) $ M.keys sizes size_class_inits = map (strinit . prettyText) $ M.elems sizes- num_sizes = M.size sizes-+ size_default_inits = map (intinit . fromMaybe 0 . sizeDefault) $ M.elems sizes+ size_decls = map (\k -> [C.csdecl|typename int64_t *$id:k;|]) $ M.keys sizes+ num_sizes = length sizes+ GC.earlyDecl [C.cedecl|struct tuning_params { $sdecls:size_decls };|]+ GC.earlyDecl [C.cedecl|static const int num_tuning_params = $int:num_sizes;|] GC.earlyDecl [C.cedecl|static const char *tuning_param_names[] = { $inits:size_name_inits };|] GC.earlyDecl [C.cedecl|static const char *tuning_param_vars[] = { $inits:size_var_inits };|] GC.earlyDecl [C.cedecl|static const char *tuning_param_classes[] = { $inits:size_class_inits };|]-- let size_decls = map (\k -> [C.csdecl|typename int64_t *$id:k;|]) $ M.keys sizes- GC.earlyDecl [C.cedecl|struct tuning_params { $sdecls:size_decls };|]- cfg <- GC.publicDef "context_config" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:s;|],- [C.cedecl|struct $id:s { int in_use;- struct opencl_config opencl;- typename int64_t tuning_params[$int:num_sizes];- int num_build_opts;- const char **build_opts;- const char *cache_fname;- };|]- )-- let size_value_inits = zipWith sizeInit [0 .. M.size sizes - 1] (M.elems sizes)- sizeInit i size = [C.cstm|cfg->tuning_params[$int:i] = $int:val;|]- where- val = fromMaybe 0 $ sizeDefault size- GC.publicDef_ "context_config_new" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:cfg* $id:s(void);|],- [C.cedecl|struct $id:cfg* $id:s(void) {- struct $id:cfg *cfg = (struct $id:cfg*) malloc(sizeof(struct $id:cfg));- if (cfg == NULL) {- return NULL;- }-- cfg->in_use = 0;- cfg->num_build_opts = 0;- cfg->build_opts = (const char**) malloc(sizeof(const char*));- cfg->build_opts[0] = NULL;- cfg->cache_fname = NULL;- $stms:size_value_inits- opencl_config_init(&cfg->opencl, $int:num_sizes,- tuning_param_names, tuning_param_vars,- cfg->tuning_params, tuning_param_classes);- return cfg;- }|]- )-- GC.publicDef_ "context_config_free" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg) {- assert(!cfg->in_use);- free(cfg->build_opts);- free(cfg);- }|]- )-- GC.publicDef_ "context_config_add_build_option" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *opt);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *opt) {- cfg->build_opts[cfg->num_build_opts] = opt;- cfg->num_build_opts++;- cfg->build_opts = (const char**) realloc(cfg->build_opts, (cfg->num_build_opts+1) * sizeof(const char*));- cfg->build_opts[cfg->num_build_opts] = NULL;- }|]- )-- GC.publicDef_ "context_config_set_debugging" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {- cfg->opencl.profiling = cfg->opencl.logging = cfg->opencl.debugging = flag;- }|]- )-- GC.publicDef_ "context_config_set_profiling" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {- cfg->opencl.profiling = flag;- }|]- )-- GC.publicDef_ "context_config_set_logging" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {- cfg->opencl.logging = flag;- }|]- )-- GC.publicDef_ "context_config_set_device" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *s);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *s) {- set_preferred_device(&cfg->opencl, s);- }|]- )-- GC.publicDef_ "context_config_set_platform" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *s);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *s) {- set_preferred_platform(&cfg->opencl, s);- }|]- )-- GC.publicDef_ "context_config_select_device_interactively" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg) {- select_device_interactively(&cfg->opencl);- }|]- )-- GC.publicDef_ "context_config_list_devices" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg) {- (void)cfg;- list_devices();- }|]- )-- GC.publicDef_ "context_config_dump_program_to" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path) {- cfg->opencl.dump_program_to = path;- }|]- )-- GC.publicDef_ "context_config_load_program_from" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path) {- cfg->opencl.load_program_from = path;- }|]- )-- GC.publicDef_ "context_config_dump_binary_to" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path) {- cfg->opencl.dump_binary_to = path;- }|]- )-- GC.publicDef_ "context_config_load_binary_from" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, const char *path) {- cfg->opencl.load_binary_from = path;- }|]- )-- GC.publicDef_ "context_config_set_default_group_size" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int size);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int size) {- cfg->opencl.default_group_size = size;- cfg->opencl.default_group_size_changed = 1;- }|]- )-- GC.publicDef_ "context_config_set_default_num_groups" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int num);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int num) {- cfg->opencl.default_num_groups = num;- }|]- )-- GC.publicDef_ "context_config_set_default_tile_size" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int num);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int size) {- cfg->opencl.default_tile_size = size;- cfg->opencl.default_tile_size_changed = 1;- }|]- )-- GC.publicDef_ "context_config_set_default_reg_tile_size" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int num);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int size) {- cfg->opencl.default_reg_tile_size = size;- }|]- )-- GC.publicDef_ "context_config_set_default_threshold" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int num);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int size) {- cfg->opencl.default_threshold = size;- }|]- )-- GC.publicDef_ "context_config_set_tuning_param" GC.InitDecl $ \s ->- ( [C.cedecl|int $id:s(struct $id:cfg* cfg, const char *param_name, size_t new_value);|],- [C.cedecl|int $id:s(struct $id:cfg* cfg, const char *param_name, size_t new_value) {-- for (int i = 0; i < $int:num_sizes; i++) {- if (strcmp(param_name, tuning_param_names[i]) == 0) {- cfg->tuning_params[i] = new_value;- return 0;- }- }-- if (strcmp(param_name, "default_group_size") == 0) {- cfg->opencl.default_group_size = new_value;- return 0;- }-- if (strcmp(param_name, "default_num_groups") == 0) {- cfg->opencl.default_num_groups = new_value;- return 0;- }-- if (strcmp(param_name, "default_threshold") == 0) {- cfg->opencl.default_threshold = new_value;- return 0;- }-- if (strcmp(param_name, "default_tile_size") == 0) {- cfg->opencl.default_tile_size = new_value;- return 0;- }-- if (strcmp(param_name, "default_reg_tile_size") == 0) {- cfg->opencl.default_reg_tile_size = new_value;- return 0;- }-- return 1;- }|]- )-- (fields, init_fields, free_fields) <- GC.contextContents- ctx <- GC.publicDef "context" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:s;|],- [C.cedecl|struct $id:s {- struct $id:cfg* cfg;- int detail_memory;- int debugging;- int profiling;- int profiling_paused;- int logging;- typename lock_t lock;- char *error;- typename lock_t error_lock;- typename FILE *log;- struct free_list free_list;- $sdecls:fields- $sdecls:ctx_opencl_fields- typename cl_mem global_failure;- typename cl_mem global_failure_args;- struct opencl_context opencl;- struct tuning_params tuning_params;- // True if a potentially failing kernel has been enqueued.- typename cl_int failure_is_an_option;- };|]- )-- mapM_ GC.earlyDecl later_top_decls-- GC.earlyDecl- [C.cedecl|static void init_context_early(struct $id:cfg *cfg, struct $id:ctx* ctx) {- ctx->opencl.cfg = cfg->opencl;- ctx->detail_memory = cfg->opencl.debugging;- ctx->debugging = cfg->opencl.debugging;- ctx->profiling = cfg->opencl.profiling;- ctx->profiling_paused = 0;- ctx->logging = cfg->opencl.logging;- ctx->error = NULL;- context_setup(ctx);- ctx->log = stderr;- ctx->opencl.profiling_records_capacity = 200;- ctx->opencl.profiling_records_used = 0;- ctx->opencl.profiling_records =- malloc(ctx->opencl.profiling_records_capacity *- sizeof(struct profiling_record));-- ctx->failure_is_an_option = 0;- $stms:init_fields- $stms:ctx_opencl_inits- }|]-- let set_tuning_params =- zipWith- (\i k -> [C.cstm|ctx->tuning_params.$id:k = &cfg->tuning_params[$int:i];|])- [(0 :: Int) ..]- $ M.keys sizes- max_failure_args =- foldl max 0 $ map (errorMsgNumArgs . failureError) failures-- GC.earlyDecl- [C.cedecl|static int init_context_late(struct $id:cfg *cfg, struct $id:ctx* ctx, typename cl_program prog) {- typename cl_int error;-- typename cl_int no_error = -1;- ctx->global_failure =- clCreateBuffer(ctx->opencl.ctx,- CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,- sizeof(cl_int), &no_error, &error);- OPENCL_SUCCEED_OR_RETURN(error);-- // The +1 is to avoid zero-byte allocations.- ctx->global_failure_args =- clCreateBuffer(ctx->opencl.ctx,- CL_MEM_READ_WRITE,- sizeof(int64_t)*($int:max_failure_args+1), NULL, &error);- OPENCL_SUCCEED_OR_RETURN(error);-- // Load all the kernels.- $stms:(map loadKernel (M.toList kernels))-- $stms:final_inits- $stms:set_tuning_params-- init_constants(ctx);- // Clear the free list of any deallocations that occurred while initialising constants.- OPENCL_SUCCEED_OR_RETURN(opencl_free_all(&ctx->opencl));-- // The program will be properly freed after all the kernels have also been freed.- OPENCL_SUCCEED_OR_RETURN(clReleaseProgram(prog));-- return futhark_context_sync(ctx);- }|]-- let set_required_types =- [ [C.cstm|required_types |= OPENCL_F64; |]- | FloatType Float64 `elem` types- ]-- GC.publicDef_ "context_new" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg);|],- [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg) {- assert(!cfg->in_use);- struct $id:ctx* ctx = (struct $id:ctx*) malloc(sizeof(struct $id:ctx));- if (ctx == NULL) {- return NULL;- }- ctx->cfg = cfg;- ctx->cfg->in_use = 1;-- int required_types = 0;- $stms:set_required_types-- init_context_early(cfg, ctx);- typename cl_program prog =- setup_opencl(&ctx->opencl, opencl_program, required_types, cfg->build_opts,- cfg->cache_fname);- init_context_late(cfg, ctx, prog);- return ctx;- }|]- )-- GC.publicDef_ "context_new_with_command_queue" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg, typename cl_command_queue queue);|],- [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg, typename cl_command_queue queue) {- assert(!cfg->in_use);- struct $id:ctx* ctx = (struct $id:ctx*) malloc(sizeof(struct $id:ctx));- if (ctx == NULL) {- return NULL;- }- ctx->cfg = cfg;- ctx->cfg->in_use = 1;-- int required_types = 0;- $stms:set_required_types-- init_context_early(cfg, ctx);- typename cl_program prog =- setup_opencl_with_command_queue(&ctx->opencl, queue, opencl_program, required_types, cfg->build_opts,- cfg->cache_fname);- init_context_late(cfg, ctx, prog);- return ctx;- }|]- )-- GC.publicDef_ "context_free" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:ctx* ctx);|],- [C.cedecl|void $id:s(struct $id:ctx* ctx) {- $stms:free_fields- context_teardown(ctx);- $stms:(map releaseKernel (M.toList kernels))- OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->global_failure));- OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->global_failure_args));- teardown_opencl(&ctx->opencl);- ctx->cfg->in_use = 0;- free(ctx);- }|]- )-- GC.publicDef_ "context_sync" GC.MiscDecl $ \s ->- ( [C.cedecl|int $id:s(struct $id:ctx* ctx);|],- [C.cedecl|int $id:s(struct $id:ctx* ctx) {- // Check for any delayed error.- typename cl_int failure_idx = -1;- if (ctx->failure_is_an_option) {- OPENCL_SUCCEED_OR_RETURN(- clEnqueueReadBuffer(ctx->opencl.queue,- ctx->global_failure,- CL_FALSE,- 0, sizeof(typename cl_int), &failure_idx,- 0, NULL, $exp:(profilingEvent copyScalarFromDev)));- ctx->failure_is_an_option = 0;- }-- OPENCL_SUCCEED_OR_RETURN(clFinish(ctx->opencl.queue));-- if (failure_idx >= 0) {- // We have to clear global_failure so that the next entry point- // is not considered a failure from the start.- typename cl_int no_failure = -1;- OPENCL_SUCCEED_OR_RETURN(- clEnqueueWriteBuffer(ctx->opencl.queue, ctx->global_failure, CL_TRUE,- 0, sizeof(cl_int), &no_failure,- 0, NULL, NULL));-- typename int64_t args[$int:max_failure_args+1];- OPENCL_SUCCEED_OR_RETURN(- clEnqueueReadBuffer(ctx->opencl.queue,- ctx->global_failure_args,- CL_TRUE,- 0, sizeof(args), &args,- 0, NULL, $exp:(profilingEvent copyDevToHost)));-- $stm:(failureSwitch failures)-- return FUTHARK_PROGRAM_ERROR;- }- return 0;- }|]- )-- GC.publicDef_ "context_get_command_queue" GC.InitDecl $ \s ->- ( [C.cedecl|typename cl_command_queue $id:s(struct $id:ctx* ctx);|],- [C.cedecl|typename cl_command_queue $id:s(struct $id:ctx* ctx) {- return ctx->opencl.queue;- }|]- )-- GC.onClear- [C.citem|if (ctx->error == NULL) {- ctx->error = OPENCL_SUCCEED_NONFATAL(opencl_free_all(&ctx->opencl));- }|]-- GC.profileReport [C.citem|OPENCL_SUCCEED_FATAL(opencl_tally_profiling_records(&ctx->opencl));|]- mapM_ GC.profileReport $- costCentreReport $- cost_centres ++ M.keys kernels--openClDecls ::- [Name] ->- M.Map KernelName KernelSafety ->- T.Text ->- ([C.FieldGroup], [C.Stm], [C.Definition], [C.Definition])-openClDecls cost_centres kernels opencl_program =- (ctx_fields, ctx_inits, openCL_boilerplate, openCL_load)- where- opencl_program_fragments =- -- Some C compilers limit the size of literal strings, so- -- chunk the entire program into small bits here, and- -- concatenate it again at runtime.- [ [C.cinit|$string:s|]- | s <- chunk 2000 $ T.unpack opencl_program- ]-- ctx_fields =- [ [C.csdecl|int total_runs;|],- [C.csdecl|long int total_runtime;|]- ]- ++ [ [C.csdecl|typename cl_kernel $id:name;|]- | name <- M.keys kernels- ]- ++ concat- [ [ [C.csdecl|typename int64_t $id:(kernelRuntime name);|],- [C.csdecl|int $id:(kernelRuns name);|]- ]- | name <- cost_centres ++ M.keys kernels- ]-- ctx_inits =- [ [C.cstm|ctx->total_runs = 0;|],- [C.cstm|ctx->total_runtime = 0;|]- ]- ++ concat- [ [ [C.cstm|ctx->$id:(kernelRuntime name) = 0;|],- [C.cstm|ctx->$id:(kernelRuns name) = 0;|]- ]- | name <- cost_centres ++ M.keys kernels- ]-- openCL_load =- [ [C.cedecl|-void post_opencl_setup(struct opencl_context *ctx, struct opencl_device_option *option) {- $stms:(map sizeHeuristicsCode sizeHeuristicsTable)-}|]- ]+ GC.earlyDecl [C.cedecl|static typename int64_t tuning_param_defaults[] = { $inits:size_default_inits };|] - program_fragments = opencl_program_fragments ++ [[C.cinit|NULL|]]- openCL_boilerplate =- [C.cunit|- $esc:(T.unpack openclH)- static const char *opencl_program[] = {$inits:program_fragments};|]+releaseKernel :: (KernelName, KernelSafety) -> C.Stm+releaseKernel (name, _) = [C.cstm|OPENCL_SUCCEED_FATAL(clReleaseKernel(ctx->program->$id:name));|] loadKernel :: (KernelName, KernelSafety) -> C.Stm loadKernel (name, safety) = [C.cstm|{- ctx->$id:name = clCreateKernel(prog, $string:(T.unpack (idText (C.toIdent name mempty))), &error);+ ctx->program->$id:name = clCreateKernel(ctx->clprogram, $string:(T.unpack (idText (C.toIdent name mempty))), &error); OPENCL_SUCCEED_FATAL(error); $items:set_args if (ctx->debugging) {@@ -590,20 +103,113 @@ where set_global_failure = [C.citem|OPENCL_SUCCEED_FATAL(- clSetKernelArg(ctx->$id:name, 0, sizeof(typename cl_mem),+ clSetKernelArg(ctx->program->$id:name, 0, sizeof(typename cl_mem), &ctx->global_failure));|] set_global_failure_args = [C.citem|OPENCL_SUCCEED_FATAL(- clSetKernelArg(ctx->$id:name, 2, sizeof(typename cl_mem),+ clSetKernelArg(ctx->program->$id:name, 2, sizeof(typename cl_mem), &ctx->global_failure_args));|] set_args = case safety of SafetyNone -> [] SafetyCheap -> [set_global_failure] SafetyFull -> [set_global_failure, set_global_failure_args] -releaseKernel :: (KernelName, KernelSafety) -> C.Stm-releaseKernel (name, _) = [C.cstm|OPENCL_SUCCEED_FATAL(clReleaseKernel(ctx->$id:name));|]+generateOpenCLDecls ::+ [Name] ->+ M.Map KernelName KernelSafety ->+ GC.CompilerM op s ()+generateOpenCLDecls cost_centres kernels = do+ forM_ (M.toList kernels) $ \(name, safety) ->+ GC.contextFieldDyn+ (C.toIdent name mempty)+ [C.cty|typename cl_kernel|]+ (loadKernel (name, safety))+ (releaseKernel (name, safety))+ forM_ (cost_centres <> M.keys kernels) $ \name -> do+ GC.contextField+ (C.toIdent (kernelRuntime name) mempty)+ [C.cty|typename int64_t|]+ (Just [C.cexp|0|])+ GC.contextField+ (C.toIdent (kernelRuns name) mempty)+ [C.cty|int|]+ (Just [C.cexp|0|])+ GC.earlyDecl+ [C.cedecl|+void post_opencl_setup(struct futhark_context *ctx, struct opencl_device_option *option) {+ $stms:(map sizeHeuristicsCode sizeHeuristicsTable)+}|] +-- | Called after most code has been generated to generate the bulk of+-- the boilerplate.+generateBoilerplate ::+ T.Text ->+ T.Text ->+ [Name] ->+ M.Map KernelName KernelSafety ->+ [PrimType] ->+ M.Map Name SizeClass ->+ [FailureMsg] ->+ GC.CompilerM OpenCL () ()+generateBoilerplate opencl_program opencl_prelude cost_centres kernels types sizes failures = do+ let opencl_program_fragments =+ -- Some C compilers limit the size of literal strings, so+ -- chunk the entire program into small bits here, and+ -- concatenate it again at runtime.+ [[C.cinit|$string:s|] | s <- chunk 2000 $ T.unpack $ opencl_prelude <> opencl_program]+ program_fragments = opencl_program_fragments ++ [[C.cinit|NULL|]]+ f64_required+ | FloatType Float64 `elem` types = [C.cexp|1|]+ | otherwise = [C.cexp|0|]+ max_failure_args = foldl max 0 $ map (errorMsgNumArgs . failureError) failures+ generateTuningParams sizes+ mapM_+ GC.earlyDecl+ [C.cunit|static const int max_failure_args = $int:max_failure_args;+ static const int f64_required = $exp:f64_required;+ static const char *opencl_program[] = {$inits:program_fragments};+ $esc:(T.unpack backendsOpenclH)+ |]+ GC.earlyDecl $ failureMsgFunction failures++ generateOpenCLDecls cost_centres kernels++ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_add_build_option(struct futhark_context_config *cfg, const char* opt);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_device(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_platform(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_select_device_interactively(struct futhark_context_config *cfg);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_list_devices(struct futhark_context_config *cfg);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_dump_program_to(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_load_program_from(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_dump_binary_to(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_load_binary_from(struct futhark_context_config *cfg, const char* s);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_group_size(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_num_groups(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_tile_size(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_reg_tile_size(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_default_threshold(struct futhark_context_config *cfg, int size);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_command_queue(struct futhark_context_config *cfg, typename cl_command_queue);|]+ GC.headerDecl GC.MiscDecl [C.cedecl|typename cl_command_queue futhark_context_get_command_queue(struct futhark_context* ctx);|]++ let set_tuning_params =+ zipWith+ (\i k -> [C.cstm|ctx->tuning_params.$id:k = &ctx->cfg->tuning_params[$int:i];|])+ [(0 :: Int) ..]+ $ M.keys sizes++ GC.earlyDecl+ [C.cedecl|static void set_tuning_params(struct futhark_context* ctx) {+ $stms:set_tuning_params+ }|]++ GC.generateProgramStruct++ GC.onClear+ [C.citem|if (ctx->error == NULL) { ctx->error = OPENCL_SUCCEED_NONFATAL(opencl_free_all(ctx)); }|]++ GC.profileReport [C.citem|OPENCL_SUCCEED_FATAL(opencl_tally_profiling_records(ctx));|]+ mapM_ GC.profileReport $ costCentreReport $ cost_centres ++ M.keys kernels+ kernelRuntime :: KernelName -> Name kernelRuntime = (<> "_total_runtime") @@ -627,19 +233,17 @@ in [ [C.citem| str_builder(&builder, $string:(format_string (prettyString name)),- ctx->$id:runs,- (long int) ctx->$id:total_runtime / (ctx->$id:runs != 0 ? ctx->$id:runs : 1),- (long int) ctx->$id:total_runtime);+ ctx->program->$id:runs,+ (long int) ctx->program->$id:total_runtime / (ctx->program->$id:runs != 0 ? ctx->program->$id:runs : 1),+ (long int) ctx->program->$id:total_runtime); |],- [C.citem|ctx->total_runtime += ctx->$id:total_runtime;|],- [C.citem|ctx->total_runs += ctx->$id:runs;|]+ [C.citem|ctx->total_runtime += ctx->program->$id:total_runtime;|],+ [C.citem|ctx->total_runs += ctx->program->$id:runs;|] ] report_total =- [C.citem|- str_builder(&builder, "%d operations with cumulative runtime: %6ldus\n",- ctx->total_runs, ctx->total_runtime);- |]+ [C.citem|str_builder(&builder, "%d operations with cumulative runtime: %6ldus\n",+ ctx->total_runs, ctx->total_runtime);|] sizeHeuristicsCode :: SizeHeuristic -> C.Stm sizeHeuristicsCode (SizeHeuristic platform_name device_type which (TPrimExp what)) =@@ -655,11 +259,11 @@ which' = case which of LockstepWidth -> [C.cexp|ctx->lockstep_width|]- NumGroups -> [C.cexp|ctx->cfg.default_num_groups|]- GroupSize -> [C.cexp|ctx->cfg.default_group_size|]- TileSize -> [C.cexp|ctx->cfg.default_tile_size|]- RegTileSize -> [C.cexp|ctx->cfg.default_reg_tile_size|]- Threshold -> [C.cexp|ctx->cfg.default_threshold|]+ NumGroups -> [C.cexp|ctx->cfg->default_num_groups|]+ GroupSize -> [C.cexp|ctx->cfg->default_group_size|]+ TileSize -> [C.cexp|ctx->cfg->default_tile_size|]+ RegTileSize -> [C.cexp|ctx->cfg->default_reg_tile_size|]+ Threshold -> [C.cexp|ctx->cfg->default_threshold|] get_size = let (e, m) = runState (GC.compilePrimExp onLeaf what) mempty@@ -743,3 +347,5 @@ optionAction = [C.cstm|futhark_context_config_set_default_threshold(cfg, atoi(optarg));|] } ]++{-# NOINLINE generateBoilerplate #-}
src/Futhark/CodeGen/Backends/GenericC.hs view
@@ -66,7 +66,6 @@ opsAllocate = defAllocate, opsDeallocate = defDeallocate, opsCopy = defCopy,- opsStaticArray = defStaticArray, opsMemoryType = defMemoryType, opsCompiler = defCompiler, opsFatMemory = True,@@ -87,8 +86,6 @@ copyMemoryDefaultSpace destmem destoffset srcmem srcoffset size defCopy _ _ _ _ _ _ _ _ = error "Cannot copy to or from non-default memory space"- defStaticArray _ _ _ _ =- error "Cannot create static array in non-default memory space" defMemoryType _ = error "Has no type for non-default memory space" defCompiler _ =@@ -119,17 +116,14 @@ entryDecls = declsCode (== EntryDecl) miscDecls = declsCode (== MiscDecl) -defineMemorySpace :: Space -> CompilerM op s (C.Definition, [C.Definition], C.BlockItem)+defineMemorySpace :: Space -> CompilerM op s ([C.Definition], C.BlockItem) defineMemorySpace space = do rm <- rawMemCType space- let structdef =- [C.cedecl|struct $id:sname { int *references;- $ty:rm mem;- typename int64_t size;- const char *desc; };|]-- contextField peakname [C.cty|typename int64_t|] $ Just [C.cexp|0|]- contextField usagename [C.cty|typename int64_t|] $ Just [C.cexp|0|]+ earlyDecl+ [C.cedecl|struct $id:sname { int *references;+ $ty:rm mem;+ typename int64_t size;+ const char *desc; };|] -- Unreferencing a memory block consists of decreasing its reference -- count and freeing the corresponding memory if the count reaches@@ -234,8 +228,7 @@ let peakmsg = "Peak memory usage for " ++ spacedesc ++ ": %lld bytes.\n" pure- ( structdef,- [unrefdef, allocdef, setdef],+ ( [unrefdef, allocdef, setdef], -- Do not report memory usage for DefaultSpace (CPU memory), -- because it would not be accurate anyway. This whole -- tracking probably needs to be rethought.@@ -458,7 +451,7 @@ Definitions types consts (Functions funs) = prog compileProgAction = do- (memstructs, memfuns, memreport) <- unzip3 <$> mapM defineMemorySpace spaces+ (memfuns, memreport) <- unzip <$> mapM defineMemorySpace spaces get_consts <- compileConstants consts @@ -467,10 +460,19 @@ (prototypes, functions) <- unzip <$> mapM (compileFun get_consts [[C.cparam|$ty:ctx_ty *ctx|]]) funs - mapM_ earlyDecl memstructs (entry_points, entry_points_manifest) <- unzip . catMaybes <$> mapM (uncurry (onEntryPoint get_consts)) funs + headerDecl InitDecl [C.cedecl|struct futhark_context_config;|]+ headerDecl InitDecl [C.cedecl|struct futhark_context_config* futhark_context_config_new(void);|]+ headerDecl InitDecl [C.cedecl|void futhark_context_config_free(struct futhark_context_config* cfg);|]+ headerDecl InitDecl [C.cedecl|int futhark_context_config_set_tuning_param(struct futhark_context_config *cfg, const char *param_name, size_t new_value);|]++ headerDecl InitDecl [C.cedecl|struct futhark_context;|]+ headerDecl InitDecl [C.cedecl|struct futhark_context* futhark_context_new(struct futhark_context_config* cfg);|]+ headerDecl InitDecl [C.cedecl|void futhark_context_free(struct futhark_context* cfg);|]+ headerDecl MiscDecl [C.cedecl|int futhark_context_sync(struct futhark_context* ctx);|]+ extra mapM_ earlyDecl $ concat memfuns@@ -508,6 +510,27 @@ ops <- asks envOperations profilereport <- gets $ DL.toList . compProfileItems + publicDef_ "context_config_set_debugging" InitDecl $ \s ->+ ( [C.cedecl|void $id:s($ty:cfg* cfg, int flag);|],+ [C.cedecl|void $id:s($ty:cfg* cfg, int flag) {+ cfg->profiling = cfg->logging = cfg->debugging = flag;+ }|]+ )++ publicDef_ "context_config_set_profiling" InitDecl $ \s ->+ ( [C.cedecl|void $id:s($ty:cfg* cfg, int flag);|],+ [C.cedecl|void $id:s($ty:cfg* cfg, int flag) {+ cfg->profiling = flag;+ }|]+ )++ publicDef_ "context_config_set_logging" InitDecl $ \s ->+ ( [C.cedecl|void $id:s($ty:cfg* cfg, int flag);|],+ [C.cedecl|void $id:s($ty:cfg* cfg, int flag) {+ cfg->logging = flag;+ }|]+ )+ publicDef_ "context_config_set_cache_file" MiscDecl $ \s -> ( [C.cedecl|void $id:s($ty:cfg* cfg, const char *f);|], [C.cedecl|void $id:s($ty:cfg* cfg, const char *f) {@@ -518,7 +541,7 @@ publicDef_ "get_tuning_param_count" InitDecl $ \s -> ( [C.cedecl|int $id:s(void);|], [C.cedecl|int $id:s(void) {- return sizeof(tuning_param_names)/sizeof(tuning_param_names[0]);+ return num_tuning_params; }|] ) @@ -588,22 +611,16 @@ publicDef_ "context_clear_caches" MiscDecl $ \s -> ( [C.cedecl|int $id:s($ty:ctx* ctx);|], [C.cedecl|int $id:s($ty:ctx* ctx) {- $items:(criticalSection ops clears)- return ctx->error != NULL;- }|]+ $items:(criticalSection ops clears)+ return ctx->error != NULL;+ }|] ) compileConstants :: Constants op -> CompilerM op s [C.BlockItem] compileConstants (Constants ps init_consts) = do ctx_ty <- contextType const_fields <- mapM constParamField ps- -- Avoid an empty struct, as that is apparently undefined behaviour.- let const_fields'- | null const_fields = [[C.csdecl|int dummy;|]]- | otherwise = const_fields- contextField "constants" [C.cty|struct { $sdecls:const_fields' }|] Nothing- earlyDecl [C.cedecl|static int init_constants($ty:ctx_ty*);|]- earlyDecl [C.cedecl|static int free_constants($ty:ctx_ty*);|]+ earlyDecl [C.cedecl|struct constants { int dummy; $sdecls:const_fields };|] inNewFunction $ do -- We locally define macros for the constants, so that when we@@ -650,18 +667,18 @@ constMacro p = ([C.citem|$escstm:def|], [C.citem|$escstm:undef|]) where p' = T.unpack $ idText (C.toIdent (paramName p) mempty)- def = "#define " ++ p' ++ " (" ++ "ctx->constants." ++ p' ++ ")"+ def = "#define " ++ p' ++ " (" ++ "ctx->constants->" ++ p' ++ ")" undef = "#undef " ++ p' resetMemConst ScalarParam {} = pure () resetMemConst (MemParam name space) = resetMem name space freeConst ScalarParam {} = pure ()- freeConst (MemParam name space) = unRefMem [C.cexp|ctx->constants.$id:name|] space+ freeConst (MemParam name space) = unRefMem [C.cexp|ctx->constants->$id:name|] space getConst (ScalarParam name bt) = do let ctp = primTypeToCType bt- pure [C.citem|$ty:ctp $id:name = ctx->constants.$id:name;|]+ pure [C.citem|$ty:ctp $id:name = ctx->constants->$id:name;|] getConst (MemParam name space) = do ty <- memToCType name space- pure [C.citem|$ty:ty $id:name = ctx->constants.$id:name;|]+ pure [C.citem|$ty:ty $id:name = ctx->constants->$id:name;|]
src/Futhark/CodeGen/Backends/GenericC/CLI.hs view
@@ -13,6 +13,7 @@ import Futhark.CodeGen.Backends.GenericC.Pretty import Futhark.CodeGen.Backends.SimpleRep ( cproduct,+ escapeName, primAPIType, primStorageType, scalarToPrim,@@ -305,7 +306,8 @@ printstms = printResult manifest $ zip (map outputType outputs) output_vals - cli_entry_point_function_name = "futrts_cli_entry_" ++ T.unpack entry_point_name+ cli_entry_point_function_name =+ "futrts_cli_entry_" <> T.unpack (escapeName entry_point_name) pause_profiling = "futhark_context_pause_profiling" :: T.Text unpause_profiling = "futhark_context_unpause_profiling" :: T.Text
src/Futhark/CodeGen/Backends/GenericC/Code.hs view
@@ -12,7 +12,6 @@ where import Control.Monad.Reader-import Data.Loc import Data.Maybe import Data.Text qualified as T import Futhark.CodeGen.Backends.GenericC.Monad@@ -325,9 +324,7 @@ compileCode (DeclareScalar name vol t) = do let ct = primTypeToCType t decl [C.cdecl|$tyquals:(volQuals vol) $ty:ct $id:name;|]-compileCode (DeclareArray name ScalarSpace {} _ _) =- error $ "Cannot declare array " ++ prettyString name ++ " in scalar space."-compileCode (DeclareArray name DefaultSpace t vs) = do+compileCode (DeclareArray name t vs) = do name_realtype <- newVName $ baseString name ++ "_realtype" let ct = primTypeToCType t case vs of@@ -337,22 +334,12 @@ ArrayZeros n -> earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:n];|] -- Fake a memory block.- contextField- (C.toIdent name noLoc)- [C.cty|struct memblock|]- $ Just- [C.cexp|(struct memblock){NULL,- (unsigned char*)$id:name_realtype,- 0,- $string:(prettyString name)}|]- item [C.citem|struct memblock $id:name = ctx->$id:name;|]-compileCode (DeclareArray name (Space space) t vs) =- join $- asks (opsStaticArray . envOperations)- <*> pure name- <*> pure space- <*> pure t- <*> pure vs+ item+ [C.citem|struct memblock $id:name =+ (struct memblock){NULL,+ (unsigned char*)$id:name_realtype,+ 0,+ $string:(prettyString name)};|] -- For assignments of the form 'x = x OP e', we generate C assignment -- operators to make the resulting code slightly nicer. This has no -- effect on performance.
src/Futhark/CodeGen/Backends/GenericC/EntryPoints.hs view
@@ -13,7 +13,6 @@ import Futhark.CodeGen.Backends.GenericC.Types (opaqueToCType, valueTypeToCType) import Futhark.CodeGen.ImpCode import Futhark.Manifest qualified as Manifest-import Futhark.Util (zEncodeText) import Language.C.Quote.OpenCL qualified as C import Language.C.Syntax qualified as C @@ -132,9 +131,7 @@ stms $ zipWith maybeCopyDim shape [0 .. rank - 1] entryName :: Name -> T.Text-entryName v- | isValidCName (nameToText v) = "entry_" <> nameToText v- | otherwise = "entry_" <> zEncodeText (nameToText v)+entryName = ("entry_" <>) . escapeName . nameToText onEntryPoint :: [C.BlockItem] ->
src/Futhark/CodeGen/Backends/GenericC/Fun.hs view
@@ -29,8 +29,9 @@ let ctp = primTypeToCType pt decl [C.cdecl|$ty:ctp $id:name;|] - setRetVal' p (MemParam name space) = do- resetMem [C.cexp|*$exp:p|] space+ setRetVal' p (MemParam name space) =+ -- It is required that the memory block is already initialised+ -- (although it may be NULL). setMem [C.cexp|*$exp:p|] name space setRetVal' p (ScalarParam name _) = stm [C.cstm|*$exp:p = $id:name;|]
src/Futhark/CodeGen/Backends/GenericC/Monad.hs view
@@ -18,7 +18,6 @@ Deallocate, CopyBarrier (..), Copy,- StaticArray, -- * Monadic compiler interface CompilerM,@@ -26,8 +25,7 @@ CompilerEnv (..), getUserState, modifyUserState,- contextContents,- contextFinalInits,+ generateProgramStruct, runCompilerM, inNewFunction, cachingMemory,@@ -38,7 +36,6 @@ stm, stms, decl,- atInit, headerDecl, publicDef, publicDef_,@@ -77,7 +74,6 @@ fatMemUnRef, criticalSection, module Futhark.CodeGen.Backends.SimpleRep,- isValidCName, ) where @@ -85,7 +81,6 @@ import Control.Monad.Reader import Control.Monad.State import Data.Bifunctor (first)-import Data.Char (isAlpha, isAlphaNum) import Data.DList qualified as DL import Data.List (unzip4) import Data.Loc@@ -110,12 +105,11 @@ data CompilerState s = CompilerState { compArrayTypes :: M.Map ArrayType Publicness, compEarlyDecls :: DL.DList C.Definition,- compInit :: [C.Stm], compNameSrc :: VNameSource, compUserState :: s, compHeaderDecls :: M.Map HeaderSection (DL.DList C.Definition), compLibDecls :: DL.DList C.Definition,- compCtxFields :: DL.DList (C.Id, C.Type, Maybe C.Exp, Maybe C.Stm),+ compCtxFields :: DL.DList (C.Id, C.Type, Maybe C.Exp, Maybe (C.Stm, C.Stm)), compProfileItems :: DL.DList C.BlockItem, compClearItems :: DL.DList C.BlockItem, compDeclaredMem :: [(VName, Space)],@@ -127,7 +121,6 @@ CompilerState { compArrayTypes = mempty, compEarlyDecls = mempty,- compInit = [], compNameSrc = src, compUserState = s, compHeaderDecls = mempty,@@ -158,7 +151,7 @@ -- | The address space qualifiers for a pointer of the given type with -- the given annotation.-type PointerQuals op s = String -> CompilerM op s [C.TypeQual]+type PointerQuals = String -> [C.TypeQual] -- | The type of a memory block in the given memory space. type MemoryType op s = SpaceId -> CompilerM op s C.Type@@ -187,9 +180,6 @@ -- given size,, which is in the given memory space. type Deallocate op s = C.Exp -> C.Exp -> C.Exp -> SpaceId -> CompilerM op s () --- | Create a static array of values - initialised at load time.-type StaticArray op s = VName -> SpaceId -> PrimType -> ArrayContents -> CompilerM op s ()- -- | Whether a copying operation should implicitly function as a -- barrier regarding further operations on the source. This is a -- rather subtle detail and is mostly useful for letting some@@ -222,7 +212,6 @@ opsAllocate :: Allocate op s, opsDeallocate :: Deallocate op s, opsCopy :: Copy op s,- opsStaticArray :: StaticArray op s, opsMemoryType :: MemoryType op s, opsCompiler :: OpCompiler op s, opsError :: ErrorCompiler op s,@@ -265,13 +254,34 @@ | (name, ty) <- zip field_names field_types ] init_fields =- [ [C.cstm|ctx->$id:name = $exp:e;|]+ [ [C.cstm|ctx->program->$id:name = $exp:e;|] | (name, Just e) <- zip field_names field_values ]- pure (fields, init_fields, catMaybes field_frees)+ (setup, free) = unzip $ catMaybes field_frees+ pure (fields, init_fields <> setup, free) -contextFinalInits :: CompilerM op s [C.Stm]-contextFinalInits = gets compInit+generateProgramStruct :: CompilerM op s ()+generateProgramStruct = do+ (fields, init_fields, free_fields) <- contextContents+ mapM_+ earlyDecl+ [C.cunit|struct program {+ $sdecls:fields+ };+ static void setup_program(struct futhark_context* ctx) {+ (void)ctx;+ int error = 0;+ (void)error;+ ctx->program = malloc(sizeof(struct program));+ $stms:init_fields+ }+ static void teardown_program(struct futhark_context *ctx) {+ (void)ctx;+ int error = 0;+ (void)error;+ $stms:free_fields+ free(ctx->program);+ }|] newtype CompilerM op s a = CompilerM (ReaderT (CompilerEnv op s) (State (CompilerState s)) a)@@ -305,10 +315,6 @@ modifyUserState f = modify $ \compstate -> compstate {compUserState = f $ compUserState compstate} -atInit :: C.Stm -> CompilerM op s ()-atInit x = modify $ \s ->- s {compInit = compInit s ++ [x]}- collect :: CompilerM op s () -> CompilerM op s [C.BlockItem] collect m = snd <$> collect' m @@ -394,9 +400,9 @@ contextField name ty initial = modify $ \s -> s {compCtxFields = compCtxFields s <> DL.singleton (name, ty, initial, Nothing)} -contextFieldDyn :: C.Id -> C.Type -> Maybe C.Exp -> C.Stm -> CompilerM op s ()-contextFieldDyn name ty initial free = modify $ \s ->- s {compCtxFields = compCtxFields s <> DL.singleton (name, ty, initial, Just free)}+contextFieldDyn :: C.Id -> C.Type -> C.Stm -> C.Stm -> CompilerM op s ()+contextFieldDyn name ty create free = modify $ \s ->+ s {compCtxFields = compCtxFields s <> DL.singleton (name, ty, Nothing, Just (create, free))} profileReport :: C.BlockItem -> CompilerM op s () profileReport x = modify $ \s ->@@ -634,21 +640,15 @@ volQuals Volatile = [C.ctyquals|volatile|] volQuals Nonvolatile = [] -writeScalarPointerWithQuals :: PointerQuals op s -> WriteScalar op s+writeScalarPointerWithQuals :: PointerQuals -> WriteScalar op s writeScalarPointerWithQuals quals_f dest i elemtype space vol v = do- quals <- quals_f space- let quals' = volQuals vol ++ quals- deref =- derefPointer- dest- i- [C.cty|$tyquals:quals' $ty:elemtype*|]+ let quals' = volQuals vol ++ quals_f space+ deref = derefPointer dest i [C.cty|$tyquals:quals' $ty:elemtype*|] stm [C.cstm|$exp:deref = $exp:v;|] -readScalarPointerWithQuals :: PointerQuals op s -> ReadScalar op s+readScalarPointerWithQuals :: PointerQuals -> ReadScalar op s readScalarPointerWithQuals quals_f dest i elemtype space vol = do- quals <- quals_f space- let quals' = volQuals vol ++ quals+ let quals' = volQuals vol ++ quals_f space pure $ derefPointer dest i [C.cty|$tyquals:quals' $ty:elemtype*|] criticalSection :: Operations op s -> [C.BlockItem] -> [C.BlockItem]@@ -672,11 +672,3 @@ configType = do name <- publicName "context_config" pure [C.cty|struct $id:name|]---- | Is this name a valid C identifier? If not, it should be escaped--- before being emitted into C.-isValidCName :: T.Text -> Bool-isValidCName = maybe True check . T.uncons- where- check (c, cs) = isAlpha c && T.all constituent cs- constituent c = isAlphaNum c || c == '_'
src/Futhark/CodeGen/Backends/GenericPython.hs view
@@ -28,7 +28,6 @@ ReadScalar, Allocate, Copy,- StaticArray, EntryOutput, EntryInput, CompilerEnv (..),@@ -44,6 +43,7 @@ import Control.Monad.Identity import Control.Monad.RWS+import Data.Char (isAlpha, isAlphaNum) import Data.Map qualified as M import Data.Maybe import Data.Text qualified as T@@ -102,9 +102,6 @@ PrimType -> CompilerM op s () --- | Create a static array of values - initialised at load time.-type StaticArray op s = VName -> Imp.SpaceId -> PrimType -> Imp.ArrayContents -> CompilerM op s ()- -- | Construct the Python array being returned from an entry point. type EntryOutput op s = VName ->@@ -129,7 +126,6 @@ opsReadScalar :: ReadScalar op s, opsAllocate :: Allocate op s, opsCopy :: Copy op s,- opsStaticArray :: StaticArray op s, opsCompiler :: OpCompiler op s, opsEntryOutput :: EntryOutput op s, opsEntryInput :: EntryInput op s@@ -145,7 +141,6 @@ opsReadScalar = defReadScalar, opsAllocate = defAllocate, opsCopy = defCopy,- opsStaticArray = defStaticArray, opsCompiler = defCompiler, opsEntryOutput = defEntryOutput, opsEntryInput = defEntryInput@@ -159,8 +154,6 @@ error "Cannot allocate in non-default memory space" defCopy _ _ _ _ _ _ _ _ = error "Cannot copy to or from non-default memory space"- defStaticArray _ _ _ _ =- error "Cannot create static array in non-default memory space" defCompiler _ = error "The default compiler cannot compile extended operations" defEntryOutput _ _ _ _ =@@ -170,7 +163,7 @@ data CompilerEnv op s = CompilerEnv { envOperations :: Operations op s,- envVarExp :: M.Map VName PyExp+ envVarExp :: M.Map String PyExp } envOpCompiler :: CompilerEnv op s -> OpCompiler op s@@ -188,9 +181,6 @@ envCopy :: CompilerEnv op s -> Copy op s envCopy = opsCopy . envOperations -envStaticArray :: CompilerEnv op s -> StaticArray op s-envStaticArray = opsStaticArray . envOperations- envEntryOutput :: CompilerEnv op s -> EntryOutput op s envEntryOutput = opsEntryOutput . envOperations @@ -331,6 +321,23 @@ functionExternalValues entry = map snd (Imp.entryPointResults entry) ++ map snd (Imp.entryPointArgs entry) +-- | Is this name a valid Python identifier? If not, it should be escaped+-- before being emitted.+isValidPyName :: T.Text -> Bool+isValidPyName = maybe True check . T.uncons+ where+ check (c, cs) = isAlpha c && T.all constituent cs+ constituent c = isAlphaNum c || c == '_'++-- | If the provided text is a valid identifier, then return it+-- verbatim. Otherwise, escape it such that it becomes valid.+escapeName :: Name -> T.Text+escapeName v+ | isValidPyName v' = v'+ | otherwise = zEncodeText v'+ where+ v' = nameToText v+ opaqueDefs :: Imp.Functions a -> M.Map T.Text [PyExp] opaqueDefs (Imp.Functions funs) = mconcat@@ -491,7 +498,7 @@ where constExp p = M.singleton- (Imp.paramName p)+ (compileName $ Imp.paramName p) (Index (Var "self.constants") $ IdxExp $ String $ prettyText $ Imp.paramName p) compileConstants :: Imp.Constants op -> CompilerM op s ()@@ -886,9 +893,15 @@ pure $ Just- ( Def (nameToString ename) ("self" : params) $+ ( Def (T.unpack (escapeName ename)) ("self" : params) $ prepareIn ++ do_run ++ prepareOut ++ sync ++ [ret],- (String (nameToText ename), Tuple [List (map String pts), List (map String rts)])+ ( String (nameToText ename),+ Tuple+ [ String (escapeName ename),+ List (map String pts),+ List (map String rts)+ ]+ ) ) | otherwise = pure Nothing @@ -930,7 +943,7 @@ str_output <- printValue res - let fname' = "entry_" ++ nameToString fname+ let fname' = "entry_" ++ T.unpack (escapeName fname) pure $ Just@@ -1105,8 +1118,9 @@ compilePrimValue UnitValue = Var "None" compileVar :: VName -> CompilerM op s PyExp-compileVar v =- asks $ fromMaybe (Var $ compileName v) . M.lookup v . envVarExp+compileVar v = asks $ fromMaybe (Var v') . M.lookup v' . envVarExp+ where+ v' = compileName v -- | Tell me how to compile a @v@, and I'll Compile any @PrimExp v@ for you. compilePrimExp :: Monad m => (v -> m PyExp) -> Imp.PrimExp v -> m PyExp@@ -1197,38 +1211,27 @@ v' <- compileVar v stm $ Assign v' $ Var "True" compileCode Imp.DeclareScalar {} = pure ()-compileCode (Imp.DeclareArray name (Space space) t vs) =- join $- asks envStaticArray- <*> pure name- <*> pure space- <*> pure t- <*> pure vs-compileCode (Imp.DeclareArray name _ t vs) = do+compileCode (Imp.DeclareArray name t vs) = do let arr_name = compileName name <> "_arr" -- It is important to store the Numpy array in a temporary variable -- to prevent it from going "out-of-scope" before calling -- unwrapArray (which internally uses the .ctype method); see -- https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.ctypes.html- atInit $- Assign (Field (Var "self") arr_name) $ case vs of- Imp.ArrayValues vs' ->- Call- (Var "np.array")- [ Arg $ List $ map compilePrimValue vs',- ArgKeyword "dtype" $ Var $ compilePrimToNp t- ]- Imp.ArrayZeros n ->- Call- (Var "np.zeros")- [ Arg $ Integer $ fromIntegral n,- ArgKeyword "dtype" $ Var $ compilePrimToNp t- ]- atInit $- Assign (Field (Var "self") (compileName name)) $- simpleCall "unwrapArray" [Field (Var "self") arr_name]+ stm $ Assign (Var arr_name) $ case vs of+ Imp.ArrayValues vs' ->+ Call+ (Var "np.array")+ [ Arg $ List $ map compilePrimValue vs',+ ArgKeyword "dtype" $ Var $ compilePrimToNp t+ ]+ Imp.ArrayZeros n ->+ Call+ (Var "np.zeros")+ [ Arg $ Integer $ fromIntegral n,+ ArgKeyword "dtype" $ Var $ compilePrimToNp t+ ] name' <- compileVar name- stm $ Assign name' $ Field (Var "self") (compileName name)+ stm $ Assign name' $ simpleCall "unwrapArray" [Var arr_name] compileCode (Imp.Comment s code) = do code' <- collect $ compileCode code stm $ Comment (T.unpack s) code'
src/Futhark/CodeGen/Backends/GenericWASM.hs view
@@ -53,7 +53,7 @@ emccExportNames :: [JSEntryPoint] -> [String] emccExportNames jses =- map (\jse -> "'_futhark_entry_" ++ name jse ++ "'") jses+ map (\jse -> "'_futhark_entry_" ++ T.unpack (GC.escapeName (T.pack (name jse))) ++ "'") jses ++ map (\arg -> "'" ++ gfn "new" arg ++ "'") arrays ++ map (\arg -> "'" ++ gfn "free" arg ++ "'") arrays ++ map (\arg -> "'" ++ gfn "shape" arg ++ "'") arrays@@ -151,9 +151,10 @@ dicEntry :: JSEntryPoint -> T.Text dicEntry jse = [text|- '${ename}' : [${params}, ${rets}]+ "${ename}" : ["${fname}", ${params}, ${rets}] |] where+ fname = GC.escapeName $ T.pack $ name jse ename = T.pack $ name jse params = showText $ parameters jse rets = showText $ ret jse@@ -176,7 +177,7 @@ } |] where- func_name = T.pack $ name jse+ func_name = GC.escapeName $ T.pack $ name jse alp = [0 .. length (parameters jse) - 1] inparams = T.pack $ intercalate ", " ["in" ++ show i | i <- alp]
src/Futhark/CodeGen/Backends/MulticoreC.hs view
@@ -4,7 +4,6 @@ -- program to an equivalent C program. module Futhark.CodeGen.Backends.MulticoreC ( compileProg,- generateContext, GC.CParts (..), GC.asLibrary, GC.asExecutable,@@ -35,10 +34,10 @@ import Data.Text qualified as T import Futhark.CodeGen.Backends.GenericC qualified as GC import Futhark.CodeGen.Backends.GenericC.Options+import Futhark.CodeGen.Backends.MulticoreC.Boilerplate (generateBoilerplate) import Futhark.CodeGen.Backends.SimpleRep import Futhark.CodeGen.ImpCode.Multicore hiding (ValueType) import Futhark.CodeGen.ImpGen.Multicore qualified as ImpGen-import Futhark.CodeGen.RTS.C (schedulerH) import Futhark.IR.MCMem (MCMem, Prog) import Futhark.MonadFreshNames import Language.C.Quote.OpenCL qualified as C@@ -53,187 +52,13 @@ "multicore" version operations- generateContext+ generateBoilerplate "" (DefaultSpace, [DefaultSpace]) cliOptions ) <=< ImpGen.compileProg --- | Generate the multicore context definitions. This is exported--- because the WASM backend needs it.-generateContext :: GC.CompilerM op s ()-generateContext = do- mapM_ GC.earlyDecl [C.cunit|$esc:(T.unpack schedulerH)|]-- cfg <- GC.publicDef "context_config" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:s;|],- [C.cedecl|struct $id:s { int in_use;- int debugging;- int profiling;- int num_threads;- const char *cache_fname;- };|]- )-- GC.publicDef_ "context_config_new" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:cfg* $id:s(void);|],- [C.cedecl|struct $id:cfg* $id:s(void) {- struct $id:cfg *cfg = (struct $id:cfg*) malloc(sizeof(struct $id:cfg));- if (cfg == NULL) {- return NULL;- }- cfg->in_use = 0;- cfg->debugging = 0;- cfg->profiling = 0;- cfg->cache_fname = NULL;- cfg->num_threads = 0;- return cfg;- }|]- )-- GC.publicDef_ "context_config_free" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg) {- assert(!cfg->in_use);- free(cfg);- }|]- )-- GC.publicDef_ "context_config_set_debugging" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int detail) {- cfg->debugging = detail;- }|]- )-- GC.publicDef_ "context_config_set_profiling" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {- cfg->profiling = flag;- }|]- )-- GC.publicDef_ "context_config_set_logging" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int detail) {- // Does nothing for this backend.- (void)cfg; (void)detail;- }|]- )-- GC.publicDef_ "context_config_set_num_threads" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg *cfg, int n);|],- [C.cedecl|void $id:s(struct $id:cfg *cfg, int n) {- cfg->num_threads = n;- }|]- )-- (fields, init_fields, free_fields) <- GC.contextContents-- ctx <- GC.publicDef "context" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:s;|],- [C.cedecl|struct $id:s {- struct $id:cfg* cfg;- struct scheduler scheduler;- int detail_memory;- int debugging;- int profiling;- int profiling_paused;- int logging;- typename lock_t lock;- char *error;- typename lock_t error_lock;- typename FILE *log;- int total_runs;- long int total_runtime;- struct free_list free_list;- $sdecls:fields-- // Tuning parameters- typename int64_t tuning_timing;- typename int64_t tuning_iter;- };|]- )-- GC.publicDef_ "context_new" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg);|],- [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg) {- assert(!cfg->in_use);- struct $id:ctx* ctx = (struct $id:ctx*) malloc(sizeof(struct $id:ctx));- if (ctx == NULL) {- return NULL;- }- ctx->cfg = cfg;- ctx->cfg->in_use = 1;-- // Initialize rand()- fast_srand(time(0));- ctx->detail_memory = cfg->debugging;- ctx->debugging = cfg->debugging;- ctx->profiling = cfg->profiling;- ctx->profiling_paused = 0;- ctx->logging = 0;- ctx->error = NULL;- ctx->log = stderr;-- context_setup(ctx);-- int tune_kappa = 0;- double kappa = 5.1f * 1000;-- if (tune_kappa) {- if (determine_kappa(&kappa) != 0) {- return NULL;- }- }-- if (scheduler_init(&ctx->scheduler,- cfg->num_threads > 0 ?- cfg->num_threads : num_processors(),- kappa) != 0) {- return NULL;- }-- $stms:init_fields-- init_constants(ctx);-- return ctx;- }|]- )-- GC.publicDef_ "context_free" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:ctx* ctx);|],- [C.cedecl|void $id:s(struct $id:ctx* ctx) {- $stms:free_fields- context_teardown(ctx);- (void)scheduler_destroy(&ctx->scheduler);- ctx->cfg->in_use = 0;- free(ctx);- }|]- )-- GC.publicDef_ "context_sync" GC.InitDecl $ \s ->- ( [C.cedecl|int $id:s(struct $id:ctx* ctx);|],- [C.cedecl|int $id:s(struct $id:ctx* ctx) {- (void)ctx;- return 0;- }|]- )-- GC.earlyDecl [C.cedecl|static const char *tuning_param_names[0];|]- GC.earlyDecl [C.cedecl|static const char *tuning_param_vars[0];|]- GC.earlyDecl [C.cedecl|static const char *tuning_param_classes[0];|]-- GC.publicDef_ "context_config_set_tuning_param" GC.InitDecl $ \s ->- ( [C.cedecl|int $id:s(struct $id:cfg* cfg, const char *param_name, size_t param_value);|],- [C.cedecl|int $id:s(struct $id:cfg* cfg, const char *param_name, size_t param_value) {- (void)cfg; (void)param_name; (void)param_value;- return 1;- }|]- )- -- | Multicore-related command line options. cliOptions :: [Option] cliOptions =@@ -415,12 +240,12 @@ fprintf(ctx->log, $string:(format_string name is_array), i,- ctx->$id:runs[i],- (long int) ctx->$id:total_runtime[i] / (ctx->$id:runs[i] != 0 ? ctx->$id:runs[i] : 1),- (long int) ctx->$id:total_runtime[i],- (double) ctx->$id:total_runtime[i] / (ctx->$id:iters[i] == 0 ? 1 : (double)ctx->$id:iters[i]),- (long int) (ctx->$id:iters[i]),- (long int) (ctx->$id:iters[i]) / (ctx->$id:runs[i] != 0 ? ctx->$id:runs[i] : 1)+ ctx->program->$id:runs[i],+ (long int) ctx->program->$id:total_runtime[i] / (ctx->program->$id:runs[i] != 0 ? ctx->program->$id:runs[i] : 1),+ (long int) ctx->program->$id:total_runtime[i],+ (double) ctx->program->$id:total_runtime[i] / (ctx->program->$id:iters[i] == 0 ? 1 : (double)ctx->program->$id:iters[i]),+ (long int) (ctx->program->$id:iters[i]),+ (long int) (ctx->program->$id:iters[i]) / (ctx->program->$id:runs[i] != 0 ? ctx->program->$id:runs[i] : 1) ); } |]@@ -429,15 +254,15 @@ [ [C.citem| fprintf(ctx->log, $string:(format_string name is_array),- ctx->$id:runs,- (long int) ctx->$id:total_runtime / (ctx->$id:runs != 0 ? ctx->$id:runs : 1),- (long int) ctx->$id:total_runtime,- (double) ctx->$id:total_runtime / (ctx->$id:iters == 0 ? 1 : (double)ctx->$id:iters),- (long int) (ctx->$id:iters),- (long int) (ctx->$id:iters) / (ctx->$id:runs != 0 ? ctx->$id:runs : 1));+ ctx->program->$id:runs,+ (long int) ctx->program->$id:total_runtime / (ctx->program->$id:runs != 0 ? ctx->program->$id:runs : 1),+ (long int) ctx->program->$id:total_runtime,+ (double) ctx->program->$id:total_runtime / (ctx->program->$id:iters == 0 ? 1 : (double)ctx->program->$id:iters),+ (long int) (ctx->program->$id:iters),+ (long int) (ctx->program->$id:iters) / (ctx->program->$id:runs != 0 ? ctx->program->$id:runs : 1)); |],- [C.citem|ctx->total_runtime += ctx->$id:total_runtime;|],- [C.citem|ctx->total_runs += ctx->$id:runs;|]+ [C.citem|ctx->total_runtime += ctx->program->$id:total_runtime;|],+ [C.citem|ctx->total_runs += ctx->program->$id:runs;|] ] addBenchmarkFields :: Name -> Maybe C.Id -> GC.CompilerM op s ()@@ -445,18 +270,18 @@ GC.contextFieldDyn (functionRuntime name) [C.cty|typename int64_t*|]- (Just [C.cexp|calloc(sizeof(typename int64_t), ctx->scheduler.num_threads)|])- [C.cstm|free(ctx->$id:(functionRuntime name));|]+ [C.cstm|ctx->program->$id:(functionRuntime name) = calloc(sizeof(typename int64_t), ctx->scheduler.num_threads);|]+ [C.cstm|free(ctx->program->$id:(functionRuntime name));|] GC.contextFieldDyn (functionRuns name) [C.cty|int*|]- (Just [C.cexp|calloc(sizeof(int), ctx->scheduler.num_threads)|])- [C.cstm|free(ctx->$id:(functionRuns name));|]+ [C.cstm|ctx->program->$id:(functionRuns name) = calloc(sizeof(int), ctx->scheduler.num_threads);|]+ [C.cstm|free(ctx->program->$id:(functionRuns name));|] GC.contextFieldDyn (functionIter name) [C.cty|typename int64_t*|]- (Just [C.cexp|calloc(sizeof(sizeof(typename int64_t)), ctx->scheduler.num_threads)|])- [C.cstm|free(ctx->$id:(functionIter name));|]+ [C.cstm|ctx->program->$id:(functionIter name) = calloc(sizeof(sizeof(typename int64_t)), ctx->scheduler.num_threads);|]+ [C.cstm|free(ctx->program->$id:(functionIter name));|] addBenchmarkFields name Nothing = do GC.contextField (functionRuntime name) [C.cty|typename int64_t|] $ Just [C.cexp|0|] GC.contextField (functionRuns name) [C.cty|int|] $ Just [C.cexp|0|]@@ -482,13 +307,13 @@ start = name <> "_start" end = name <> "_end" updateFields Nothing =- [C.citems|__atomic_fetch_add(&ctx->$id:(functionRuns name), 1, __ATOMIC_RELAXED);- __atomic_fetch_add(&ctx->$id:(functionRuntime name), elapsed, __ATOMIC_RELAXED);- __atomic_fetch_add(&ctx->$id:(functionIter name), iterations, __ATOMIC_RELAXED);|]+ [C.citems|__atomic_fetch_add(&ctx->program->$id:(functionRuns name), 1, __ATOMIC_RELAXED);+ __atomic_fetch_add(&ctx->program->$id:(functionRuntime name), elapsed, __ATOMIC_RELAXED);+ __atomic_fetch_add(&ctx->program->$id:(functionIter name), iterations, __ATOMIC_RELAXED);|] updateFields (Just _tid') =- [C.citems|ctx->$id:(functionRuns name)[tid]++;- ctx->$id:(functionRuntime name)[tid] += elapsed;- ctx->$id:(functionIter name)[tid] += iterations;|]+ [C.citems|ctx->program->$id:(functionRuns name)[tid]++;+ ctx->program->$id:(functionRuntime name)[tid] += elapsed;+ ctx->program->$id:(functionIter name)[tid] += iterations;|] functionTiming :: Name -> C.Id functionTiming = (`C.toIdent` mempty) . (<> "_total_time")@@ -609,8 +434,8 @@ GC.stm [C.cstm|$id:ftask_name.name = $string:(nameToString fpar_task);|] GC.stm [C.cstm|$id:ftask_name.iterations = $exp:e';|] -- Create the timing fields for the task- GC.stm [C.cstm|$id:ftask_name.task_time = &ctx->$id:(functionTiming fpar_task);|]- GC.stm [C.cstm|$id:ftask_name.task_iter = &ctx->$id:(functionIterations fpar_task);|]+ GC.stm [C.cstm|$id:ftask_name.task_time = &ctx->program->$id:(functionTiming fpar_task);|]+ GC.stm [C.cstm|$id:ftask_name.task_iter = &ctx->program->$id:(functionIterations fpar_task);|] case sched of Dynamic -> GC.stm [C.cstm|$id:ftask_name.sched = DYNAMIC;|]
+ src/Futhark/CodeGen/Backends/MulticoreC/Boilerplate.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE QuasiQuotes #-}++-- | Boilerplate for multicore C code.+module Futhark.CodeGen.Backends.MulticoreC.Boilerplate (generateBoilerplate) where++import Data.Text qualified as T+import Futhark.CodeGen.Backends.GenericC qualified as GC+import Futhark.CodeGen.RTS.C (backendsMulticoreH, schedulerH)+import Language.C.Quote.OpenCL qualified as C++-- | Generate the necessary boilerplate.+generateBoilerplate :: GC.CompilerM op s ()+generateBoilerplate = do+ GC.earlyDecl [C.cedecl|static const int num_tuning_params = 0;|]+ GC.earlyDecl [C.cedecl|static const char *tuning_param_names[1];|]+ GC.earlyDecl [C.cedecl|static const char *tuning_param_vars[1];|]+ GC.earlyDecl [C.cedecl|static const char *tuning_param_classes[1];|]+ GC.earlyDecl [C.cedecl|static typename int64_t *tuning_param_defaults[1];|]+ mapM_ GC.earlyDecl [C.cunit|$esc:(T.unpack schedulerH)|]+ mapM_ GC.earlyDecl [C.cunit|$esc:(T.unpack backendsMulticoreH)|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_num_threads(struct futhark_context_config *cfg, int n);|]+ GC.generateProgramStruct+{-# NOINLINE generateBoilerplate #-}
src/Futhark/CodeGen/Backends/MulticoreISPC.hs view
@@ -27,6 +27,7 @@ import Futhark.CodeGen.Backends.GenericC qualified as GC import Futhark.CodeGen.Backends.GenericC.Pretty import Futhark.CodeGen.Backends.MulticoreC qualified as MC+import Futhark.CodeGen.Backends.MulticoreC.Boilerplate (generateBoilerplate) import Futhark.CodeGen.Backends.SimpleRep import Futhark.CodeGen.ImpCode.Multicore import Futhark.CodeGen.ImpGen.Multicore qualified as ImpGen@@ -74,7 +75,7 @@ operations (ISPCState mempty mempty) ( do- MC.generateContext+ generateBoilerplate mapM_ compileBuiltinFun funs ) mempty@@ -499,7 +500,7 @@ let ct = GC.primTypeToCType t quals <- getVariabilityQuals name GC.decl [C.cdecl|$tyquals:quals $ty:ct $id:name;|]-compileCode (DeclareArray name DefaultSpace t vs) = do+compileCode (DeclareArray name t vs) = do name_realtype <- newVName $ baseString name ++ "_realtype" let ct = GC.primTypeToCType t case vs of@@ -508,19 +509,17 @@ GC.earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:(length vs')] = {$inits:vs''};|] ArrayZeros n -> GC.earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:n];|]- -- Fake a memory block.- GC.contextField- (C.toIdent name noLoc)- [C.cty|struct memblock|]- $ Just [C.cexp|(struct memblock){NULL, (char*)$id:name_realtype, 0}|]- -- Make an exported C shim to access it+ -- Make an exported C shim to access a faked memory block. shim <- MC.multicoreDef "get_static_array_shim" $ \f ->- pure [C.cedecl|struct memblock* $id:f(struct futhark_context* ctx) { return &ctx->$id:name; }|]+ pure+ [C.cedecl|struct memblock $id:f(struct futhark_context* ctx) {+ return (struct memblock){NULL,(unsigned char*)$id:name_realtype,0};+ }|] ispcDecl- [C.cedecl|extern "C" $tyqual:unmasked $tyqual:uniform struct memblock * $tyqual:uniform+ [C.cedecl|extern "C" $tyqual:unmasked $tyqual:uniform struct memblock $tyqual:uniform $id:shim($tyqual:uniform struct futhark_context* $tyqual:uniform ctx);|] -- Call it- GC.item [C.citem|$tyqual:uniform struct memblock $id:name = *$id:shim(ctx);|]+ GC.item [C.citem|$tyqual:uniform struct memblock $id:name = $id:shim(ctx);|] compileCode (c1 :>>: c2) = go (GC.linearCode (c1 :>>: c2)) where go (DeclareScalar name _ t : SetScalar dest e : code)@@ -782,8 +781,8 @@ GC.stm [C.cstm|$id:ftask_name.name = $string:(nameToString fpar_task);|] GC.stm [C.cstm|$id:ftask_name.iterations = iterations;|] -- Create the timing fields for the task- GC.stm [C.cstm|$id:ftask_name.task_time = &ctx->$id:(MC.functionTiming fpar_task);|]- GC.stm [C.cstm|$id:ftask_name.task_iter = &ctx->$id:(MC.functionIterations fpar_task);|]+ GC.stm [C.cstm|$id:ftask_name.task_time = &ctx->program->$id:(MC.functionTiming fpar_task);|]+ GC.stm [C.cstm|$id:ftask_name.task_iter = &ctx->program->$id:(MC.functionIterations fpar_task);|] case sched of Dynamic -> GC.stm [C.cstm|$id:ftask_name.sched = DYNAMIC;|]
src/Futhark/CodeGen/Backends/MulticoreWASM.hs view
@@ -18,6 +18,7 @@ import Futhark.CodeGen.Backends.GenericC qualified as GC import Futhark.CodeGen.Backends.GenericWASM import Futhark.CodeGen.Backends.MulticoreC qualified as MC+import Futhark.CodeGen.Backends.MulticoreC.Boilerplate (generateBoilerplate) import Futhark.CodeGen.ImpCode.Multicore qualified as Imp import Futhark.CodeGen.ImpGen.Multicore qualified as ImpGen import Futhark.IR.MCMem@@ -48,7 +49,7 @@ "wasm_multicore" version MC.operations- MC.generateContext+ generateBoilerplate "" (DefaultSpace, [DefaultSpace]) MC.cliOptions
src/Futhark/CodeGen/Backends/PyOpenCL.hs view
@@ -189,7 +189,6 @@ Py.opsReadScalar = readOpenCLScalar, Py.opsAllocate = allocateOpenCLBuffer, Py.opsCopy = copyOpenCLMemory,- Py.opsStaticArray = staticOpenCLArray, Py.opsEntryOutput = packArrayOutput, Py.opsEntryInput = unpackArrayInput }@@ -346,10 +345,9 @@ ArgKeyword "device_offset" $ asLong srcidx, ArgKeyword "is_blocking" $ Var "synchronous" ]-copyOpenCLMemory destmem destidx (Imp.Space "device") srcmem srcidx Imp.DefaultSpace nbytes bt = do- let divide = BinOp "//" nbytes (Integer $ Imp.primByteSize bt)- end = BinOp "+" srcidx divide- src = Index srcmem (IdxRange srcidx end)+copyOpenCLMemory destmem destidx (Imp.Space "device") srcmem srcidx Imp.DefaultSpace nbytes _ = do+ let end = BinOp "+" srcidx nbytes+ src = Index (Py.simpleCall "createArray" [srcmem, List [nbytes], Var "np.byte"]) (IdxRange srcidx end) Py.stm $ ifNotZeroSize nbytes $ Exp $@@ -379,58 +377,6 @@ Py.copyMemoryDefaultSpace destmem destidx srcmem srcidx nbytes copyOpenCLMemory _ _ destspace _ _ srcspace _ _ = error $ "Cannot copy to " ++ show destspace ++ " from " ++ show srcspace--staticOpenCLArray :: Py.StaticArray Imp.OpenCL ()-staticOpenCLArray name "device" t vs = do- mapM_ Py.atInit <=< Py.collect $ do- -- Create host-side Numpy array with intended values.- Py.stm $- Assign (Var name') $ case vs of- Imp.ArrayValues vs' ->- Call- (Var "np.array")- [ Arg $ List $ map Py.compilePrimValue vs',- ArgKeyword "dtype" $ Var $ Py.compilePrimToNp t- ]- Imp.ArrayZeros n ->- Call- (Var "np.zeros")- [ Arg $ Integer $ fromIntegral n,- ArgKeyword "dtype" $ Var $ Py.compilePrimToNp t- ]-- let num_elems = case vs of- Imp.ArrayValues vs' -> length vs'- Imp.ArrayZeros n -> n-- -- Create memory block on the device.- static_mem <- newVName "static_mem"- let size = Integer $ toInteger num_elems * Imp.primByteSize t- allocateOpenCLBuffer (Var (Py.compileName static_mem)) size "device"-- -- Copy Numpy array to the device memory block.- Py.stm $- ifNotZeroSize size $- Exp $- Call- (Var "cl.enqueue_copy")- [ Arg $ Var "self.queue",- Arg $ Var $ Py.compileName static_mem,- Arg $ Call (Var "normaliseArray") [Arg (Var name')],- ArgKeyword "is_blocking" $ Var "synchronous"- ]-- -- Store the memory block for later reference.- Py.stm $- Assign (Field (Var "self") name') $- Var $- Py.compileName static_mem-- Py.stm $ Assign (Var name') (Field (Var "self") name')- where- name' = Py.compileName name-staticOpenCLArray _ space _ _ =- error $ "PyOpenCL backend cannot create static array in memory space '" ++ space ++ "'" packArrayOutput :: Py.EntryOutput Imp.OpenCL () packArrayOutput mem "device" bt ept dims = do
src/Futhark/CodeGen/Backends/SequentialC/Boilerplate.hs view
@@ -3,134 +3,19 @@ -- | Boilerplate for sequential C code. module Futhark.CodeGen.Backends.SequentialC.Boilerplate (generateBoilerplate) where +import Data.Text qualified as T import Futhark.CodeGen.Backends.GenericC qualified as GC+import Futhark.CodeGen.RTS.C (backendsCH) import Language.C.Quote.OpenCL qualified as C -- | Generate the necessary boilerplate. generateBoilerplate :: GC.CompilerM op s () generateBoilerplate = do- cfg <- GC.publicDef "context_config" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:s;|],- [C.cedecl|struct $id:s { int debugging;- int in_use;- const char *cache_fname;- };|]- )-- GC.publicDef_ "context_config_new" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:cfg* $id:s(void);|],- [C.cedecl|struct $id:cfg* $id:s(void) {- struct $id:cfg *cfg = (struct $id:cfg*) malloc(sizeof(struct $id:cfg));- if (cfg == NULL) {- return NULL;- }- cfg->in_use = 0;- cfg->debugging = 0;- cfg->cache_fname = NULL;- return cfg;- }|]- )-- GC.publicDef_ "context_config_free" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg) {- assert(!cfg->in_use);- free(cfg);- }|]- )-- GC.publicDef_ "context_config_set_debugging" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int detail) {- cfg->debugging = detail;- }|]- )-- GC.publicDef_ "context_config_set_profiling" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {- (void)cfg; (void)flag;- }|]- )-- GC.publicDef_ "context_config_set_logging" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],- [C.cedecl|void $id:s(struct $id:cfg* cfg, int detail) {- // Does nothing for this backend.- (void)cfg; (void)detail;- }|]- )-- (fields, init_fields, free_fields) <- GC.contextContents-- ctx <- GC.publicDef "context" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:s;|],- [C.cedecl|struct $id:s {- struct $id:cfg* cfg;- int detail_memory;- int debugging;- int profiling;- int logging;- typename lock_t lock;- char *error;- typename lock_t error_lock;- typename FILE *log;- int profiling_paused;- struct free_list free_list;- $sdecls:fields- };|]- )-- GC.publicDef_ "context_new" GC.InitDecl $ \s ->- ( [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg);|],- [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg) {- assert(!cfg->in_use);- struct $id:ctx* ctx = (struct $id:ctx*) malloc(sizeof(struct $id:ctx));- if (ctx == NULL) {- return NULL;- }- ctx->cfg = cfg;- ctx->cfg->in_use = 1;-- ctx->detail_memory = cfg->debugging;- ctx->debugging = cfg->debugging;- ctx->profiling = cfg->debugging;- ctx->logging = cfg->debugging;- ctx->error = NULL;- ctx->log = stderr;- context_setup(ctx);- $stms:init_fields- init_constants(ctx);- return ctx;- }|]- )-- GC.publicDef_ "context_free" GC.InitDecl $ \s ->- ( [C.cedecl|void $id:s(struct $id:ctx* ctx);|],- [C.cedecl|void $id:s(struct $id:ctx* ctx) {- $stms:free_fields- context_teardown(ctx);- ctx->cfg->in_use = 0;- free(ctx);- }|]- )-- GC.publicDef_ "context_sync" GC.MiscDecl $ \s ->- ( [C.cedecl|int $id:s(struct $id:ctx* ctx);|],- [C.cedecl|int $id:s(struct $id:ctx* ctx) {- (void)ctx;- return 0;- }|]- )-- GC.earlyDecl [C.cedecl|static const char *tuning_param_names[0];|]- GC.earlyDecl [C.cedecl|static const char *tuning_param_vars[0];|]- GC.earlyDecl [C.cedecl|static const char *tuning_param_classes[0];|]-- GC.publicDef_ "context_config_set_tuning_param" GC.InitDecl $ \s ->- ( [C.cedecl|int $id:s(struct $id:cfg* cfg, const char *param_name, size_t param_value);|],- [C.cedecl|int $id:s(struct $id:cfg* cfg, const char *param_name, size_t param_value) {- (void)cfg; (void)param_name; (void)param_value;- return 1;- }|]- )+ GC.earlyDecl [C.cedecl|static const int num_tuning_params = 0;|]+ GC.earlyDecl [C.cedecl|static const char *tuning_param_names[1];|]+ GC.earlyDecl [C.cedecl|static const char *tuning_param_vars[1];|]+ GC.earlyDecl [C.cedecl|static const char *tuning_param_classes[1];|]+ GC.earlyDecl [C.cedecl|static typename int64_t *tuning_param_defaults[1];|]+ GC.earlyDecl [C.cedecl|$esc:(T.unpack backendsCH)|]+ GC.generateProgramStruct+{-# NOINLINE generateBoilerplate #-}
src/Futhark/CodeGen/Backends/SimpleRep.hs view
@@ -18,6 +18,8 @@ primAPIType, arrayName, opaqueName,+ isValidCName,+ escapeName, toStorage, fromStorage, cproduct,@@ -35,7 +37,7 @@ where import Data.Bits (shiftR, xor)-import Data.Char (isAlphaNum, isDigit, ord)+import Data.Char (isAlpha, isAlphaNum, isDigit, ord) import Data.Text qualified as T import Futhark.CodeGen.ImpCode import Futhark.CodeGen.RTS.C (scalarF16H, scalarH)@@ -107,6 +109,21 @@ arrayName :: PrimType -> Signedness -> Int -> T.Text arrayName pt signed rank = prettySigned (signed == Unsigned) pt <> "_" <> prettyText rank <> "d"++-- | Is this name a valid C identifier? If not, it should be escaped+-- before being emitted into C.+isValidCName :: T.Text -> Bool+isValidCName = maybe True check . T.uncons+ where+ check (c, cs) = isAlpha c && T.all constituent cs+ constituent c = isAlphaNum c || c == '_'++-- | If the provided text is a valid C identifier, then return it+-- verbatim. Otherwise, escape it such that it becomes valid.+escapeName :: T.Text -> T.Text+escapeName v+ | isValidCName v = v+ | otherwise = zEncodeText v -- | The name of exposed opaque types. opaqueName :: Name -> T.Text
src/Futhark/CodeGen/ImpCode.hs view
@@ -99,6 +99,7 @@ import Data.Bifunctor (second) import Data.List (intersperse) import Data.Map qualified as M+import Data.Ord (comparing) import Data.Set qualified as S import Data.Text qualified as T import Data.Traversable@@ -121,6 +122,7 @@ ValueType (..), errorMsgArgTypes, )+import Futhark.Util (nubByOrd) import Futhark.Util.Pretty hiding (space) import Language.Futhark.Core import Language.Futhark.Primitive@@ -177,6 +179,13 @@ instance Functor Constants where fmap f (Constants params code) = Constants params (fmap f code) +instance Monoid (Constants a) where+ mempty = Constants mempty mempty++instance Semigroup (Constants a) where+ Constants ps1 c1 <> Constants ps2 c2 =+ Constants (nubByOrd (comparing (prettyString . paramName)) $ ps1 <> ps2) (c1 <> c2)+ -- | A description of an externally meaningful value. data ValueDesc = -- | An array with memory block memory space, element type,@@ -254,12 +263,10 @@ DeclareMem VName Space | -- | Declare a scalar variable with an initially undefined value. DeclareScalar VName Volatility PrimType- | -- | Create an array containing the given values. The- -- lifetime of the array will be the entire application.- -- This is mostly used for constant arrays, but also for- -- some bookkeeping data, like the synchronisation- -- counts used to implement reduction.- DeclareArray VName Space PrimType ArrayContents+ | -- | Create a DefaultSpace array containing the given values. The+ -- lifetime of the array will be the entire application. This is+ -- mostly used for constant arrays.+ DeclareArray VName PrimType ArrayContents | -- | Memory space must match the corresponding -- 'DeclareMem'. Allocate VName (Count Bytes (TExp Int64)) Space@@ -534,9 +541,9 @@ vol' = case vol of Volatile -> "volatile " Nonvolatile -> mempty- pretty (DeclareArray name space t vs) =+ pretty (DeclareArray name t vs) = "array"- <+> pretty name <> "@" <> pretty space+ <+> pretty name <+> ":" <+> pretty t <+> equals@@ -571,7 +578,7 @@ "assert" <> parens (commasep [pretty msg, pretty e]) pretty (Copy t dest destoffset destspace src srcoffset srcspace size) = "copy"- <> parens+ <> (parens . align) ( pretty t <> comma </> ppMemLoc dest destoffset <> pretty destspace <> comma </> ppMemLoc src srcoffset <> pretty srcspace <> comma@@ -652,8 +659,8 @@ pure $ DeclareMem name space traverse _ (DeclareScalar name vol bt) = pure $ DeclareScalar name vol bt- traverse _ (DeclareArray name space t vs) =- pure $ DeclareArray name space t vs+ traverse _ (DeclareArray name t vs) =+ pure $ DeclareArray name t vs traverse _ (Allocate name size s) = pure $ Allocate name size s traverse _ (Free name space) =@@ -684,7 +691,7 @@ declaredIn :: Code a -> Names declaredIn (DeclareMem name _) = oneName name declaredIn (DeclareScalar name _ _) = oneName name-declaredIn (DeclareArray name _ _ _) = oneName name+declaredIn (DeclareArray name _ _) = oneName name declaredIn (If _ t f) = declaredIn t <> declaredIn f declaredIn (x :>>: y) = declaredIn x <> declaredIn y declaredIn (For i _ body) = oneName i <> declaredIn body
src/Futhark/CodeGen/ImpGen.hs view
@@ -114,6 +114,7 @@ (<--), (<~~), function,+ genConstants, warn, module Language.Futhark.Warnings, )@@ -285,6 +286,7 @@ { stateVTable :: VTable rep, stateFunctions :: Imp.Functions op, stateCode :: Imp.Code op,+ stateConstants :: Imp.Constants op, stateWarnings :: Warnings, -- | Maps the arrays backing each accumulator to their -- update function and neutral elements. This works@@ -297,7 +299,7 @@ } newState :: VNameSource -> ImpState rep r op-newState = ImpState mempty mempty mempty mempty mempty+newState = ImpState mempty mempty mempty mempty mempty mempty newtype ImpM rep r op a = ImpM (ReaderT (Env rep r op) (State (ImpState rep r op)) a)@@ -370,6 +372,7 @@ stateFunctions = mempty, stateCode = mempty, stateNameSource = stateNameSource s,+ stateConstants = mempty, stateWarnings = mempty, stateAccs = stateAccs s }@@ -445,11 +448,14 @@ unzip $ parMap rpar (compileFunDef' src) funs free_in_funs = freeIn $ mconcat $ map stateFunctions ss- (consts', s') =+ ((), s') = runImpM (compileConsts free_in_funs consts) r ops space $ combineStates ss in ( ( stateWarnings s',- Imp.Definitions types consts' (stateFunctions s')+ Imp.Definitions+ types+ (stateConstants s' <> foldMap stateConstants ss)+ (stateFunctions s') ), stateNameSource s' )@@ -472,27 +478,10 @@ mconcat $ map stateWarnings ss } -compileConsts :: Names -> Stms rep -> ImpM rep r op (Imp.Constants op)-compileConsts used_consts stms = do- code <- collect $ compileStms used_consts stms $ pure ()- pure $ uncurry Imp.Constants $ first DL.toList $ extract code- where- -- Fish out those top-level declarations in the constant- -- initialisation code that are free in the functions.- extract (x Imp.:>>: y) =- extract x <> extract y- extract (Imp.DeclareMem name space)- | name `nameIn` used_consts =- ( DL.singleton $ Imp.MemParam name space,- mempty- )- extract (Imp.DeclareScalar name _ t)- | name `nameIn` used_consts =- ( DL.singleton $ Imp.ScalarParam name t,- mempty- )- extract s =- (mempty, s)+compileConsts :: Names -> Stms rep -> ImpM rep r op ()+compileConsts used_consts stms = genConstants $ do+ compileStms used_consts stms $ pure ()+ pure (used_consts, ()) lookupOpaqueType :: Name -> OpaqueTypes -> OpaqueType lookupOpaqueType v (OpaqueTypes types) =@@ -983,15 +972,13 @@ defCompileBasicOp (Pat [pe]) (ArrayLit es _) | Just vs@(v : _) <- mapM isLiteral es = do dest_mem <- entryArrayLoc <$> lookupArray (patElemName pe)- dest_space <- entryMemSpace <$> lookupMemory (memLocName dest_mem) let t = primValueType v static_array <- newVNameForFun "static_array"- emit $ Imp.DeclareArray static_array dest_space t $ Imp.ArrayValues vs+ emit $ Imp.DeclareArray static_array t $ Imp.ArrayValues vs let static_src = MemLoc static_array [intConst Int64 $ fromIntegral $ length es] $ IxFun.iota [fromIntegral $ length es]- entry = MemVar Nothing $ MemEntry dest_space- addVar static_array entry+ addVar static_array $ MemVar Nothing $ MemEntry DefaultSpace copy t dest_mem static_src | otherwise = forM_ (zip [0 ..] es) $ \(i, e) ->@@ -1877,15 +1864,15 @@ sAllocArrayPerm name pt shape space [0 .. shapeRank shape - 1] -- | Uses linear/iota index function.-sStaticArray :: String -> Space -> PrimType -> Imp.ArrayContents -> ImpM rep r op VName-sStaticArray name space pt vs = do+sStaticArray :: String -> PrimType -> Imp.ArrayContents -> ImpM rep r op VName+sStaticArray name pt vs = do let num_elems = case vs of Imp.ArrayValues vs' -> length vs' Imp.ArrayZeros n -> fromIntegral n shape = Shape [intConst Int64 $ toInteger num_elems] mem <- newVNameForFun $ name ++ "_mem"- emit $ Imp.DeclareArray mem space pt vs- addVar mem $ MemVar Nothing $ MemEntry space+ emit $ Imp.DeclareArray mem pt vs+ addVar mem $ MemVar Nothing $ MemEntry DefaultSpace sArray name pt shape mem $ IxFun.iota [fromIntegral num_elems] sWrite :: VName -> [Imp.TExp Int64] -> Imp.Exp -> ImpM rep r op ()@@ -1973,6 +1960,40 @@ addParam (Imp.ScalarParam name bt) = addVar name $ ScalarVar Nothing $ ScalarEntry bt newFunction env = env {envFunction = Just fname}++-- Fish out those top-level declarations in the constant+-- initialisation code that are free in the functions.+constParams :: Names -> Imp.Code a -> (DL.DList Imp.Param, Imp.Code a)+constParams used (x Imp.:>>: y) =+ constParams used x <> constParams used y+constParams used (Imp.DeclareMem name space)+ | name `nameIn` used =+ ( DL.singleton $ Imp.MemParam name space,+ mempty+ )+constParams used (Imp.DeclareScalar name _ t)+ | name `nameIn` used =+ ( DL.singleton $ Imp.ScalarParam name t,+ mempty+ )+constParams used s@(Imp.DeclareArray name _ _)+ | name `nameIn` used =+ ( DL.singleton $ Imp.MemParam name DefaultSpace,+ s+ )+constParams _ s =+ (mempty, s)++-- | Generate constants that get put outside of all functions. Will+-- be executed at program startup. Action must return the names that+-- should should be made available. This one has real sharp edges. Do+-- not use inside 'subImpM'. Do not use any variable from the context.+genConstants :: ImpM rep r op (Names, a) -> ImpM rep r op a+genConstants m = do+ ((avail, a), code) <- collect' m+ let consts = uncurry Imp.Constants $ first DL.toList $ constParams avail code+ modify $ \s -> s {stateConstants = stateConstants s <> consts}+ pure a dSlices :: [Imp.TExp Int64] -> ImpM rep r op [Imp.TExp Int64] dSlices = fmap (drop 1 . snd) . dSlices'
src/Futhark/CodeGen/ImpGen/GPU.hs view
@@ -12,7 +12,6 @@ where import Control.Monad.Except-import Data.Bifunctor (second) import Data.List (foldl') import Data.Map qualified as M import Data.Maybe@@ -25,7 +24,6 @@ import Futhark.CodeGen.ImpGen.GPU.SegRed import Futhark.CodeGen.ImpGen.GPU.SegScan import Futhark.CodeGen.ImpGen.GPU.Transpose-import Futhark.CodeGen.SetDefaultSpace import Futhark.Error import Futhark.IR.GPUMem import Futhark.IR.Mem.IxFun qualified as IxFun@@ -78,19 +76,10 @@ HostEnv -> Prog GPUMem -> m (Warnings, Imp.Program)-compileProg env prog =- second (fmap setOpSpace . setDefaultSpace device_space)- <$> Futhark.CodeGen.ImpGen.compileProg env callKernelOperations device_space prog+compileProg env =+ Futhark.CodeGen.ImpGen.compileProg env callKernelOperations device_space where device_space = Imp.Space "device"- global_space = Imp.Space "global"- setOpSpace (Imp.CallKernel kernel) =- Imp.CallKernel- kernel- { Imp.kernelBody =- setDefaultCodeSpace global_space $ Imp.kernelBody kernel- }- setOpSpace op = op -- | Compile a 'GPUMem' program to low-level parallel code, with -- either CUDA or OpenCL characteristics.@@ -228,9 +217,7 @@ | Just (op_lam, _) <- op, AtomicLocking _ <- atomicUpdateLocking atomics op_lam = do let num_locks = 100151- locks_arr <-- sStaticArray "withacc_locks" (Space "device") int32 $- Imp.ArrayZeros num_locks+ locks_arr <- genZeroes "withacc_locks" num_locks let locks = Locks locks_arr num_locks extend env = env {hostLocks = M.insert c locks $ hostLocks env} localEnv extend $ locksForInputs atomics inputs'
src/Futhark/CodeGen/ImpGen/GPU/Base.hs view
@@ -29,6 +29,7 @@ groupCoverSpace, fenceForArrays, updateAcc,+ genZeroes, -- * Host-level bulk operations sReplicate,@@ -161,6 +162,16 @@ f locking space arrs is' Nothing -> error $ "Missing locks for " ++ prettyString acc++-- | Generate a constant device array of 32-bit integer zeroes with+-- the given number of elements. Initialised with a replicate.+genZeroes :: String -> Int -> CallKernelGen VName+genZeroes desc n = genConstants $ do+ counters_mem <- sAlloc (desc <> "_mem") (4 * fromIntegral n) (Space "device")+ let shape = Shape [intConst Int64 (fromIntegral n)]+ counters <- sArrayInMem desc int32 shape counters_mem+ sReplicate counters $ intConst Int32 0+ pure (namesFromList [counters_mem], counters) compileThreadExp :: ExpCompiler GPUMem KernelEnv Imp.KernelOp compileThreadExp (Pat [pe]) (BasicOp (Opaque _ se)) =
src/Futhark/CodeGen/ImpGen/GPU/SegHist.hs view
@@ -185,9 +185,7 @@ ++ [tvSize (slugNumSubhistos slug)] ++ shapeDims (histShape (slugOp slug)) - locks <-- sStaticArray "hist_locks" (Space "device") int32 $- Imp.ArrayZeros num_locks+ locks <- genZeroes "hist_locks" num_locks let l' = Locking locks 0 1 0 (pure . (`rem` fromIntegral num_locks) . flattenIndex dims) pure (Just l', f l' (Space "global") dests) @@ -724,8 +722,8 @@ sOp $ Imp.Barrier Imp.FenceLocal - kernelLoop pgtid_in_segment threads_per_segment (sExt32 segment_size') $ \ie -> do- dPrimV_ i_in_segment $ sExt64 ie+ kernelLoop (sExt64 pgtid_in_segment) (sExt64 threads_per_segment) segment_size' $ \ie -> do+ dPrimV_ i_in_segment ie -- We execute the bucket function once and update each histogram -- serially. This also involves writing to the mapout arrays if
src/Futhark/CodeGen/ImpGen/GPU/SegRed.hs view
@@ -189,9 +189,7 @@ global_tid = Imp.le64 $ segFlat space w = last dims' - counter <-- sStaticArray "counter" (Space "device") int32 $- Imp.ArrayZeros (fromIntegral maxNumOps)+ counter <- genZeroes "counters" $ fromIntegral maxNumOps reds_group_res_arrs <- groupResultArrays num_groups group_size reds @@ -430,9 +428,7 @@ -- if the group count exceeds the maximum group size, which is at -- most 1024 anyway. let num_counters = fromIntegral maxNumOps * 1024- counter <-- sStaticArray "counter" (Space "device") int32 $- Imp.ArrayZeros num_counters+ counter <- genZeroes "counters" num_counters sKernelThread "segred_large" (segFlat space) (defKernelAttrs num_groups group_size) $ do constants <- kernelConstants <$> askEnv
src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs view
@@ -260,7 +260,7 @@ emit $ Imp.DebugPrint "Register constraint" $ Just $ untyped (fromIntegral reg_constraint :: Imp.TExp Int32) emit $ Imp.DebugPrint "sumT'" $ Just $ untyped (fromIntegral sumT' :: Imp.TExp Int32) - globalId <- sStaticArray "id_counter" (Space "device") int32 $ Imp.ArrayZeros 1+ globalId <- genZeroes "id_counter" 1 statusFlags <- sAllocArray "status_flags" int8 (Shape [unCount num_groups]) (Space "device") (aggregateArrays, incprefixArrays) <- fmap unzip $
src/Futhark/CodeGen/ImpGen/GPU/ToOpenCL.hs view
@@ -96,14 +96,18 @@ SizeThreshold (filter ((`elem` known) . fst) path) def clean s = s -pointerQuals :: Monad m => String -> m [C.TypeQual]-pointerQuals "global" = pure [C.ctyquals|__global|]-pointerQuals "local" = pure [C.ctyquals|__local|]-pointerQuals "private" = pure [C.ctyquals|__private|]-pointerQuals "constant" = pure [C.ctyquals|__constant|]-pointerQuals "write_only" = pure [C.ctyquals|__write_only|]-pointerQuals "read_only" = pure [C.ctyquals|__read_only|]-pointerQuals "kernel" = pure [C.ctyquals|__kernel|]+pointerQuals :: String -> [C.TypeQual]+pointerQuals "global" = [C.ctyquals|__global|]+pointerQuals "local" = [C.ctyquals|__local|]+pointerQuals "private" = [C.ctyquals|__private|]+pointerQuals "constant" = [C.ctyquals|__constant|]+pointerQuals "write_only" = [C.ctyquals|__write_only|]+pointerQuals "read_only" = [C.ctyquals|__read_only|]+pointerQuals "kernel" = [C.ctyquals|__kernel|]+-- OpenCL does not actually have a "device" space, but we use it in+-- the compiler pipeline to defer to memory on the device, as opposed+-- to the host. From a kernel's perspective, this is "global".+pointerQuals "device" = pointerQuals "global" pointerQuals s = error $ "'" ++ s ++ "' is not an OpenCL kernel address space." -- In-kernel name and per-workgroup size in bytes.@@ -348,13 +352,17 @@ let (use_params, unpack_params) = unzip $ mapMaybe useAsParam $ kernelUses kernel + -- The local_failure variable is an int despite only really storing+ -- a single bit of information, as some OpenCL implementations+ -- (e.g. AMD) does not like byte-sized local memory (and the others+ -- likely pad to a whole word anyway). let (safety, error_init) -- We conservatively assume that any called function can fail. | not $ null called = ( SafetyFull,- [C.citems|volatile __local bool local_failure;+ [C.citems|volatile __local int local_failure; // Harmless for all threads to write this.- local_failure = false;|]+ local_failure = 0;|] ) | length (kernelFailures kstate) == length failures = if kernelFailureTolerant kernel@@ -374,7 +382,7 @@ else ( SafetyFull, [C.citems|- volatile __local bool local_failure;+ volatile __local int local_failure; if (failure_is_an_option) { int failed = *global_failure >= 0; if (failed) {@@ -382,7 +390,7 @@ } } // All threads write this value - it looks like CUDA has a compiler bug otherwise.- local_failure = false;+ local_failure = 0; barrier(CLK_LOCAL_MEM_FENCE); |] )@@ -696,7 +704,6 @@ GC.opsAllocate = cannotAllocate, GC.opsDeallocate = cannotDeallocate, GC.opsCopy = copyInKernel,- GC.opsStaticArray = noStaticArrays, GC.opsFatMemory = False, GC.opsError = errorInKernel, GC.opsCall = callInKernel,@@ -743,9 +750,9 @@ atomicCast s t = do let volatile = [C.ctyquals|volatile|]- quals <- case s of- Space sid -> pointerQuals sid- _ -> pointerQuals "global"+ let quals = case s of+ Space sid -> pointerQuals sid+ _ -> pointerQuals "global" pure [C.cty|$tyquals:(volatile++quals) $ty:t|] atomicSpace (Space sid) = sid@@ -833,13 +840,8 @@ copyInKernel _ _ _ _ _ _ _ _ = error "Cannot bulk copy in kernel." - noStaticArrays :: GC.StaticArray KernelOp KernelState- noStaticArrays _ _ _ _ =- error "Cannot create static array in kernel."-- kernelMemoryType space = do- quals <- pointerQuals space- pure [C.cty|$tyquals:quals $ty:defaultMemBlockType|]+ kernelMemoryType space =+ pure [C.cty|$tyquals:(pointerQuals space) $ty:defaultMemBlockType|] kernelWriteScalar = GC.writeScalarPointerWithQuals pointerQuals@@ -852,7 +854,7 @@ pendingError True pure $ if has_communication- then [C.citems|local_failure = true; goto $id:label;|]+ then [C.citems|local_failure = 1; goto $id:label;|] else if mode == FunMode then [C.citems|return 1;|]@@ -907,7 +909,7 @@ typesInCode (While (TPrimExp e) c) = typesInExp e <> typesInCode c typesInCode DeclareMem {} = mempty typesInCode (DeclareScalar _ _ t) = S.singleton t-typesInCode (DeclareArray _ _ t _) = S.singleton t+typesInCode (DeclareArray _ t _) = S.singleton t typesInCode (Allocate _ (Count (TPrimExp e)) _) = typesInExp e typesInCode Free {} = mempty typesInCode (Copy _ _ (Count (TPrimExp e1)) _ _ (Count (TPrimExp e2)) _ (Count (TPrimExp e3))) =
src/Futhark/CodeGen/ImpGen/Multicore.hs view
@@ -105,8 +105,7 @@ AtomicLocking _ <- atomicUpdateLocking atomics op_lam = do let num_locks = 100151 locks_arr <-- sStaticArray "withacc_locks" DefaultSpace int32 $- Imp.ArrayZeros num_locks+ sStaticArray "withacc_locks" int32 $ Imp.ArrayZeros num_locks let locks = Locks locks_arr num_locks extend env = env {hostLocks = M.insert c locks $ hostLocks env} localEnv extend $ locksForInputs atomics inputs'@@ -123,9 +122,9 @@ compileMCOp :: Pat LetDecMem ->- MCOp MCMem () ->+ MCOp NoOp MCMem -> ImpM MCMem HostEnv Imp.Multicore ()-compileMCOp _ (OtherOp ()) = pure ()+compileMCOp _ (OtherOp NoOp) = pure () compileMCOp pat (ParOp par_op op) = do let space = getSpace op dPrimV_ (segFlat space) (0 :: Imp.TExp Int64)
src/Futhark/CodeGen/ImpGen/Multicore/SegHist.hs view
@@ -96,7 +96,7 @@ let num_locks = 100151 -- This number is taken from the GPU backend dims = map pe64 $ shapeDims (histOpShape op <> histShape op) locks <-- sStaticArray "hist_locks" DefaultSpace int32 $+ sStaticArray "hist_locks" int32 $ Imp.ArrayZeros num_locks let l' = Locking locks 0 1 0 (pure . (`rem` fromIntegral num_locks) . flattenIndex dims) pure $ f l'
src/Futhark/CodeGen/ImpGen/Sequential.hs view
@@ -19,4 +19,4 @@ ops = ImpGen.defaultOperations opCompiler opCompiler dest (Alloc e space) = ImpGen.compileAlloc dest e space- opCompiler _ (Inner ()) = pure ()+ opCompiler _ (Inner NoOp) = pure ()
src/Futhark/CodeGen/RTS/C.hs view
@@ -5,11 +5,9 @@ ( atomicsH, contextH, contextPrototypesH,- cudaH, freeListH, halfH, lockH,- openclH, scalarF16H, scalarH, schedulerH,@@ -22,6 +20,10 @@ cacheH, uniformH, ispcUtilH,+ backendsOpenclH,+ backendsCudaH,+ backendsCH,+ backendsMulticoreH, ) where @@ -41,11 +43,6 @@ uniformH = $(embedStringFile "rts/c/uniform.h") {-# NOINLINE uniformH #-} --- | @rts/c/cuda.h@-cudaH :: T.Text-cudaH = $(embedStringFile "rts/c/cuda.h")-{-# NOINLINE cudaH #-}- -- | @rts/c/free_list.h@ freeListH :: T.Text freeListH = $(embedStringFile "rts/c/free_list.h")@@ -61,11 +58,6 @@ lockH = $(embedStringFile "rts/c/lock.h") {-# NOINLINE lockH #-} --- | @rts/c/opencl.h@-openclH :: T.Text-openclH = $(embedStringFile "rts/c/opencl.h")-{-# NOINLINE openclH #-}- -- | @rts/c/scalar_f16.h@ scalarF16H :: T.Text scalarF16H = $(embedStringFile "rts/c/scalar_f16.h")@@ -130,3 +122,23 @@ contextPrototypesH :: T.Text contextPrototypesH = $(embedStringFile "rts/c/context_prototypes.h") {-# NOINLINE contextPrototypesH #-}++-- | @rts/c/backends/opencl.h@+backendsOpenclH :: T.Text+backendsOpenclH = $(embedStringFile "rts/c/backends/opencl.h")+{-# NOINLINE backendsOpenclH #-}++-- | @rts/c/backends/cuda.h@+backendsCudaH :: T.Text+backendsCudaH = $(embedStringFile "rts/c/backends/cuda.h")+{-# NOINLINE backendsCudaH #-}++-- | @rts/c/backends/c.h@+backendsCH :: T.Text+backendsCH = $(embedStringFile "rts/c/backends/c.h")+{-# NOINLINE backendsCH #-}++-- | @rts/c/backends/multicore.h@+backendsMulticoreH :: T.Text+backendsMulticoreH = $(embedStringFile "rts/c/backends/multicore.h")+{-# NOINLINE backendsMulticoreH #-}
− src/Futhark/CodeGen/SetDefaultSpace.hs
@@ -1,112 +0,0 @@--- | Change 'DefaultSpace' in a program to some other memory space.--- This is needed because the GPU backends use 'DefaultSpace' to refer--- to GPU memory for most of the pipeline, but final code generation--- assumes that 'DefaultSpace' is CPU memory.-module Futhark.CodeGen.SetDefaultSpace- ( setDefaultSpace,- setDefaultCodeSpace,- )-where--import Futhark.CodeGen.ImpCode---- | Set all uses of 'DefaultSpace' in the given definitions to another--- memory space.-setDefaultSpace :: Space -> Definitions op -> Definitions op-setDefaultSpace space (Definitions types (Constants ps consts) (Functions fundecs)) =- Definitions- types- (Constants (map (setParamSpace space) ps) (setCodeSpace space consts))- ( Functions- [ (fname, setFunctionSpace space func)- | (fname, func) <- fundecs- ]- )---- | Like 'setDefaultSpace', but for 'Code'.-setDefaultCodeSpace :: Space -> Code op -> Code op-setDefaultCodeSpace = setCodeSpace--setFunctionSpace :: Space -> Function op -> Function op-setFunctionSpace space (Function entry outputs inputs body) =- Function- (setEntrySpace space <$> entry)- (map (setParamSpace space) outputs)- (map (setParamSpace space) inputs)- (setCodeSpace space body)--setEntrySpace :: Space -> EntryPoint -> EntryPoint-setEntrySpace space (EntryPoint name results args) =- EntryPoint- name- (map (fmap $ setExtValueSpace space) results)- (map (fmap $ setExtValueSpace space) args)--setParamSpace :: Space -> Param -> Param-setParamSpace space (MemParam name DefaultSpace) =- MemParam name space-setParamSpace _ param =- param--setExtValueSpace :: Space -> ExternalValue -> ExternalValue-setExtValueSpace space (OpaqueValue desc vs) =- OpaqueValue desc $ map (setValueSpace space) vs-setExtValueSpace space (TransparentValue v) =- TransparentValue $ setValueSpace space v--setValueSpace :: Space -> ValueDesc -> ValueDesc-setValueSpace space (ArrayValue mem _ bt ept shape) =- ArrayValue mem space bt ept shape-setValueSpace _ (ScalarValue bt ept v) =- ScalarValue bt ept v--setCodeSpace :: Space -> Code op -> Code op-setCodeSpace space (Allocate v e old_space) =- Allocate v e $ setSpace space old_space-setCodeSpace space (Free v old_space) =- Free v $ setSpace space old_space-setCodeSpace space (DeclareMem name old_space) =- DeclareMem name $ setSpace space old_space-setCodeSpace space (DeclareArray name _ t vs) =- DeclareArray name space t vs-setCodeSpace space (Copy t dest dest_offset dest_space src src_offset src_space n) =- Copy t dest dest_offset dest_space' src src_offset src_space' n- where- dest_space' = setSpace space dest_space- src_space' = setSpace space src_space-setCodeSpace space (Write dest dest_offset bt dest_space vol e) =- Write dest dest_offset bt (setSpace space dest_space) vol e-setCodeSpace space (Read x dest dest_offset bt dest_space vol) =- Read x dest dest_offset bt (setSpace space dest_space) vol-setCodeSpace space (c1 :>>: c2) =- setCodeSpace space c1 :>>: setCodeSpace space c2-setCodeSpace space (For i e body) =- For i e $ setCodeSpace space body-setCodeSpace space (While e body) =- While e $ setCodeSpace space body-setCodeSpace space (If e c1 c2) =- If e (setCodeSpace space c1) (setCodeSpace space c2)-setCodeSpace space (Comment s c) =- Comment s $ setCodeSpace space c-setCodeSpace _ Skip =- Skip-setCodeSpace _ (DeclareScalar name vol bt) =- DeclareScalar name vol bt-setCodeSpace _ (SetScalar name e) =- SetScalar name e-setCodeSpace space (SetMem to from old_space) =- SetMem to from $ setSpace space old_space-setCodeSpace _ (Call dests fname args) =- Call dests fname args-setCodeSpace _ (Assert e msg loc) =- Assert e msg loc-setCodeSpace _ (DebugPrint s v) =- DebugPrint s v-setCodeSpace _ (TracePrint msg) =- TracePrint msg-setCodeSpace _ (Op op) =- Op op--setSpace :: Space -> Space -> Space-setSpace space DefaultSpace = space-setSpace _ space = space
src/Futhark/Doc/Generator.hs view
@@ -113,7 +113,7 @@ vnameToFileMap :: Imports -> FileMap vnameToFileMap = mconcat . map forFile where- forFile (file, FileModule abs file_env _prog) =+ forFile (file, FileModule abs file_env _prog _) = mconcat (map (vname Type) (M.keys abs)) <> forEnv file_env where@@ -436,7 +436,7 @@ ps' <- modParamHtml ps pure $ specRow (keyword "module " <> name') ": " (ps' <> sig') - FileModule _abs Env {envModTable = modtable} _ = fm+ FileModule _abs Env {envModTable = modtable} _ _ = fm envSig (ModEnv e) = renderEnv e envSig (ModFun (FunSig _ _ (MTy _ m))) = envSig m
src/Futhark/IR/Aliases.hs view
@@ -28,6 +28,8 @@ mkAliasedBody, mkAliasedPat, mkBodyAliasing,+ CanBeAliased (..),+ AliasableRep, -- * Removing aliases removeProgAliases,@@ -49,9 +51,9 @@ import Control.Monad.Identity import Control.Monad.Reader+import Data.Kind qualified import Data.Map.Strict qualified as M import Data.Maybe-import Futhark.Analysis.Rephrase import Futhark.Builder import Futhark.IR.Pretty import Futhark.IR.Prop@@ -63,7 +65,7 @@ import Futhark.Util.Pretty qualified as PP -- | The rep for the basic representation.-data Aliases rep+data Aliases (rep :: Data.Kind.Type) -- | A wrapper around 'AliasDec' to get around the fact that we need an -- 'Ord' instance, which 'AliasDec does not have.@@ -104,7 +106,7 @@ -- consumed inside of it. type BodyAliasing = ([VarAliases], ConsumedInExp) -instance (RepTypes rep, CanBeAliased (Op rep)) => RepTypes (Aliases rep) where+instance (RepTypes rep, ASTConstraints (OpC rep (Aliases rep))) => RepTypes (Aliases rep) where type LetDec (Aliases rep) = (VarAliases, LetDec rep) type ExpDec (Aliases rep) = (ConsumedInExp, ExpDec rep) type BodyDec (Aliases rep) = (BodyAliasing, BodyDec rep)@@ -112,7 +114,7 @@ type LParamInfo (Aliases rep) = LParamInfo rep type RetType (Aliases rep) = RetType rep type BranchType (Aliases rep) = BranchType rep- type Op (Aliases rep) = OpWithAliases (Op rep)+ type OpC (Aliases rep) = OpC rep instance AliasesOf (VarAliases, dec) where aliasesOf = unAliases . fst@@ -127,15 +129,15 @@ scope <- asksScope removeScopeAliases runReaderT m scope -instance (ASTRep rep, CanBeAliased (Op rep)) => ASTRep (Aliases rep) where+instance (ASTRep rep, AliasedOp (OpC rep (Aliases rep))) => ASTRep (Aliases rep) where expTypesFromPat = withoutAliases . expTypesFromPat . removePatAliases -instance (ASTRep rep, CanBeAliased (Op rep)) => Aliased (Aliases rep) where+instance (ASTRep rep, AliasedOp (OpC rep (Aliases rep))) => Aliased (Aliases rep) where bodyAliases = map unAliases . fst . fst . bodyDec consumedInBody = unAliases . snd . fst . bodyDec -instance (ASTRep rep, CanBeAliased (Op rep)) => PrettyRep (Aliases rep) where+instance (ASTRep rep, AliasedOp (OpC rep (Aliases rep))) => PrettyRep (Aliases rep) where ppExpDec (consumed, inner) e = maybeComment . catMaybes $ [exp_dec, merge_dec, ppExpDec inner $ removeExpAliases e]@@ -176,7 +178,7 @@ <> " aliases " <> PP.commasep (map PP.pretty als') -removeAliases :: CanBeAliased (Op rep) => Rephraser Identity (Aliases rep) rep+removeAliases :: RephraseOp (OpC rep) => Rephraser Identity (Aliases rep) rep removeAliases = Rephraser { rephraseExpDec = pure . snd,@@ -186,7 +188,7 @@ rephraseLParamDec = pure, rephraseRetType = pure, rephraseBranchType = pure,- rephraseOp = pure . removeOpAliases+ rephraseOp = rephraseInOp removeAliases } -- | Remove alias information from an aliased scope.@@ -200,42 +202,42 @@ -- | Remove alias information from a program. removeProgAliases ::- CanBeAliased (Op rep) =>+ RephraseOp (OpC rep) => Prog (Aliases rep) -> Prog rep removeProgAliases = runIdentity . rephraseProg removeAliases -- | Remove alias information from a function. removeFunDefAliases ::- CanBeAliased (Op rep) =>+ RephraseOp (OpC rep) => FunDef (Aliases rep) -> FunDef rep removeFunDefAliases = runIdentity . rephraseFunDef removeAliases -- | Remove alias information from an expression. removeExpAliases ::- CanBeAliased (Op rep) =>+ RephraseOp (OpC rep) => Exp (Aliases rep) -> Exp rep removeExpAliases = runIdentity . rephraseExp removeAliases -- | Remove alias information from statements. removeStmAliases ::- CanBeAliased (Op rep) =>+ RephraseOp (OpC rep) => Stm (Aliases rep) -> Stm rep removeStmAliases = runIdentity . rephraseStm removeAliases -- | Remove alias information from body. removeBodyAliases ::- CanBeAliased (Op rep) =>+ RephraseOp (OpC rep) => Body (Aliases rep) -> Body rep removeBodyAliases = runIdentity . rephraseBody removeAliases -- | Remove alias information from lambda. removeLambdaAliases ::- CanBeAliased (Op rep) =>+ RephraseOp (OpC rep) => Lambda (Aliases rep) -> Lambda rep removeLambdaAliases = runIdentity . rephraseLambda removeAliases@@ -249,7 +251,7 @@ -- | Augment a body decoration with aliasing information provided by -- the statements and result of that body. mkAliasedBody ::- (ASTRep rep, CanBeAliased (Op rep)) =>+ (ASTRep rep, AliasedOp (OpC rep (Aliases rep))) => BodyDec rep -> Stms (Aliases rep) -> Result ->@@ -264,26 +266,22 @@ Pat dec -> Exp rep -> Pat (VarAliases, dec)-mkAliasedPat pat e = Pat $ zipWith annotatePatElem (patElems pat) als+mkAliasedPat (Pat pes) e =+ Pat $ zipWith annotate pes $ expAliases pes e where- -- Repeat mempty in case the pattern has more elements (this- -- implies a type error).- als = expAliases e ++ repeat mempty- annotatePatElem bindee names =- bindee `setPatElemDec` (AliasDec names', patElemDec bindee)+ annotate (PatElem v dec) names = PatElem v (AliasDec names', dec) where names' =- case patElemType bindee of+ case typeOf dec of Array {} -> names Mem _ -> names _ -> mempty -- | Given statements (with aliasing information) and a body result, -- produce aliasing information for the corresponding body as a whole.--- This is basically just looking up the aliasing of each element of--- the result, and removing the names that are no longer in scope.--- Note that this does *not* include aliases of results that are not--- bound in the statements!+-- The aliasing includes names bound in the body, i.e. which are not+-- in scope outside of it. Note that this does *not* include aliases+-- of results that are not bound in the statements! mkBodyAliasing :: Aliased rep => Stms rep ->@@ -296,9 +294,8 @@ -- bound in stms. let (aliases, consumed) = mkStmsAliases stms res boundNames = foldMap (namesFromList . patNames . stmPat) stms- aliases' = map (`namesSubtract` boundNames) aliases consumed' = consumed `namesSubtract` boundNames- in (map AliasDec aliases', AliasDec consumed')+ in (map AliasDec aliases, AliasDec consumed') -- | The aliases of the result and everything consumed in the given -- statements.@@ -360,7 +357,7 @@ look k = M.findWithDefault mempty k aliasmap mkAliasedStm ::- (ASTRep rep, CanBeAliased (Op rep)) =>+ (ASTRep rep, AliasedOp (OpC rep (Aliases rep))) => Pat (LetDec rep) -> StmAux (ExpDec rep) -> Exp (Aliases rep) ->@@ -371,7 +368,7 @@ (StmAux cs attrs (AliasDec $ consumedInExp e, dec)) e -instance (Buildable rep, CanBeAliased (Op rep)) => Buildable (Aliases rep) where+instance (Buildable rep, AliasedOp (OpC rep (Aliases rep))) => Buildable (Aliases rep) where mkExpDec pat e = let dec = mkExpDec (removePatAliases pat) $ removeExpAliases e in (AliasDec $ consumedInExp e, dec)@@ -391,7 +388,26 @@ instance ( ASTRep rep,- CanBeAliased (Op rep),+ AliasedOp (OpC rep (Aliases rep)), Buildable (Aliases rep) ) => BuilderOps (Aliases rep)++-- | What we require of an aliasable representation.+type AliasableRep rep =+ ( ASTRep rep,+ RephraseOp (OpC rep),+ CanBeAliased (OpC rep),+ AliasedOp (OpC rep (Aliases rep))+ )++-- | The class of operations that can be given aliasing information.+-- This is a somewhat subtle concept that is only used in the+-- simplifier and when using "rep adapters".+class CanBeAliased op where+ -- | Add aliases to this op.+ addOpAliases ::+ AliasableRep rep => AliasTable -> op rep -> op (Aliases rep)++instance CanBeAliased NoOp where+ addOpAliases _ NoOp = NoOp
src/Futhark/IR/GPU.hs view
@@ -17,6 +17,7 @@ import Futhark.Builder import Futhark.Construct+import Futhark.IR.Aliases (Aliases) import Futhark.IR.GPU.Op import Futhark.IR.GPU.Sizes import Futhark.IR.Pretty@@ -30,18 +31,21 @@ data GPU instance RepTypes GPU where- type Op GPU = HostOp GPU (SOAC GPU)+ type OpC GPU = HostOp SOAC instance ASTRep GPU where expTypesFromPat = pure . expExtTypesFromPat -instance TC.CheckableOp GPU where+instance TC.Checkable GPU where checkOp = typeCheckGPUOp Nothing where+ -- GHC 9.2 goes into an infinite loop without the type annotation.+ typeCheckGPUOp ::+ Maybe SegLevel ->+ HostOp SOAC (Aliases GPU) ->+ TC.TypeM GPU () typeCheckGPUOp lvl = typeCheckHostOp (typeCheckGPUOp . Just) lvl typeCheckSOAC--instance TC.Checkable GPU instance Buildable GPU where mkBody = Body ()
src/Futhark/IR/GPU/Op.hs view
@@ -30,7 +30,7 @@ import Futhark.Analysis.Metrics import Futhark.Analysis.SymbolTable qualified as ST import Futhark.IR-import Futhark.IR.Aliases (Aliases, removeBodyAliases)+import Futhark.IR.Aliases (Aliases, CanBeAliased (..)) import Futhark.IR.GPU.Sizes import Futhark.IR.Prop.Aliases import Futhark.IR.SegOp@@ -239,11 +239,11 @@ TC.require [Prim int64] group_size -- | A host-level operation; parameterised by what else it can do.-data HostOp rep op+data HostOp op rep = -- | A segmented operation. SegOp (SegOp SegLevel rep) | SizeOp SizeOp- | OtherOp op+ | OtherOp (op rep) | -- | Code to run sequentially on the GPU, -- in a single thread. GPUBody [Type] (Body rep)@@ -252,8 +252,8 @@ -- | A helper for defining 'TraverseOpStms'. traverseHostOpStms :: Monad m =>- OpStmsTraverser m op rep ->- OpStmsTraverser m (HostOp rep op) rep+ OpStmsTraverser m (op rep) rep ->+ OpStmsTraverser m (HostOp op rep) rep traverseHostOpStms _ f (SegOp segop) = SegOp <$> traverseSegOpStms f segop traverseHostOpStms _ _ (SizeOp sizeop) = pure $ SizeOp sizeop traverseHostOpStms onOtherOp f (OtherOp other) = OtherOp <$> onOtherOp f other@@ -261,7 +261,7 @@ stms <- f mempty $ bodyStms body pure $ GPUBody ts $ body {bodyStms = stms} -instance (ASTRep rep, Substitute op) => Substitute (HostOp rep op) where+instance (ASTRep rep, Substitute (op rep)) => Substitute (HostOp op rep) where substituteNames substs (SegOp op) = SegOp $ substituteNames substs op substituteNames substs (OtherOp op) =@@ -271,13 +271,13 @@ substituteNames substs (GPUBody ts body) = GPUBody (substituteNames substs ts) (substituteNames substs body) -instance (ASTRep rep, Rename op) => Rename (HostOp rep op) where+instance (ASTRep rep, Rename (op rep)) => Rename (HostOp op rep) where rename (SegOp op) = SegOp <$> rename op rename (OtherOp op) = OtherOp <$> rename op rename (SizeOp op) = SizeOp <$> rename op rename (GPUBody ts body) = GPUBody <$> rename ts <*> rename body -instance (ASTRep rep, IsOp op) => IsOp (HostOp rep op) where+instance (ASTRep rep, IsOp (op rep)) => IsOp (HostOp op rep) where safeOp (SegOp op) = safeOp op safeOp (OtherOp op) = safeOp op safeOp (SizeOp op) = safeOp op@@ -291,14 +291,14 @@ -- transfer scalars to device. SQ.null (bodyStms body) && all ((== 0) . arrayRank) types -instance TypedOp op => TypedOp (HostOp rep op) where+instance TypedOp (op rep) => TypedOp (HostOp op rep) where opType (SegOp op) = opType op opType (OtherOp op) = opType op opType (SizeOp op) = opType op opType (GPUBody ts _) = pure $ staticShapes $ map (`arrayOfRow` intConst Int64 1) ts -instance (Aliased rep, AliasedOp op, ASTRep rep) => AliasedOp (HostOp rep op) where+instance (Aliased rep, AliasedOp (op rep)) => AliasedOp (HostOp op rep) where opAliases (SegOp op) = opAliases op opAliases (OtherOp op) = opAliases op opAliases (SizeOp op) = opAliases op@@ -309,56 +309,48 @@ consumedInOp (SizeOp op) = consumedInOp op consumedInOp (GPUBody _ body) = consumedInBody body -instance (ASTRep rep, FreeIn op) => FreeIn (HostOp rep op) where+instance (ASTRep rep, FreeIn (op rep)) => FreeIn (HostOp op rep) where freeIn' (SegOp op) = freeIn' op freeIn' (OtherOp op) = freeIn' op freeIn' (SizeOp op) = freeIn' op freeIn' (GPUBody ts body) = freeIn' ts <> freeIn' body -instance (CanBeAliased (Op rep), CanBeAliased op, ASTRep rep) => CanBeAliased (HostOp rep op) where- type OpWithAliases (HostOp rep op) = HostOp (Aliases rep) (OpWithAliases op)-+instance CanBeAliased op => CanBeAliased (HostOp op) where addOpAliases aliases (SegOp op) = SegOp $ addOpAliases aliases op addOpAliases aliases (GPUBody ts body) = GPUBody ts $ Alias.analyseBody aliases body addOpAliases aliases (OtherOp op) = OtherOp $ addOpAliases aliases op addOpAliases _ (SizeOp op) = SizeOp op - removeOpAliases (SegOp op) = SegOp $ removeOpAliases op- removeOpAliases (OtherOp op) = OtherOp $ removeOpAliases op- removeOpAliases (SizeOp op) = SizeOp op- removeOpAliases (GPUBody ts body) = GPUBody ts $ removeBodyAliases body--instance (CanBeWise (Op rep), CanBeWise op, ASTRep rep) => CanBeWise (HostOp rep op) where- type OpWithWisdom (HostOp rep op) = HostOp (Wise rep) (OpWithWisdom op)-- removeOpWisdom (SegOp op) = SegOp $ removeOpWisdom op- removeOpWisdom (OtherOp op) = OtherOp $ removeOpWisdom op- removeOpWisdom (SizeOp op) = SizeOp op- removeOpWisdom (GPUBody ts body) = GPUBody ts $ removeBodyWisdom body-+instance CanBeWise op => CanBeWise (HostOp op) where addOpWisdom (SegOp op) = SegOp $ addOpWisdom op addOpWisdom (OtherOp op) = OtherOp $ addOpWisdom op addOpWisdom (SizeOp op) = SizeOp op addOpWisdom (GPUBody ts body) = GPUBody ts $ informBody body -instance (ASTRep rep, ST.IndexOp op) => ST.IndexOp (HostOp rep op) where+instance (ASTRep rep, ST.IndexOp (op rep)) => ST.IndexOp (HostOp op rep) where indexOp vtable k (SegOp op) is = ST.indexOp vtable k op is indexOp vtable k (OtherOp op) is = ST.indexOp vtable k op is indexOp _ _ _ _ = Nothing -instance (PrettyRep rep, PP.Pretty op) => PP.Pretty (HostOp rep op) where+instance (PrettyRep rep, PP.Pretty (op rep)) => PP.Pretty (HostOp op rep) where pretty (SegOp op) = pretty op pretty (OtherOp op) = pretty op pretty (SizeOp op) = pretty op pretty (GPUBody ts body) = "gpu" <+> PP.colon <+> ppTuple' (map pretty ts) <+> PP.nestedBlock "{" "}" (pretty body) -instance (OpMetrics (Op rep), OpMetrics op) => OpMetrics (HostOp rep op) where+instance (OpMetrics (Op rep), OpMetrics (op rep)) => OpMetrics (HostOp op rep) where opMetrics (SegOp op) = opMetrics op opMetrics (OtherOp op) = opMetrics op opMetrics (SizeOp op) = opMetrics op opMetrics (GPUBody _ body) = inside "GPUBody" $ bodyMetrics body +instance RephraseOp op => RephraseOp (HostOp op) where+ rephraseInOp r (SegOp op) = SegOp <$> rephraseInOp r op+ rephraseInOp r (OtherOp op) = OtherOp <$> rephraseInOp r op+ rephraseInOp _ (SizeOp op) = pure $ SizeOp op+ rephraseInOp r (GPUBody ts body) = GPUBody ts <$> rephraseBody r body+ checkGrid :: TC.Checkable rep => KernelGrid -> TC.TypeM rep () checkGrid grid = do TC.require [Prim int64] $ unCount $ gridNumGroups grid@@ -390,10 +382,10 @@ typeCheckHostOp :: TC.Checkable rep =>- (SegLevel -> OpWithAliases (Op rep) -> TC.TypeM rep ()) ->+ (SegLevel -> Op (Aliases rep) -> TC.TypeM rep ()) -> Maybe SegLevel ->- (op -> TC.TypeM rep ()) ->- HostOp (Aliases rep) op ->+ (op (Aliases rep) -> TC.TypeM rep ()) ->+ HostOp op (Aliases rep) -> TC.TypeM rep () typeCheckHostOp checker lvl _ (SegOp op) = TC.checkOpWith (checker $ segLevel op) $
src/Futhark/IR/GPU/Simplify.hs view
@@ -43,9 +43,9 @@ ( Engine.SimplifiableRep rep, BodyDec rep ~ () ) =>- Simplify.SimplifyOp rep op ->- HostOp (Wise rep) op ->- Engine.SimpleM rep (HostOp (Wise rep) op, Stms (Wise rep))+ Simplify.SimplifyOp rep (op (Wise rep)) ->+ HostOp op (Wise rep) ->+ Engine.SimpleM rep (HostOp op (Wise rep), Stms (Wise rep)) simplifyKernelOp f (OtherOp op) = do (op', stms) <- f op pure (OtherOp op', stms)
src/Futhark/IR/GPUMem.hs view
@@ -16,6 +16,7 @@ import Futhark.Analysis.PrimExp.Convert import Futhark.Analysis.UsageTable qualified as UT+import Futhark.IR.Aliases (Aliases) import Futhark.IR.GPU.Op import Futhark.IR.GPU.Simplify (simplifyKernelOp) import Futhark.IR.Mem@@ -34,30 +35,33 @@ type LParamInfo GPUMem = LParamMem type RetType GPUMem = RetTypeMem type BranchType GPUMem = BranchTypeMem- type Op GPUMem = MemOp (HostOp GPUMem ())+ type OpC GPUMem = MemOp (HostOp NoOp) instance ASTRep GPUMem where expTypesFromPat = pure . map snd . bodyReturnsFromPat -instance OpReturns (HostOp GPUMem ()) where+instance OpReturns (HostOp NoOp GPUMem) where opReturns (SegOp op) = segOpReturns op opReturns k = extReturns <$> opType k -instance OpReturns (HostOp (Engine.Wise GPUMem) ()) where+instance OpReturns (HostOp NoOp (Engine.Wise GPUMem)) where opReturns (SegOp op) = segOpReturns op opReturns k = extReturns <$> opType k instance PrettyRep GPUMem -instance TC.CheckableOp GPUMem where+instance TC.Checkable GPUMem where checkOp = typeCheckMemoryOp Nothing where+ -- GHC 9.2 goes into an infinite loop without the type annotation.+ typeCheckMemoryOp ::+ Maybe SegLevel ->+ MemOp (HostOp NoOp) (Aliases GPUMem) ->+ TC.TypeM GPUMem () typeCheckMemoryOp _ (Alloc size _) = TC.require [Prim int64] size typeCheckMemoryOp lvl (Inner op) = typeCheckHostOp (typeCheckMemoryOp . Just) lvl (const $ pure ()) op--instance TC.Checkable GPUMem where checkFParamDec = checkMemInfo checkLParamDec = checkMemInfo checkLetBoundDec = checkMemInfo@@ -71,12 +75,12 @@ instance BuilderOps GPUMem where mkExpDecB _ _ = pure () mkBodyB stms res = pure $ Body () stms res- mkLetNamesB = mkLetNamesB' ()+ mkLetNamesB = mkLetNamesB' (Space "device") () instance BuilderOps (Engine.Wise GPUMem) where mkExpDecB pat e = pure $ Engine.mkWiseExpDec pat () e mkBodyB stms res = pure $ Engine.mkWiseBody () stms res- mkLetNamesB = mkLetNamesB''+ mkLetNamesB = mkLetNamesB'' (Space "device") instance TraverseOpStms (Engine.Wise GPUMem) where traverseOpStms = traverseMemOpStms (traverseHostOpStms (const pure))@@ -90,7 +94,7 @@ simpleGPUMem :: Engine.SimpleOps GPUMem simpleGPUMem =- simpleGeneric usage $ simplifyKernelOp $ const $ pure ((), mempty)+ simpleGeneric usage $ simplifyKernelOp $ const $ pure (NoOp, mempty) where -- Slightly hackily and very inefficiently, we look at the inside -- of SegOps to figure out the sizes of local memory allocations,
src/Futhark/IR/MC.hs view
@@ -37,15 +37,13 @@ data MC instance RepTypes MC where- type Op MC = MCOp MC (SOAC MC)+ type OpC MC = MCOp SOAC instance ASTRep MC where expTypesFromPat = pure . expExtTypesFromPat -instance TypeCheck.CheckableOp MC where+instance TypeCheck.Checkable MC where checkOp = typeCheckMCOp typeCheckSOAC--instance TypeCheck.Checkable MC instance Buildable MC where mkBody = Body ()
src/Futhark/IR/MC/Op.hs view
@@ -18,7 +18,7 @@ import Futhark.Analysis.Metrics import Futhark.Analysis.SymbolTable qualified as ST import Futhark.IR-import Futhark.IR.Aliases (Aliases)+import Futhark.IR.Aliases (Aliases, CanBeAliased (..)) import Futhark.IR.Prop.Aliases import Futhark.IR.SegOp import Futhark.IR.TypeCheck qualified as TC@@ -38,7 +38,7 @@ -- | An operation for the multicore representation. Feel free to -- extend this on an ad hoc basis as needed. Parameterised with some -- other operation.-data MCOp rep op+data MCOp op rep = -- | The first 'SegOp' (if it exists) contains nested parallelism, -- while the second one has a fully sequential body. They are -- semantically fully equivalent.@@ -46,86 +46,66 @@ (Maybe (SegOp () rep)) (SegOp () rep) | -- | Something else (in practice often a SOAC).- OtherOp op+ OtherOp (op rep) deriving (Eq, Ord, Show) -traverseMCOpStms :: Monad m => OpStmsTraverser m op rep -> OpStmsTraverser m (MCOp rep op) rep+traverseMCOpStms ::+ Monad m =>+ OpStmsTraverser m (op rep) rep ->+ OpStmsTraverser m (MCOp op rep) rep traverseMCOpStms _ f (ParOp par_op op) = ParOp <$> traverse (traverseSegOpStms f) par_op <*> traverseSegOpStms f op traverseMCOpStms onInner f (OtherOp op) = OtherOp <$> onInner f op -instance (ASTRep rep, Substitute op) => Substitute (MCOp rep op) where+instance (ASTRep rep, Substitute (op rep)) => Substitute (MCOp op rep) where substituteNames substs (ParOp par_op op) = ParOp (substituteNames substs <$> par_op) (substituteNames substs op) substituteNames substs (OtherOp op) = OtherOp $ substituteNames substs op -instance (ASTRep rep, Rename op) => Rename (MCOp rep op) where+instance (ASTRep rep, Rename (op rep)) => Rename (MCOp op rep) where rename (ParOp par_op op) = ParOp <$> rename par_op <*> rename op rename (OtherOp op) = OtherOp <$> rename op -instance (ASTRep rep, FreeIn op) => FreeIn (MCOp rep op) where+instance (ASTRep rep, FreeIn (op rep)) => FreeIn (MCOp op rep) where freeIn' (ParOp par_op op) = freeIn' par_op <> freeIn' op freeIn' (OtherOp op) = freeIn' op -instance (ASTRep rep, IsOp op) => IsOp (MCOp rep op) where+instance (ASTRep rep, IsOp (op rep)) => IsOp (MCOp op rep) where safeOp (ParOp _ op) = safeOp op safeOp (OtherOp op) = safeOp op cheapOp (ParOp _ op) = cheapOp op cheapOp (OtherOp op) = cheapOp op -instance TypedOp op => TypedOp (MCOp rep op) where+instance TypedOp (op rep) => TypedOp (MCOp op rep) where opType (ParOp _ op) = opType op opType (OtherOp op) = opType op -instance- (Aliased rep, AliasedOp op, ASTRep rep) =>- AliasedOp (MCOp rep op)- where+instance (Aliased rep, AliasedOp (op rep)) => AliasedOp (MCOp op rep) where opAliases (ParOp _ op) = opAliases op opAliases (OtherOp op) = opAliases op consumedInOp (ParOp _ op) = consumedInOp op consumedInOp (OtherOp op) = consumedInOp op -instance- (CanBeAliased (Op rep), CanBeAliased op, ASTRep rep) =>- CanBeAliased (MCOp rep op)- where- type OpWithAliases (MCOp rep op) = MCOp (Aliases rep) (OpWithAliases op)-+instance CanBeAliased op => CanBeAliased (MCOp op) where addOpAliases aliases (ParOp par_op op) = ParOp (addOpAliases aliases <$> par_op) (addOpAliases aliases op) addOpAliases aliases (OtherOp op) = OtherOp $ addOpAliases aliases op - removeOpAliases (ParOp par_op op) =- ParOp (removeOpAliases <$> par_op) (removeOpAliases op)- removeOpAliases (OtherOp op) =- OtherOp $ removeOpAliases op--instance- (CanBeWise (Op rep), CanBeWise op, ASTRep rep) =>- CanBeWise (MCOp rep op)- where- type OpWithWisdom (MCOp rep op) = MCOp (Wise rep) (OpWithWisdom op)-- removeOpWisdom (ParOp par_op op) =- ParOp (removeOpWisdom <$> par_op) (removeOpWisdom op)- removeOpWisdom (OtherOp op) =- OtherOp $ removeOpWisdom op-+instance CanBeWise op => CanBeWise (MCOp op) where addOpWisdom (ParOp par_op op) = ParOp (addOpWisdom <$> par_op) (addOpWisdom op) addOpWisdom (OtherOp op) = OtherOp $ addOpWisdom op -instance (ASTRep rep, ST.IndexOp op) => ST.IndexOp (MCOp rep op) where+instance (ASTRep rep, ST.IndexOp (op rep)) => ST.IndexOp (MCOp op rep) where indexOp vtable k (ParOp _ op) is = ST.indexOp vtable k op is indexOp vtable k (OtherOp op) is = ST.indexOp vtable k op is -instance (PrettyRep rep, Pretty op) => Pretty (MCOp rep op) where+instance (PrettyRep rep, Pretty (op rep)) => Pretty (MCOp op rep) where pretty (ParOp Nothing op) = pretty op pretty (ParOp (Just par_op) op) = "par"@@ -134,14 +114,19 @@ <+> nestedBlock "{" "}" (pretty op) pretty (OtherOp op) = pretty op -instance (OpMetrics (Op rep), OpMetrics op) => OpMetrics (MCOp rep op) where+instance (OpMetrics (Op rep), OpMetrics (op rep)) => OpMetrics (MCOp op rep) where opMetrics (ParOp par_op op) = opMetrics par_op >> opMetrics op opMetrics (OtherOp op) = opMetrics op +instance RephraseOp op => RephraseOp (MCOp op) where+ rephraseInOp r (ParOp par_op op) =+ ParOp <$> traverse (rephraseInOp r) par_op <*> rephraseInOp r op+ rephraseInOp r (OtherOp op) = OtherOp <$> rephraseInOp r op+ typeCheckMCOp :: TC.Checkable rep =>- (op -> TC.TypeM rep ()) ->- MCOp (Aliases rep) op ->+ (op (Aliases rep) -> TC.TypeM rep ()) ->+ MCOp op (Aliases rep) -> TC.TypeM rep () typeCheckMCOp _ (ParOp (Just par_op) op) = do -- It is valid for the same array to be consumed in both par_op and op.@@ -155,9 +140,9 @@ ( Engine.SimplifiableRep rep, BodyDec rep ~ () ) =>- Simplify.SimplifyOp rep op ->- MCOp (Wise rep) op ->- Engine.SimpleM rep (MCOp (Wise rep) op, Stms (Wise rep))+ Simplify.SimplifyOp rep (op (Wise rep)) ->+ MCOp op (Wise rep) ->+ Engine.SimpleM rep (MCOp op (Wise rep), Stms (Wise rep)) simplifyMCOp f (OtherOp op) = do (op', stms) <- f op pure (OtherOp op', stms)
src/Futhark/IR/MCMem.hs view
@@ -31,30 +31,28 @@ type LParamInfo MCMem = LParamMem type RetType MCMem = RetTypeMem type BranchType MCMem = BranchTypeMem- type Op MCMem = MemOp (MCOp MCMem ())+ type OpC MCMem = MemOp (MCOp NoOp) instance ASTRep MCMem where expTypesFromPat = pure . map snd . bodyReturnsFromPat -instance OpReturns (MCOp MCMem ()) where+instance OpReturns (MCOp NoOp MCMem) where opReturns (ParOp _ op) = segOpReturns op- opReturns (OtherOp ()) = pure []+ opReturns (OtherOp NoOp) = pure [] -instance OpReturns (MCOp (Engine.Wise MCMem) ()) where+instance OpReturns (MCOp NoOp (Engine.Wise MCMem)) where opReturns (ParOp _ op) = segOpReturns op opReturns k = extReturns <$> opType k instance PrettyRep MCMem -instance TC.CheckableOp MCMem where+instance TC.Checkable MCMem where checkOp = typeCheckMemoryOp where typeCheckMemoryOp (Alloc size _) = TC.require [Prim int64] size typeCheckMemoryOp (Inner op) =- typeCheckMCOp pure op--instance TC.Checkable MCMem where+ typeCheckMCOp (const $ pure ()) op checkFParamDec = checkMemInfo checkLParamDec = checkMemInfo checkLetBoundDec = checkMemInfo@@ -68,12 +66,12 @@ instance BuilderOps MCMem where mkExpDecB _ _ = pure () mkBodyB stms res = pure $ Body () stms res- mkLetNamesB = mkLetNamesB' ()+ mkLetNamesB = mkLetNamesB' DefaultSpace () instance BuilderOps (Engine.Wise MCMem) where mkExpDecB pat e = pure $ Engine.mkWiseExpDec pat () e mkBodyB stms res = pure $ Engine.mkWiseBody () stms res- mkLetNamesB = mkLetNamesB''+ mkLetNamesB = mkLetNamesB'' DefaultSpace instance TraverseOpStms (Engine.Wise MCMem) where traverseOpStms = traverseMemOpStms (traverseMCOpStms (const pure))@@ -83,4 +81,4 @@ simpleMCMem :: Engine.SimpleOps MCMem simpleMCMem =- simpleGeneric (const mempty) $ simplifyMCOp $ const $ pure ((), mempty)+ simpleGeneric (const mempty) $ simplifyMCOp $ const $ pure (NoOp, mempty)
src/Futhark/IR/Mem.hs view
@@ -105,6 +105,7 @@ import Control.Monad.State import Data.Foldable (traverse_) import Data.Function ((&))+import Data.Kind qualified import Data.List (elemIndex, find) import Data.Map.Strict qualified as M import Data.Maybe@@ -115,6 +116,7 @@ import Futhark.Analysis.SymbolTable qualified as ST import Futhark.IR.Aliases ( Aliases,+ CanBeAliased (..), removeExpAliases, removePatAliases, removeScopeAliases,@@ -163,8 +165,9 @@ RetType rep ~ RetTypeMem, BranchType rep ~ BranchTypeMem, ASTRep rep,- OpReturns inner,- Op rep ~ MemOp inner+ OpReturns (inner rep),+ RephraseOp inner,+ Op rep ~ MemOp inner rep ) instance IsRetType FunReturns where@@ -174,29 +177,33 @@ instance IsBodyType BodyReturns where primBodyType = MemPrim -data MemOp inner+data MemOp (inner :: Data.Kind.Type -> Data.Kind.Type) (rep :: Data.Kind.Type) = -- | Allocate a memory block. Alloc SubExp Space- | Inner inner+ | Inner (inner rep) deriving (Eq, Ord, Show) -- | A helper for defining 'TraverseOpStms'. traverseMemOpStms :: Monad m =>- OpStmsTraverser m inner rep ->- OpStmsTraverser m (MemOp inner) rep+ OpStmsTraverser m (inner rep) rep ->+ OpStmsTraverser m (MemOp inner rep) rep traverseMemOpStms _ _ op@Alloc {} = pure op traverseMemOpStms onInner f (Inner inner) = Inner <$> onInner f inner -instance FreeIn inner => FreeIn (MemOp inner) where+instance RephraseOp inner => RephraseOp (MemOp inner) where+ rephraseInOp _ (Alloc e space) = pure (Alloc e space)+ rephraseInOp r (Inner x) = Inner <$> rephraseInOp r x++instance FreeIn (inner rep) => FreeIn (MemOp inner rep) where freeIn' (Alloc size _) = freeIn' size freeIn' (Inner k) = freeIn' k -instance TypedOp inner => TypedOp (MemOp inner) where+instance TypedOp (inner rep) => TypedOp (MemOp inner rep) where opType (Alloc _ space) = pure [Mem space] opType (Inner k) = opType k -instance AliasedOp inner => AliasedOp (MemOp inner) where+instance AliasedOp (inner rep) => AliasedOp (MemOp inner rep) where opAliases Alloc {} = [mempty] opAliases (Inner k) = opAliases k @@ -204,31 +211,27 @@ consumedInOp (Inner k) = consumedInOp k instance CanBeAliased inner => CanBeAliased (MemOp inner) where- type OpWithAliases (MemOp inner) = MemOp (OpWithAliases inner)- removeOpAliases (Alloc se space) = Alloc se space- removeOpAliases (Inner k) = Inner $ removeOpAliases k- addOpAliases _ (Alloc se space) = Alloc se space addOpAliases aliases (Inner k) = Inner $ addOpAliases aliases k -instance Rename inner => Rename (MemOp inner) where+instance Rename (inner rep) => Rename (MemOp inner rep) where rename (Alloc size space) = Alloc <$> rename size <*> pure space rename (Inner k) = Inner <$> rename k -instance Substitute inner => Substitute (MemOp inner) where+instance Substitute (inner rep) => Substitute (MemOp inner rep) where substituteNames subst (Alloc size space) = Alloc (substituteNames subst size) space substituteNames subst (Inner k) = Inner $ substituteNames subst k -instance PP.Pretty inner => PP.Pretty (MemOp inner) where+instance PP.Pretty (inner rep) => PP.Pretty (MemOp inner rep) where pretty (Alloc e DefaultSpace) = "alloc" <> PP.apply [PP.pretty e] pretty (Alloc e s) = "alloc" <> PP.apply [PP.pretty e, PP.pretty s] pretty (Inner k) = PP.pretty k -instance OpMetrics inner => OpMetrics (MemOp inner) where+instance OpMetrics (inner rep) => OpMetrics (MemOp inner rep) where opMetrics Alloc {} = seen "Alloc" opMetrics (Inner k) = opMetrics k -instance IsOp inner => IsOp (MemOp inner) where+instance IsOp (inner rep) => IsOp (MemOp inner rep) where safeOp (Alloc (Constant (IntValue (Int64Value k))) _) = k >= 0 safeOp Alloc {} = False safeOp (Inner k) = safeOp k@@ -236,13 +239,10 @@ cheapOp Alloc {} = True instance CanBeWise inner => CanBeWise (MemOp inner) where- type OpWithWisdom (MemOp inner) = MemOp (OpWithWisdom inner)- removeOpWisdom (Alloc size space) = Alloc size space- removeOpWisdom (Inner k) = Inner $ removeOpWisdom k addOpWisdom (Alloc size space) = Alloc size space addOpWisdom (Inner k) = Inner $ addOpWisdom k -instance ST.IndexOp inner => ST.IndexOp (MemOp inner) where+instance ST.IndexOp (inner rep) => ST.IndexOp (MemOp inner rep) where indexOp vtable k (Inner op) is = ST.indexOp vtable k op is indexOp _ _ _ _ = Nothing @@ -473,7 +473,7 @@ instance PP.Pretty MemReturn where pretty (ReturnsInBlock v ixfun) =- PP.parens $ pretty v <+> "->" PP.</> PP.pretty ixfun+ pretty v <+> "->" PP.</> PP.pretty ixfun pretty (ReturnsNewBlock space i ixfun) = "?" <> pretty i <> PP.pretty space <+> "->" PP.</> PP.pretty ixfun @@ -1117,12 +1117,12 @@ opReturns :: (Mem rep inner, Monad m, HasScope rep m) => op -> m [ExpReturns] opReturns op = extReturns <$> opType op -instance OpReturns inner => OpReturns (MemOp inner) where+instance OpReturns (inner rep) => OpReturns (MemOp inner rep) where opReturns (Alloc _ space) = pure [MemMem space] opReturns (Inner op) = opReturns op -instance OpReturns () where- opReturns () = pure []+instance OpReturns (NoOp rep) where+ opReturns NoOp = pure [] applyFunReturns :: Typed dec =>
src/Futhark/IR/Mem/Simplify.hs view
@@ -31,18 +31,20 @@ LetDec rep ~ LetDecMem, ExpDec rep ~ (), BodyDec rep ~ (),- CanBeWise (Op rep),+ CanBeWise (OpC rep), BuilderOps (Wise rep),- OpReturns (OpWithWisdom inner),- ST.IndexOp (OpWithWisdom inner),- AliasedOp (OpWithWisdom inner),- Mem rep inner+ OpReturns (inner (Wise rep)),+ ST.IndexOp (inner (Wise rep)),+ AliasedOp (inner (Wise rep)),+ Mem rep inner,+ CanBeWise inner,+ RephraseOp inner ) simpleGeneric :: (SimplifyMemory rep inner) =>- (OpWithWisdom inner -> UT.UsageTable) ->- Simplify.SimplifyOp rep (OpWithWisdom inner) ->+ (inner (Wise rep) -> UT.UsageTable) ->+ Simplify.SimplifyOp rep (inner (Wise rep)) -> Simplify.SimpleOps rep simpleGeneric = simplifiable @@ -85,17 +87,17 @@ scope stms -isResultAlloc :: Op rep ~ MemOp op => Engine.BlockPred rep+isResultAlloc :: OpC rep ~ MemOp op => Engine.BlockPred rep isResultAlloc _ usage (Let (Pat [pe]) _ (Op Alloc {})) = UT.isInResult (patElemName pe) usage isResultAlloc _ _ _ = False -isAlloc :: Op rep ~ MemOp op => Engine.BlockPred rep+isAlloc :: OpC rep ~ MemOp op => Engine.BlockPred rep isAlloc _ _ (Let _ _ (Op Alloc {})) = True isAlloc _ _ _ = False blockers ::- (Op rep ~ MemOp inner) =>+ (OpC rep ~ MemOp inner) => Simplify.HoistBlockers rep blockers = Engine.noExtraHoistBlockers
src/Futhark/IR/Parse.hs view
@@ -941,7 +941,7 @@ <$> (lexeme "groups=" $> GPU.Count <*> pSubExp <* pSemi) <*> (lexeme "groupsize=" $> GPU.Count <*> pSubExp) -pHostOp :: PR rep -> Parser op -> Parser (GPU.HostOp rep op)+pHostOp :: PR rep -> Parser (op rep) -> Parser (GPU.HostOp op rep) pHostOp pr pOther = choice [ GPU.SegOp <$> pSegOp pr pSegLevel,@@ -950,7 +950,7 @@ keyword "gpu" $> GPU.GPUBody <*> (pColon *> pTypes) <*> braces (pBody pr) ] -pMCOp :: PR rep -> Parser op -> Parser (MC.MCOp rep op)+pMCOp :: PR rep -> Parser (op rep) -> Parser (MC.MCOp op rep) pMCOp pr pOther = choice [ MC.ParOp . Just@@ -1038,7 +1038,7 @@ pMemReturn :: Parser MemReturn pMemReturn = choice- [ parens $ ReturnsInBlock <$> pVName <* lexeme "->" <*> pExtIxFun,+ [ ReturnsInBlock <$> pVName <* lexeme "->" <*> pExtIxFun, do i <- "?" *> pInt space <- choice [pSpace, pure DefaultSpace] <* lexeme "->"@@ -1060,7 +1060,7 @@ pLetDecMem :: Parser LetDecMem pLetDecMem = pMemInfo pSubExp (pure NoUniqueness) pMemBind -pMemOp :: Parser inner -> Parser (MemOp inner)+pMemOp :: Parser (inner rep) -> Parser (MemOp inner rep) pMemOp pInner = choice [ keyword "alloc"
src/Futhark/IR/Pretty.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | Futhark prettyprinter. This module defines 'Pretty' instances@@ -33,6 +32,9 @@ where ppExpDec :: ExpDec rep -> Exp rep -> Maybe (Doc a) ppExpDec _ _ = Nothing++instance Pretty (NoOp rep) where+ pretty NoOp = "noop" instance Pretty VName where pretty (VName vn i) = pretty vn <> "_" <> pretty (show i)
src/Futhark/IR/Prop.hs view
@@ -13,6 +13,7 @@ module Futhark.IR.Prop.Patterns, module Futhark.IR.Prop.Names, module Futhark.IR.RetType,+ module Futhark.IR.Rephrase, -- * Built-in functions isBuiltInFunction,@@ -49,6 +50,7 @@ import Futhark.IR.Prop.Reshape import Futhark.IR.Prop.TypeOf import Futhark.IR.Prop.Types+import Futhark.IR.Rephrase import Futhark.IR.RetType import Futhark.IR.Syntax import Futhark.Transform.Rename (Rename, Renameable)@@ -177,7 +179,7 @@ certify cs1 (Let pat (StmAux cs2 attrs dec) e) = Let pat (StmAux (cs2 <> cs1) attrs dec) e --- | A handy shorthand for properties that we usually want to things+-- | A handy shorthand for properties that we usually want for things -- we stuff into ASTs. type ASTConstraints a = (Eq a, Ord a, Show a, Rename a, Substitute a, FreeIn a, Pretty a)@@ -190,9 +192,9 @@ -- | Should we try to hoist this out of branches? cheapOp :: op -> Bool -instance IsOp () where- safeOp () = True- cheapOp () = True+instance IsOp (NoOp rep) where+ safeOp NoOp = True+ cheapOp NoOp = True -- | Representation-specific attributes; also means the rep supports -- some basic facilities.@@ -208,7 +210,8 @@ FreeIn (LParamInfo rep), FreeIn (RetType rep), FreeIn (BranchType rep),- IsOp (Op rep)+ IsOp (Op rep),+ RephraseOp (OpC rep) ) => ASTRep rep where
src/Futhark/IR/Prop/Aliases.hs view
@@ -25,23 +25,22 @@ -- * Extensibility AliasTable, AliasedOp (..),- CanBeAliased (..), ) where import Data.Bifunctor (first, second)-import Data.Kind qualified import Data.List (find, transpose) import Data.Map qualified as M-import Futhark.IR.Prop (IsOp, NameInfo (..), Scope)+import Futhark.IR.Prop (ASTRep, IsOp, NameInfo (..), Scope) import Futhark.IR.Prop.Names import Futhark.IR.Prop.Patterns import Futhark.IR.Prop.Types import Futhark.IR.Syntax -- | The class of representations that contain aliasing information.-class (RepTypes rep, AliasedOp (Op rep), AliasesOf (LetDec rep)) => Aliased rep where- -- | The aliases of the body results.+class (ASTRep rep, AliasedOp (Op rep), AliasesOf (LetDec rep)) => Aliased rep where+ -- | The aliases of the body results. Note that this includes names+ -- bound in the body! bodyAliases :: Body rep -> [Names] -- | The variables consumed in the body.@@ -85,25 +84,56 @@ where (alses, conses) = unzip l +returnAliases :: [TypeBase shape Uniqueness] -> [(Names, Diet)] -> [Names]+returnAliases rts args = map returnType' rts+ where+ returnType' (Array _ _ Nonunique) =+ mconcat $ map (uncurry maskAliases) args+ returnType' (Array _ _ Unique) =+ mempty+ returnType' (Prim _) =+ mempty+ returnType' Acc {} =+ error "returnAliases Acc"+ returnType' Mem {} =+ mconcat $ map (uncurry maskAliases) args+ funcallAliases :: [(SubExp, Diet)] -> [TypeBase shape Uniqueness] -> [Names] funcallAliases args t = returnAliases t [(subExpAliases se, d) | (se, d) <- args] --- | The aliases of an expression, one per non-context value returned.-expAliases :: (Aliased rep) => Exp rep -> [Names]-expAliases (Match _ cases defbody _) =- matchAliases $ onBody defbody : map (onBody . caseBody) cases+-- | The aliases of an expression, one for each pattern element.+--+-- The pattern is important because some aliasing might be through+-- variables that are no longer in scope (consider the aliases for a+-- body that returns the same value multiple times).+expAliases :: (Aliased rep) => [PatElem dec] -> Exp rep -> [Names]+expAliases pes (Match _ cases defbody _) =+ -- Repeat mempty in case the pattern has more elements (this+ -- implies a type error).+ zipWith grow (map patElemName pes) $ als ++ repeat mempty where+ als = matchAliases $ onBody defbody : map (onBody . caseBody) cases onBody body = (bodyAliases body, consumedInBody body)-expAliases (BasicOp op) = basicOpAliases op-expAliases (DoLoop merge _ loopbody) = do+ bound = foldMap boundInBody $ defbody : map caseBody cases+ grow v names = (names <> pe_names) `namesSubtract` bound+ where+ pe_names =+ namesFromList+ . filter (/= v)+ . map (patElemName . fst)+ . filter (namesIntersect names . snd)+ $ zip pes als+expAliases _ (BasicOp op) = basicOpAliases op+expAliases _ (DoLoop merge _ loopbody) = do (p, als) <- transitive . zip params $ zipWith mappend arg_aliases (bodyAliases loopbody) let als' = als `namesSubtract` param_names if unique $ paramDeclType p then pure mempty- else pure als'+ else pure $ als' `namesSubtract` bound where+ bound = boundInBody loopbody arg_aliases = map (subExpAliases . snd) merge params = map fst merge param_names = namesFromList $ map paramName params@@ -115,28 +145,16 @@ where look v = maybe mempty snd $ find ((== v) . paramName . fst) merge_and_als expand als = als <> foldMap look (namesToList als)-expAliases (Apply _ args t _) =+expAliases _ (Apply _ args t _) = funcallAliases args $ map declExtTypeOf t-expAliases (WithAcc inputs lam) =- concatMap inputAliases inputs ++ drop num_accs (bodyAliases (lambdaBody lam))+expAliases _ (WithAcc inputs lam) =+ concatMap inputAliases inputs+ ++ drop num_accs (map (`namesSubtract` boundInBody body) $ bodyAliases body) where+ body = lambdaBody lam inputAliases (_, arrs, _) = replicate (length arrs) mempty num_accs = length inputs-expAliases (Op op) = opAliases op--returnAliases :: [TypeBase shape Uniqueness] -> [(Names, Diet)] -> [Names]-returnAliases rts args = map returnType' rts- where- returnType' (Array _ _ Nonunique) =- mconcat $ map (uncurry maskAliases) args- returnType' (Array _ _ Unique) =- mempty- returnType' (Prim _) =- mempty- returnType' Acc {} =- error "returnAliases Acc"- returnType' Mem {} =- mconcat $ map (uncurry maskAliases) args+expAliases _ (Op op) = opAliases op maskAliases :: Names -> Diet -> Names maskAliases _ Consume = mempty@@ -186,9 +204,9 @@ consumedByLambda :: Aliased rep => Lambda rep -> Names consumedByLambda = consumedInBody . lambdaBody --- | The aliases of each pattern element (including the context).+-- | The aliases of each pattern element. patAliases :: AliasesOf dec => Pat dec -> [Names]-patAliases = map (aliasesOf . patElemDec) . patElems+patAliases = map aliasesOf . patElems -- | Something that contains alias information. class AliasesOf a where@@ -215,28 +233,10 @@ opAliases :: op -> [Names] consumedInOp :: op -> Names -instance AliasedOp () where- opAliases () = []- consumedInOp () = mempty+instance AliasedOp (NoOp rep) where+ opAliases NoOp = []+ consumedInOp NoOp = mempty -- | Pre-existing aliases for variables. Used to add transitive -- aliases. type AliasTable = M.Map VName Names---- | The class of operations that can be given aliasing information.--- This is a somewhat subtle concept that is only used in the--- simplifier and when using "rep adapters".-class AliasedOp (OpWithAliases op) => CanBeAliased op where- -- | The op that results when we add aliases to this op.- type OpWithAliases op :: Data.Kind.Type-- -- | Remove aliases from this op.- removeOpAliases :: OpWithAliases op -> op-- -- | Add aliases to this op.- addOpAliases :: AliasTable -> op -> OpWithAliases op--instance CanBeAliased () where- type OpWithAliases () = ()- removeOpAliases = id- addOpAliases = const id
src/Futhark/IR/Prop/Names.hs view
@@ -222,6 +222,9 @@ instance FreeIn a => FreeIn (S.Set a) where freeIn' = foldMap freeIn' +instance FreeIn (NoOp rep) where+ freeIn' NoOp = mempty+ instance ( FreeDec (ExpDec rep), FreeDec (BodyDec rep),
src/Futhark/IR/Prop/TypeOf.hs view
@@ -15,7 +15,6 @@ -- also obtaining information about the storage location of results. module Futhark.IR.Prop.TypeOf ( expExtType,- expExtTypeSize, subExpType, subExpResType, basicOpType,@@ -145,27 +144,6 @@ num_accs = length inputs expExtType (Op op) = opType op --- | The number of values returned by an expression.-expExtTypeSize ::- (RepTypes rep, TypedOp (Op rep)) =>- Exp rep ->- Int-expExtTypeSize = length . feelBad . expExtType---- FIXME, this is a horrible quick hack.-newtype FeelBad rep a = FeelBad {feelBad :: a}--instance Functor (FeelBad rep) where- fmap f = FeelBad . f . feelBad--instance Applicative (FeelBad rep) where- pure = FeelBad- f <*> x = FeelBad $ feelBad f $ feelBad x--instance RepTypes rep => HasScope rep (FeelBad rep) where- lookupType = const $ pure $ Prim $ IntType Int64- askScope = pure mempty- -- | Given the parameters of a loop, produce the return type. loopExtType :: Typed dec => [Param dec] -> [ExtType] loopExtType params =@@ -178,5 +156,5 @@ class TypedOp op where opType :: HasScope t m => op -> m [ExtType] -instance TypedOp () where- opType () = pure []+instance TypedOp (NoOp rep) where+ opType NoOp = pure []
src/Futhark/IR/Rep.hs view
@@ -4,6 +4,8 @@ -- which is then used to invoke the type families defined here. module Futhark.IR.Rep ( RepTypes (..),+ Op,+ NoOp (..), module Futhark.IR.RetType, ) where@@ -13,6 +15,11 @@ import Futhark.IR.RetType import Futhark.IR.Syntax.Core (DeclExtType, DeclType, ExtType, Type) +-- | Returns nothing and does nothing. Placeholder for when we don't+-- really want an operation.+data NoOp rep = NoOp+ deriving (Eq, Ord, Show)+ -- | A collection of type families giving various common types for a -- representation, along with constraints specifying that the types -- they map to should satisfy some minimal requirements.@@ -85,7 +92,14 @@ type BranchType l = ExtType - -- | Extensible operation.- type Op l :: Data.Kind.Type+ -- | Type constructor for the extensible operation. The somewhat+ -- funky definition is to ensure that we can change the "inner"+ -- representation in a generic way (e.g. add aliasing information)+ -- In most code, you will use the 'Op' alias instead.+ type OpC l :: Data.Kind.Type -> Data.Kind.Type - type Op l = ()+ type OpC l = NoOp++-- | Apply the 'OpC' constructor of a representation to that+-- representation.+type Op l = OpC l l
+ src/Futhark/IR/Rephrase.hs view
@@ -0,0 +1,114 @@+-- | Facilities for changing the representation of some fragment,+-- within a monadic context. We call this "rephrasing", for no deep+-- reason.+module Futhark.IR.Rephrase+ ( rephraseProg,+ rephraseFunDef,+ rephraseExp,+ rephraseBody,+ rephraseStm,+ rephraseLambda,+ rephrasePat,+ rephrasePatElem,+ Rephraser (..),+ RephraseOp (..),+ )+where++import Futhark.IR.Syntax+import Futhark.IR.Traversals++-- | A collection of functions that together allow us to rephrase some+-- IR fragment, in some monad @m@. If we let @m@ be the 'Maybe'+-- monad, we can conveniently do rephrasing that might fail. This is+-- useful if you want to see if some IR in e.g. the @Kernels@ rep+-- actually uses any @Kernels@-specific operations.+data Rephraser m from to = Rephraser+ { rephraseExpDec :: ExpDec from -> m (ExpDec to),+ rephraseLetBoundDec :: LetDec from -> m (LetDec to),+ rephraseFParamDec :: FParamInfo from -> m (FParamInfo to),+ rephraseLParamDec :: LParamInfo from -> m (LParamInfo to),+ rephraseBodyDec :: BodyDec from -> m (BodyDec to),+ rephraseRetType :: RetType from -> m (RetType to),+ rephraseBranchType :: BranchType from -> m (BranchType to),+ rephraseOp :: Op from -> m (Op to)+ }++-- | Rephrase an entire program.+rephraseProg :: Monad m => Rephraser m from to -> Prog from -> m (Prog to)+rephraseProg rephraser prog = do+ consts <- mapM (rephraseStm rephraser) (progConsts prog)+ funs <- mapM (rephraseFunDef rephraser) (progFuns prog)+ pure $ prog {progConsts = consts, progFuns = funs}++-- | Rephrase a function definition.+rephraseFunDef :: Monad m => Rephraser m from to -> FunDef from -> m (FunDef to)+rephraseFunDef rephraser fundec = do+ body' <- rephraseBody rephraser $ funDefBody fundec+ params' <- mapM (rephraseParam $ rephraseFParamDec rephraser) $ funDefParams fundec+ rettype' <- mapM (rephraseRetType rephraser) $ funDefRetType fundec+ pure fundec {funDefBody = body', funDefParams = params', funDefRetType = rettype'}++-- | Rephrase an expression.+rephraseExp :: Monad m => Rephraser m from to -> Exp from -> m (Exp to)+rephraseExp = mapExpM . mapper++-- | Rephrase a statement.+rephraseStm :: Monad m => Rephraser m from to -> Stm from -> m (Stm to)+rephraseStm rephraser (Let pat (StmAux cs attrs dec) e) =+ Let+ <$> rephrasePat (rephraseLetBoundDec rephraser) pat+ <*> (StmAux cs attrs <$> rephraseExpDec rephraser dec)+ <*> rephraseExp rephraser e++-- | Rephrase a pattern.+rephrasePat ::+ Monad m =>+ (from -> m to) ->+ Pat from ->+ m (Pat to)+rephrasePat = traverse++-- | Rephrase a pattern element.+rephrasePatElem :: Monad m => (from -> m to) -> PatElem from -> m (PatElem to)+rephrasePatElem rephraser (PatElem ident from) =+ PatElem ident <$> rephraser from++-- | Rephrase a parameter.+rephraseParam :: Monad m => (from -> m to) -> Param from -> m (Param to)+rephraseParam rephraser (Param attrs name from) =+ Param attrs name <$> rephraser from++-- | Rephrase a body.+rephraseBody :: Monad m => Rephraser m from to -> Body from -> m (Body to)+rephraseBody rephraser (Body rep stms res) =+ Body+ <$> rephraseBodyDec rephraser rep+ <*> (stmsFromList <$> mapM (rephraseStm rephraser) (stmsToList stms))+ <*> pure res++-- | Rephrase a lambda.+rephraseLambda :: Monad m => Rephraser m from to -> Lambda from -> m (Lambda to)+rephraseLambda rephraser lam = do+ body' <- rephraseBody rephraser $ lambdaBody lam+ params' <- mapM (rephraseParam $ rephraseLParamDec rephraser) $ lambdaParams lam+ pure lam {lambdaBody = body', lambdaParams = params'}++mapper :: Monad m => Rephraser m from to -> Mapper from to m+mapper rephraser =+ identityMapper+ { mapOnBody = const $ rephraseBody rephraser,+ mapOnRetType = rephraseRetType rephraser,+ mapOnBranchType = rephraseBranchType rephraser,+ mapOnFParam = rephraseParam (rephraseFParamDec rephraser),+ mapOnLParam = rephraseParam (rephraseLParamDec rephraser),+ mapOnOp = rephraseOp rephraser+ }++-- | Rephrasing any fragments inside an Op from one representation to+-- another.+class RephraseOp op where+ rephraseInOp :: Monad m => Rephraser m from to -> op from -> m (op to)++instance RephraseOp NoOp where+ rephraseInOp _ NoOp = pure NoOp
src/Futhark/IR/SOACS.hs view
@@ -27,15 +27,13 @@ data SOACS instance RepTypes SOACS where- type Op SOACS = SOAC SOACS+ type OpC SOACS = SOAC instance ASTRep SOACS where expTypesFromPat = pure . expExtTypesFromPat -instance TC.CheckableOp SOACS where+instance TC.Checkable SOACS where checkOp = typeCheckSOAC--instance TC.Checkable SOACS instance Buildable SOACS where mkBody = Body ()
src/Futhark/IR/SOACS/SOAC.hs view
@@ -62,7 +62,7 @@ import Futhark.Analysis.SymbolTable qualified as ST import Futhark.Construct import Futhark.IR-import Futhark.IR.Aliases (Aliases, removeLambdaAliases)+import Futhark.IR.Aliases (Aliases, CanBeAliased (..)) import Futhark.IR.Prop.Aliases import Futhark.IR.TypeCheck qualified as TC import Futhark.Optimise.Simplify.Rep@@ -529,7 +529,7 @@ instance ASTRep rep => TypedOp (SOAC rep) where opType = pure . staticShapes . soacType -instance (ASTRep rep, Aliased rep) => AliasedOp (SOAC rep) where+instance Aliased rep => AliasedOp (SOAC rep) where opAliases = map (const mempty) . soacType consumedInOp JVP {} = mempty@@ -560,15 +560,7 @@ mapHistOp f (HistOp w rf dests nes lam) = HistOp w rf dests nes $ f lam -instance- ( ASTRep rep,- ASTRep (Aliases rep),- CanBeAliased (Op rep)- ) =>- CanBeAliased (SOAC rep)- where- type OpWithAliases (SOAC rep) = SOAC (Aliases rep)-+instance CanBeAliased SOAC where addOpAliases aliases (JVP lam args vec) = JVP (Alias.analyseLambda aliases lam) args vec addOpAliases aliases (VJP lam args vec) =@@ -593,10 +585,6 @@ onRed red = red {redLambda = Alias.analyseLambda aliases $ redLambda red} onScan scan = scan {scanLambda = Alias.analyseLambda aliases $ scanLambda scan} - removeOpAliases = runIdentity . mapSOACM remove- where- remove = SOACMapper pure (pure . removeLambdaAliases) pure- instance ASTRep rep => IsOp (SOAC rep) where safeOp _ = False cheapOp _ = False@@ -614,10 +602,7 @@ substNamesInSubExp subs (Var idd) = M.findWithDefault (Var idd) idd subs -instance (ASTRep rep, CanBeWise (Op rep)) => CanBeWise (SOAC rep) where- type OpWithWisdom (SOAC rep) = SOAC (Wise rep)-- removeOpWisdom = runIdentity . mapSOACM (SOACMapper pure (pure . removeLambdaWisdom) pure)+instance CanBeWise SOAC where addOpWisdom = runIdentity . mapSOACM (SOACMapper pure (pure . informLambda) pure) instance RepTypes rep => ST.IndexOp (SOAC rep) where@@ -836,6 +821,31 @@ $ "Map function return type " <> prettyTuple map_lam_ts <> " wrong for given scan and reduction functions."++instance RephraseOp SOAC where+ rephraseInOp r (VJP lam args vec) =+ VJP <$> rephraseLambda r lam <*> pure args <*> pure vec+ rephraseInOp r (JVP lam args vec) =+ JVP <$> rephraseLambda r lam <*> pure args <*> pure vec+ rephraseInOp r (Stream w arrs acc lam) =+ Stream w arrs acc <$> rephraseLambda r lam+ rephraseInOp r (Scatter w arrs lam dests) =+ Scatter w arrs <$> rephraseLambda r lam <*> pure dests+ rephraseInOp r (Hist w arrs ops lam) =+ Hist w arrs <$> mapM onOp ops <*> rephraseLambda r lam+ where+ onOp (HistOp dest_shape rf dests nes op) =+ HistOp dest_shape rf dests nes <$> rephraseLambda r op+ rephraseInOp r (Screma w arrs (ScremaForm scans red lam)) =+ Screma w arrs+ <$> ( ScremaForm+ <$> mapM onScan scans+ <*> mapM onRed red+ <*> rephraseLambda r lam+ )+ where+ onScan (Scan op nes) = Scan <$> rephraseLambda r op <*> pure nes+ onRed (Reduce comm op nes) = Reduce comm <$> rephraseLambda r op <*> pure nes instance OpMetrics (Op rep) => OpMetrics (SOAC rep) where opMetrics (VJP lam _ _) =
src/Futhark/IR/SegOp.hs view
@@ -71,8 +71,7 @@ import Futhark.IR import Futhark.IR.Aliases ( Aliases,- removeLambdaAliases,- removeStmAliases,+ CanBeAliased (..), ) import Futhark.IR.Mem import Futhark.IR.Prop.Aliases@@ -280,9 +279,7 @@ -- | Perform alias analysis on a 'KernelBody'. aliasAnalyseKernelBody ::- ( ASTRep rep,- CanBeAliased (Op rep)- ) =>+ Alias.AliasableRep rep => AliasTable -> KernelBody rep -> KernelBody (Aliases rep)@@ -290,21 +287,6 @@ let Body dec' stms' _ = Alias.analyseBody aliases $ Body dec stms [] in KernelBody dec' stms' res -removeKernelBodyAliases ::- CanBeAliased (Op rep) =>- KernelBody (Aliases rep) ->- KernelBody rep-removeKernelBodyAliases (KernelBody (_, dec) stms res) =- KernelBody dec (fmap removeStmAliases stms) res--removeKernelBodyWisdom ::- CanBeWise (Op rep) =>- KernelBody (Wise rep) ->- KernelBody rep-removeKernelBodyWisdom (KernelBody dec stms res) =- let Body dec' stms' _ = removeBodyWisdom $ Body dec stms []- in KernelBody dec' stms' res- -- | The variables consumed in the kernel body. consumedInKernelBody :: Aliased rep =>@@ -549,10 +531,7 @@ instance TypedOp (SegOp lvl rep) where opType = pure . staticShapes . segOpType -instance- (ASTRep rep, Aliased rep, ASTConstraints lvl) =>- AliasedOp (SegOp lvl rep)- where+instance (ASTConstraints lvl, Aliased rep) => AliasedOp (SegOp lvl rep) where opAliases = map (const mempty) . segOpType consumedInOp (SegMap _ _ _ kbody) =@@ -776,6 +755,44 @@ Array et <$> traverse (mapOnSegOpSubExp tv) shape <*> pure u mapOnSegOpType _tv (Mem s) = pure $ Mem s +rephraseBinOp ::+ Monad f =>+ Rephraser f from rep ->+ SegBinOp from ->+ f (SegBinOp rep)+rephraseBinOp r (SegBinOp comm lam nes shape) =+ SegBinOp comm <$> rephraseLambda r lam <*> pure nes <*> pure shape++rephraseKernelBody ::+ Monad f =>+ Rephraser f from rep ->+ KernelBody from ->+ f (KernelBody rep)+rephraseKernelBody r (KernelBody dec stms res) =+ KernelBody <$> rephraseBodyDec r dec <*> traverse (rephraseStm r) stms <*> pure res++instance RephraseOp (SegOp lvl) where+ rephraseInOp r (SegMap lvl space ts body) =+ SegMap lvl space ts <$> rephraseKernelBody r body+ rephraseInOp r (SegRed lvl space reds ts body) =+ SegRed lvl space+ <$> mapM (rephraseBinOp r) reds+ <*> pure ts+ <*> rephraseKernelBody r body+ rephraseInOp r (SegScan lvl space scans ts body) =+ SegScan lvl space+ <$> mapM (rephraseBinOp r) scans+ <*> pure ts+ <*> rephraseKernelBody r body+ rephraseInOp r (SegHist lvl space hists ts body) =+ SegHist lvl space+ <$> mapM onOp hists+ <*> pure ts+ <*> rephraseKernelBody r body+ where+ onOp (HistOp w rf arrs nes shape op) =+ HistOp w rf arrs nes shape <$> rephraseLambda r op+ -- | A helper for defining 'TraverseOpStms'. traverseSegOpStms :: Monad m => OpStmsTraverser m (SegOp lvl rep) rep traverseSegOpStms f segop = mapSegOpM mapper segop@@ -899,16 +916,7 @@ </> pretty shape <> PP.comma </> pretty op -instance- ( ASTRep rep,- ASTRep (Aliases rep),- CanBeAliased (Op rep),- ASTConstraints lvl- ) =>- CanBeAliased (SegOp lvl rep)- where- type OpWithAliases (SegOp lvl rep) = SegOp lvl (Aliases rep)-+instance CanBeAliased (SegOp lvl) where addOpAliases aliases = runIdentity . mapSegOpM alias where alias =@@ -919,36 +927,11 @@ pure pure - removeOpAliases = runIdentity . mapSegOpM remove- where- remove =- SegOpMapper- pure- (pure . removeLambdaAliases)- (pure . removeKernelBodyAliases)- pure- pure- informKernelBody :: Informing rep => KernelBody rep -> KernelBody (Wise rep) informKernelBody (KernelBody dec stms res) = mkWiseKernelBody dec (informStms stms) res -instance- (CanBeWise (Op rep), ASTRep rep, ASTConstraints lvl) =>- CanBeWise (SegOp lvl rep)- where- type OpWithWisdom (SegOp lvl rep) = SegOp lvl (Wise rep)-- removeOpWisdom = runIdentity . mapSegOpM remove- where- remove =- SegOpMapper- pure- (pure . removeLambdaWisdom)- (pure . removeKernelBodyWisdom)- pure- pure-+instance CanBeWise (SegOp lvl) where addOpWisdom = runIdentity . mapSegOpM add where add =@@ -1034,7 +1017,7 @@ <*> Engine.simplify what mkWiseKernelBody ::- (ASTRep rep, CanBeWise (Op rep)) =>+ Informing rep => BodyDec rep -> Stms (Wise rep) -> [KernelResult] ->
src/Futhark/IR/Seq.hs view
@@ -30,16 +30,13 @@ -- | The phantom type for the Seq representation. data Seq -instance RepTypes Seq where- type Op Seq = ()+instance RepTypes Seq instance ASTRep Seq where expTypesFromPat = pure . expExtTypesFromPat -instance TC.CheckableOp Seq where- checkOp = pure--instance TC.Checkable Seq+instance TC.Checkable Seq where+ checkOp NoOp = pure () instance Buildable Seq where mkBody = Body ()@@ -60,7 +57,7 @@ traverseOpStms _ = pure simpleSeq :: Simplify.SimpleOps Seq-simpleSeq = Simplify.bindableSimpleOps (const $ pure ((), mempty))+simpleSeq = Simplify.bindableSimpleOps (const $ pure (NoOp, mempty)) -- | Simplify a sequential program. simplifyProg :: Prog Seq -> PassM (Prog Seq)
src/Futhark/IR/SeqMem.hs view
@@ -28,20 +28,16 @@ type LParamInfo SeqMem = LParamMem type RetType SeqMem = RetTypeMem type BranchType SeqMem = BranchTypeMem- type Op SeqMem = MemOp ()+ type OpC SeqMem = MemOp NoOp instance ASTRep SeqMem where expTypesFromPat = pure . map snd . bodyReturnsFromPat instance PrettyRep SeqMem -instance TC.CheckableOp SeqMem where- checkOp (Alloc size _) =- TC.require [Prim int64] size- checkOp (Inner ()) =- pure ()- instance TC.Checkable SeqMem where+ checkOp (Alloc size _) = TC.require [Prim int64] size+ checkOp (Inner NoOp) = pure () checkFParamDec = checkMemInfo checkLParamDec = checkMemInfo checkLetBoundDec = checkMemInfo@@ -55,7 +51,7 @@ instance BuilderOps SeqMem where mkExpDecB _ _ = pure () mkBodyB stms res = pure $ Body () stms res- mkLetNamesB = mkLetNamesB' ()+ mkLetNamesB = mkLetNamesB' DefaultSpace () instance TraverseOpStms SeqMem where traverseOpStms _ = pure@@ -63,7 +59,7 @@ instance BuilderOps (Engine.Wise SeqMem) where mkExpDecB pat e = pure $ Engine.mkWiseExpDec pat () e mkBodyB stms res = pure $ Engine.mkWiseBody () stms res- mkLetNamesB = mkLetNamesB''+ mkLetNamesB = mkLetNamesB'' DefaultSpace instance TraverseOpStms (Engine.Wise SeqMem) where traverseOpStms _ = pure@@ -73,4 +69,4 @@ simpleSeqMem :: Engine.SimpleOps SeqMem simpleSeqMem =- simpleGeneric (const mempty) $ const $ pure ((), mempty)+ simpleGeneric (const mempty) $ const $ pure (NoOp, mempty)
src/Futhark/IR/Syntax.hs view
@@ -306,9 +306,9 @@ -- | Which kind of reshape is this? data ReshapeKind- = -- | Any kind of reshaping.+ = -- | New shape is dynamically same as original. ReshapeCoerce- | -- | New shape is dynamically same as original.+ | -- | Any kind of reshaping. ReshapeArbitrary deriving (Eq, Ord, Show)
src/Futhark/IR/TypeCheck.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE Strict #-} {-# LANGUAGE TypeFamilies #-} -- | The type checker checks whether the program is type-consistent.@@ -14,7 +13,6 @@ bad, context, Checkable (..),- CheckableOp (..), lookupVar, lookupAliases, checkOpWith,@@ -53,6 +51,7 @@ import Data.Maybe import Data.Set qualified as S import Data.Text qualified as T+import Futhark.Analysis.Alias import Futhark.Analysis.PrimExp import Futhark.Construct (instantiateShapes) import Futhark.IR.Aliases hiding (lookupAliases)@@ -276,7 +275,7 @@ data Env rep = Env { envVtable :: M.Map VName (VarBinding rep), envFtable :: M.Map Name (FunBinding rep),- envCheckOp :: OpWithAliases (Op rep) -> TypeM rep (),+ envCheckOp :: Op (Aliases rep) -> TypeM rep (), envContext :: [T.Text] } @@ -375,7 +374,7 @@ pure (x, o) checkOpWith ::- (OpWithAliases (Op rep) -> TypeM rep ()) ->+ (Op (Aliases rep) -> TypeM rep ()) -> TypeM rep a -> TypeM rep a checkOpWith checker = local $ \env -> env {envCheckOp = checker}@@ -1485,12 +1484,8 @@ unless (primExpType e == t) . bad . TypeError $ prettyText e <> " must have type " <> prettyText t -class ASTRep rep => CheckableOp rep where- checkOp :: OpWithAliases (Op rep) -> TypeM rep ()- -- ^ Used at top level; can be locally changed with 'checkOpWith'.- -- | The class of representations that can be type-checked.-class (ASTRep rep, CanBeAliased (Op rep), CheckableOp rep) => Checkable rep where+class (AliasableRep rep, TypedOp (OpC rep (Aliases rep))) => Checkable rep where checkExpDec :: ExpDec rep -> TypeM rep () checkBodyDec :: BodyDec rep -> TypeM rep () checkFParamDec :: VName -> FParamInfo rep -> TypeM rep ()@@ -1502,6 +1497,9 @@ matchReturnType :: [RetType rep] -> Result -> TypeM rep () matchBranchType :: [BranchType rep] -> Body (Aliases rep) -> TypeM rep () matchLoopResult :: [FParam (Aliases rep)] -> Result -> TypeM rep ()++ -- | Used at top level; can be locally changed with 'checkOpWith'.+ checkOp :: Op (Aliases rep) -> TypeM rep () default checkExpDec :: ExpDec rep ~ () => ExpDec rep -> TypeM rep () checkExpDec = pure
src/Futhark/Internalise/Defunctionalise.hs view
@@ -632,13 +632,14 @@ (e1', _) <- defuncExp e1 (e2', sv) <- defuncExp e2 pure (Assert e1' e2' desc loc, sv)-defuncExp (Constr name es (Info (Scalar (Sum all_fs))) loc) = do+defuncExp (Constr name es (Info sum_t@(Scalar (Sum all_fs))) loc) = do (es', svs) <- unzip <$> mapM defuncExp es let sv = SumSV name svs $ M.toList $ name `M.delete` M.map (map defuncType) all_fs- pure (Constr name es' (Info (typeFromSV sv)) loc, sv)+ sum_t' = combineTypeShapes sum_t (typeFromSV sv)+ pure (Constr name es' (Info sum_t') loc, sv) where defuncType :: Monoid als =>
src/Futhark/Optimise/ArrayShortCircuiting.hs view
@@ -46,15 +46,12 @@ replaceInParams :: CoalsTab -> [Param FParamMem] -> (Names, [Param FParamMem]) replaceInParams coalstab fparams = let (mem_allocs_to_remove, fparams') =- foldl- replaceInParam- (mempty, mempty)- fparams+ foldl replaceInParam (mempty, mempty) fparams in (mem_allocs_to_remove, reverse fparams') where replaceInParam (to_remove, acc) (Param attrs name dec) = case dec of- MemMem DefaultSpace+ MemMem _ | Just entry <- M.lookup name coalstab -> (oneName (dstmem entry) <> to_remove, Param attrs (dstmem entry) dec : acc) MemArray pt shp u (ArrayIn m ixf)@@ -71,11 +68,11 @@ & pure pass ::- (Mem rep inner, LetDec rep ~ LetDecMem, CanBeAliased inner) =>+ (Mem rep inner, LetDec rep ~ LetDecMem, AliasableRep rep) => String -> String -> (Prog (Aliases rep) -> Pass.PassM (M.Map Name CoalsTab)) ->- (inner -> UpdateM inner inner) ->+ (inner rep -> UpdateM (inner rep) (inner rep)) -> (CoalsTab -> [FParam (Aliases rep)] -> (Names, [FParam (Aliases rep)])) -> Pass rep rep pass flag desc mk on_inner on_fparams =@@ -107,12 +104,18 @@ Just entry -> res {resSubExp = Var $ dstmem entry} Nothing -> res -updateStms :: (Mem rep inner, LetDec rep ~ LetDecMem) => Stms rep -> UpdateM inner (Stms rep)+updateStms ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ Stms rep ->+ UpdateM (inner rep) (Stms rep) updateStms stms = do stms' <- mapM replaceInStm stms removeAllocsInStms stms' -replaceInStm :: (Mem rep inner, LetDec rep ~ LetDecMem) => Stm rep -> UpdateM inner (Stm rep)+replaceInStm ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ Stm rep ->+ UpdateM (inner rep) (Stm rep) replaceInStm (Let (Pat elems) d e) = do elems' <- mapM replaceInPatElem elems e' <- replaceInExp elems' e@@ -123,7 +126,11 @@ fromMaybe p <$> lookupAndReplace vname PatElem u replaceInPatElem p = pure p -replaceInExp :: (Mem rep inner, LetDec rep ~ LetDecMem) => [PatElem LetDecMem] -> Exp rep -> UpdateM inner (Exp rep)+replaceInExp ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ [PatElem LetDecMem] ->+ Exp rep ->+ UpdateM (inner rep) (Exp rep) replaceInExp _ e@(BasicOp _) = pure e replaceInExp pat_elems (Match cond_ses cases defbody dec) = do defbody' <- replaceInIfBody defbody@@ -149,7 +156,7 @@ replaceInSegOp :: (Mem rep inner, LetDec rep ~ LetDecMem) => SegOp lvl rep ->- UpdateM inner (SegOp lvl rep)+ UpdateM (inner rep) (SegOp lvl rep) replaceInSegOp (SegMap lvl sp tps body) = do stms <- updateStms $ kernelBodyStms body pure $ SegMap lvl sp tps $ body {kernelBodyStms = stms}@@ -163,11 +170,11 @@ stms <- updateStms $ kernelBodyStms body pure $ SegHist lvl sp hist_ops tps $ body {kernelBodyStms = stms} -replaceInHostOp :: HostOp GPUMem () -> UpdateM (HostOp GPUMem ()) (HostOp GPUMem ())+replaceInHostOp :: HostOp NoOp GPUMem -> UpdateM (HostOp NoOp GPUMem) (HostOp NoOp GPUMem) replaceInHostOp (SegOp op) = SegOp <$> replaceInSegOp op replaceInHostOp op = pure op -replaceInMCOp :: MCOp MCMem () -> UpdateM (MCOp MCMem ()) (MCOp MCMem ())+replaceInMCOp :: MCOp NoOp MCMem -> UpdateM (MCOp NoOp MCMem) (MCOp NoOp MCMem) replaceInMCOp (ParOp par_op op) = ParOp <$> traverse replaceInSegOp par_op <*> replaceInSegOp op replaceInMCOp op = pure op@@ -187,7 +194,7 @@ else pure m generalizeIxfun _ _ m = pure m -replaceInIfBody :: (Mem rep inner, LetDec rep ~ LetDecMem) => Body rep -> UpdateM inner (Body rep)+replaceInIfBody :: (Mem rep inner, LetDec rep ~ LetDecMem) => Body rep -> UpdateM (inner rep) (Body rep) replaceInIfBody b@(Body _ stms res) = do coaltab <- asks envCoalesceTab stms' <- updateStms stms
src/Futhark/Optimise/ArrayShortCircuiting/ArrayCoalescing.hs view
@@ -21,6 +21,7 @@ import Data.Maybe import Data.Sequence (Seq (..)) import Data.Set qualified as S+import Futhark.Analysis.LastUse import Futhark.Analysis.PrimExp.Convert import Futhark.IR.Aliases import Futhark.IR.GPUMem as GPU@@ -29,7 +30,6 @@ import Futhark.IR.SeqMem import Futhark.MonadFreshNames import Futhark.Optimise.ArrayShortCircuiting.DataStructs-import Futhark.Optimise.ArrayShortCircuiting.LastUse import Futhark.Optimise.ArrayShortCircuiting.MemRefAggreg import Futhark.Optimise.ArrayShortCircuiting.TopdownAnalysis import Futhark.Util@@ -39,15 +39,19 @@ ( Mem rep inner, ASTRep rep, CanBeAliased inner,- Op rep ~ MemOp inner,+ AliasableRep rep,+ Op rep ~ MemOp inner rep, HasMemBlock (Aliases rep), LetDec rep ~ LetDecMem,- TopDownHelper (OpWithAliases inner)+ TopDownHelper (inner (Aliases rep)) ) +type ComputeScalarTable rep op =+ ScopeTab rep -> op -> ScalarTableM rep (M.Map VName (PrimExp VName))+ -- Helper type for computing scalar tables on ops. newtype ComputeScalarTableOnOp rep = ComputeScalarTableOnOp- { scalarTableOnOp :: ScopeTab rep -> Op (Aliases rep) -> ScalarTableM rep (M.Map VName (PrimExp VName))+ { scalarTableOnOp :: ComputeScalarTable rep (Op (Aliases rep)) } type ScalarTableM rep a = Reader (ComputeScalarTableOnOp rep) a@@ -109,7 +113,7 @@ -- | Given a 'Prog' in 'GPUMem' representation, compute the coalescing table -- by folding over each function.-mkCoalsTabGPU :: (MonadFreshNames m) => Prog (Aliases GPUMem) -> m (M.Map Name CoalsTab)+mkCoalsTabGPU :: MonadFreshNames m => Prog (Aliases GPUMem) -> m (M.Map Name CoalsTab) mkCoalsTabGPU prog = mkCoalsTabProg (lastUseGPUMem prog)@@ -267,7 +271,7 @@ td_env bu_env shortCircuitGPUMem _ _ (Inner (GPU.SizeOp _)) _ bu_env = pure bu_env-shortCircuitGPUMem _ _ (Inner (GPU.OtherOp ())) _ bu_env = pure bu_env+shortCircuitGPUMem _ _ (Inner (GPU.OtherOp NoOp)) _ bu_env = pure bu_env shortCircuitMCMem :: LUTabFun ->@@ -277,7 +281,7 @@ BotUpEnv -> ShortCircuitM MCMem BotUpEnv shortCircuitMCMem _ _ (Alloc _ _) _ bu_env = pure bu_env-shortCircuitMCMem _ _ (Inner (MC.OtherOp ())) _ bu_env = pure bu_env+shortCircuitMCMem _ _ (Inner (MC.OtherOp NoOp)) _ bu_env = pure bu_env shortCircuitMCMem lutab pat (Inner (MC.ParOp (Just par_op) op)) td_env bu_env = shortCircuitSegOp (const True) lutab pat par_op td_env bu_env >>= shortCircuitSegOp (const True) lutab pat op td_env@@ -771,8 +775,7 @@ ) pure bu_env- { activeCoals =- actv_res,+ { activeCoals = actv_res, successCoals = succ_res, inhibit = inhibit_res }@@ -1262,10 +1265,10 @@ TopdownEnv rep -> [PatElem (VarAliases, LetDecMem)] -> (CoalsTab, InhibitTab)-filterSafetyCond2and5 act_coal inhb_coal scals_env td_env =- foldl helper (act_coal, inhb_coal)+filterSafetyCond2and5 act_coal inhb_coal scals_env td_env pes =+ foldl helper (act_coal, inhb_coal) pes where- helper (acc, inhb) patel =+ helper (acc, inhb) patel = do -- For each pattern element in the input list case (patElemName patel, patElemDec patel) of (b, (_, MemArray tp0 shp0 _ (ArrayIn m_b _idxfn_b))) ->@@ -1275,27 +1278,33 @@ Just info@(CoalsEntry x_mem _ _ vtab _ _) -> -- And m_b we're trying to coalesce m_b let failed = markFailedCoal (acc, inhb) m_b- in case M.lookup b vtab of- Nothing ->- case getDirAliasedIxfn td_env acc b of- Nothing -> failed- Just (_, _, b_indfun') ->- -- And we have the index function of b- case freeVarSubstitutions (scope td_env) scals_env b_indfun' of- Nothing -> failed- Just fv_subst ->- let mem_info = Coalesced TransitiveCoal (MemBlock tp0 shp0 x_mem b_indfun') fv_subst- info' = info {vartab = M.insert b mem_info vtab}- in (M.insert m_b info' acc, inhb)- Just (Coalesced k (MemBlock pt shp _ new_indfun) _) ->- let safe_2 = isInScope td_env x_mem- in case freeVarSubstitutions (scope td_env) scals_env new_indfun of- Just fv_subst- | safe_2 ->- let mem_info = Coalesced k (MemBlock pt shp x_mem new_indfun) fv_subst- info' = info {vartab = M.insert b mem_info vtab}- in (M.insert m_b info' acc, inhb)- _ -> failed+ in -- It is not safe to short circuit if some other pattern+ -- element is aliased to this one, as this indicates the+ -- two pattern elements reference the same physical+ -- value somehow.+ if any ((`nameIn` aliasesOf patel) . patElemName) pes+ then failed+ else case M.lookup b vtab of+ Nothing ->+ case getDirAliasedIxfn td_env acc b of+ Nothing -> failed+ Just (_, _, b_indfun') ->+ -- And we have the index function of b+ case freeVarSubstitutions (scope td_env) scals_env b_indfun' of+ Nothing -> failed+ Just fv_subst ->+ let mem_info = Coalesced TransitiveCoal (MemBlock tp0 shp0 x_mem b_indfun') fv_subst+ info' = info {vartab = M.insert b mem_info vtab}+ in (M.insert m_b info' acc, inhb)+ Just (Coalesced k (MemBlock pt shp _ new_indfun) _) ->+ let safe_2 = isInScope td_env x_mem+ in case freeVarSubstitutions (scope td_env) scals_env new_indfun of+ Just fv_subst+ | safe_2 ->+ let mem_info = Coalesced k (MemBlock pt shp x_mem new_indfun) fv_subst+ info' = info {vartab = M.insert b mem_info vtab}+ in (M.insert m_b info' acc, inhb)+ _ -> failed _ -> (acc, inhb) -- | Pattern matches a potentially coalesced statement and@@ -1469,8 +1478,8 @@ Nothing genSSPointInfoMemOp ::- GenSSPoint rep inner ->- GenSSPoint rep (MemOp inner)+ GenSSPoint rep (inner (Aliases rep)) ->+ GenSSPoint rep (MemOp inner (Aliases rep)) genSSPointInfoMemOp onOp lutab td_end scopetab pat (Inner op) = onOp lutab td_end scopetab pat op genSSPointInfoMemOp _ _ _ _ _ _ = Nothing@@ -1700,11 +1709,8 @@ on_op scope_table op computeScalarTable _ _ = pure mempty -type ComputeScalarTable rep op =- ScopeTab rep -> op -> ScalarTableM rep (M.Map VName (PrimExp VName))- computeScalarTableMemOp ::- ComputeScalarTable rep inner -> ComputeScalarTable rep (MemOp inner)+ ComputeScalarTable rep (inner (Aliases rep)) -> ComputeScalarTable rep (MemOp inner (Aliases rep)) computeScalarTableMemOp _ _ (Alloc _ _) = pure mempty computeScalarTableMemOp onInner scope_table (Inner op) = onInner scope_table op @@ -1721,19 +1727,19 @@ (stmsToList $ kernelBodyStms $ segBody segop) computeScalarTableGPUMem ::- ComputeScalarTable GPUMem (GPU.HostOp (Aliases GPUMem) ())+ ComputeScalarTable GPUMem (GPU.HostOp NoOp (Aliases GPUMem)) computeScalarTableGPUMem scope_table (GPU.SegOp segop) = computeScalarTableSegOp scope_table segop computeScalarTableGPUMem _ (GPU.SizeOp _) = pure mempty-computeScalarTableGPUMem _ (GPU.OtherOp ()) = pure mempty+computeScalarTableGPUMem _ (GPU.OtherOp NoOp) = pure mempty computeScalarTableGPUMem scope_table (GPU.GPUBody _ body) = concatMapM (computeScalarTable $ scope_table <> scopeOf (bodyStms body)) (stmsToList $ bodyStms body) computeScalarTableMCMem ::- ComputeScalarTable MCMem (MC.MCOp (Aliases MCMem) ())-computeScalarTableMCMem _ (MC.OtherOp ()) = pure mempty+ ComputeScalarTable MCMem (MC.MCOp NoOp (Aliases MCMem))+computeScalarTableMCMem _ (MC.OtherOp NoOp) = pure mempty computeScalarTableMCMem scope_table (MC.ParOp par_op segop) = (<>) <$> maybe (pure mempty) (computeScalarTableSegOp scope_table) par_op
src/Futhark/Optimise/ArrayShortCircuiting/DataStructs.hs view
@@ -379,7 +379,7 @@ -- argument. Otherwise look up the type of the argument and return a 'LeafExp' -- if it is a 'PrimType'. vnameToPrimExp ::- (CanBeAliased (Op rep), RepTypes rep) =>+ (AliasableRep rep) => ScopeTab rep -> ScalarTab -> VName ->
− src/Futhark/Optimise/ArrayShortCircuiting/LastUse.hs
@@ -1,458 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}---- | Last use analysis for array short circuiting------ Last-Use analysis of a Futhark program in aliased explicit-memory lore form.--- Takes as input such a program or a function and produces a 'M.Map VName--- Names', in which the key identified the let stmt, and the list argument--- identifies the variables that were lastly used in that stmt. Note that the--- results of a body do not have a last use, and neither do a function--- parameters if it happens to not be used inside function's body. Such cases--- are supposed to be treated separately.------ This pass is different from "Futhark.Analysis.LastUse" in that memory blocks--- are used to alias arrays. For instance, an 'Update' will not result in a last--- use of the array being updated, because the result lives in the same memory.-module Futhark.Optimise.ArrayShortCircuiting.LastUse- ( lastUseSeqMem,- lastUseGPUMem,- lastUseMCMem,- LUTabFun,- LUTabProg,- )-where--import Control.Monad.Reader-import Control.Monad.State.Strict-import Data.Bifunctor (bimap)-import Data.Function ((&))-import Data.Map.Strict qualified as M-import Data.Maybe-import Data.Sequence (Seq (..))-import Futhark.IR.Aliases-import Futhark.IR.GPUMem-import Futhark.IR.GPUMem qualified as GPU-import Futhark.IR.MCMem-import Futhark.IR.MCMem qualified as MC-import Futhark.IR.SeqMem-import Futhark.Optimise.ArrayShortCircuiting.DataStructs-import Futhark.Util---- | Maps a name indentifying a Stm to the last uses in that Stm.-type LUTabFun = M.Map VName Names---- | LU-table for the constants, and for each function.-type LUTabProg = (LUTabFun, M.Map Name LUTabFun)--type LastUseOp rep = Op (Aliases rep) -> Names -> LastUseM rep (LUTabFun, Names, Names)---- | 'LastUseReader' allows us to abstract over representations by supplying the--- 'onOp' function.-data LastUseReader rep = LastUseReader- { onOp :: LastUseOp rep,- scope :: Scope (Aliases rep)- }---- | Maps a variable or memory block to its aliases.-type AliasTab = M.Map VName Names--newtype LastUseM rep a = LastUseM (StateT AliasTab (Reader (LastUseReader rep)) a)- deriving- ( Monad,- Functor,- Applicative,- MonadReader (LastUseReader rep),- MonadState AliasTab- )--instance- (RepTypes rep, CanBeAliased (Op rep)) =>- HasScope (Aliases rep) (LastUseM rep)- where- askScope = asks scope--instance- (RepTypes rep, CanBeAliased (Op rep)) =>- LocalScope (Aliases rep) (LastUseM rep)- where- localScope sc (LastUseM m) = LastUseM $ do- local (\rd -> rd {scope = scope rd <> sc}) m--type Constraints rep =- ( LocalScope (Aliases rep) (LastUseM rep),- ASTRep rep,- FreeIn (OpWithAliases (Op rep)),- HasMemBlock (Aliases rep),- CanBeAliased (Op rep)- )--runLastUseM :: LastUseOp rep -> LastUseM rep a -> a-runLastUseM onOp (LastUseM m) =- runReader (evalStateT m mempty) (LastUseReader onOp mempty)--aliasLookup :: VName -> LastUseM rep Names-aliasLookup vname =- gets $ fromMaybe mempty . M.lookup vname--lastUseProg ::- Constraints rep =>- Prog (Aliases rep) ->- LastUseM rep LUTabProg-lastUseProg prog =- let bound_in_consts =- progConsts prog- & concatMap (patNames . stmPat)- & namesFromList- consts = progConsts prog- funs = progFuns prog- in inScopeOf consts $ do- (consts_lu, _) <- lastUseStms consts mempty mempty- lus <- mapM (lastUseFun bound_in_consts) funs- pure (consts_lu, M.fromList $ zip (map funDefName funs) lus)--lastUseFun ::- Constraints rep =>- Names ->- FunDef (Aliases rep) ->- LastUseM rep LUTabFun-lastUseFun bound_in_consts f =- inScopeOf f $ fst <$> lastUseBody (funDefBody f) (mempty, bound_in_consts)---- | Perform last-use analysis on a 'Prog' in 'SeqMem'-lastUseSeqMem :: Prog (Aliases SeqMem) -> LUTabProg-lastUseSeqMem = runLastUseM lastUseSeqOp . lastUseProg---- | Perform last-use analysis on a 'Prog' in 'GPUMem'-lastUseGPUMem :: Prog (Aliases GPUMem) -> LUTabProg-lastUseGPUMem = runLastUseM (lastUseMemOp lastUseGPUOp) . lastUseProg---- | Perform last-use analysis on a 'Prog' in 'MCMem'-lastUseMCMem :: Prog (Aliases MCMem) -> LUTabProg-lastUseMCMem = runLastUseM (lastUseMemOp lastUseMCOp) . lastUseProg---- | Performing the last-use analysis on a body.------ The implementation consists of a bottom-up traversal of the body's statements--- in which the the variables lastly used in a statement are computed as the--- difference between the free-variables in that stmt and the set of variables--- known to be used after that statement.-lastUseBody ::- Constraints rep =>- -- | The body of statements- Body (Aliases rep) ->- -- | The current last-use table, tupled with the known set of already used names- (LUTabFun, Names) ->- -- | The result is:- -- (i) an updated last-use table,- -- (ii) an updated set of used names (including the binding).- LastUseM rep (LUTabFun, Names)-lastUseBody bdy@(Body _ stms result) (lutab, used_nms) =- -- perform analysis bottom-up in bindings: results are known to be used,- -- hence they are added to the used_nms set.- inScopeOf stms $ do- (lutab', _) <-- lastUseStms stms (lutab, used_nms) $- namesToList $- freeIn $- map resSubExp result- -- Clean up the used names by recomputing the aliasing transitive-closure- -- of the free names in body based on the current alias table @alstab@.- used_in_body <- aliasTransitiveClosure $ freeIn bdy- pure (lutab', used_nms <> used_in_body)---- | Performing the last-use analysis on a body.------ The implementation consists of a bottom-up traversal of the body's statements--- in which the the variables lastly used in a statement are computed as the--- difference between the free-variables in that stmt and the set of variables--- known to be used after that statement.-lastUseKernelBody ::- Constraints rep =>- -- | The body of statements- KernelBody (Aliases rep) ->- -- | The current last-use table, tupled with the known set of already used names- (LUTabFun, Names) ->- -- | The result is:- -- (i) an updated last-use table,- -- (ii) an updated set of used names (including the binding).- LastUseM rep (LUTabFun, Names)-lastUseKernelBody bdy@(KernelBody _ stms result) (lutab, used_nms) =- inScopeOf stms $ do- -- perform analysis bottom-up in bindings: results are known to be used,- -- hence they are added to the used_nms set.- (lutab', _) <-- lastUseStms stms (lutab, used_nms) $ namesToList $ freeIn result- -- Clean up the used names by recomputing the aliasing transitive-closure- -- of the free names in body based on the current alias table @alstab@.- used_in_body <- aliasTransitiveClosure $ freeIn bdy- pure (lutab', used_nms <> used_in_body)--lastUseStms ::- Constraints rep =>- Stms (Aliases rep) ->- (LUTabFun, Names) ->- [VName] ->- LastUseM rep (LUTabFun, Names)-lastUseStms Empty (lutab, nms) res_nms = do- aliases <- concatMapM aliasLookup res_nms- pure (lutab, nms <> aliases <> namesFromList res_nms)-lastUseStms (stm@(Let pat _ e) :<| stms) (lutab, nms) res_nms =- inScopeOf stm $ do- let extra_alias = case e of- BasicOp (Update _ old _ _) -> oneName old- BasicOp (FlatUpdate old _ _) -> oneName old- _ -> mempty- -- We build up aliases top-down- updateAliasing extra_alias pat- -- But compute last use bottom-up- (lutab', nms') <- lastUseStms stms (lutab, nms) res_nms- (lutab'', nms'') <- lastUseStm stm (lutab', nms')- pure (lutab'', nms'')--lastUseStm ::- Constraints rep =>- Stm (Aliases rep) ->- (LUTabFun, Names) ->- LastUseM rep (LUTabFun, Names)-lastUseStm (Let pat _ e) (lutab, used_nms) = do- -- analyse the expression and get the- -- (i) a new last-use table (in case the @e@ contains bodies of stmts)- -- (ii) the set of variables lastly used in the current binding.- -- (iii) aliased transitive-closure of used names, and- (lutab', last_uses, used_nms') <- lastUseExp e used_nms- sc <- asks scope- let lu_mems =- namesToList last_uses- & mapMaybe (`getScopeMemInfo` sc)- & map memName- & namesFromList- & flip namesSubtract used_nms-- -- filter-out the binded names from the set of used variables,- -- since they go out of scope, and update the last-use table.- let patnms = patNames pat- used_nms'' = used_nms' `namesSubtract` namesFromList patnms- lutab'' =- M.union lutab' $ M.insert (head patnms) (last_uses <> lu_mems) lutab- pure (lutab'', used_nms'')-------------------------------------- | Last-Use Analysis for an expression.-lastUseExp ::- Constraints rep =>- -- | The expression to analyse- Exp (Aliases rep) ->- -- | The set of used names "after" this expression- Names ->- -- | Result:- -- 1. an extra LUTab recording the last use for expression's inner bodies,- -- 2. the set of last-used vars in the expression at this level,- -- 3. the updated used names, now including expression's free vars.- LastUseM rep (LUTabFun, Names, Names)-lastUseExp (Match _ cases body _) used_nms = do- -- For an if-then-else, we duplicate the last use at each body level, meaning- -- we record the last use of the outer statement, and also the last use in the- -- statement in the inner bodies. We can safely ignore the if-condition as it is- -- a boolean scalar.- (lutab_cases, used_cases) <-- bimap mconcat mconcat . unzip- <$> mapM (flip lastUseBody (M.empty, used_nms) . caseBody) cases- (lutab', body_used_nms) <- lastUseBody body (M.empty, used_nms)- let free_in_body = freeIn body- let free_in_cases = freeIn cases- let used_nms' = used_cases <> body_used_nms- (_, last_used_arrs) <- lastUsedInNames used_nms $ free_in_body <> free_in_cases- pure (lutab_cases <> lutab', last_used_arrs, used_nms')-lastUseExp (DoLoop var_ses lf body) used_nms0 = inScopeOf lf $ do- free_in_body <- aliasTransitiveClosure $ freeIn body- -- compute the aliasing transitive closure of initializers that are not last-uses- var_inis <- catMaybes <$> mapM (initHelper (free_in_body <> used_nms0)) var_ses- let -- To record last-uses inside the loop body, we call 'lastUseBody' with used-names- -- being: (free_in_body - loop-variants-a) + used_nms0. As such we disable cases b)- -- and c) to produce loop-variant last uses inside the loop, and also we prevent- -- the free-loop-variables to having last uses inside the loop.- free_in_body' = free_in_body `namesSubtract` namesFromList (map fst var_inis)- used_nms = used_nms0 <> free_in_body' <> freeIn (bodyResult body)- (body_lutab, _) <- lastUseBody body (mempty, used_nms)-- -- add var_inis_a to the body_lutab, i.e., record the last-use of- -- initializer in the corresponding loop variant.- let lutab_res = body_lutab <> M.fromList var_inis-- -- the result used names are:- fpar_nms = namesFromList $ map (identName . paramIdent . fst) var_ses- used_nms' = (free_in_body <> freeIn (map snd var_ses)) `namesSubtract` fpar_nms- used_nms_res = used_nms0 <> used_nms' <> freeIn (bodyResult body)-- -- the last-uses at loop-statement level are the loop free variables that- -- do not belong to @used_nms0@; this includes the initializers of b), @lu_ini_b@- lu_arrs = used_nms' `namesSubtract` used_nms0- pure (lutab_res, lu_arrs, used_nms_res)- where- initHelper free_and_used (fp, se) = do- names <- aliasTransitiveClosure $ maybe mempty oneName $ subExpVar se- if names `namesIntersect` free_and_used- then pure Nothing- else pure $ Just (identName $ paramIdent fp, names)-lastUseExp (Op op) used_nms = do- on_op <- reader onOp- on_op op used_nms-lastUseExp e used_nms = do- let free_in_e = freeIn e- (used_nms', lu_vars) <- lastUsedInNames used_nms free_in_e- pure (M.empty, lu_vars, used_nms')--lastUseMemOp ::- (inner -> Names -> LastUseM rep (LUTabFun, Names, Names)) ->- MemOp inner ->- Names ->- LastUseM rep (LUTabFun, Names, Names)-lastUseMemOp _ (Alloc se sp) used_nms = do- let free_in_e = freeIn se <> freeIn sp- (used_nms', lu_vars) <- lastUsedInNames used_nms free_in_e- pure (M.empty, lu_vars, used_nms')-lastUseMemOp onInner (Inner op) used_nms = onInner op used_nms--lastUseSegOp ::- Constraints rep =>- SegOp lvl (Aliases rep) ->- Names ->- LastUseM rep (LUTabFun, Names, Names)-lastUseSegOp (SegMap _ _ tps kbody) used_nms = do- (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn tps- (body_lutab, used_nms'') <- lastUseKernelBody kbody (mempty, used_nms')- pure (body_lutab, lu_vars, used_nms' <> used_nms'')-lastUseSegOp (SegRed _ _ sbos tps kbody) used_nms = do- (lutab_sbo, lu_vars_sbo, used_nms_sbo) <- lastUseSegBinOp sbos used_nms- (used_nms', lu_vars) <- lastUsedInNames used_nms_sbo $ freeIn tps- (body_lutab, used_nms'') <- lastUseKernelBody kbody (mempty, used_nms')- pure (M.union lutab_sbo body_lutab, lu_vars <> lu_vars_sbo, used_nms_sbo <> used_nms' <> used_nms'')-lastUseSegOp (SegScan _ _ sbos tps kbody) used_nms = do- (lutab_sbo, lu_vars_sbo, used_nms_sbo) <- lastUseSegBinOp sbos used_nms- (used_nms', lu_vars) <- lastUsedInNames used_nms_sbo $ freeIn tps- (body_lutab, used_nms'') <- lastUseKernelBody kbody (mempty, used_nms')- pure (M.union lutab_sbo body_lutab, lu_vars <> lu_vars_sbo, used_nms_sbo <> used_nms' <> used_nms'')-lastUseSegOp (SegHist _ _ hos tps kbody) used_nms = do- (lutab_sbo, lu_vars_sbo, used_nms_sbo) <- lastUseHistOp hos used_nms- (used_nms', lu_vars) <- lastUsedInNames used_nms_sbo $ freeIn tps- (body_lutab, used_nms'') <- lastUseKernelBody kbody (mempty, used_nms')- pure (M.union lutab_sbo body_lutab, lu_vars <> lu_vars_sbo, used_nms_sbo <> used_nms' <> used_nms'')--lastUseGPUOp :: HostOp (Aliases GPUMem) () -> Names -> LastUseM GPUMem (LUTabFun, Names, Names)-lastUseGPUOp (GPU.OtherOp ()) used_nms =- pure (mempty, mempty, used_nms)-lastUseGPUOp (SizeOp sop) used_nms = do- (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn sop- pure (mempty, lu_vars, used_nms')-lastUseGPUOp (GPUBody tps body) used_nms = do- (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn tps- (body_lutab, used_nms'') <- lastUseBody body (mempty, used_nms')- pure (body_lutab, lu_vars, used_nms' <> used_nms'')-lastUseGPUOp (SegOp op) used_nms =- lastUseSegOp op used_nms--lastUseMCOp :: MCOp (Aliases MCMem) () -> Names -> LastUseM MCMem (LUTabFun, Names, Names)-lastUseMCOp (MC.OtherOp ()) used_nms =- pure (mempty, mempty, used_nms)-lastUseMCOp (MC.ParOp par_op op) used_nms = do- (lutab_par_op, lu_vars_par_op, used_names_par_op) <-- maybe (pure mempty) (`lastUseSegOp` used_nms) par_op- (lutab_op, lu_vars_op, used_names_op) <-- lastUseSegOp op used_nms- pure- ( lutab_par_op <> lutab_op,- lu_vars_par_op <> lu_vars_op,- used_names_par_op <> used_names_op- )--lastUseSegBinOp ::- Constraints rep =>- [SegBinOp (Aliases rep)] ->- Names ->- LastUseM rep (LUTabFun, Names, Names)-lastUseSegBinOp sbos used_nms = do- (lutab, lu_vars, used_nms') <- unzip3 <$> mapM helper sbos- pure (mconcat lutab, mconcat lu_vars, mconcat used_nms')- where- helper (SegBinOp _ l@(Lambda _ body _) neutral shp) = inScopeOf l $ do- (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn neutral <> freeIn shp- (body_lutab, used_nms'') <- lastUseBody body (mempty, used_nms')- pure (body_lutab, lu_vars, used_nms'')--lastUseHistOp ::- Constraints rep =>- [HistOp (Aliases rep)] ->- Names ->- LastUseM rep (LUTabFun, Names, Names)-lastUseHistOp hos used_nms = do- (lutab, lu_vars, used_nms') <- unzip3 <$> mapM helper hos- pure (mconcat lutab, mconcat lu_vars, mconcat used_nms')- where- helper (HistOp shp rf dest neutral shp' l@(Lambda _ body _)) = inScopeOf l $ do- (used_nms', lu_vars) <- lastUsedInNames used_nms $ freeIn shp <> freeIn rf <> freeIn dest <> freeIn neutral <> freeIn shp'- (body_lutab, used_nms'') <- lastUseBody body (mempty, used_nms')- pure (body_lutab, lu_vars, used_nms'')--lastUseSeqOp :: Op (Aliases SeqMem) -> Names -> LastUseM SeqMem (LUTabFun, Names, Names)-lastUseSeqOp (Alloc se sp) used_nms = do- let free_in_e = freeIn se <> freeIn sp- (used_nms', lu_vars) <- lastUsedInNames used_nms free_in_e- pure (mempty, lu_vars, used_nms')-lastUseSeqOp (Inner ()) used_nms = do- pure (mempty, mempty, used_nms)------------------------------------------------------------ | Given already used names and newly encountered 'Names', return an updated--- set used names and the set of names that were last used here.------ For a given name @x@ in the new uses, if neither @x@ nor any of its aliases--- are present in the set of used names, this is a last use of @x@.-lastUsedInNames ::- -- | Used names- Names ->- -- | New uses- Names ->- LastUseM rep (Names, Names)-lastUsedInNames used_nms new_uses = do- -- a use of an argument x is also a use of any variable in x alias set- -- so we update the alias-based transitive-closure of used names.- new_uses_with_aliases <- aliasTransitiveClosure new_uses- -- if neither a variable x, nor any of its alias set have been used before (in- -- the backward traversal), then it is a last use of both that variable and- -- all other variables in its alias set- last_uses <- filterM isLastUse $ namesToList new_uses- last_uses' <- aliasTransitiveClosure $ namesFromList last_uses- pure (used_nms <> new_uses_with_aliases, last_uses')- where- isLastUse x = do- with_aliases <- aliasTransitiveClosure $ oneName x- pure $ not $ with_aliases `namesIntersect` used_nms---- | Compute the transitive closure of the aliases of a set of 'Names'.-aliasTransitiveClosure :: Names -> LastUseM rep Names-aliasTransitiveClosure args = do- res <- foldl (<>) args <$> mapM aliasLookup (namesToList args)- if res == args- then pure res- else aliasTransitiveClosure res---- | For each 'PatElem' in the 'Pat', add its aliases to the 'AliasTab' in--- 'LastUseM'. Additionally, 'Names' are added as aliases of all the 'PatElemT'.-updateAliasing ::- AliasesOf dec =>- -- | Extra names that all 'PatElem' should alias.- Names ->- -- | Pattern to process- Pat dec ->- LastUseM rep ()-updateAliasing extra_aliases =- mapM_ update . patElems- where- update :: AliasesOf dec => PatElem dec -> LastUseM rep ()- update (PatElem name dec) = do- let aliases = aliasesOf dec- aliases' <- aliasTransitiveClosure $ extra_aliases <> aliases- modify $ M.insert name aliases'
src/Futhark/Optimise/ArrayShortCircuiting/MemRefAggreg.hs view
@@ -75,7 +75,7 @@ -- | This function computes the written and read memory references for the current statement getUseSumFromStm ::- (Op rep ~ MemOp inner, HasMemBlock (Aliases rep)) =>+ (Op rep ~ MemOp inner rep, HasMemBlock (Aliases rep)) => TopdownEnv rep -> CoalsTab -> Stm (Aliases rep) ->@@ -152,7 +152,7 @@ -- 2. fails the entries in active coalesced table for which the write set -- overlaps the uses of the destination (to that point) recordMemRefUses ::- (CanBeAliased (Op rep), RepTypes rep, Op rep ~ MemOp inner, HasMemBlock (Aliases rep)) =>+ (AliasableRep rep, Op rep ~ MemOp inner rep, HasMemBlock (Aliases rep)) => TopdownEnv rep -> BotUpEnv -> Stm (Aliases rep) ->@@ -254,7 +254,7 @@ -- -- This check is conservative, so unless we can guarantee that there is no -- overlap, we return 'False'.-noMemOverlap :: (CanBeAliased (Op rep), RepTypes rep) => TopdownEnv rep -> AccessSummary -> AccessSummary -> Bool+noMemOverlap :: (AliasableRep rep) => TopdownEnv rep -> AccessSummary -> AccessSummary -> Bool noMemOverlap _ _ (Set mr) | mr == mempty = True noMemOverlap _ (Set mr) _
src/Futhark/Optimise/ArrayShortCircuiting/TopdownAnalysis.hs view
@@ -141,7 +141,7 @@ scopeHelper op = scopeOfSegSpace $ segSpace op -instance TopDownHelper (HostOp (Aliases GPUMem) ()) where+instance TopDownHelper (HostOp NoOp (Aliases GPUMem)) where innerNonNegatives vs (SegOp op) = innerNonNegatives vs op innerNonNegatives [vname] (SizeOp (GetSize _ _)) = oneName vname innerNonNegatives [vname] (SizeOp (GetSizeMax _)) = oneName vname@@ -153,7 +153,7 @@ scopeHelper (SegOp op) = scopeHelper op scopeHelper _ = mempty -instance TopDownHelper inner => TopDownHelper (MC.MCOp (Aliases MCMem) inner) where+instance TopDownHelper (inner (Aliases MCMem)) => TopDownHelper (MC.MCOp inner (Aliases MCMem)) where innerNonNegatives vs (ParOp par_op op) = maybe mempty (innerNonNegatives vs) par_op <> innerNonNegatives vs op@@ -167,14 +167,14 @@ maybe mempty scopeHelper par_op <> scopeHelper op scopeHelper MC.OtherOp {} = mempty -instance TopDownHelper () where- innerNonNegatives _ () = mempty- innerKnownLessThan () = mempty- scopeHelper () = mempty+instance TopDownHelper (NoOp rep) where+ innerNonNegatives _ NoOp = mempty+ innerKnownLessThan NoOp = mempty+ scopeHelper NoOp = mempty -- | fills in the TopdownEnv table updateTopdownEnv ::- (ASTRep rep, Op rep ~ MemOp inner, TopDownHelper (OpWithAliases inner)) =>+ (ASTRep rep, Op rep ~ MemOp inner rep, TopDownHelper (inner (Aliases rep))) => TopdownEnv rep -> Stm (Aliases rep) -> TopdownEnv rep
src/Futhark/Optimise/CSE.hs view
@@ -60,10 +60,7 @@ -- memory information, since at that point arrays have identity beyond their -- value. performCSE ::- ( ASTRep rep,- CanBeAliased (Op rep),- CSEInOp (OpWithAliases (Op rep))- ) =>+ (AliasableRep rep, CSEInOp (Op (Aliases rep))) => Bool -> Pass rep rep performCSE cse_arrays =@@ -87,10 +84,7 @@ -- memory information, since at that point arrays have identity beyond their -- value. performCSEOnFunDef ::- ( ASTRep rep,- CanBeAliased (Op rep),- CSEInOp (OpWithAliases (Op rep))- ) =>+ (AliasableRep rep, CSEInOp (Op (Aliases rep))) => Bool -> FunDef rep -> FunDef rep@@ -104,10 +98,7 @@ -- memory information, since at that point arrays have identity beyond their -- value. performCSEOnStms ::- ( ASTRep rep,- CanBeAliased (Op rep),- CSEInOp (OpWithAliases (Op rep))- ) =>+ (AliasableRep rep, CSEInOp (Op (Aliases rep))) => Bool -> Stms rep -> Stms rep@@ -125,7 +116,7 @@ (newCSEState cse_arrays) cseInFunDef ::- (ASTRep rep, Aliased rep, CSEInOp (Op rep)) =>+ (Aliased rep, CSEInOp (Op rep)) => Bool -> FunDef rep -> FunDef rep@@ -151,7 +142,7 @@ type CSEM rep = Reader (CSEState rep) cseInBody ::- (ASTRep rep, Aliased rep, CSEInOp (Op rep)) =>+ (Aliased rep, CSEInOp (Op rep)) => [Diet] -> Body rep -> CSEM rep (Body rep)@@ -168,7 +159,7 @@ consumeResult _ _ = mempty cseInLambda ::- (ASTRep rep, Aliased rep, CSEInOp (Op rep)) =>+ (Aliased rep, CSEInOp (Op rep)) => Lambda rep -> CSEM rep (Lambda rep) cseInLambda lam = do@@ -176,7 +167,7 @@ pure lam {lambdaBody = body'} cseInStms ::- (ASTRep rep, Aliased rep, CSEInOp (Op rep)) =>+ (Aliased rep, CSEInOp (Op rep)) => Names -> [Stm rep] -> CSEM rep a ->@@ -288,8 +279,8 @@ -- | Perform CSE within any nested expressions. cseInOp :: op -> CSEM rep op -instance CSEInOp () where- cseInOp () = pure ()+instance CSEInOp (NoOp rep) where+ cseInOp NoOp = pure NoOp subCSE :: CSEM rep r -> CSEM otherrep r subCSE m = do@@ -297,12 +288,11 @@ pure $ runReader m $ newCSEState cse_arrays instance- ( ASTRep rep,- Aliased rep,+ ( Aliased rep, CSEInOp (Op rep),- CSEInOp op+ CSEInOp (op rep) ) =>- CSEInOp (GPU.HostOp rep op)+ CSEInOp (GPU.HostOp op rep) where cseInOp (GPU.SegOp op) = GPU.SegOp <$> cseInOp op cseInOp (GPU.OtherOp op) = GPU.OtherOp <$> cseInOp op@@ -311,12 +301,11 @@ cseInOp x = pure x instance- ( ASTRep rep,- Aliased rep,+ ( Aliased rep, CSEInOp (Op rep),- CSEInOp op+ CSEInOp (op rep) ) =>- CSEInOp (MC.MCOp rep op)+ CSEInOp (MC.MCOp op rep) where cseInOp (MC.ParOp par_op op) = MC.ParOp <$> traverse cseInOp par_op <*> cseInOp op@@ -324,7 +313,7 @@ MC.OtherOp <$> cseInOp op instance- (ASTRep rep, Aliased rep, CSEInOp (Op rep)) =>+ (Aliased rep, CSEInOp (Op rep)) => CSEInOp (GPU.SegOp lvl rep) where cseInOp =@@ -333,22 +322,19 @@ (GPU.SegOpMapper pure cseInLambda cseInKernelBody pure pure) cseInKernelBody ::- (ASTRep rep, Aliased rep, CSEInOp (Op rep)) =>+ (Aliased rep, CSEInOp (Op rep)) => GPU.KernelBody rep -> CSEM rep (GPU.KernelBody rep) cseInKernelBody (GPU.KernelBody bodydec stms res) = do Body _ stms' _ <- cseInBody (map (const Observe) res) $ Body bodydec stms [] pure $ GPU.KernelBody bodydec stms' res -instance CSEInOp op => CSEInOp (Memory.MemOp op) where+instance CSEInOp (op rep) => CSEInOp (Memory.MemOp op rep) where cseInOp o@Memory.Alloc {} = pure o cseInOp (Memory.Inner k) = Memory.Inner <$> subCSE (cseInOp k) instance- ( ASTRep rep,- CanBeAliased (Op rep),- CSEInOp (OpWithAliases (Op rep))- ) =>+ (AliasableRep rep, CSEInOp (Op (Aliases rep))) => CSEInOp (SOAC.SOAC (Aliases rep)) where cseInOp = subCSE . SOAC.mapSOACM (SOAC.SOACMapper pure cseInLambda pure)
src/Futhark/Optimise/Fusion.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Strict #-}+ -- | Perform horizontal and vertical fusion of SOACs. See the paper -- /A T2 Graph-Reduction Approach To Fusion/ for the basic idea (some -- extensions discussed in /Design and GPGPU Performance of Futhark’s@@ -91,6 +93,9 @@ forM_ (zip (patNames outputs) untransformed_outputs) $ \(output, v) -> letBindNames [output] . BasicOp . SubExp . Var =<< H.applyTransforms ots v ResNode _ -> pure mempty+ TransNode output tr ia -> do+ (cs, e) <- H.transformToExp tr ia+ runBuilder_ $ certifying cs $ letBindNames [output] e FreeNode _ -> pure mempty DoNode stm lst -> do lst' <- mapM (finalizeNode . fst) lst@@ -98,9 +103,6 @@ MatchNode stm lst -> do lst' <- mapM (finalizeNode . fst) lst pure $ mconcat lst' <> oneStm stm- FinalNode stms1 nt' stms2 -> do- stms' <- finalizeNode nt'- pure $ stms1 <> stms' <> stms2 linearizeGraph :: (HasScope SOACS m, MonadFreshNames m) => DepGraph -> m (Stms SOACS) linearizeGraph dg =@@ -111,16 +113,6 @@ modify $ \s -> s {fusionCount = 1 + fusionCount s} pure $ Just x --- | For each node, find what came before, attempt to fuse them--- horizontally. This means we only perform horizontal fusion for--- SOACs that use the same input in some way.-horizontalFusionOnNode :: G.Node -> DepGraphAug FusionM-horizontalFusionOnNode node dg@DepGraph {dgGraph = g} =- applyAugs (map (uncurry hTryFuseNodesInGraph) pairs) dg- where- incoming_nodes = map fst $ filter (isDep . snd) $ G.lpre g node- pairs = [(x, y) | x <- incoming_nodes, y <- incoming_nodes, x < y]- vFusionFeasability :: DepGraph -> G.Node -> G.Node -> Bool vFusionFeasability dg@DepGraph {dgGraph = g} n1 n2 = not (any isInf (edgesBetween dg n1 n2))@@ -129,15 +121,6 @@ hFusionFeasability :: DepGraph -> G.Node -> G.Node -> Bool hFusionFeasability = unreachableEitherDir -tryFuseNodeInGraph :: DepNode -> DepGraphAug FusionM-tryFuseNodeInGraph node_to_fuse dg@DepGraph {dgGraph = g} =- if G.gelem node_to_fuse_id g- then applyAugs (map (vTryFuseNodesInGraph node_to_fuse_id) fuses_with) dg- else pure dg- where- fuses_with = map fst $ filter (isDep . snd) $ G.lpre g (nodeFromLNode node_to_fuse)- node_to_fuse_id = nodeFromLNode node_to_fuse- vTryFuseNodesInGraph :: G.Node -> G.Node -> DepGraphAug FusionM -- find the neighbors -> verify that fusion causes no cycles -> fuse vTryFuseNodesInGraph node_1 node_2 dg@DepGraph {dgGraph = g}@@ -252,11 +235,8 @@ | isRealNode s1, null infusible = pure $ Just $ MatchNode stm2 $ (s1, e1s) : dfused-vFuseNodeT _ infusible (StmNode stm1, _, _) (SoacNode ots2 pats2 soac2 aux2, _)- | null infusible,- [stm1_out] <- patNames $ stmPat stm1,- Just (stm1_in, tr) <-- H.transformFromExp (stmAuxCerts (stmAux stm1)) (stmExp stm1) = do+vFuseNodeT _ infusible (TransNode stm1_out tr stm1_in, _, _) (SoacNode ots2 pats2 soac2 aux2, _)+ | null infusible = do stm1_in_t <- lookupType stm1_in let onInput inp | H.inputArray inp == stm1_out =@@ -359,11 +339,42 @@ removeUnusedOutputs :: DepGraphAug FusionM removeUnusedOutputs = mapAcross removeUnusedOutputsFromContext +tryFuseNodeInGraph :: DepNode -> DepGraphAug FusionM+tryFuseNodeInGraph node_to_fuse dg@DepGraph {dgGraph = g} = do+ if G.gelem node_to_fuse_id g -- Node might have been fused away since.+ then applyAugs (map (vTryFuseNodesInGraph node_to_fuse_id) fuses_with) dg+ else pure dg+ where+ fuses_with = map fst $ filter (isDep . snd) $ G.lpre g (nodeFromLNode node_to_fuse)+ node_to_fuse_id = nodeFromLNode node_to_fuse+ doVerticalFusion :: DepGraphAug FusionM-doVerticalFusion dg = applyAugs (map tryFuseNodeInGraph $ reverse $ G.labNodes (dgGraph dg)) dg+doVerticalFusion dg = applyAugs (map tryFuseNodeInGraph $ reverse $ filter relevant $ G.labNodes (dgGraph dg)) dg+ where+ relevant (_, StmNode {}) = False+ relevant (_, ResNode {}) = False+ relevant _ = True +-- | For each pair of SOAC nodes that share an input, attempt to fuse+-- them horizontally. doHorizontalFusion :: DepGraphAug FusionM-doHorizontalFusion dg = applyAugs (map horizontalFusionOnNode (G.nodes (dgGraph dg))) dg+doHorizontalFusion dg = applyAugs pairs dg+ where+ pairs :: [DepGraphAug FusionM]+ pairs = do+ (x, SoacNode _ _ soac_x _) <- G.labNodes $ dgGraph dg+ (y, SoacNode _ _ soac_y _) <- G.labNodes $ dgGraph dg+ guard $ x < y+ -- Must share an input.+ guard $+ any+ ((`elem` map H.inputArray (H.inputs soac_x)) . H.inputArray)+ (H.inputs soac_y)+ pure $ \dg' -> do+ -- Nodes might have been fused away by now.+ if G.gelem x (dgGraph dg') && G.gelem y (dgGraph dg')+ then hTryFuseNodesInGraph x y dg'+ else pure dg' doInnerFusion :: DepGraphAug FusionM doInnerFusion = mapAcross runInnerFusionOnContext
src/Futhark/Optimise/Fusion/GraphRep.hs view
@@ -53,6 +53,7 @@ import Data.Graph.Inductive.Tree qualified as G import Data.List qualified as L import Data.Map.Strict qualified as M+import Data.Maybe (mapMaybe) import Data.Set qualified as S import Futhark.Analysis.Alias qualified as Alias import Futhark.Analysis.HORep.SOAC qualified as H@@ -75,15 +76,17 @@ data NodeT = StmNode (Stm SOACS) | SoacNode H.ArrayTransforms (Pat Type) (H.SOAC SOACS) (StmAux (ExpDec SOACS))+ | -- | First 'VName' is result; last is input.+ TransNode VName H.ArrayTransform VName | -- | Node corresponding to a result of the entire computation -- (i.e. the 'Result' of a body). Any node that is not -- transitively reachable from one of these can be considered -- dead. ResNode VName- | -- | Node corresponding to a free variable.- -- Unclear whether we actually need these.+ | -- | Node corresponding to a free variable. These are used to+ -- safely handle consumption, which also means we don't have to+ -- create a node for every free single variable. FreeNode VName- | FinalNode (Stms SOACS) NodeT (Stms SOACS) | MatchNode (Stm SOACS) [(NodeT, [EdgeT])] | DoNode (Stm SOACS) [(NodeT, [EdgeT])] deriving (Eq)@@ -99,7 +102,7 @@ instance Show NodeT where show (StmNode (Let pat _ _)) = L.intercalate ", " $ map prettyString $ patNames pat show (SoacNode _ pat _ _) = prettyString pat- show (FinalNode _ nt _) = show nt+ show (TransNode _ tr _) = prettyString (show tr) show (ResNode name) = prettyString $ "Res: " ++ prettyString name show (FreeNode name) = prettyString $ "Input: " ++ prettyString name show (MatchNode stm _) = "Match: " ++ L.intercalate ", " (map prettyString $ stmNames stm)@@ -166,12 +169,6 @@ gen_dep_list :: DepNode -> [(VName, G.Node)] gen_dep_list (i, node) = [(name, i) | name <- getOutputs node] --- make a table to handle transitive aliases-makeAliasTable :: Monad m => Stms SOACS -> DepGraphAug m-makeAliasTable stms dg = do- let (_, (aliasTable', _)) = Alias.analyseStms mempty stms- pure $ dg {dgAliasTable = aliasTable'}- -- | Apply several graph augmentations in sequence. applyAugs :: Monad m => [DepGraphAug m] -> DepGraphAug m applyAugs augs g = foldlM (flip ($)) g augs@@ -243,18 +240,19 @@ addConsAndAliases :: Monad m => DepGraphAug m addConsAndAliases = augWithFun edges where- edges (StmNode s) = consEdges e <> aliasEdges e+ edges (StmNode s) = consEdges s' <> aliasEdges s' where- e = Alias.analyseExp mempty $ stmExp s+ s' = Alias.analyseStm mempty s edges _ = mempty- consEdges e = zip names (map Cons names)+ consEdges s = zip names (map Cons names) where- names = namesToList $ consumedInExp e+ names = namesToList $ consumedInStm s aliasEdges = map (\vname -> (vname, Alias vname)) . namesToList . mconcat- . expAliases+ . patAliases+ . stmPat -- extra dependencies mask the fact that consuming nodes "depend" on all other -- nodes coming before it (now also adds fake edges to aliases - hope this@@ -268,7 +266,7 @@ mapping = dgProducerMapping dg makeEdge (from, to, Cons cname) = do let aliases = namesToList $ M.findWithDefault mempty cname alias_table- to' = map (mapping M.!) aliases+ to' = mapMaybe (`M.lookup` mapping) aliases p (tonode, toedge) = tonode /= from && getName toedge `elem` (cname : aliases) (to2, _) <- filter p $ concatMap (G.lpre g) to' <> G.lpre g to@@ -293,44 +291,46 @@ pure $ DoNode s [] Match {} -> pure $ MatchNode s []+ e+ | [output] <- patNames pat,+ Just (ia, tr) <- H.transformFromExp (stmAuxCerts aux) e ->+ pure $ TransNode output tr ia _ -> pure n nodeToSoacNode n = pure n -convertGraph :: (HasScope SOACS m, Monad m) => DepGraphAug m-convertGraph = mapAcrossNodeTs nodeToSoacNode--initialGraphConstruction :: (HasScope SOACS m, Monad m) => DepGraphAug m-initialGraphConstruction =- applyAugs- [ addDeps,- addConsAndAliases,- addExtraCons,- addResEdges,- convertGraph -- Must be done after adding edges- ]- -- | Construct a graph with only nodes, but no edges. emptyGraph :: Body SOACS -> DepGraph emptyGraph body = DepGraph { dgGraph = G.mkGraph (labelNodes (stmnodes <> resnodes <> inputnodes)) [], dgProducerMapping = mempty,- dgAliasTable = mempty+ dgAliasTable = aliases } where labelNodes = zip [0 ..] stmnodes = map StmNode $ stmsToList $ bodyStms body resnodes = map ResNode $ namesToList $ freeIn $ bodyResult body- inputnodes = map FreeNode $ namesToList $ freeIn body+ inputnodes = map FreeNode $ namesToList consumed+ (_, (aliases, consumed)) = Alias.analyseStms mempty $ bodyStms body +getStmRes :: EdgeGenerator+getStmRes (ResNode name) = [(name, Res name)]+getStmRes _ = []++addResEdges :: Monad m => DepGraphAug m+addResEdges = augWithFun getStmRes+ -- | Make a dependency graph corresponding to a 'Body'. mkDepGraph :: (HasScope SOACS m, Monad m) => Body SOACS -> m DepGraph mkDepGraph body = applyAugs augs $ emptyGraph body where augs = [ makeMapping,- makeAliasTable (bodyStms body),- initialGraphConstruction+ addDeps,+ addConsAndAliases,+ addExtraCons,+ addResEdges,+ mapAcrossNodeTs nodeToSoacNode -- Must be done after adding edges ] -- | Make a dependency graph corresponding to a function.@@ -354,9 +354,6 @@ let n1 = G.node' ctx -- n1 remains pure $ dg {dgGraph = ctx G.& G.delNodes [n1, n2] (dgGraph dg)} -addResEdges :: Monad m => DepGraphAug m-addResEdges = augWithFun getStmRes- -- Utils for fusibility/infusibility -- find dependencies - either fusible or infusible. edges are generated based on these @@ -407,18 +404,14 @@ stmNames :: Stm SOACS -> [VName] stmNames = patNames . stmPat -getStmRes :: EdgeGenerator-getStmRes (ResNode name) = [(name, Res name)]-getStmRes _ = []- getOutputs :: NodeT -> [VName] getOutputs node = case node of (StmNode stm) -> stmNames stm+ (TransNode v _ _) -> [v] (ResNode _) -> [] (FreeNode name) -> [name] (MatchNode stm _) -> stmNames stm (DoNode stm _) -> stmNames stm- FinalNode {} -> error "Final nodes cannot generate edges" (SoacNode _ pat _ _) -> patNames pat -- | Is there a possibility of fusion?
src/Futhark/Optimise/Fusion/TryFusion.hs view
@@ -231,10 +231,10 @@ guard $ SOAC.width soac_p == SOAC.width soac_c -- If we are getting rid of a producer output, then it must be used- -- without any transformation.- let bare_inputs = mapMaybe SOAC.isVarishInput (inputs ker)- ker_inputs = map SOAC.inputArray (inputs ker)- inputOrUnfus v = v `elem` bare_inputs || v `notElem` ker_inputs+ -- exclusively without any transformations.+ let ker_inputs = map SOAC.inputArray (inputs ker)+ okInput v inp = v /= SOAC.inputArray inp || isJust (SOAC.isVarishInput inp)+ inputOrUnfus v = all (okInput v) (inputs ker) || v `notElem` ker_inputs guard $ all inputOrUnfus outVars @@ -258,6 +258,10 @@ (_, _, Horizontal) | not (SOAC.nullTransforms $ fsOutputTransform ker) -> fail "Horizontal fusion is invalid in the presence of output transforms."+ (_, _, Vertical)+ | unfus_set /= mempty,+ not (SOAC.nullTransforms $ fsOutputTransform ker) ->+ fail "Cannot perform diagonal fusion in the presence of output transforms." ( SOAC.Screma _ (ScremaForm scans_c reds_c _) _, SOAC.Screma _ (ScremaForm scans_p reds_p _) _, _
src/Futhark/Optimise/InPlaceLowering.hs view
@@ -118,7 +118,7 @@ descend [] m = m descend (stm : stms) m = bindingStm stm $ descend stms m -type Constraints rep = (Buildable rep, CanBeAliased (Op rep))+type Constraints rep = (Buildable rep, AliasableRep rep) optimiseBody :: Constraints rep =>@@ -198,7 +198,7 @@ } onSegOp ::- (Buildable rep, CanBeAliased (Op rep)) =>+ Constraints rep => SegOp lvl (Aliases rep) -> ForwardingM rep (SegOp lvl (Aliases rep)) onSegOp op =
src/Futhark/Optimise/InPlaceLowering/LowerIntoStm.hs view
@@ -47,7 +47,7 @@ ( MonadFreshNames m, Buildable rep, LetDec rep ~ Type,- CanBeAliased (Op rep)+ AliasableRep rep ) => LowerUpdate rep m lowerUpdate scope (Let pat aux (DoLoop merge form body)) updates = do
src/Futhark/Optimise/InliningDeadFun.hs view
@@ -111,10 +111,8 @@ inlineBecauseTiny = foldMap onFunDef . progFuns where onFunDef fd- | length (bodyStms (funDefBody fd))- < 2- || "inline"- `inAttrs` funDefAttrs fd =+ | (length (bodyStms (funDefBody fd)) < 2)+ || ("inline" `inAttrs` funDefAttrs fd) = S.singleton (funDefName fd) | otherwise = mempty @@ -126,6 +124,7 @@ where cg = buildCallGraph prog +-- Inline everything that is not #[noinline]. aggInlineFunctions :: MonadFreshNames m => Prog SOACS -> m (Prog SOACS) aggInlineFunctions prog = inlineFunctions 3 cg (S.fromList $ map funDefName $ progFuns prog) prog
src/Futhark/Optimise/MergeGPUBodies.hs view
@@ -138,7 +138,7 @@ -- To move X before Y then the dependencies of X must also not overlap with -- the variables bound by Y. - let observed = namesToSet $ rootAliasesOf (fold $ expAliases e) aliases+ let observed = namesToSet $ rootAliasesOf (fold $ patAliases pat) aliases let consumed = namesToSet $ rootAliasesOf (consumedInExp e) aliases let usage = Usage
src/Futhark/Optimise/ReduceDeviceSyncs.hs view
@@ -351,7 +351,7 @@ -- | Optimize a host operation. 'Index' statements are added to kernel code -- that depends on migrated scalars.-optimizeHostOp :: HostOp GPU op -> ReduceM (HostOp GPU op)+optimizeHostOp :: HostOp op GPU -> ReduceM (HostOp op GPU) optimizeHostOp (SegOp (SegMap lvl space types kbody)) = SegOp . SegMap lvl space types <$> addReadsToKernelBody kbody optimizeHostOp (SegOp (SegRed lvl space ops types kbody)) = do
src/Futhark/Optimise/Simplify/Engine.hs view
@@ -557,7 +557,7 @@ provides = patNames . stmPat expandUsage ::- (ASTRep rep, Aliased rep) =>+ Aliased rep => (Stm rep -> UT.UsageTable) -> ST.SymbolTable rep -> UT.UsageTable ->@@ -666,7 +666,7 @@ all (`nameIn` ST.availableAtClosestLoop vtable) . namesToList . freeIn matchBlocker ::- (ASTRep rep, CanBeWise (Op rep)) =>+ SimplifiableRep rep => [SubExp] -> MatchDec rt -> SimpleM rep (BlockPred (Wise rep))@@ -966,8 +966,10 @@ Simplifiable (RetType rep), Simplifiable (BranchType rep), TraverseOpStms (Wise rep),- CanBeWise (Op rep),- ST.IndexOp (OpWithWisdom (Op rep)),+ CanBeWise (OpC rep),+ ST.IndexOp (Op (Wise rep)),+ AliasedOp (Op (Wise rep)),+ RephraseOp (OpC rep), BuilderOps (Wise rep), IsOp (Op rep) )
src/Futhark/Optimise/Simplify/Rep.hs view
@@ -35,9 +35,7 @@ import Control.Category import Control.Monad.Identity import Control.Monad.Reader-import Data.Kind qualified import Data.Map.Strict qualified as M-import Futhark.Analysis.Rephrase import Futhark.Builder import Futhark.IR import Futhark.IR.Aliases@@ -118,7 +116,7 @@ instance FreeDec BodyWisdom where precomputed = const . fvNames . unAliases . bodyWisdomFree -instance (RepTypes rep, CanBeWise (Op rep)) => RepTypes (Wise rep) where+instance Informing rep => RepTypes (Wise rep) where type LetDec (Wise rep) = (VarWisdom, LetDec rep) type ExpDec (Wise rep) = (ExpWisdom, ExpDec rep) type BodyDec (Wise rep) = (BodyWisdom, BodyDec rep)@@ -126,7 +124,7 @@ type LParamInfo (Wise rep) = LParamInfo rep type RetType (Wise rep) = RetType rep type BranchType (Wise rep) = BranchType rep- type Op (Wise rep) = OpWithWisdom (Op rep)+ type OpC (Wise rep) = OpC rep withoutWisdom :: (HasScope (Wise rep) m, Monad m) =>@@ -136,24 +134,24 @@ scope <- asksScope removeScopeWisdom runReaderT m scope -instance (ASTRep rep, CanBeWise (Op rep)) => ASTRep (Wise rep) where+instance Informing rep => ASTRep (Wise rep) where expTypesFromPat = withoutWisdom . expTypesFromPat . removePatWisdom instance Pretty VarWisdom where pretty _ = pretty () -instance (PrettyRep rep, CanBeWise (Op rep)) => PrettyRep (Wise rep) where+instance Informing rep => PrettyRep (Wise rep) where ppExpDec (_, dec) = ppExpDec dec . removeExpWisdom instance AliasesOf (VarWisdom, dec) where aliasesOf = unAliases . varWisdomAliases . fst -instance (ASTRep rep, CanBeWise (Op rep)) => Aliased (Wise rep) where+instance Informing rep => Aliased (Wise rep) where bodyAliases = map unAliases . bodyWisdomAliases . fst . bodyDec consumedInBody = unAliases . bodyWisdomConsumed . fst . bodyDec -removeWisdom :: CanBeWise (Op rep) => Rephraser Identity (Wise rep) rep+removeWisdom :: RephraseOp (OpC rep) => Rephraser Identity (Wise rep) rep removeWisdom = Rephraser { rephraseExpDec = pure . snd,@@ -163,7 +161,7 @@ rephraseLParamDec = pure, rephraseRetType = pure, rephraseBranchType = pure,- rephraseOp = pure . removeOpWisdom+ rephraseOp = rephraseInOp removeWisdom } -- | Remove simplifier information from scope.@@ -186,23 +184,23 @@ alias (IndexName it) = IndexName it -- | Remove simplifier information from function.-removeFunDefWisdom :: CanBeWise (Op rep) => FunDef (Wise rep) -> FunDef rep+removeFunDefWisdom :: RephraseOp (OpC rep) => FunDef (Wise rep) -> FunDef rep removeFunDefWisdom = runIdentity . rephraseFunDef removeWisdom -- | Remove simplifier information from statement.-removeStmWisdom :: CanBeWise (Op rep) => Stm (Wise rep) -> Stm rep+removeStmWisdom :: RephraseOp (OpC rep) => Stm (Wise rep) -> Stm rep removeStmWisdom = runIdentity . rephraseStm removeWisdom -- | Remove simplifier information from lambda.-removeLambdaWisdom :: CanBeWise (Op rep) => Lambda (Wise rep) -> Lambda rep+removeLambdaWisdom :: RephraseOp (OpC rep) => Lambda (Wise rep) -> Lambda rep removeLambdaWisdom = runIdentity . rephraseLambda removeWisdom -- | Remove simplifier information from body.-removeBodyWisdom :: CanBeWise (Op rep) => Body (Wise rep) -> Body rep+removeBodyWisdom :: RephraseOp (OpC rep) => Body (Wise rep) -> Body rep removeBodyWisdom = runIdentity . rephraseBody removeWisdom -- | Remove simplifier information from expression.-removeExpWisdom :: CanBeWise (Op rep) => Exp (Wise rep) -> Exp rep+removeExpWisdom :: RephraseOp (OpC rep) => Exp (Wise rep) -> Exp rep removeExpWisdom = runIdentity . rephraseExp removeWisdom -- | Remove simplifier information from pattern.@@ -211,7 +209,7 @@ -- | Add simplifier information to pattern. addWisdomToPat ::- (ASTRep rep, CanBeWise (Op rep)) =>+ Informing rep => Pat (LetDec rep) -> Exp (Wise rep) -> Pat (LetDec (Wise rep))@@ -222,7 +220,7 @@ -- | Produce a body with simplifier information. mkWiseBody ::- (ASTRep rep, CanBeWise (Op rep)) =>+ Informing rep => BodyDec rep -> Stms (Wise rep) -> Result ->@@ -239,7 +237,7 @@ -- | Produce a statement with simplifier information. mkWiseStm ::- (ASTRep rep, CanBeWise (Op rep)) =>+ Informing rep => Pat (LetDec rep) -> StmAux (ExpDec rep) -> Exp (Wise rep) ->@@ -250,7 +248,7 @@ -- | Produce simplifier information for an expression. mkWiseExpDec ::- (ASTRep rep, CanBeWise (Op rep)) =>+ Informing rep => Pat (LetDec (Wise rep)) -> ExpDec rep -> Exp (Wise rep) ->@@ -262,7 +260,7 @@ expdec ) -instance (Buildable rep, CanBeWise (Op rep)) => Buildable (Wise rep) where+instance (Buildable rep, Informing rep) => Buildable (Wise rep) where mkExpPat ids e = addWisdomToPat (mkExpPat ids $ removeExpWisdom e) e @@ -281,18 +279,20 @@ -- | Constraints that let us transform a representation into a 'Wise' -- representation.-type Informing rep = (ASTRep rep, CanBeWise (Op rep))+type Informing rep =+ ( ASTRep rep,+ AliasedOp (OpC rep (Wise rep)),+ RephraseOp (OpC rep),+ CanBeWise (OpC rep),+ FreeIn (OpC rep (Wise rep))+ ) -- | A type class for indicating that this operation can be lifted into the simplifier representation.-class (AliasedOp (OpWithWisdom op), IsOp (OpWithWisdom op)) => CanBeWise op where- type OpWithWisdom op :: Data.Kind.Type- removeOpWisdom :: OpWithWisdom op -> op- addOpWisdom :: op -> OpWithWisdom op+class CanBeWise op where+ addOpWisdom :: Informing rep => op rep -> op (Wise rep) -instance CanBeWise () where- type OpWithWisdom () = ()- removeOpWisdom () = ()- addOpWisdom () = ()+instance CanBeWise NoOp where+ addOpWisdom _ = undefined -- | Construct a 'Wise' statement. informStm :: Informing rep => Stm rep -> Stm (Wise rep)
src/Futhark/Optimise/Simplify/Rules/BasicOp.hs view
@@ -38,8 +38,8 @@ case ST.lookupBasicOp v vtable of Just (ArrayLit ses _, cs) -> (ArgArrayLit ses, cs)- Just (Replicate shape se, cs) ->- (ArgReplicate [shapeSize 0 shape] se, cs)+ Just (Replicate (Shape [d]) se, cs) ->+ (ArgReplicate [d] se, cs) _ -> (ArgVar v, mempty) @@ -132,11 +132,8 @@ | -- We produce the to-be-concatenated arrays in reverse order, so -- reverse them back. y : ys <-- forSingleArray $- reverse $- foldl' fuseConcatArg mempty $- map (toConcatArg vtable) $- x : xs,+ forSingleArray . reverse . foldl' fuseConcatArg mempty $+ map (toConcatArg vtable) (x : xs), length xs /= length ys = Simplify $ do elem_type <- lookupType x
src/Futhark/Optimise/Simplify/Rules/Index.hs view
@@ -210,6 +210,10 @@ [] -> Just $ pure $ SubExpResult cs se _ | Var v2 <- se -> Just $ pure $ IndexResult cs v2 $ Slice inds' _ -> Nothing+ Just (Update Unsafe _ (Slice update_inds) se, cs)+ | inds == update_inds,+ ST.subExpAvailable se vtable ->+ Just $ pure $ SubExpResult cs se -- Indexing single-element arrays. We know the index must be 0. _ | Just t <- seType $ Var idd,
src/Futhark/Optimise/Sink.hs view
@@ -264,8 +264,8 @@ sink :: ( Buildable rep,- CanBeAliased (Op rep),- ST.IndexOp (OpWithAliases (Op rep))+ AliasableRep rep,+ ST.IndexOp (Op (Aliases rep)) ) => Sinker (SinkRep rep) (Op (SinkRep rep)) -> Pass rep rep
src/Futhark/Pass/ExpandAllocations.hs view
@@ -11,7 +11,7 @@ import Data.List (find, foldl') import Data.Map.Strict qualified as M import Data.Maybe-import Futhark.Analysis.Rephrase+import Futhark.Analysis.Alias as Alias import Futhark.Analysis.SymbolTable qualified as ST import Futhark.Error import Futhark.IR@@ -27,6 +27,7 @@ import Futhark.Tools import Futhark.Transform.CopyPropagate (copyPropagateInFun) import Futhark.Transform.Rename (renameStm)+import Futhark.Transform.Substitute import Futhark.Util (mapAccumLM) import Futhark.Util.IntegralExp import Prelude hiding (quot)@@ -246,7 +247,7 @@ then pure (mempty, (lvl, ops, kbody)) else do (lvl_stms, lvl', grid) <- ensureGridKnown lvl- allocsForBody variant_allocs invariant_allocs grid space kbody' $ \alloc_stms kbody'' -> do+ allocsForBody variant_allocs invariant_allocs grid space kbody kbody' $ \alloc_stms kbody'' -> do ops'' <- forM ops' $ \op' -> localScope (scopeOf op') $ offsetMemoryInLambda op' pure (lvl_stms <> alloc_stms, (lvl', ops'', kbody''))@@ -264,14 +265,15 @@ KernelGrid -> SegSpace -> KernelBody GPUMem ->+ KernelBody GPUMem -> (Stms GPUMem -> KernelBody GPUMem -> OffsetM b) -> ExpandM b-allocsForBody variant_allocs invariant_allocs grid space kbody' m = do+allocsForBody variant_allocs invariant_allocs grid space kbody kbody' m = do (alloc_offsets, alloc_stms) <- memoryRequirements grid space- (kernelBodyStms kbody')+ (kernelBodyStms kbody) variant_allocs invariant_allocs @@ -747,14 +749,18 @@ unAllocKernelBody (KernelBody dec stms res) = KernelBody dec <$> unAllocStms True stms <*> pure res - unAllocStms nested =- fmap (stmsFromList . catMaybes) . mapM (unAllocStm nested) . stmsToList+ unAllocStms nested = mapM (unAllocStm nested) - unAllocStm nested stm@(Let _ _ (Op Alloc {}))- | nested = throwError $ "Cannot handle nested allocation: " ++ prettyString stm- | otherwise = pure Nothing+ unAllocStm nested stm@(Let pat dec (Op Alloc {}))+ | nested =+ throwError $ "Cannot handle nested allocation: " <> prettyString stm+ | otherwise =+ Let+ <$> unAllocPat pat+ <*> pure dec+ <*> pure (BasicOp (SubExp $ Constant UnitValue)) unAllocStm _ (Let pat dec e) =- Just <$> (Let <$> unAllocPat pat <*> pure dec <*> mapExpM unAlloc' e)+ Let <$> unAllocPat pat <*> pure dec <*> mapExpM unAlloc' e unAllocLambda (Lambda params body ret) = Lambda (map unParam params) <$> unAllocBody body <*> pure ret@@ -809,6 +815,18 @@ where comb m (mem, (_, size, space)) = M.insertWith (++) size [(mem, space)] m +copyConsumed :: (MonadBuilder m, AliasableRep (Rep m)) => Stms (Rep m) -> m (Stms (Rep m))+copyConsumed stms = do+ let consumed = namesToList $ snd $ snd $ Alias.analyseStms mempty stms+ collectStms_ $ do+ consumed' <- mapM copy consumed+ let substs = M.fromList (zip consumed consumed')+ addStms $ substituteNames substs stms+ where+ copy v = letExp (baseString v <> "_copy") $ BasicOp $ Copy v++-- Important for edge cases (#1838) that the Stms here still have the+-- Allocs we are actually trying to get rid of. sliceKernelSizes :: SubExp -> [SubExp] ->@@ -834,27 +852,19 @@ flat_gtid_lparam <- newParam "flat_gtid" (Prim (IntType Int64)) - (size_lam', _) <- flip runBuilderT kernels_scope $ do- params <- replicateM num_sizes $ newParam "x" (Prim int64)- (zs, stms) <- localScope- (scopeOfLParams params <> scopeOfLParams [flat_gtid_lparam])- $ collectStms- $ do- -- Even though this SegRed is one-dimensional, we need to- -- provide indexes corresponding to the original potentially- -- multi-dimensional construct.- let (kspace_gtids, kspace_dims) = unzip $ unSegSpace space- new_inds =- unflattenIndex- (map pe64 kspace_dims)- (pe64 $ Var $ paramName flat_gtid_lparam)- zipWithM_ letBindNames (map pure kspace_gtids) =<< mapM toExp new_inds-- mapM_ addStm kstms'- pure $ subExpsRes sizes-- localScope (scopeOfSegSpace space) $- GPU.simplifyLambda (Lambda [flat_gtid_lparam] (Body () stms zs) i64s)+ size_lam' <- localScope (scopeOfSegSpace space) . fmap fst . flip runBuilderT kernels_scope $+ GPU.simplifyLambda <=< mkLambda [flat_gtid_lparam] $ do+ -- Even though this SegRed is one-dimensional, we need to+ -- provide indexes corresponding to the original potentially+ -- multi-dimensional construct.+ let (kspace_gtids, kspace_dims) = unzip $ unSegSpace space+ new_inds =+ unflattenIndex+ (map pe64 kspace_dims)+ (pe64 $ Var $ paramName flat_gtid_lparam)+ zipWithM_ letBindNames (map pure kspace_gtids) =<< mapM toExp new_inds+ mapM_ addStm =<< copyConsumed kstms'+ pure $ subExpsRes sizes ((maxes_per_thread, size_sums), slice_stms) <- flip runBuilderT kernels_scope $ do pat <-
src/Futhark/Pass/ExplicitAllocations.hs view
@@ -10,6 +10,7 @@ explicitAllocationsInStmsGeneric, ExpHint (..), defaultExpHints,+ askDefaultSpace, Allocable, AllocM, AllocEnv (..),@@ -70,7 +71,7 @@ BodyDec fromrep ~ (), BodyDec torep ~ (), ExpDec torep ~ (),- SizeSubst inner,+ SizeSubst (inner torep), BuilderOps torep ) @@ -123,22 +124,25 @@ f <- asks envExpHints f e +-- | The space in which we allocate memory if we have no other+-- preferences or constraints. askDefaultSpace :: AllocM fromrep torep Space askDefaultSpace = asks allocSpace runAllocM :: MonadFreshNames m =>+ Space -> (Op fromrep -> AllocM fromrep torep (Op torep)) -> (Exp torep -> AllocM fromrep torep [ExpHint]) -> AllocM fromrep torep a -> m a-runAllocM handleOp hints (AllocM m) =+runAllocM space handleOp hints (AllocM m) = fmap fst $ modifyNameSource $ runState $ runReaderT (runBuilderT m mempty) env where env = AllocEnv { aggressiveReuse = False,- allocSpace = DefaultSpace,+ allocSpace = space, envConsts = mempty, allocInOp = handleOp, envExpHints = hints@@ -164,7 +168,7 @@ arraySizeInBytes = letSubExp "bytes" <=< toExp <=< arraySizeInBytesExpM allocForArray' ::- (MonadBuilder m, Op (Rep m) ~ MemOp inner) =>+ (MonadBuilder m, Op (Rep m) ~ MemOp inner (Rep m)) => Type -> Space -> m VName@@ -216,7 +220,7 @@ f _ Nothing = newIdent "ext" $ Prim int64 allocsForPat ::- (MonadBuilder m, Op (Rep m) ~ MemOp inner) =>+ (MonadBuilder m, Op (Rep m) ~ MemOp inner (Rep m)) => Space -> [Ident] -> [ExpReturns] ->@@ -270,7 +274,7 @@ inst (Free x) = pure x summaryForBindage ::- (MonadBuilder m, Op (Rep m) ~ MemOp inner) =>+ (MonadBuilder m, Op (Rep m) ~ MemOp inner (Rep m)) => Space -> Type -> ExpHint ->@@ -425,7 +429,8 @@ then do -- Arrays with loop-variant shape cannot be in scalar -- space, so copy them elsewhere and try again.- (_, v') <- lift $ allocLinearArray DefaultSpace (baseString v) v+ space <- lift askDefaultSpace+ (_, v') <- lift $ allocLinearArray space (baseString v) v allocInMergeParam (mergeparam, Var v') else do p <- newParam "mem_param" $ MemMem v_mem_space@@ -467,7 +472,7 @@ pure (mergeparam', se, linearFuncallArg (paramType mergeparam) space) arrayWithIxFun ::- (MonadBuilder m, Op (Rep m) ~ MemOp inner, LetDec (Rep m) ~ LetDecMem) =>+ (MonadBuilder m, Op (Rep m) ~ MemOp inner (Rep m), LetDec (Rep m) ~ LetDecMem) => Space -> IxFun -> Type ->@@ -559,22 +564,23 @@ explicitAllocationsGeneric :: (Allocable fromrep torep inner) =>+ Space -> (Op fromrep -> AllocM fromrep torep (Op torep)) -> (Exp torep -> AllocM fromrep torep [ExpHint]) -> Pass fromrep torep-explicitAllocationsGeneric handleOp hints =+explicitAllocationsGeneric space handleOp hints = Pass "explicit allocations" "Transform program to explicit memory representation" $ intraproceduralTransformationWithConsts onStms allocInFun where onStms stms =- runAllocM handleOp hints $ collectStms_ $ allocInStms stms $ pure ()+ runAllocM space handleOp hints $ collectStms_ $ allocInStms stms $ pure () allocInFun consts (FunDef entry attrs fname rettype params fbody) =- runAllocM handleOp hints . inScopeOf consts $- allocInFParams (zip params $ repeat DefaultSpace) $ \params' -> do+ runAllocM space handleOp hints . inScopeOf consts $+ allocInFParams (zip params $ repeat space) $ \params' -> do (fbody', mem_rets) <-- allocInFunBody (map (const $ Just DefaultSpace) rettype) fbody- let rettype' = mem_rets ++ memoryInDeclExtType (length mem_rets) rettype+ allocInFunBody (map (const $ Just space) rettype) fbody+ let rettype' = mem_rets ++ memoryInDeclExtType space (length mem_rets) rettype pure $ FunDef entry attrs fname rettype' params' fbody' explicitAllocationsInStmsGeneric ::@@ -582,27 +588,28 @@ HasScope torep m, Allocable fromrep torep inner ) =>+ Space -> (Op fromrep -> AllocM fromrep torep (Op torep)) -> (Exp torep -> AllocM fromrep torep [ExpHint]) -> Stms fromrep -> m (Stms torep)-explicitAllocationsInStmsGeneric handleOp hints stms = do+explicitAllocationsInStmsGeneric space handleOp hints stms = do scope <- askScope- runAllocM handleOp hints $+ runAllocM space handleOp hints $ localScope scope $ collectStms_ $ allocInStms stms $ pure () -memoryInDeclExtType :: Int -> [DeclExtType] -> [FunReturns]-memoryInDeclExtType k dets = evalState (mapM addMem dets) 0+memoryInDeclExtType :: Space -> Int -> [DeclExtType] -> [FunReturns]+memoryInDeclExtType space k dets = evalState (mapM addMem dets) 0 where addMem (Prim t) = pure $ MemPrim t addMem Mem {} = error "memoryInDeclExtType: too much memory" addMem (Array pt shape u) = do i <- get <* modify (+ 1) let shape' = fmap shift shape- pure . MemArray pt shape' u . ReturnsNewBlock DefaultSpace i $+ pure . MemArray pt shape' u . ReturnsNewBlock space i $ IxFun.iota $ map convert $ shapeDims shape'@@ -891,10 +898,11 @@ pure $ DoLoop merge' form' body' allocInExp (Apply fname args rettype loc) = do args' <- funcallArgs args+ space <- askDefaultSpace -- We assume that every array is going to be in its own memory.- pure $ Apply fname args' (mems ++ memoryInDeclExtType num_arrays rettype) loc+ pure $ Apply fname args' (mems space ++ memoryInDeclExtType space num_arrays rettype) loc where- mems = replicate num_arrays (MemMem DefaultSpace)+ mems space = replicate num_arrays (MemMem space) num_arrays = length $ filter ((> 0) . arrayRank . declExtTypeOf) rettype allocInExp (Match ses cases defbody (MatchDec rets ifsort)) = do (defbody', def_reqs) <- allocInMatchBody rets defbody@@ -954,7 +962,8 @@ pure $ Param attrs p $ MemPrim t onYParam is (Param attrs p (Array pt shape u)) arr = do arr_t <- lookupType arr- mem <- allocForArray arr_t DefaultSpace+ space <- askDefaultSpace+ mem <- allocForArray arr_t space let base_dims = map pe64 $ arrayDims arr_t ixfun = IxFun.iota base_dims pure $ mkP attrs p pt shape u mem ixfun is@@ -1000,9 +1009,9 @@ opIsConst :: op -> Bool opIsConst = const False -instance SizeSubst ()+instance SizeSubst (NoOp rep) -instance SizeSubst op => SizeSubst (MemOp op) where+instance SizeSubst (op rep) => SizeSubst (MemOp op rep) where opIsConst (Inner op) = opIsConst op opIsConst _ = False @@ -1017,12 +1026,13 @@ MonadBuilder m, ExpDec (Rep m) ~ () ) =>+ Space -> ExpDec (Rep m) -> [VName] -> Exp (Rep m) -> m (Stm (Rep m))-mkLetNamesB' dec names e = do- pat <- patWithAllocations DefaultSpace names e nohints+mkLetNamesB' space dec names e = do+ pat <- patWithAllocations space names e nohints pure $ Let pat (defAux dec) e where nohints = map (const NoHint) names@@ -1030,39 +1040,60 @@ mkLetNamesB'' :: ( Mem rep inner, LetDec rep ~ LetDecMem,- OpReturns (Engine.OpWithWisdom inner),+ OpReturns (inner (Engine.Wise rep)), ExpDec rep ~ (), Rep m ~ Engine.Wise rep, HasScope (Engine.Wise rep) m, MonadBuilder m,+ AliasedOp (inner (Engine.Wise rep)),+ RephraseOp (MemOp inner), Engine.CanBeWise inner ) =>+ Space -> [VName] -> Exp (Engine.Wise rep) -> m (Stm (Engine.Wise rep))-mkLetNamesB'' names e = do- pat <- patWithAllocations DefaultSpace names e nohints+mkLetNamesB'' space names e = do+ pat <- patWithAllocations space names e nohints let pat' = Engine.addWisdomToPat pat e dec = Engine.mkWiseExpDec pat' () e pure $ Let pat' (defAux dec) e where nohints = map (const NoHint) names +simplifyMemOp ::+ Engine.SimplifiableRep rep =>+ ( inner (Engine.Wise rep) ->+ Engine.SimpleM rep (inner (Engine.Wise rep), Stms (Engine.Wise rep))+ ) ->+ MemOp inner (Engine.Wise rep) ->+ Engine.SimpleM rep (MemOp inner (Engine.Wise rep), Stms (Engine.Wise rep))+simplifyMemOp _ (Alloc size space) =+ (,) <$> (Alloc <$> Engine.simplify size <*> pure space) <*> pure mempty+simplifyMemOp onInner (Inner k) = do+ (k', hoisted) <- onInner k+ pure (Inner k', hoisted)+ simplifiable :: ( Engine.SimplifiableRep rep, LetDec rep ~ LetDecMem, ExpDec rep ~ (), BodyDec rep ~ (),- OpReturns (Engine.OpWithWisdom inner),- AliasedOp (Engine.OpWithWisdom inner),- IndexOp (Engine.OpWithWisdom inner),- Mem rep inner+ Mem (Engine.Wise rep) inner,+ Engine.CanBeWise inner,+ RephraseOp inner,+ IsOp (inner rep),+ OpReturns (inner (Engine.Wise rep)),+ AliasedOp (inner (Engine.Wise rep)),+ IndexOp (inner (Engine.Wise rep)) ) =>- (Engine.OpWithWisdom inner -> UT.UsageTable) ->- (Engine.OpWithWisdom inner -> Engine.SimpleM rep (Engine.OpWithWisdom inner, Stms (Engine.Wise rep))) ->+ (inner (Engine.Wise rep) -> UT.UsageTable) ->+ ( inner (Engine.Wise rep) ->+ Engine.SimpleM rep (inner (Engine.Wise rep), Stms (Engine.Wise rep))+ ) -> SimpleOps rep simplifiable innerUsage simplifyInnerOp =- SimpleOps mkExpDecS' mkBodyS' protectOp opUsage simplifyPat simplifyOp+ SimpleOps mkExpDecS' mkBodyS' protectOp opUsage simplifyPat (simplifyMemOp simplifyInnerOp) where mkExpDecS' _ pat e = pure $ Engine.mkWiseExpDec pat () e@@ -1086,12 +1117,6 @@ opUsage (Inner inner) = innerUsage inner - simplifyOp (Alloc size space) =- (,) <$> (Alloc <$> Engine.simplify size <*> pure space) <*> pure mempty- simplifyOp (Inner k) = do- (k', hoisted) <- simplifyInnerOp k- pure (Inner k', hoisted)- simplifyPat (Pat pes) e = do rets <- expReturns e Pat <$> zipWithM update pes rets@@ -1116,5 +1141,5 @@ = NoHint | Hint IxFun Space -defaultExpHints :: (Monad m, ASTRep rep) => Exp rep -> m [ExpHint]-defaultExpHints e = pure $ replicate (expExtTypeSize e) NoHint+defaultExpHints :: (ASTRep rep, HasScope rep m) => Exp rep -> m [ExpHint]+defaultExpHints e = map (const NoHint) <$> expExtType e
src/Futhark/Pass/ExplicitAllocations/GPU.hs view
@@ -30,8 +30,8 @@ where space = case lvl of SegGroup {} -> Space "local"- SegThread {} -> DefaultSpace- SegThreadInGroup {} -> DefaultSpace+ SegThread {} -> Space "device"+ SegThreadInGroup {} -> Space "device" handleSegOp :: Maybe SegLevel ->@@ -79,8 +79,8 @@ handleHostOp :: Maybe SegLevel ->- HostOp GPU (SOAC GPU) ->- AllocM GPU GPUMem (MemOp (HostOp GPUMem ()))+ HostOp SOAC GPU ->+ AllocM GPU GPUMem (MemOp (HostOp NoOp) GPUMem) handleHostOp _ (SizeOp op) = pure $ Inner $ SizeOp op handleHostOp _ (OtherOp op) =@@ -96,7 +96,7 @@ let perm_inv = rearrangeInverse perm dims' = rearrangeShape perm dims ixfun = IxFun.permute (IxFun.iota $ map pe64 dims') perm_inv- pure [Hint ixfun DefaultSpace]+ pure [Hint ixfun $ Space "device"] kernelExpHints (Op (Inner (SegOp (SegMap lvl@(SegThread _ _) space ts body)))) = zipWithM (mapResultHint lvl space) ts $ kernelBodyResult body kernelExpHints (Op (Inner (SegOp (SegRed lvl@(SegThread _ _) space reds ts body)))) =@@ -104,8 +104,7 @@ where num_reds = segBinOpResults reds (red_res, map_res) = splitAt num_reds $ kernelBodyResult body-kernelExpHints e =- pure $ replicate (expExtTypeSize e) NoHint+kernelExpHints e = defaultExpHints e mapResultHint :: SegLevel ->@@ -124,7 +123,7 @@ hint t Returns {} | coalesceReturnOfShape (primByteSize (elemType t)) $ arrayDims t = do let space_dims = segSpaceDims space- pure $ Hint (innermost space_dims (arrayDims t)) DefaultSpace+ pure $ Hint (innermost space_dims (arrayDims t)) $ Space "device" hint _ _ = pure NoHint innermost :: [SubExp] -> [SubExp] -> IxFun@@ -167,7 +166,7 @@ where private (Returns ResultPrivate _ _) = True private _ = False-inGroupExpHints e = pure $ replicate (expExtTypeSize e) NoHint+inGroupExpHints e = defaultExpHints e inThreadExpHints :: Exp GPUMem -> AllocM GPU GPUMem [ExpHint] inThreadExpHints e = do@@ -184,11 +183,11 @@ -- | The pass from 'GPU' to 'GPUMem'. explicitAllocations :: Pass GPU GPUMem-explicitAllocations = explicitAllocationsGeneric (handleHostOp Nothing) kernelExpHints+explicitAllocations = explicitAllocationsGeneric (Space "device") (handleHostOp Nothing) kernelExpHints -- | Convert some 'GPU' stms to 'GPUMem'. explicitAllocationsInStms :: (MonadFreshNames m, HasScope GPUMem m) => Stms GPU -> m (Stms GPUMem)-explicitAllocationsInStms = explicitAllocationsInStmsGeneric (handleHostOp Nothing) kernelExpHints+explicitAllocationsInStms = explicitAllocationsInStmsGeneric (Space "device") (handleHostOp Nothing) kernelExpHints
src/Futhark/Pass/ExplicitAllocations/MC.hs view
@@ -33,4 +33,4 @@ -- | The pass from 'MC' to 'MCMem'. explicitAllocations :: Pass MC MCMem-explicitAllocations = explicitAllocationsGeneric handleMCOp defaultExpHints+explicitAllocations = explicitAllocationsGeneric DefaultSpace handleMCOp defaultExpHints
src/Futhark/Pass/ExplicitAllocations/SegOp.hs view
@@ -50,7 +50,7 @@ BinOp (Mul Int64 OverflowUndef) num_threads $ intConst Int64 2 let t = paramType x `arrayOfRow` twice_num_threads- mem <- allocForArray t DefaultSpace+ mem <- allocForArray t =<< askDefaultSpace -- XXX: this iota ixfun is a bit inefficient; leading to -- uncoalesced access. let base_dims = map pe64 $ arrayDims t
src/Futhark/Pass/ExplicitAllocations/Seq.hs view
@@ -10,4 +10,8 @@ import Futhark.Pass.ExplicitAllocations explicitAllocations :: Pass Seq SeqMem-explicitAllocations = explicitAllocationsGeneric (pure . Inner) defaultExpHints+explicitAllocations =+ explicitAllocationsGeneric+ DefaultSpace+ (const $ pure $ Inner NoOp)+ defaultExpHints
src/Futhark/Pass/ExtractKernels.hs view
@@ -823,6 +823,56 @@ -- FIXME: work around bogus targets. acc' {distTargets = singleTarget (mempty, mempty)} + -- GHC 9.2 loops without the type annotation.+ generate ::+ [Int] ->+ KernelNest ->+ Pat Type ->+ Lambda SOACS ->+ DistEnv GPU DistribM ->+ Scope GPU ->+ DistribM (Stms GPU)+ generate perm nest pat' lam' dist_env extra_scope = localScope extra_scope $ do+ let maploop' = MapLoop pat' aux w lam' arrs++ exploitInnerParallelism path' = do+ let dist_env' =+ dist_env+ { distOnTopLevelStms = onTopLevelStms path',+ distOnInnerMap = onInnerMap path'+ }+ runDistNestT dist_env' . inNesting nest . localScope extra_scope $+ discardTargets+ <$> distributeMap maploop' acc {distStms = mempty}+ -- Normally the permutation is for the output pattern, but+ -- we can't really change that, so we change the result+ -- order instead.+ let lam_res' =+ rearrangeShape (rearrangeInverse perm) $+ bodyResult $+ lambdaBody lam'+ lam'' = lam' {lambdaBody = (lambdaBody lam') {bodyResult = lam_res'}}+ map_nesting = MapNesting pat' aux w $ zip (lambdaParams lam') arrs+ nest' = pushInnerKernelNesting (pat', lam_res') map_nesting nest++ -- XXX: we do not construct a new KernelPath when+ -- sequentialising. This is only OK as long as further+ -- versioning does not take place down that branch (it currently+ -- does not).+ (sequentialised_kernel, nestw_stms) <- localScope extra_scope $ do+ let sequentialised_lam = soacsLambdaToGPU lam''+ constructKernel segThreadCapped nest' $ lambdaBody sequentialised_lam++ let outer_pat = loopNestingPat $ fst nest+ (nestw_stms <>)+ <$> onMap'+ nest'+ path+ (const $ pure $ oneStm sequentialised_kernel)+ exploitInnerParallelism+ outer_pat+ lam''+ multiVersion perm nest acc' pat' lam' = do -- The kernel can be distributed by itself, so now we can -- decide whether to just sequentialise, or exploit inner@@ -830,48 +880,6 @@ dist_env <- ask let extra_scope = targetsScope $ distTargets acc' - stms <- liftInner $- localScope extra_scope $ do- let maploop' = MapLoop pat' aux w lam' arrs-- exploitInnerParallelism path' = do- let dist_env' =- dist_env- { distOnTopLevelStms = onTopLevelStms path',- distOnInnerMap = onInnerMap path'- }- runDistNestT dist_env' . inNesting nest . localScope extra_scope $- discardTargets- <$> distributeMap maploop' acc {distStms = mempty}-- -- Normally the permutation is for the output pattern, but- -- we can't really change that, so we change the result- -- order instead.- let lam_res' =- rearrangeShape (rearrangeInverse perm) $- bodyResult $- lambdaBody lam'- lam'' = lam' {lambdaBody = (lambdaBody lam') {bodyResult = lam_res'}}- map_nesting = MapNesting pat' aux w $ zip (lambdaParams lam') arrs- nest' = pushInnerKernelNesting (pat', lam_res') map_nesting nest-- -- XXX: we do not construct a new KernelPath when- -- sequentialising. This is only OK as long as further- -- versioning does not take place down that branch (it currently- -- does not).- (sequentialised_kernel, nestw_stms) <- localScope extra_scope $ do- let sequentialised_lam = soacsLambdaToGPU lam''- constructKernel segThreadCapped nest' $ lambdaBody sequentialised_lam-- let outer_pat = loopNestingPat $ fst nest- (nestw_stms <>)- <$> onMap'- nest'- path- (const $ pure $ oneStm sequentialised_kernel)- exploitInnerParallelism- outer_pat- lam''-+ stms <- liftInner $ generate perm nest pat' lam' dist_env extra_scope postStm stms pure acc'
src/Futhark/Pass/ExtractKernels/BlockedKernel.hs view
@@ -21,8 +21,8 @@ import Control.Monad.Writer import Futhark.Analysis.PrimExp import Futhark.IR+import Futhark.IR.Aliases (AliasableRep) import Futhark.IR.GPU.Op (SegVirt (..))-import Futhark.IR.Prop.Aliases import Futhark.IR.SegOp import Futhark.MonadFreshNames import Futhark.Tools@@ -37,7 +37,7 @@ LetDec rep ~ Type, ExpDec rep ~ (), BodyDec rep ~ (),- CanBeAliased (Op rep)+ AliasableRep rep ) data ThreadRecommendation = ManyThreads | NoRecommendation SegVirt
src/Futhark/Pass/ExtractKernels/StreamKernel.hs view
@@ -38,7 +38,7 @@ deriving (Eq, Ord, Show) numberOfGroups ::- (MonadBuilder m, Op (Rep m) ~ HostOp (Rep m) inner) =>+ (MonadBuilder m, Op (Rep m) ~ HostOp inner (Rep m)) => String -> SubExp -> SubExp ->
src/Futhark/Pass/ExtractKernels/ToGPU.hs view
@@ -13,7 +13,6 @@ import Control.Monad.Identity import Data.List ()-import Futhark.Analysis.Rephrase import Futhark.IR import Futhark.IR.GPU import Futhark.IR.SOACS (SOACS)@@ -21,7 +20,7 @@ import Futhark.Tools getSize ::- (MonadBuilder m, Op (Rep m) ~ HostOp (Rep m) inner) =>+ (MonadBuilder m, Op (Rep m) ~ HostOp inner (Rep m)) => String -> SizeClass -> m SubExp@@ -30,7 +29,7 @@ letSubExp desc $ Op $ SizeOp $ GetSize size_key size_class segThread ::- (MonadBuilder m, Op (Rep m) ~ HostOp (Rep m) inner) =>+ (MonadBuilder m, Op (Rep m) ~ HostOp inner (Rep m)) => String -> m SegLevel segThread desc =
src/Futhark/Pass/ExtractMulticore.hs view
@@ -9,7 +9,6 @@ import Control.Monad.Reader import Control.Monad.State import Data.Bitraversable-import Futhark.Analysis.Rephrase import Futhark.IR import Futhark.IR.MC import Futhark.IR.MC qualified as MC
src/Futhark/Pass/LiftAllocations.hs view
@@ -64,7 +64,10 @@ type LiftM inner a = Reader (Env inner) a -liftAllocationsInBody :: (Mem rep inner, LetDec rep ~ LetDecMem) => Body rep -> LiftM inner (Body rep)+liftAllocationsInBody ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ Body rep ->+ LiftM (inner rep) (Body rep) liftAllocationsInBody body = do stms <- liftAllocationsInStms (bodyStms body) mempty mempty mempty pure $ body {bodyStms = stms}@@ -79,7 +82,7 @@ Stms rep -> -- | Names we need to lift Names ->- LiftM inner (Stms rep)+ LiftM (inner rep) (Stms rep) liftAllocationsInStms Empty lifted acc _ = pure $ lifted <> acc liftAllocationsInStms (stms :|> stm@(Let (Pat [PatElem vname _]) _ (Op (Alloc _ _)))) lifted acc to_lift = liftAllocationsInStms stms (stm :<| lifted) acc ((freeIn stm <> to_lift) `namesSubtract` oneName vname)@@ -126,7 +129,7 @@ liftAllocationsInSegOp :: (Mem rep inner, LetDec rep ~ LetDecMem) => SegOp lvl rep ->- LiftM inner (SegOp lvl rep)+ LiftM (inner rep) (SegOp lvl rep) liftAllocationsInSegOp (SegMap lvl sp tps body) = do stms <- liftAllocationsInStms (kernelBodyStms body) mempty mempty mempty pure $ SegMap lvl sp tps $ body {kernelBodyStms = stms}@@ -140,11 +143,11 @@ stms <- liftAllocationsInStms (kernelBodyStms body) mempty mempty mempty pure $ SegHist lvl sp histops tps $ body {kernelBodyStms = stms} -liftAllocationsInHostOp :: HostOp GPUMem () -> LiftM (HostOp GPUMem ()) (HostOp GPUMem ())+liftAllocationsInHostOp :: HostOp NoOp GPUMem -> LiftM (HostOp NoOp GPUMem) (HostOp NoOp GPUMem) liftAllocationsInHostOp (SegOp op) = SegOp <$> liftAllocationsInSegOp op liftAllocationsInHostOp op = pure op -liftAllocationsInMCOp :: MCOp MCMem () -> LiftM (MCOp MCMem ()) (MCOp MCMem ())+liftAllocationsInMCOp :: MCOp NoOp MCMem -> LiftM (MCOp NoOp MCMem) (MCOp NoOp MCMem) liftAllocationsInMCOp (ParOp par op) = ParOp <$> traverse liftAllocationsInSegOp par <*> liftAllocationsInSegOp op liftAllocationsInMCOp op = pure op
src/Futhark/Pass/LowerAllocations.hs view
@@ -66,7 +66,10 @@ type LowerM inner a = Reader (Env inner) a -lowerAllocationsInBody :: (Mem rep inner, LetDec rep ~ LetDecMem) => Body rep -> LowerM inner (Body rep)+lowerAllocationsInBody ::+ (Mem rep inner, LetDec rep ~ LetDecMem) =>+ Body rep ->+ LowerM (inner rep) (Body rep) lowerAllocationsInBody body = do stms <- lowerAllocationsInStms (bodyStms body) mempty mempty pure $ body {bodyStms = stms}@@ -79,7 +82,7 @@ M.Map VName (Stm rep) -> -- | The other statements processed so far Stms rep ->- LowerM inner (Stms rep)+ LowerM (inner rep) (Stms rep) lowerAllocationsInStms Empty allocs acc = pure $ acc <> Seq.fromList (M.elems allocs) lowerAllocationsInStms (stm@(Let (Pat [PatElem vname _]) _ (Op (Alloc _ _))) :<| stms) allocs acc = lowerAllocationsInStms stms (M.insert vname stm allocs) acc@@ -120,7 +123,7 @@ lowerAllocationsInSegOp :: (Mem rep inner, LetDec rep ~ LetDecMem) => SegOp lvl rep ->- LowerM inner (SegOp lvl rep)+ LowerM (inner rep) (SegOp lvl rep) lowerAllocationsInSegOp (SegMap lvl sp tps body) = do stms <- lowerAllocationsInStms (kernelBodyStms body) mempty mempty pure $ SegMap lvl sp tps $ body {kernelBodyStms = stms}@@ -134,11 +137,11 @@ stms <- lowerAllocationsInStms (kernelBodyStms body) mempty mempty pure $ SegHist lvl sp histops tps $ body {kernelBodyStms = stms} -lowerAllocationsInHostOp :: HostOp GPUMem () -> LowerM (HostOp GPUMem ()) (HostOp GPUMem ())+lowerAllocationsInHostOp :: HostOp NoOp GPUMem -> LowerM (HostOp NoOp GPUMem) (HostOp NoOp GPUMem) lowerAllocationsInHostOp (SegOp op) = SegOp <$> lowerAllocationsInSegOp op lowerAllocationsInHostOp op = pure op -lowerAllocationsInMCOp :: MCOp MCMem () -> LowerM (MCOp MCMem ()) (MCOp MCMem ())+lowerAllocationsInMCOp :: MCOp NoOp MCMem -> LowerM (MCOp NoOp MCMem) (MCOp NoOp MCMem) lowerAllocationsInMCOp (ParOp par op) = ParOp <$> traverse lowerAllocationsInSegOp par <*> lowerAllocationsInSegOp op lowerAllocationsInMCOp op = pure op
src/Futhark/Pipeline.hs view
@@ -23,11 +23,13 @@ where import Control.Category+import Control.Exception (SomeException, catch, throwIO) import Control.Monad import Control.Monad.Except import Control.Monad.Reader import Control.Monad.State import Control.Monad.Writer.Strict hiding (pass)+import Control.Parallel import Data.Text qualified as T import Data.Text.IO qualified as T import Data.Time.Clock@@ -81,14 +83,33 @@ modify $ \s -> s {futharkPrevLog = now} when verb $ liftIO $ T.hPutStrLn stderr $ T.pack prefix <> msg +runFutharkM' ::+ FutharkM a ->+ FutharkState ->+ FutharkEnv ->+ IO (Either CompilerError a, FutharkState)+runFutharkM' (FutharkM m) s =+ runReaderT (runStateT (runExceptT m) s)+ -- | Run a 'FutharkM' action. runFutharkM :: FutharkM a -> Verbosity -> IO (Either CompilerError a)-runFutharkM (FutharkM m) verbose = do+runFutharkM m verbose = do s <- FutharkState <$> getCurrentTime <*> pure blankNameSource- runReaderT (evalStateT (runExceptT m) s) newEnv- where- newEnv = FutharkEnv verbose+ fst <$> runFutharkM' m s (FutharkEnv verbose) +catchIO :: FutharkM a -> (SomeException -> FutharkM a) -> FutharkM a+catchIO m f = FutharkM $ do+ s <- get+ env <- ask+ (x, s') <-+ liftIO $+ runFutharkM' m s env `catch` \e ->+ runFutharkM' (f e) s env+ put s'+ case x of+ Left e -> throwError e+ Right x' -> pure x'+ -- | A compilation always ends with some kind of action. data Action rep = Action { actionName :: String,@@ -105,14 +126,21 @@ -- | A compiler pipeline is conceptually a function from programs to -- programs, where the actual representation may change. Pipelines -- can be composed using their 'Category' instance.-newtype Pipeline fromrep torep = Pipeline {unPipeline :: PipelineConfig -> Prog fromrep -> FutharkM (Prog torep)}+newtype Pipeline fromrep torep = Pipeline+ { unPipeline ::+ forall a.+ PipelineConfig ->+ Prog fromrep ->+ FutharkM ((Prog torep -> FutharkM a) -> FutharkM a)+ } instance Category Pipeline where- id = Pipeline $ const pure+ id = Pipeline $ \_ prog -> pure $ \c -> c prog p2 . p1 = Pipeline perform where- perform cfg prog =- runPipeline p2 cfg =<< runPipeline p1 cfg prog+ perform cfg prog = do+ rc <- unPipeline p1 cfg prog+ rc $ unPipeline p2 cfg -- | Run the pipeline on the given program. runPipeline ::@@ -120,7 +148,9 @@ PipelineConfig -> Prog fromrep -> FutharkM (Prog torep)-runPipeline = unPipeline+runPipeline p cfg prog = do+ rc <- unPipeline p cfg prog+ rc pure -- | Construct a pipeline from a single compiler pass. onePass ::@@ -130,16 +160,28 @@ onePass pass = Pipeline perform where perform cfg prog = do- when (pipelineVerbose cfg) $- logMsg $- "Running pass " <> T.pack (passName pass)+ when (pipelineVerbose cfg) . logMsg $+ "Running pass " <> T.pack (passName pass) prog' <- runPass pass prog- let prog'' = Alias.aliasAnalysis prog'- when (pipelineValidate cfg) $- case checkProg prog'' of- Left err -> validationError pass prog'' $ show err- Right () -> pure ()- pure prog'+ -- Spark validation in a separate task and speculatively execute+ -- next pass. If the next pass throws an exception, we better+ -- be ready to catch it and check if it might be because the+ -- program was actually ill-typed.+ let check =+ if pipelineValidate cfg+ then validate prog'+ else Right ()+ par check $ pure $ \c ->+ (errorOnError check pure =<< c prog')+ `catchIO` errorOnError check (liftIO . throwIO)+ validate prog =+ let prog' = Alias.aliasAnalysis prog+ in case checkProg prog' of+ Left err -> Left (prog', err)+ Right () -> Right ()+ errorOnError (Left (prog, err)) _ _ =+ validationError pass prog $ show err+ errorOnError _ c x = c x -- | Conditionally run pipeline if predicate is true. condPipeline ::@@ -148,7 +190,7 @@ Pipeline $ \cfg prog -> if cond prog then f cfg prog- else pure prog+ else pure $ \c -> c prog -- | Create a pipeline from a list of passes. passes ::
src/Futhark/Pkg/Info.hs view
@@ -6,7 +6,8 @@ pkgInfo, PkgRevInfo (..), GetManifest (getManifest),- downloadZipball,+ GetFiles (getFiles),+ CacheDir (..), -- * Package registry PkgRegistry,@@ -17,42 +18,27 @@ ) where -import Codec.Archive.Zip qualified as Zip+import Control.Monad (unless, void) import Control.Monad.IO.Class import Data.ByteString qualified as BS-import Data.ByteString.Lazy qualified as LBS import Data.IORef import Data.List (foldl', intersperse) import Data.Map qualified as M import Data.Maybe import Data.Text qualified as T import Data.Text.Encoding qualified as T-import Data.Time (UTCTime, defaultTimeLocale, formatTime, getCurrentTime)+import Data.Text.IO qualified as T+import Data.Time (UTCTime, defaultTimeLocale, formatTime)+import Data.Time.Format.ISO8601 (iso8601ParseM)+import Data.Time.LocalTime (zonedTimeToUTC) import Futhark.Pkg.Types-import Futhark.Util (maybeHead, showText)+import Futhark.Util (directoryContents, showText, zEncodeText) import Futhark.Util.Log+import System.Directory (doesDirectoryExist) import System.Exit-import System.FilePath.Posix qualified as Posix-import System.IO+import System.FilePath (makeRelative, (</>)) import System.Process.ByteString (readProcessWithExitCode) --- | Download URL via shelling out to @curl@.-curl :: String -> IO (Either String BS.ByteString)-curl url = do- (code, out, err) <-- -- The -L option follows HTTP redirects.- liftIO $ readProcessWithExitCode "curl" ["-L", url] mempty- case code of- ExitFailure 127 ->- pure $- Left $- "'" <> unwords ["curl", "-L", url] <> "' failed (program not found?)."- ExitFailure _ -> do- liftIO $ BS.hPutStr stderr err- pure $ Left $ "'" <> unwords ["curl", "-L", url] <> "' failed."- ExitSuccess ->- pure $ Right out- -- | The manifest is stored as a monadic action, because we want to -- fetch them on-demand. It would be a waste to fetch it information -- for every version of every package if we only actually need a small@@ -60,36 +46,40 @@ newtype GetManifest m = GetManifest {getManifest :: m PkgManifest} instance Show (GetManifest m) where- show _ = "#<revdeps>"+ show _ = "#<GetManifest>" instance Eq (GetManifest m) where _ == _ = True +-- | Get the absolute path to a package directory on disk, as well as+-- /relative/ paths to files that should be installed from this+-- package. Composing the package directory and one of these paths+-- refers to a local file (pointing into the cache) and is valid at+-- least until the next cache operation.+newtype GetFiles m = GetFiles {getFiles :: m (FilePath, [FilePath])}++instance Show (GetFiles m) where+ show _ = "#<GetFiles>"++instance Eq (GetFiles m) where+ _ == _ = True+ -- | Information about a version of a single package. The version -- number is stored separately. data PkgRevInfo m = PkgRevInfo- { pkgRevZipballUrl :: T.Text,- -- | The directory inside the zipball- -- containing the @lib@ directory, in- -- which the package files themselves- -- are stored (Based on the package- -- path).- pkgRevZipballDir :: FilePath,- -- | The commit ID can be used for- -- verification ("freezing"), by- -- storing what it was at the time this- -- version was last selected.+ { pkgGetFiles :: GetFiles m,+ -- | The commit ID can be used for verification ("freezing"), by+ -- storing what it was at the time this version was last selected. pkgRevCommit :: T.Text, pkgRevGetManifest :: GetManifest m,- -- | Timestamp for when the revision- -- was made (rarely used).+ -- | Timestamp for when the revision was made (rarely used). pkgRevTime :: UTCTime } deriving (Eq, Show) -- | Create memoisation around a 'GetManifest' action to ensure that -- multiple inspections of the same revisions will not result in--- potentially expensive network round trips.+-- potentially expensive IO operations. memoiseGetManifest :: MonadIO m => GetManifest m -> m (GetManifest m) memoiseGetManifest (GetManifest m) = do ref <- liftIO $ newIORef Nothing@@ -103,25 +93,6 @@ liftIO $ writeIORef ref $ Just v' pure v' --- | Download the zip archive corresponding to a specific package--- version.-downloadZipball ::- (MonadLogger m, MonadIO m, MonadFail m) =>- PkgRevInfo m ->- m Zip.Archive-downloadZipball info = do- let url = pkgRevZipballUrl info- logMsg $ "Downloading " <> T.unpack url-- let bad = fail . (("When downloading " <> T.unpack url <> ": ") <>)- http <- liftIO $ curl $ T.unpack url- case http of- Left e -> bad e- Right r ->- case Zip.toArchiveOrFail $ LBS.fromStrict r of- Left e -> bad $ show e- Right a -> pure a- -- | Information about a package. The name of the package is stored -- separately. data PkgInfo m = PkgInfo@@ -135,238 +106,144 @@ lookupPkgRev :: SemVer -> PkgInfo m -> Maybe (PkgRevInfo m) lookupPkgRev v = M.lookup v . pkgVersions -majorRevOfPkg :: PkgPath -> (PkgPath, [Word])+majorRevOfPkg :: PkgPath -> (T.Text, [Word]) majorRevOfPkg p = case T.splitOn "@" p of [p', v] | [(v', "")] <- reads $ T.unpack v -> (p', [v']) _ -> (p, [0, 1]) --- | Retrieve information about a package based on its package path.--- This uses Semantic Import Versioning when interacting with--- repositories. For example, a package @github.com/user/repo@ will--- match version 0.* or 1.* tags only, a package--- @github.com/user/repo/v2@ will match 2.* tags, and so forth..-pkgInfo ::- (MonadIO m, MonadLogger m, MonadFail m) =>- PkgPath ->- m (Either T.Text (PkgInfo m))-pkgInfo path- | ["github.com", owner, repo] <- T.splitOn "/" path =- let (repo', vs) = majorRevOfPkg repo- in ghPkgInfo owner repo' vs- | "github.com" : owner : repo : _ <- T.splitOn "/" path =- pure $- Left $- T.intercalate- "\n"- [nope, "Do you perhaps mean 'github.com/" <> owner <> "/" <> repo <> "'?"]- | ["gitlab.com", owner, repo] <- T.splitOn "/" path =- let (repo', vs) = majorRevOfPkg repo- in glPkgInfo owner repo' vs- | "gitlab.com" : owner : repo : _ <- T.splitOn "/" path =- pure $- Left $- T.intercalate- "\n"- [nope, "Do you perhaps mean 'gitlab.com/" <> owner <> "/" <> repo <> "'?"]- | otherwise =- pure $ Left nope- where- nope = "Unable to handle package paths of the form '" <> path <> "'"---- For GitHub, we unfortunately cannot use the (otherwise very nice)--- GitHub web API, because it is rate-limited to 60 requests per hour--- for non-authenticated users. Instead we fall back to a combination--- of calling 'git' directly and retrieving things from the GitHub--- webserver, which is not rate-limited. This approach is also used--- by other systems (Go most notably), so we should not be stepping on--- any toes.--gitCmd :: (MonadIO m, MonadFail m) => [String] -> m BS.ByteString+gitCmd :: (MonadIO m, MonadLogger m, MonadFail m) => [String] -> m BS.ByteString gitCmd opts = do+ logMsg $ "Running command: " <> T.unwords ("git" : map T.pack opts) (code, out, err) <- liftIO $ readProcessWithExitCode "git" opts mempty- liftIO $ BS.hPutStr stderr err+ unless (err == mempty) $ logMsg $ T.decodeUtf8 err case code of ExitFailure 127 -> fail $ "'" <> unwords ("git" : opts) <> "' failed (program not found?)." ExitFailure _ -> fail $ "'" <> unwords ("git" : opts) <> "' failed." ExitSuccess -> pure out --- The GitLab and GitHub interactions are very similar, so we define a--- couple of generic functions that are used to implement support for--- both.--ghglRevGetManifest ::- (MonadIO m, MonadLogger m, MonadFail m) =>- T.Text ->- T.Text ->- T.Text ->- T.Text ->- GetManifest m-ghglRevGetManifest url owner repo tag = GetManifest $ do- logMsg $ "Downloading package manifest from " <> url+gitCmd_ :: (MonadIO m, MonadLogger m, MonadFail m) => [String] -> m ()+gitCmd_ = void . gitCmd - let path =- T.unpack $- owner- <> "/"- <> repo- <> "@"- <> tag- <> "/"- <> T.pack futharkPkg- msg = (("When reading " <> path <> ": ") <>)- http <- liftIO $ curl $ T.unpack url- case http of- Left e -> fail e- Right r' ->- case T.decodeUtf8' r' of- Left e -> fail $ msg $ show e- Right s ->- case parsePkgManifest path s of- Left e -> fail $ msg $ errorBundlePretty e- Right pm -> pure pm+gitCmdLines :: (MonadIO m, MonadLogger m, MonadFail m) => [String] -> m [T.Text]+gitCmdLines = fmap (T.lines . T.decodeUtf8) . gitCmd -ghglLookupCommit ::- (MonadIO m, MonadLogger m, MonadFail m) =>- T.Text ->- T.Text ->- (T.Text -> T.Text) ->- T.Text ->- T.Text ->- T.Text ->- T.Text ->- T.Text ->- m (PkgRevInfo m)-ghglLookupCommit archive_url manifest_url mk_zip_dir owner repo d ref hash = do- gd <- memoiseGetManifest $ ghglRevGetManifest manifest_url owner repo ref- let dir = Posix.addTrailingPathSeparator $ T.unpack $ mk_zip_dir d- time <- liftIO getCurrentTime -- FIXME- pure $ PkgRevInfo archive_url dir hash gd time+-- | A temporary directory in which we store Git checkouts while+-- running. This is to avoid constantly re-cloning. Will be deleted+-- when @futhark pkg@ terminates. In principle we could keep this+-- around for longer, but then we would have to 'git pull' now and+-- then also. Note that the cache is stateful - we are going to use+-- @git checkout@ to move around the history. It is generally not+-- safe to have multiple operations running concurrently.+newtype CacheDir = CacheDir FilePath -ghglPkgInfo ::+ensureGit :: (MonadIO m, MonadLogger m, MonadFail m) =>- T.Text ->- (T.Text -> T.Text) ->- (T.Text -> T.Text) ->- (T.Text -> T.Text) ->- T.Text ->+ CacheDir -> T.Text ->- [Word] ->- m (Either T.Text (PkgInfo m))-ghglPkgInfo repo_url mk_archive_url mk_manifest_url mk_zip_dir owner repo versions = do- logMsg $ "Retrieving list of tags from " <> repo_url- remote_lines <- T.lines . T.decodeUtf8 <$> gitCmd ["ls-remote", T.unpack repo_url]+ m FilePath+ensureGit (CacheDir cachedir) url = do+ exists <- liftIO $ doesDirectoryExist gitdir+ unless exists $+ gitCmd_ ["-C", cachedir, "clone", "https://" <> T.unpack url, url']+ pure gitdir+ where+ url' = T.unpack $ zEncodeText url+ gitdir = cachedir </> url' - head_ref <-- maybe (fail $ "Cannot find HEAD ref for " <> T.unpack repo_url) pure $- maybeHead $- mapMaybe isHeadRef remote_lines- let def = fromMaybe head_ref+-- A git reference (tag, commit, HEAD, etc).+type Ref = String - rev_info <- M.fromList . catMaybes <$> mapM revInfo remote_lines+versionRef :: SemVer -> Ref+versionRef v = T.unpack $ "v" <> prettySemVer v +revInfo ::+ (MonadIO m, MonadLogger m, MonadFail m) =>+ FilePath ->+ PkgPath ->+ Ref ->+ m (PkgRevInfo m)+revInfo gitdir path ref = do+ gitCmd_ ["-C", gitdir, "rev-parse", ref, "--"]+ [sha] <- gitCmdLines ["-C", gitdir, "rev-list", "-n1", ref]+ [time] <- gitCmdLines ["-C", gitdir, "show", "-s", "--format=%cI", ref]+ utc <- zonedTimeToUTC <$> iso8601ParseM (T.unpack time)+ gm <- memoiseGetManifest getManifest' pure $- Right $- PkgInfo rev_info $ \r ->- ghglLookupCommit- (mk_archive_url (def r))- (mk_manifest_url (def r))- mk_zip_dir- owner- repo- (def r)- (def r)- (def r)+ PkgRevInfo+ { pkgGetFiles = getFiles gm,+ pkgRevCommit = sha,+ pkgRevGetManifest = gm,+ pkgRevTime = utc+ } where- isHeadRef l- | [hash, "HEAD"] <- T.words l = Just hash- | otherwise = Nothing+ noPkgDir pdir =+ fail $+ T.unpack path+ <> "-"+ <> ref+ <> " does not contain a directory "+ <> pdir - revInfo l- | [hash, ref] <- T.words l,- ["refs", "tags", t] <- T.splitOn "/" ref,- "v" `T.isPrefixOf` t,- Right v <- parseVersion $ T.drop 1 t,- _svMajor v `elem` versions = do- pinfo <-- ghglLookupCommit- (mk_archive_url t)- (mk_manifest_url t)- mk_zip_dir- owner- repo- (prettySemVer v)- t- hash- pure $ Just (v, pinfo)- | otherwise = pure Nothing+ noPkgPath =+ fail $+ "futhark.pkg for "+ <> T.unpack path+ <> "-"+ <> ref+ <> " does not define a package path." -ghPkgInfo ::- (MonadIO m, MonadLogger m, MonadFail m) =>- T.Text ->- T.Text ->- [Word] ->- m (Either T.Text (PkgInfo m))-ghPkgInfo owner repo versions =- ghglPkgInfo- repo_url- mk_archive_url- mk_manifest_url- mk_zip_dir- owner- repo- versions- where- repo_url = "https://github.com/" <> owner <> "/" <> repo- mk_archive_url r = repo_url <> "/archive/" <> r <> ".zip"- mk_manifest_url r =- "https://raw.githubusercontent.com/"- <> owner- <> "/"- <> repo- <> "/"- <> r- <> "/"- <> T.pack futharkPkg- mk_zip_dir r = repo <> "-" <> r+ getFiles gm = GetFiles $ do+ gitCmd_ ["-C", gitdir, "checkout", ref, "--"]+ pdir <- maybe noPkgPath pure . pkgDir =<< getManifest gm+ let pdir_abs = gitdir </> pdir+ exists <- liftIO $ doesDirectoryExist pdir_abs+ unless exists $ noPkgDir pdir+ fs <- liftIO $ directoryContents pdir_abs+ pure (pdir_abs, map (makeRelative pdir_abs) fs) -glPkgInfo ::+ getManifest' = GetManifest $ do+ gitCmd_ ["-C", gitdir, "checkout", ref, "--"]+ let f = gitdir </> futharkPkg+ s <- liftIO $ T.readFile f+ let msg =+ "When reading package manifest for "+ <> T.unpack path+ <> " "+ <> ref+ <> ":\n"+ case parsePkgManifest f s of+ Left e -> fail $ msg <> errorBundlePretty e+ Right pm -> pure pm++-- | Retrieve information about a package based on its package path.+-- This uses Semantic Import Versioning when interacting with+-- repositories. For example, a package @github.com/user/repo@ will+-- match version 0.* or 1.* tags only, a package+-- @github.com/user/repo/v2@ will match 2.* tags, and so forth..+pkgInfo :: (MonadIO m, MonadLogger m, MonadFail m) =>- T.Text ->- T.Text ->- [Word] ->- m (Either T.Text (PkgInfo m))-glPkgInfo owner repo versions =- ghglPkgInfo- repo_url- mk_archive_url- mk_manifest_url- mk_zip_dir- owner- repo- versions+ CacheDir ->+ PkgPath ->+ m (PkgInfo m)+pkgInfo cachedir path = do+ gitdir <- ensureGit cachedir url+ versions <- mapMaybe isVersionRef <$> gitCmdLines ["-C", gitdir, "tag"]+ versions' <-+ M.fromList . zip versions+ <$> mapM (revInfo gitdir path . versionRef) versions+ pure $ PkgInfo versions' $ lookupCommit gitdir where- base_url = "https://gitlab.com/" <> owner <> "/" <> repo- repo_url = base_url <> ".git"- mk_archive_url r =- base_url- <> "/-/archive/"- <> r- <> "/"- <> repo- <> "-"- <> r- <> ".zip"- mk_manifest_url r =- base_url- <> "/raw/"- <> r- <> "/"- <> T.pack futharkPkg- mk_zip_dir r- | Right _ <- parseVersion r = repo <> "-v" <> r- | otherwise = repo <> "-" <> r+ (url, path_versions) = majorRevOfPkg path+ isVersionRef l+ | "v" `T.isPrefixOf` l,+ Right v <- parseVersion $ T.drop 1 l,+ _svMajor v `elem` path_versions =+ Just v+ | otherwise = Nothing + lookupCommit gitdir = revInfo gitdir path . maybe "HEAD" T.unpack+ -- | A package registry is a mapping from package paths to information -- about the package. It is unlikely that any given registry is -- global; rather small registries are constructed on-demand based on@@ -395,28 +272,27 @@ -- | Given a package path, look up information about that package. lookupPackage :: MonadPkgRegistry m =>+ CacheDir -> PkgPath -> m (PkgInfo m)-lookupPackage p = do+lookupPackage cachedir p = do r@(PkgRegistry m) <- getPkgRegistry case lookupKnownPackage p r of Just info -> pure info Nothing -> do- e <- pkgInfo p- case e of- Left e' -> fail $ T.unpack e'- Right pinfo -> do- putPkgRegistry $ PkgRegistry $ M.insert p pinfo m- pure pinfo+ pinfo <- pkgInfo cachedir p+ putPkgRegistry $ PkgRegistry $ M.insert p pinfo m+ pure pinfo lookupPackageCommit :: MonadPkgRegistry m =>+ CacheDir -> PkgPath -> Maybe T.Text -> m (SemVer, PkgRevInfo m)-lookupPackageCommit p ref = do- pinfo <- lookupPackage p+lookupPackageCommit cachedir p ref = do+ pinfo <- lookupPackage cachedir p rev_info <- pkgLookupCommit pinfo ref let timestamp = T.pack $@@ -431,14 +307,15 @@ -- | Look up information about a specific version of a package. lookupPackageRev :: MonadPkgRegistry m =>+ CacheDir -> PkgPath -> SemVer -> m (PkgRevInfo m)-lookupPackageRev p v+lookupPackageRev cachedir p v | Just commit <- isCommitVersion v =- snd <$> lookupPackageCommit p (Just commit)+ snd <$> lookupPackageCommit cachedir p (Just commit) | otherwise = do- pinfo <- lookupPackage p+ pinfo <- lookupPackage cachedir p case lookupPkgRev v pinfo of Nothing -> let versions = case M.keys $ pkgVersions pinfo of@@ -470,12 +347,13 @@ -- | Find the newest version of a package. lookupNewestRev :: MonadPkgRegistry m =>+ CacheDir -> PkgPath -> m SemVer-lookupNewestRev p = do- pinfo <- lookupPackage p+lookupNewestRev cachedir p = do+ pinfo <- lookupPackage cachedir p case M.keys $ pkgVersions pinfo of [] -> do logMsg $ "Package " <> p <> " has no released versions. Using HEAD."- fst <$> lookupPackageCommit p Nothing+ fst <$> lookupPackageCommit cachedir p Nothing v : vs -> pure $ foldl' max v vs
src/Futhark/Pkg/Solve.hs view
@@ -75,9 +75,10 @@ -- a cache of the lookups performed, as well as a build list. solveDeps :: MonadPkgRegistry m =>+ CacheDir -> PkgRevDeps -> m BuildList-solveDeps deps =+solveDeps cachedir deps = buildList (depRoots deps) <$> runF (execStateT (doSolveDeps deps) emptyRoughBuildList)@@ -85,7 +86,7 @@ step where step (OpGetDeps p v h c) = do- pinfo <- lookupPackageRev p v+ pinfo <- lookupPackageRev cachedir p v checkHash p v pinfo h
src/Futhark/Script.hs view
@@ -22,6 +22,7 @@ -- * Evaluation EvalBuiltin,+ scriptBuiltin, evalExp, getExpValue, evalExpToGround,@@ -32,6 +33,7 @@ import Control.Monad.Except import Data.Bifunctor (bimap)+import Data.ByteString.Lazy qualified as LBS import Data.Char import Data.Foldable (toList) import Data.Functor@@ -42,6 +44,7 @@ import Data.Text qualified as T import Data.Traversable import Data.Void+import Data.Word (Word8) import Futhark.Data.Parser qualified as V import Futhark.Server import Futhark.Server.Values (getValue, putValue)@@ -50,6 +53,7 @@ import Futhark.Util.Pretty hiding (line, sep, space, (</>)) import Language.Futhark.Core (Name, nameFromText, nameToText) import Language.Futhark.Tuple (areTupleFields)+import System.FilePath ((</>)) import Text.Megaparsec import Text.Megaparsec.Char (space) import Text.Megaparsec.Char.Lexer (charLiteral)@@ -289,6 +293,38 @@ -- | How to evaluate a builtin function. type EvalBuiltin m = T.Text -> [V.CompoundValue] -> m V.CompoundValue++loadData ::+ (MonadIO m, MonadError T.Text m) =>+ FilePath ->+ m (V.Compound V.Value)+loadData datafile = do+ contents <- liftIO $ LBS.readFile datafile+ let maybe_vs = V.readValues contents+ case maybe_vs of+ Nothing ->+ throwError $ "Failed to read data file " <> T.pack datafile+ Just [v] ->+ pure $ V.ValueAtom v+ Just vs ->+ pure $ V.ValueTuple $ map V.ValueAtom vs++-- | Handles the following builtin functions: @loaddata@. Fails for+-- everything else. The 'FilePath' indicates the directory that files+-- should be read relative to.+scriptBuiltin :: (MonadIO m, MonadError T.Text m) => FilePath -> EvalBuiltin m+scriptBuiltin dir "loaddata" vs =+ case vs of+ [V.ValueAtom v]+ | Just path <- V.getValue v -> do+ let path' = map (chr . fromIntegral) (path :: [Word8])+ loadData $ dir </> path'+ _ ->+ throwError $+ "$loaddata does not accept arguments of types: "+ <> T.intercalate ", " (map (prettyText . fmap V.valueType) vs)+scriptBuiltin _ f _ =+ throwError $ "Unknown builtin function $" <> prettyText f -- | Symbol table used for local variable lookups during expression evaluation. type VTable = M.Map VarName ExpValue
src/Futhark/Test.hs view
@@ -215,13 +215,10 @@ mapM_ (BS.hPutStr tmpf_h . Bin.encode) vs hClose tmpf_h cmdRestore server tmpf names_and_types-valuesAsVars server names_and_types _ _ (ScriptValues e) =+valuesAsVars server names_and_types _ dir (ScriptValues e) = Script.withScriptServer' server $ \server' -> do- e_v <- Script.evalExp noBuiltin server' e+ e_v <- Script.evalExp (Script.scriptBuiltin dir) server' e scriptValueAsVars server names_and_types e_v- where- noBuiltin f _ = do- throwError $ "Unknown builtin procedure: " <> f valuesAsVars server names_and_types futhark dir (ScriptFile f) = do e <- either throwError pure . Script.parseExpFromText f@@ -264,7 +261,8 @@ genValues :: FutharkExe -> [GenValue] -> IO SBS.ByteString genValues (FutharkExe futhark) gens = do- (code, stdout, stderr) <- readProcessWithExitCode futhark ("dataset" : args) mempty+ (code, stdout, stderr) <-+ readProcessWithExitCode futhark ("dataset" : map T.unpack args) mempty case code of ExitSuccess -> pure stdout@@ -279,7 +277,7 @@ argForGen g = ["-g", genValueType g] genFileName :: GenValue -> FilePath-genFileName gen = genValueType gen ++ ".in"+genFileName gen = T.unpack (genValueType gen) <> ".in" -- | Compute the expected size of the file. We use this to check -- whether an existing file is broken/truncated.@@ -304,7 +302,7 @@ <> ":" <> T.unpack entry <> "-"- <> map clean (runDescription tr)+ <> map clean (T.unpack (runDescription tr)) <.> "out" where clean '/' = '_' -- Would this ever happen?
src/Futhark/Test/Spec.hs view
@@ -27,7 +27,7 @@ import Control.Monad import Data.Char import Data.Functor-import Data.List (foldl')+import Data.List (foldl', (\\)) import Data.Map.Strict qualified as M import Data.Maybe import Data.Text qualified as T@@ -38,7 +38,7 @@ import Futhark.Data.Parser qualified as V import Futhark.Script qualified as Script import Futhark.Test.Values qualified as V-import Futhark.Util (directoryContents)+import Futhark.Util (directoryContents, nubOrd, showText) import Futhark.Util.Pretty (prettyTextOneLine) import System.Exit import System.FilePath@@ -46,6 +46,7 @@ import System.IO.Error import Text.Megaparsec hiding (many, some) import Text.Megaparsec.Char+import Text.Megaparsec.Char.Lexer (charLiteral) import Text.Regex.TDFA import Prelude @@ -112,7 +113,7 @@ runInput :: Values, runExpectedResult :: ExpectedResult Success, runIndex :: Int,- runDescription :: String+ runDescription :: T.Text } deriving (Show) @@ -137,11 +138,11 @@ -- | A prettyprinted representation of type of value produced by a -- 'GenValue'.-genValueType :: GenValue -> String+genValueType :: GenValue -> T.Text genValueType (GenValue (V.ValueType ds t)) =- concatMap (\d -> "[" ++ show d ++ "]") ds ++ T.unpack (V.primTypeText t)+ foldMap (\d -> "[" <> showText d <> "]") ds <> V.primTypeText t genValueType (GenPrim v) =- T.unpack $ V.valueText v+ V.valueText v -- | How a test case is expected to terminate. data ExpectedResult values@@ -240,6 +241,10 @@ guard $ s `notElem` ["input", "structure", "warning"] pure s +parseStringLiteral :: Parser () -> Parser T.Text+parseStringLiteral sep =+ lexeme sep . fmap T.pack $ char '"' >> manyTill charLiteral (char '"')+ parseRunCases :: Parser () -> Parser [TestRun] parseRunCases sep = parseRunCases' (0 :: Int) where@@ -247,6 +252,7 @@ (:) <$> parseRunCase i <*> parseRunCases' (i + 1) <|> pure [] parseRunCase i = do+ name <- optional $ parseStringLiteral sep tags <- parseRunTags void $ lexeme sep "input" input <-@@ -257,7 +263,7 @@ then parseScriptValues sep else parseValues sep expr <- parseExpectedResult sep- pure $ TestRun tags input expr i $ desc i input+ pure $ TestRun tags input expr i $ fromMaybe (desc i input) name -- If the file is gzipped, we strip the 'gz' extension from -- the dataset name. This makes it more convenient to rename@@ -265,22 +271,22 @@ -- does not change (which would make comparisons to historical -- data harder). desc _ (InFile path)- | takeExtension path == ".gz" = dropExtension path- | otherwise = path+ | takeExtension path == ".gz" = T.pack $ dropExtension path+ | otherwise = T.pack path desc i (Values vs) = -- Turn linebreaks into space.- "#" ++ show i ++ " (\"" ++ unwords (lines vs') ++ "\")"+ "#" <> showText i <> " (\"" <> T.unwords (T.lines vs') <> "\")" where- vs' = case unwords $ map (T.unpack . V.valueText) vs of+ vs' = case T.unwords $ map V.valueText vs of s- | length s > 50 -> take 50 s ++ "..."+ | T.length s > 50 -> T.take 50 s <> "..." | otherwise -> s desc _ (GenValues gens) =- unwords $ map genValueType gens+ T.unwords $ map genValueType gens desc _ (ScriptValues e) =- T.unpack $ prettyTextOneLine e+ prettyTextOneLine e desc _ (ScriptFile path) =- path+ T.pack path parseExpectedResult :: Parser () -> Parser (ExpectedResult Success) parseExpectedResult sep =@@ -395,10 +401,25 @@ pInputOutputs = "--" *> sep *> parseDescription sep *> parseInputOutputs sep <* pEndOfTestBlock +validate :: FilePath -> ProgramTest -> Either String ProgramTest+validate path pt = do+ case testAction pt of+ CompileTimeFailure {} -> pure pt+ RunCases ios _ _ -> do+ mapM_ (noDups . map runDescription . iosTestRuns) ios+ Right pt+ where+ noDups xs =+ let xs' = nubOrd xs+ in -- Works because \\ only removes first instance.+ case xs \\ xs' of+ [] -> Right ()+ x : _ -> Left $ path <> ": multiple datasets with name " <> show (T.unpack x)+ -- | Read the test specification from the given Futhark program. testSpecFromProgram :: FilePath -> IO (Either String ProgramTest) testSpecFromProgram path =- ( either (Left . errorBundlePretty) Right . parse pProgramTest path+ ( either (Left . errorBundlePretty) (validate path) . parse pProgramTest path <$> T.readFile path ) `catch` couldNotRead
src/Futhark/Transform/FirstOrderTransform.hs view
@@ -35,7 +35,7 @@ BuilderOps rep, LetDec SOACS ~ LetDec rep, LParamInfo SOACS ~ LParamInfo rep,- CanBeAliased (Op rep)+ Alias.AliasableRep rep ) -- | First-order-transform a single function, with the given scope@@ -69,7 +69,7 @@ Buildable (Rep m), BuilderOps (Rep m), LParamInfo SOACS ~ LParamInfo (Rep m),- CanBeAliased (Op (Rep m))+ Alias.AliasableRep (Rep m) ) transformBody ::@@ -375,7 +375,7 @@ LocalScope somerep m, SameScope somerep rep, LetDec rep ~ LetDec SOACS,- CanBeAliased (Op rep)+ Alias.AliasableRep rep ) => Lambda SOACS -> m (AST.Lambda rep)
src/Futhark/Transform/Rename.hs view
@@ -325,6 +325,9 @@ instance Rename () where rename = pure +instance Rename (NoOp rep) where+ rename NoOp = pure NoOp+ instance Rename d => Rename (DimIndex d) where rename (DimFix i) = DimFix <$> rename i rename (DimSlice i n s) = DimSlice <$> rename i <*> rename n <*> rename s
src/Futhark/Transform/Substitute.hs view
@@ -138,6 +138,9 @@ instance Substitute () where substituteNames _ = id +instance Substitute (NoOp rep) where+ substituteNames _ = id+ instance Substitute d => Substitute (ShapeBase d) where substituteNames substs (Shape es) = Shape $ map (substituteNames substs) es
src/Futhark/Util.hs view
@@ -437,9 +437,9 @@ -- | Truncate to at most this many characters, making the last three -- characters "..." if truncation is necessary.-atMostChars :: Int -> String -> String+atMostChars :: Int -> T.Text -> T.Text atMostChars n s- | length s > n = take (n - 3) s ++ "..."+ | T.length s > n = T.take (n - 3) s <> "..." | otherwise = s -- | Invert a map, handling duplicate values (now keys) by
src/Futhark/Util/Log.hs view
@@ -13,6 +13,8 @@ import Control.Monad.Writer import Data.DList qualified as DL import Data.Text qualified as T+import Data.Text.IO qualified as T+import System.IO (stderr) -- | An efficiently catenable sequence of log entries. newtype Log = Log {unLog :: DL.DList T.Text}@@ -55,3 +57,6 @@ instance Monad m => MonadLogger (Control.Monad.RWS.Strict.RWST r Log s m) where addLog = tell++instance MonadLogger IO where+ addLog = mapM_ (T.hPutStrLn stderr) . unLog
src/Language/Futhark/Interpreter.hs view
@@ -348,12 +348,11 @@ T.envVtable = vtable } -break :: Loc -> EvalM ()-break loc = do- backtrace <- asks fst- case NE.nonEmpty backtrace of- Nothing -> pure ()- Just backtrace' -> liftF $ ExtOpBreak loc BreakPoint backtrace' ()+break :: Env -> Loc -> EvalM ()+break env loc = do+ imports <- asks snd+ backtrace <- asks ((StackFrame loc (Ctx env imports) NE.:|) . fst)+ liftF $ ExtOpBreak loc BreakPoint backtrace () fromArray :: Value -> (ValueShape, [Value]) fromArray (ValueArray shape as) = (shape, elems as)@@ -800,7 +799,7 @@ let t = T.BoundV [] $ toStruct $ unInfo $ identType dest eval (valEnv (M.singleton (identName dest) (Just t, dest')) <> env) body where- oob = bad loc env "Bad update"+ oob = bad loc env "Update out of bounds" evalAppExp env _ (DoLoop sparams pat init_e form body _) = do init_v <- eval env init_e case form of@@ -991,7 +990,7 @@ shape <- typeValueShape env $ toStruct t pure $ ValueSum shape c vs eval env (Attr (AttrAtom (AtomName "break") _) e loc) = do- break (locOf loc)+ break env (locOf loc) eval env e eval env (Attr (AttrAtom (AtomName "trace") _) e loc) = do v <- eval env e
src/Language/Futhark/Interpreter/Values.hs view
@@ -227,10 +227,12 @@ SVec.Vector Int -> SVec.Vector a -> Value m-fromDataValueWith f shape vector =- if SVec.null shape- then ValuePrim $ f $ SVec.head vector- else+fromDataValueWith f shape vector+ | SVec.null shape = ValuePrim $ f $ SVec.head vector+ | SVec.null vector =+ toArray (fromDataShape shape) $+ replicate (SVec.head shape) (fromDataValueWith f shape' vector)+ | otherwise = toArray (fromDataShape shape) . map (fromDataValueWith f shape' . SVec.fromList) $ chunk (SVec.product shape') (SVec.toList vector)
src/Language/Futhark/Parser/Lexer.x view
@@ -102,10 +102,10 @@ @intlit u64 { tokenM $ pure . U64LIT . readIntegral . T.filter (/= '_') . T.takeWhile (/='u') } @intlit { tokenM $ pure . INTLIT . readIntegral . T.filter (/= '_') } - [^\.] ^ @reallit f16 { tokenM $ fmap F16LIT . tryRead "f16" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }- [^\.] ^ @reallit f32 { tokenM $ fmap F32LIT . tryRead "f32" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }- [^\.] ^ @reallit f64 { tokenM $ fmap F64LIT . tryRead "f64" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }- [^\.] ^ @reallit { tokenM $ fmap FLOATLIT . tryRead "f64" . suffZero . T.filter (/= '_') }+ [\n[^\.]] ^ @reallit f16 { tokenM $ fmap F16LIT . tryRead "f16" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }+ [\n[^\.]] ^ @reallit f32 { tokenM $ fmap F32LIT . tryRead "f32" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }+ [\n[^\.]] ^ @reallit f64 { tokenM $ fmap F64LIT . tryRead "f64" . suffZero . T.filter (/= '_') . T.takeWhile (/='f') }+ [\n[^\.]] ^ @reallit { tokenM $ fmap FLOATLIT . tryRead "f64" . suffZero . T.filter (/= '_') } @hexreallit f16 { tokenM $ fmap F16LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 } @hexreallit f32 { tokenM $ fmap F32LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 } @hexreallit f64 { tokenM $ fmap F64LIT . readHexRealLit . T.filter (/= '_') . T.dropEnd 3 }
src/Language/Futhark/Parser/Parser.y view
@@ -124,6 +124,8 @@ '^...' { L _ (SYMBOL Xor _ _) } '||...' { L _ (SYMBOL LogOr _ _) } '&&...' { L _ (SYMBOL LogAnd _ _) }+ '!...' { L _ (SYMBOL Bang _ _) }+ '=...' { L _ (SYMBOL Equ _ _) } '(' { L $$ LPAR } ')' { L $$ RPAR }@@ -162,11 +164,12 @@ hole { L $$ HOLE } %left bottom+%left typeprec %left ifprec letprec caseprec typeprec enumprec sumprec %left ',' case id constructor '(' '{' %right ':' ':>' %right '...' '..<' '..>' '..'-%left '`'+%left '`' '!...' %right '->' %left with %left '='@@ -174,14 +177,15 @@ %right '<|...' %left '||...' %left '&&...'-%left '<=...' '>=...' '>...' '<' '<...' '==...' '!=...'+%left '<=...' '>=...' '>...' '<' '<...' '==...' '!=...' '!...' '=...' %left '&...' '^...' '^' '|...' '|' %left '<<...' '>>...' %left '+...' '-...' '-' %left '*...' '*' '/...' '%...' '//...' '%%...' %left '**...' %left juxtprec-%left indexprec+%left '[' '...[' indexprec+%left top %% -- The main parser.@@ -379,6 +383,8 @@ | '<|...' { binOpName $1 } | '|>...' { binOpName $1 } | '<' { (qualName (nameFromString "<"), $1) }+ | '!...' { binOpName $1 }+ | '=...' { binOpName $1 } | '`' QualName '`' { $2 } BindingBinOp :: { Name }@@ -387,6 +393,7 @@ Just "Cannot use a qualified name in binding position." pure name } | '-' { nameFromString "-" }+ | '!' {% parseErrorAt $1 $ Just $ "'!' is a prefix operator and cannot be used as infix operator." } BindingId :: { (Name, Loc) } : id { let L loc (ID name) = $1 in (name, loc) }@@ -455,28 +462,22 @@ TypeExpTerm :: { UncheckedTypeExp } : '*' TypeExpTerm { TEUnique $2 (srcspan $1 $>) }- | '[' SizeExp ']' TypeExpTerm %prec indexprec- { TEArray $2 $4 (srcspan $1 $>) }- | '...[' SizeExp ']' TypeExpTerm %prec indexprec- { TEArray $2 $4 (srcspan $1 $>) }- | TypeExpApply %prec sumprec { $1 }- | SumType { $1 }+ | TypeExpApply %prec typeprec { $1 }+ | SumClauses %prec sumprec+ { let (cs, loc) = $1 in TESum cs (srclocOf loc) } -- Errors | '[' SizeExp ']' %prec bottom {% parseErrorAt (srcspan $1 $>) $ Just $- T.unlines ["missing array row type.",+ T.unlines ["Missing array row type.", "Did you mean []" <> prettyText $2 <> "?"] } | '...[' SizeExp ']' %prec bottom {% parseErrorAt (srcspan $1 $>) $ Just $- T.unlines ["missing array row type.",+ T.unlines ["Missing array row type.", "Did you mean []" <> prettyText $2 <> "?"] } -SumType :: { UncheckedTypeExp }-SumType : SumClauses %prec sumprec { let (cs, loc) = $1 in TESum cs (srclocOf loc) }- SumClauses :: { ([(Name, [UncheckedTypeExp])], Loc) } : SumClauses '|' SumClause %prec sumprec { let (cs, loc1) = $1; (c, ts, loc2) = $3@@ -484,11 +485,13 @@ | SumClause %prec sumprec { let (n, ts, loc) = $1 in ([(n, ts)], loc) } +SumPayload :: { [UncheckedTypeExp] }+ : %prec bottom { [] }+ | TypeExpAtom SumPayload { $1 : $2 }+ SumClause :: { (Name, [UncheckedTypeExp], Loc) }- : SumClause TypeExpAtom- { let (n, ts, loc) = $1 in (n, ts ++ [$2], locOf (srcspan loc $>))}- | Constr- { (fst $1, [], snd $1) }+ : Constr SumPayload+ { (fst $1, $2, locOf (srcspan (snd $1) $>)) } TypeExpApply :: { UncheckedTypeExp } : TypeExpApply TypeArg@@ -502,15 +505,22 @@ | '(' TypeExp ',' TupleTypes ')' { TETuple ($2:$4) (srcspan $1 $>) } | '{' '}' { TERecord [] (srcspan $1 $>) } | '{' FieldTypes1 '}' { TERecord $2 (srcspan $1 $>) }+ | '[' SizeExp ']' TypeExpTerm+ { TEArray $2 $4 (srcspan $1 $>) }+ | '...[' SizeExp ']' TypeExpTerm+ { TEArray $2 $4 (srcspan $1 $>) } | QualName { TEVar (fst $1) (srclocOf (snd $1)) } Constr :: { (Name, Loc) } : constructor { let L _ (CONSTRUCTOR c) = $1 in (c, locOf $1) } TypeArg :: { TypeArgExp Name }- : '[' SizeExp ']' { TypeArgExpDim $2 (srcspan $1 $>) }- | '...[' SizeExp ']' { TypeArgExpDim $2 (srcspan $1 $>) }- | TypeExpAtom { TypeArgExpType $1 }+ : '[' SizeExp ']' %prec top+ { TypeArgExpDim $2 (srcspan $1 $>) }+ | '...[' SizeExp ']' %prec top+ { TypeArgExpDim $2 (srcspan $1 $>) }+ | TypeExpAtom+ { TypeArgExpType $1 } FieldType :: { (Name, UncheckedTypeExp) } FieldType : FieldId ':' TypeExp { (fst $1, $3) }@@ -740,7 +750,9 @@ | Exp2 '>=...' Exp2 { binOp $1 $2 $3 } | Exp2 '|>...' Exp2 { binOp $1 $2 $3 } | Exp2 '<|...' Exp2 { binOp $1 $2 $3 }- | Exp2 '<' Exp2 { binOp $1 (L $2 (SYMBOL Less [] (nameFromString "<"))) $3 }+ | Exp2 '<' Exp2 { binOp $1 (L $2 (SYMBOL Less [] (nameFromString "<"))) $3 }+ | Exp2 '!...' Exp2 { binOp $1 $2 $3 }+ | Exp2 '=...' Exp2 { binOp $1 $2 $3 } | Exp2 '`' QualName '`' Exp2 { AppExp (BinOp (second srclocOf $3) NoInfo ($1, NoInfo) ($5, NoInfo) (srcspan $1 $>)) NoInfo } SectionExp :: { UncheckedExp }
src/Language/Futhark/Pretty.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | Futhark prettyprinter. This module defines 'Pretty' instances@@ -157,7 +156,7 @@ prettyTypeArg _ (TypeArgDim d _) = pretty $ Shape [d] prettyTypeArg p (TypeArgType t _) = prettyType p t -instance Pretty (Shape dim) => Pretty (TypeArg dim) where+instance Pretty (TypeArg Size) where pretty = prettyTypeArg 0 instance (Eq vn, IsName vn) => Pretty (TypeExp vn) where@@ -367,7 +366,8 @@ p name = "." <> pretty name prettyExp _ (IndexSection idxs _ _) = parens $ "." <> brackets (commasep (map pretty idxs))-prettyExp _ (Constr n cs _ _) = "#" <> pretty n <+> sep (map pretty cs)+prettyExp _ (Constr n cs t _) =+ "#" <> pretty n <+> sep (map pretty cs) <> prettyInst t prettyExp _ (Attr attr e _) = prettyAttr attr </> prettyExp (-1) e prettyExp i (AppExp e _) = prettyAppExp i e@@ -564,6 +564,8 @@ precedence Xor = 1 precedence Equal = 2 precedence NotEqual = 2+ precedence Bang = 2+ precedence Equ = 2 precedence Less = 2 precedence Leq = 2 precedence Greater = 2
src/Language/Futhark/Primitive.hs view
@@ -135,6 +135,7 @@ import Futhark.Util (convFloat) import Futhark.Util.CMath import Futhark.Util.Pretty+import Numeric (log1p) import Numeric.Half import Prelude hiding (id, (.)) @@ -1193,6 +1194,10 @@ f16 "log10_16" (logBase 10), f32 "log10_32" (logBase 10), f64 "log10_64" (logBase 10),+ --+ f16 "log1p_16" log1p,+ f32 "log1p_32" log1p,+ f64 "log1p_64" log1p, -- f16 "log2_16" (logBase 2), f32 "log2_32" (logBase 2),
src/Language/Futhark/Prop.hs view
@@ -192,8 +192,10 @@ uniqueness :: TypeBase shape as -> Uniqueness uniqueness (Array _ u _ _) = u uniqueness (Scalar (TypeVar _ u _ _)) = u-uniqueness (Scalar (Sum ts)) = foldMap (foldMap uniqueness) $ M.elems ts-uniqueness (Scalar (Record fs)) = foldMap uniqueness $ M.elems fs+uniqueness (Scalar (Sum ts))+ | any (any unique) ts = Unique+uniqueness (Scalar (Record fs))+ | any unique fs = Unique uniqueness _ = Nonunique -- | @unique t@ is 'True' if the type of the argument is unique.
src/Language/Futhark/Semantic.hs view
@@ -80,8 +80,12 @@ data FileModule = FileModule { -- | Abstract types. fileAbs :: TySet,+ -- | The environment made available when importing this module. fileEnv :: Env,- fileProg :: Prog+ fileProg :: Prog,+ -- | The environment at the bottom of the file. Includes local+ -- parts.+ fileScope :: Env } -- | A mapping from import names to imports. The ordering is significant.
src/Language/Futhark/Syntax.hs view
@@ -497,8 +497,13 @@ = -- | A pseudo-operator standing in for any normal -- identifier used as an operator (they all have the -- same fixity).- -- Binary Ops for Numbers Backtick+ | -- | Not a real operator, but operator with this as a prefix may+ -- be defined by the user.+ Bang+ | -- | Not a real operator, but operator with this as a prefix+ -- may be defined by the user.+ Equ | Plus | Minus | Pow@@ -1236,6 +1241,8 @@ instance Pretty BinOp where pretty Backtick = "``"+ pretty Bang = "!"+ pretty Equ = "=" pretty Plus = "+" pretty Minus = "-" pretty Pow = "**"
src/Language/Futhark/Traversals.hs view
@@ -219,8 +219,8 @@ <$> mapM (astMap tv) idxs <*> traverse (mapOnPatType tv) t <*> pure loc- astMap tv (Constr name es ts loc) =- Constr name <$> traverse (mapOnExp tv) es <*> traverse (mapOnPatType tv) ts <*> pure loc+ astMap tv (Constr name es t loc) =+ Constr name <$> traverse (mapOnExp tv) es <*> traverse (mapOnPatType tv) t <*> pure loc astMap tv (Attr attr e loc) = Attr attr <$> mapOnExp tv e <*> pure loc astMap tv (AppExp e res) =
src/Language/Futhark/TypeChecker.hs view
@@ -143,8 +143,8 @@ checkProgM :: UncheckedProg -> TypeM FileModule checkProgM (Prog doc decs) = do checkForDuplicateDecs decs- (abs, env, decs') <- checkDecs decs- pure (FileModule abs env $ Prog doc decs')+ (abs, env, decs', full_env) <- checkDecs decs+ pure (FileModule abs env (Prog doc decs') full_env) dupDefinitionError :: MonadTypeChecker m =>@@ -378,7 +378,7 @@ pure (abs, mty, ModParens e' loc) checkOneModExp (ModDecs decs loc) = do checkForDuplicateDecs decs- (abstypes, env, decs') <- checkDecs decs+ (abstypes, env, decs', _) <- checkDecs decs pure ( abstypes, MTy abstypes $ ModEnv env,@@ -626,6 +626,51 @@ onRetType te t = ([], EntryType t te) +checkEntryPoint ::+ SrcLoc ->+ [TypeParam] ->+ [Pat] ->+ Maybe (TypeExp VName) ->+ StructRetType ->+ TypeM ()+checkEntryPoint loc tparams params maybe_tdecl rettype+ | any isTypeParam tparams =+ typeError loc mempty $+ withIndexLink+ "polymorphic-entry"+ "Entry point functions may not be polymorphic."+ | not (all patternOrderZero params)+ || not (all orderZero rettype_params)+ || not (orderZero rettype') =+ typeError loc mempty $+ withIndexLink+ "higher-order-entry"+ "Entry point functions may not be higher-order."+ | sizes_only_in_ret <-+ S.fromList (map typeParamName tparams)+ `S.intersection` freeInType rettype'+ `S.difference` foldMap freeInType (map patternStructType params ++ rettype_params),+ not $ S.null sizes_only_in_ret =+ typeError loc mempty $+ withIndexLink+ "size-polymorphic-entry"+ "Entry point functions must not be size-polymorphic in their return type."+ | p : _ <- filter nastyParameter params =+ warn loc $+ "Entry point parameter\n"+ </> indent 2 (pretty p)+ </> "\nwill have an opaque type, so the entry point will likely not be callable."+ | nastyReturnType maybe_tdecl rettype_t =+ warn loc $+ "Entry point return type\n"+ </> indent 2 (pretty rettype)+ </> "\nwill have an opaque type, so the result will likely not be usable."+ | otherwise =+ pure ()+ where+ (RetType _ rettype_t) = rettype+ (rettype_params, rettype') = unfoldFunType rettype_t+ checkValBind :: ValBindBase NoInfo Name -> TypeM (Env, ValBind) checkValBind (ValBind entry fname maybe_tdecl NoInfo tparams params body doc attrs loc) = do top_level <- atTopLevel@@ -633,45 +678,13 @@ typeError loc mempty $ withIndexLink "nested-entry" "Entry points may not be declared inside modules." - (fname', tparams', params', maybe_tdecl', rettype@(RetType _ rettype_t), body') <-+ (fname', tparams', params', maybe_tdecl', rettype, body') <- checkFunDef (fname, maybe_tdecl, tparams, params, body, loc) - let (rettype_params, rettype') = unfoldFunType rettype_t- entry' = Info (entryPoint params' maybe_tdecl' rettype) <$ entry+ let entry' = Info (entryPoint params' maybe_tdecl' rettype) <$ entry case entry' of- Just _- | any isTypeParam tparams' ->- typeError loc mempty $- withIndexLink- "polymorphic-entry"- "Entry point functions may not be polymorphic."- | not (all patternOrderZero params')- || not (all orderZero rettype_params)- || not (orderZero rettype') ->- typeError loc mempty $- withIndexLink- "higher-order-entry"- "Entry point functions may not be higher-order."- | sizes_only_in_ret <-- S.fromList (map typeParamName tparams')- `S.intersection` freeInType rettype'- `S.difference` foldMap freeInType (map patternStructType params' ++ rettype_params),- not $ S.null sizes_only_in_ret ->- typeError loc mempty $- withIndexLink- "size-polymorphic-entry"- "Entry point functions must not be size-polymorphic in their return type."- | p : _ <- filter nastyParameter params' ->- warn loc $- "Entry point parameter\n"- </> indent 2 (pretty p)- </> "\nwill have an opaque type, so the entry point will likely not be callable."- | nastyReturnType maybe_tdecl' rettype_t ->- warn loc $- "Entry point return type\n"- </> indent 2 (pretty rettype)- </> "\nwill have an opaque type, so the result will likely not be usable."+ Just _ -> checkEntryPoint loc tparams' params' maybe_tdecl' rettype _ -> pure () attrs' <- mapM checkAttr attrs@@ -749,17 +762,19 @@ (env, vb') <- checkValBind vb pure (mempty, env, ValDec vb') -checkDecs :: [DecBase NoInfo Name] -> TypeM (TySet, Env, [DecBase Info VName])+checkDecs :: [DecBase NoInfo Name] -> TypeM (TySet, Env, [DecBase Info VName], Env) checkDecs (d : ds) = do (d_abstypes, d_env, d') <- checkOneDec d- (ds_abstypes, ds_env, ds') <- localEnv d_env $ checkDecs ds+ (ds_abstypes, ds_env, ds', full_env) <- localEnv d_env $ checkDecs ds pure ( d_abstypes <> ds_abstypes, case d' of LocalDec {} -> ds_env ImportDec {} -> ds_env _ -> ds_env <> d_env,- d' : ds'+ d' : ds',+ full_env )-checkDecs [] =- pure (mempty, mempty, [])+checkDecs [] = do+ full_env <- askEnv+ pure (mempty, mempty, [], full_env)
src/Language/Futhark/TypeChecker/Terms.hs view
@@ -1438,6 +1438,8 @@ uniques = uniqueParamNames params delve (Scalar (Record fs)) = Scalar $ Record $ M.map delve fs+ delve (Scalar (Sum cs)) =+ Scalar $ Sum $ M.map (map delve) cs delve t' | all (`S.member` uniques) (boundArrayAliases t'), not $ any ((`S.member` forbidden) . aliasVar) (aliases t') =
src/Language/Futhark/TypeChecker/Terms/Monad.hs view
@@ -172,8 +172,9 @@ allOccurring :: Occurrences -> Names allOccurring occs = allConsumed occs <> allObserved occs +-- | Find any consumption that references a variable in scope. anyConsumption :: Occurrences -> Maybe Occurrence-anyConsumption = find (isJust . consumed)+anyConsumption = find (maybe False (not . null) . consumed) seqOccurrences :: Occurrences -> Occurrences -> Occurrences seqOccurrences occurs1 occurs2 =@@ -304,7 +305,7 @@ "Cannot apply" <+> dquotes (pretty fname) <+> "to"- <+> dquotes (shorten $ group $ pretty e) <> " (invalid type)."+ <+> dquotes (align $ shorten $ group $ pretty e) <> " (invalid type)." pretty (CheckingReturn expected actual) = "Function body does not have expected type." </> "Expected:"
src/Language/Futhark/TypeChecker/Terms/Pat.hs view
@@ -283,7 +283,7 @@ t <- newTypeVar loc "t" pure $ Id name' (Info t) loc checkPat' _ (Wildcard _ loc) (Ascribed t) =- pure $ Wildcard (Info $ t `setUniqueness` Nonunique) loc+ pure $ Wildcard (Info t) loc checkPat' _ (Wildcard NoInfo loc) NoneInferred = do t <- newTypeVar loc "t" pure $ Wildcard (Info t) loc@@ -364,7 +364,9 @@ pure $ PatConstr n (Info (Scalar (Sum cs))) ps' loc checkPat' sizes (PatConstr n NoInfo ps loc) (Ascribed t) = do t' <- newTypeVar loc "t"- ps' <- mapM (\p -> checkPat' sizes p NoneInferred) ps+ ps' <- forM ps $ \p -> do+ p_t <- newTypeVar (srclocOf p) "t"+ checkPat' sizes p $ Ascribed $ addAliasesFromType p_t t mustHaveConstr usage n t' (patternStructType <$> ps') unify usage t' (toStruct t) t'' <- normTypeFully t
src/Language/Futhark/TypeChecker/Unify.hs view
@@ -484,36 +484,44 @@ link (not ord) v2 lvl t1' ( Scalar (Arrow _ p1 a1 (RetType b1_dims b1)), Scalar (Arrow _ p2 a2 (RetType b2_dims b2))- ) -> do- -- Introduce the existentials as size variables so they- -- are subject to unification. We will remove them again- -- afterwards.- let (r1, r2) =- swap- ord- (Size Nothing $ Usage Nothing mempty)- (UnknowableSize mempty RigidUnify)- lvl <- curLevel- modifyConstraints (M.fromList (zip b1_dims $ repeat (lvl, r1)) <>)- modifyConstraints (M.fromList (zip b2_dims $ repeat (lvl, r2)) <>)+ )+ | uncurry (<) $ swap ord (uniqueness a1) (uniqueness a2) -> do+ unifyError usage mempty bcs . withIndexLink "unify-consuming-param" $+ "Parameter types"+ </> indent 2 (pretty a1)+ </> "and"+ </> indent 2 (pretty a2)+ </> "are incompatible regarding consuming their arguments."+ | otherwise -> do+ -- Introduce the existentials as size variables so they+ -- are subject to unification. We will remove them again+ -- afterwards.+ let (r1, r2) =+ swap+ ord+ (Size Nothing $ Usage Nothing mempty)+ (UnknowableSize mempty RigidUnify)+ lvl <- curLevel+ modifyConstraints (M.fromList (zip b1_dims $ repeat (lvl, r1)) <>)+ modifyConstraints (M.fromList (zip b2_dims $ repeat (lvl, r2)) <>) - let bound' = bound <> mapMaybe pname [p1, p2] <> b1_dims <> b2_dims- subunify- (not ord)- bound- (breadCrumb (Matching "When matching parameter types.") bcs)- a1- a2- subunify- ord- bound'- (breadCrumb (Matching "When matching return types.") bcs)- b1'- b2'+ let bound' = bound <> mapMaybe pname [p1, p2] <> b1_dims <> b2_dims+ subunify+ (not ord)+ bound+ (breadCrumb (Matching "When matching parameter types.") bcs)+ a1+ a2+ subunify+ ord+ bound'+ (breadCrumb (Matching "When matching return types.") bcs)+ b1'+ b2' - -- Delete the size variables we introduced to represent- -- the existential sizes.- modifyConstraints $ \m -> foldl' (flip M.delete) m (b1_dims <> b2_dims)+ -- Delete the size variables we introduced to represent+ -- the existential sizes.+ modifyConstraints $ \m -> foldl' (flip M.delete) m (b1_dims <> b2_dims) where (b1', b2') = -- Replace one parameter name with the other in the
unittests/Futhark/BenchTests.hs view
@@ -17,7 +17,7 @@ instance Arbitrary DataResult where arbitrary = DataResult- <$> printable+ <$> (T.pack <$> printable) <*> oneof [ Left <$> arbText, Right