futhark 0.25.2 → 0.25.3
raw patch · 251 files changed
+10911/−9253 lines, 251 filesdep ~bytestringPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: bytestring
API changes (from Hackage documentation)
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: copyDevToDev :: Name
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: copyDevToHost :: Name
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: copyHostToDev :: Name
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: copyScalarFromDev :: Name
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: copyScalarToDev :: Name
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: costCentreReport :: [Name] -> [BlockItem]
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: failureMsgFunction :: [FailureMsg] -> Definition
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: generateBoilerplate :: Text -> Text -> [Name] -> Map KernelName KernelSafety -> [FailureMsg] -> CompilerM OpenCL () ()
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: kernelRuns :: KernelName -> Name
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: kernelRuntime :: KernelName -> Name
- Futhark.CodeGen.Backends.CCUDA.Boilerplate: profilingEnclosure :: Name -> ([BlockItem], [BlockItem])
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: commonOptions :: [Option]
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: copyDevToDev :: Name
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: copyDevToHost :: Name
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: copyHostToDev :: Name
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: copyScalarFromDev :: Name
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: copyScalarToDev :: Name
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: costCentreReport :: [Name] -> [BlockItem]
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: failureMsgFunction :: [FailureMsg] -> Definition
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: generateBoilerplate :: Text -> Text -> [Name] -> Map KernelName KernelSafety -> [PrimType] -> [FailureMsg] -> CompilerM OpenCL () ()
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: kernelRuns :: KernelName -> Name
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: kernelRuntime :: KernelName -> Name
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: profilingEvent :: Name -> Exp
- Futhark.CodeGen.Backends.COpenCL.Boilerplate: sizeLoggingCode :: VName -> Name -> Exp -> CompilerM op () ()
- Futhark.CodeGen.ImpCode: Copy :: PrimType -> VName -> Count Bytes (TExp Int64) -> Space -> VName -> Count Bytes (TExp Int64) -> Space -> Count Bytes (TExp Int64) -> Code a
- Futhark.CodeGen.ImpCode.OpenCL: SharedMemoryKArg :: Count Bytes Exp -> KernelArg
- Futhark.CodeGen.ImpGen: [memLocIxFun] :: MemLoc -> IxFun (TExp Int64)
- Futhark.CodeGen.ImpGen: copyElementWise :: CopyCompiler rep r op
- Futhark.CodeGen.ImpGen: isMapTransposeCopy :: PrimType -> MemLoc -> MemLoc -> Maybe (TExp Bool, (TExp Int64, TExp Int64, TExp Int64, TExp Int64, TExp Int64))
- Futhark.CodeGen.ImpGen: sCopy :: VName -> Count Bytes (TExp Int64) -> Space -> VName -> Count Bytes (TExp Int64) -> Space -> Count Elements (TExp Int64) -> PrimType -> ImpM rep r op ()
- Futhark.CodeGen.ImpGen.GPU.Base: sCopy :: VName -> Count Bytes (TExp Int64) -> Space -> VName -> Count Bytes (TExp Int64) -> Space -> Count Elements (TExp Int64) -> PrimType -> ImpM rep r op ()
- Futhark.CodeGen.ImpGen.GPU.Copy: copyKernel :: PrimType -> (TExp Int64, GroupDim) -> (VName, LMAD (TExp Int64)) -> (VName, LMAD (TExp Int64)) -> Kernel
- Futhark.CodeGen.ImpGen.GPU.Transpose: TransposeLowHeight :: TransposeType
- Futhark.CodeGen.ImpGen.GPU.Transpose: TransposeLowWidth :: TransposeType
- Futhark.CodeGen.ImpGen.GPU.Transpose: TransposeNormal :: TransposeType
- Futhark.CodeGen.ImpGen.GPU.Transpose: TransposeSmall :: TransposeType
- Futhark.CodeGen.ImpGen.GPU.Transpose: data TransposeType
- Futhark.CodeGen.ImpGen.GPU.Transpose: instance GHC.Classes.Eq Futhark.CodeGen.ImpGen.GPU.Transpose.TransposeType
- Futhark.CodeGen.ImpGen.GPU.Transpose: instance GHC.Classes.Ord Futhark.CodeGen.ImpGen.GPU.Transpose.TransposeType
- Futhark.CodeGen.ImpGen.GPU.Transpose: instance GHC.Show.Show Futhark.CodeGen.ImpGen.GPU.Transpose.TransposeType
- Futhark.CodeGen.ImpGen.GPU.Transpose: mapTransposeKernel :: forall int. IntExp int => (PrimType, VName -> TExp int) -> String -> Integer -> TransposeArgs int -> PrimType -> TransposeType -> Kernel
- Futhark.CodeGen.ImpGen.GPU.Transpose: type TransposeArgs int = (VName, TExp int, VName, TExp int, TExp int, TExp int, TExp int, TExp int, TExp int, VName)
- Futhark.CodeGen.ImpGen.Transpose: mapTransposeFunction :: Name -> PrimType -> Function op
- Futhark.CodeGen.ImpGen.Transpose: transposeArgs :: PrimType -> VName -> Count Bytes (TExp Int64) -> VName -> Count Bytes (TExp Int64) -> TExp Int64 -> TExp Int64 -> TExp Int64 -> [Arg]
- Futhark.IR.Mem.IxFun: [ldPerm] :: LMADDim num -> Int
- Futhark.IR.Mem.IxFun: dynamicEqualsLMAD :: Eq num => LMAD (TPrimExp t num) -> LMAD (TPrimExp t num) -> TPrimExp Bool num
- Futhark.IR.Mem.IxFun: equivalent :: Eq num => IxFun num -> IxFun num -> Bool
- Futhark.IR.Mem.IxFun: iotaOffset :: IntegralExp num => num -> Shape num -> IxFun num
- Futhark.IR.Mem.IxFun: permutation :: IxFun num -> Permutation
- Futhark.IR.Mem.IxFun: permuteInv :: Permutation -> [a] -> [a]
- Futhark.IR.Mem.IxFun: rebase :: (Eq num, IntegralExp num) => IxFun num -> IxFun num -> Maybe (IxFun num)
- Futhark.IR.Mem.LMAD: [ldPerm] :: LMADDim num -> Int
- Futhark.IR.Mem.LMAD: contiguous :: (Pretty num, Eq num) => LMAD (TPrimExp Int64 num) -> TPrimExp Bool num
- Futhark.IR.Mem.LMAD: memcpyable :: (Pretty num, Eq num) => LMAD (TPrimExp Int64 num) -> LMAD (TPrimExp Int64 num) -> TPrimExp Bool num
- Futhark.IR.Mem.LMAD: noPermutation :: LMAD t -> LMAD t
- Futhark.IR.Mem.LMAD: permutation :: LMAD num -> Permutation
- Futhark.IR.Mem.LMAD: permuteFwd :: Permutation -> [a] -> [a]
- Futhark.IR.Mem.LMAD: permuteInv :: Permutation -> [a] -> [a]
- Futhark.IR.Mem.LMAD: setPermutation :: Permutation -> LMAD num -> LMAD num
- Futhark.IR.Mem.LMAD: setShape :: Shape num -> LMAD num -> LMAD num
- Futhark.IR.Mem.LMAD: shapeBase :: LMAD num -> Shape num
- Futhark.IR.Syntax: DoLoop :: [(FParam rep, SubExp)] -> LoopForm rep -> Body rep -> Exp rep
- Futhark.Optimise.Simplify: [simplifyPatFromExpS] :: SimpleOps rep -> Pat (LetDec rep) -> Exp (Wise rep) -> SimpleM rep (Pat (LetDec rep))
- Futhark.Optimise.Simplify.Engine: [simplifyPatFromExpS] :: SimpleOps rep -> Pat (LetDec rep) -> Exp (Wise rep) -> SimpleM rep (Pat (LetDec 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 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.Rule: RuleDoLoop :: RuleDoLoop rep a -> SimplificationRule rep a
- Futhark.Optimise.Simplify.Rule: type BottomUpRuleDoLoop rep = RuleDoLoop rep (BottomUp rep)
- Futhark.Optimise.Simplify.Rule: type RuleDoLoop rep a = a -> Pat (LetDec rep) -> StmAux (ExpDec rep) -> ([(FParam rep, SubExp)], LoopForm rep, Body rep) -> Rule rep
- Futhark.Optimise.Simplify.Rule: type TopDownRuleDoLoop rep = RuleDoLoop rep (TopDown rep)
- Language.Futhark.Syntax: DoLoop :: [VName] -> PatBase f vn ParamType -> ExpBase f vn -> LoopFormBase f vn -> ExpBase f vn -> SrcLoc -> AppExpBase f vn
- Language.Futhark.Traversals: instance Language.Futhark.Traversals.ASTMappable (Language.Futhark.Syntax.QualName Language.Futhark.Core.VName)
- Language.Futhark.Traversals: instance Language.Futhark.Traversals.ASTMappable (Language.Futhark.Syntax.SizeBinder Language.Futhark.Core.VName)
- Language.Futhark.Traversals: instance Language.Futhark.Traversals.ASTMappable (Language.Futhark.Syntax.TypeParamBase Language.Futhark.Core.VName)
- Language.Futhark.TypeChecker.Terms.DoLoop: checkDoLoop :: (UncheckedExp -> TermTypeM Exp) -> UncheckedLoop -> SrcLoc -> TermTypeM (CheckedLoop, AppRes)
- Language.Futhark.TypeChecker.Terms.DoLoop: type CheckedLoop = ([VName], Pat ParamType, Exp, LoopFormBase Info VName, Exp)
- Language.Futhark.TypeChecker.Terms.DoLoop: type UncheckedLoop = (UncheckedPat ParamType, UncheckedExp, LoopFormBase NoInfo Name, UncheckedExp)
+ Futhark.Actions: compileHIPAction :: FutharkConfig -> CompilerMode -> FilePath -> Action GPUMem
+ Futhark.CLI.HIP: main :: String -> [String] -> IO ()
+ Futhark.CodeGen.Backends.GPU: generateGPUBoilerplate :: Text -> Text -> [Name] -> [PrimType] -> [FailureMsg] -> CompilerM OpenCL () ()
+ Futhark.CodeGen.Backends.GPU: gpuOperations :: Operations OpenCL ()
+ Futhark.CodeGen.Backends.GPU: gpuOptions :: [Option]
+ Futhark.CodeGen.Backends.GenericC.Code: compileLMADCopy :: PrimType -> [Count Elements (TExp Int64)] -> (VName, Space) -> (Count Elements (TExp Int64), [Count Elements (TExp Int64)]) -> (VName, Space) -> (Count Elements (TExp Int64), [Count Elements (TExp Int64)]) -> CompilerM op s ()
+ Futhark.CodeGen.Backends.GenericC.Code: compileLMADCopyWith :: [Count Elements (TExp Int64)] -> (Exp -> Exp -> CompilerM op s ()) -> (Count Elements (TExp Int64), [Count Elements (TExp Int64)]) -> (Exp -> CompilerM op s Exp) -> (Count Elements (TExp Int64), [Count Elements (TExp Int64)]) -> CompilerM op s ()
+ Futhark.CodeGen.Backends.GenericC.Monad: [opsCopies] :: Operations op s -> Map (Space, Space) (DoLMADCopy op s)
+ Futhark.CodeGen.Backends.GenericC.Monad: type DoLMADCopy op s = CopyBarrier -> PrimType -> [Count Elements Exp] -> Exp -> (Count Elements Exp, [Count Elements Exp]) -> Exp -> (Count Elements Exp, [Count Elements Exp]) -> CompilerM op s ()
+ Futhark.CodeGen.Backends.GenericPython: [opsCopies] :: Operations op s -> Map (Space, Space) (DoLMADCopy op s)
+ Futhark.CodeGen.Backends.GenericPython: type DoLMADCopy op s = PrimType -> [Count Elements PyExp] -> PyExp -> (Count Elements PyExp, [Count Elements PyExp]) -> PyExp -> (Count Elements PyExp, [Count Elements PyExp]) -> CompilerM op s ()
+ Futhark.CodeGen.Backends.HIP: CParts :: Text -> Text -> Text -> Text -> Text -> Text -> CParts
+ Futhark.CodeGen.Backends.HIP: [cCLI] :: CParts -> Text
+ Futhark.CodeGen.Backends.HIP: [cHeader] :: CParts -> Text
+ Futhark.CodeGen.Backends.HIP: [cJsonManifest] :: CParts -> Text
+ Futhark.CodeGen.Backends.HIP: [cLib] :: CParts -> Text
+ Futhark.CodeGen.Backends.HIP: [cServer] :: CParts -> Text
+ Futhark.CodeGen.Backends.HIP: [cUtils] :: CParts -> Text
+ Futhark.CodeGen.Backends.HIP: asExecutable :: CParts -> Text
+ Futhark.CodeGen.Backends.HIP: asLibrary :: CParts -> (Text, Text, Text)
+ Futhark.CodeGen.Backends.HIP: asServer :: CParts -> Text
+ Futhark.CodeGen.Backends.HIP: compileProg :: MonadFreshNames m => Text -> Prog GPUMem -> m (Warnings, CParts)
+ Futhark.CodeGen.Backends.HIP: data CParts
+ Futhark.CodeGen.ImpCode: LMADCopy :: PrimType -> [Count Elements (TExp Int64)] -> (VName, Space) -> (Count Elements (TExp Int64), [Count Elements (TExp Int64)]) -> (VName, Space) -> (Count Elements (TExp Int64), [Count Elements (TExp Int64)]) -> Code a
+ Futhark.CodeGen.ImpCode: declsFirst :: Code a -> Code a
+ Futhark.CodeGen.ImpCode.OpenCL: TargetHIP :: KernelTarget
+ Futhark.CodeGen.ImpGen: [memLocLMAD] :: MemLoc -> LMAD (TExp Int64)
+ Futhark.CodeGen.ImpGen: lmadCopy :: CopyCompiler rep r op
+ Futhark.CodeGen.ImpGen.GPU: compileProgHIP :: MonadFreshNames m => Prog GPUMem -> m (Warnings, Program)
+ Futhark.CodeGen.ImpGen.GPU.Base: HIP :: Target
+ Futhark.CodeGen.ImpGen.GPU.ToOpenCL: kernelsToHIP :: Program -> Program
+ Futhark.CodeGen.ImpGen.HIP: compileProg :: MonadFreshNames m => Prog GPUMem -> m (Warnings, Program)
+ Futhark.CodeGen.ImpGen.HIP: data Warnings
+ Futhark.CodeGen.RTS.C: backendsHipH :: Text
+ Futhark.CodeGen.RTS.C: copyH :: Text
+ Futhark.CodeGen.RTS.C: gpuH :: Text
+ Futhark.CodeGen.RTS.C: gpuPrototypesH :: Text
+ Futhark.CodeGen.RTS.CUDA: preludeCU :: Text
+ Futhark.CodeGen.RTS.OpenCL: copyCL :: Text
+ Futhark.CodeGen.RTS.OpenCL: preludeCL :: Text
+ Futhark.CodeGen.RTS.OpenCL: transposeCL :: Text
+ Futhark.IR.Mem: type LMAD = LMAD (TPrimExp Int64 VName)
+ Futhark.IR.Mem.IxFun: expand :: (Eq num, IntegralExp num) => num -> num -> IxFun num -> Maybe (IxFun num)
+ Futhark.IR.Mem.LMAD: equivalent :: Eq num => LMAD num -> LMAD num -> Bool
+ Futhark.IR.Mem.LMAD: isDirect :: (Eq num, IntegralExp num) => LMAD num -> Bool
+ Futhark.IR.Mem.LMAD: rank :: LMAD num -> Int
+ Futhark.IR.Mem.Simplify: memRuleBook :: SimplifyMemory rep inner => RuleBook (Wise rep)
+ Futhark.IR.Syntax: Loop :: [(FParam rep, SubExp)] -> LoopForm rep -> Body rep -> Exp 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). 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.Rule: RuleLoop :: RuleLoop rep a -> SimplificationRule rep a
+ Futhark.Optimise.Simplify.Rule: type BottomUpRuleLoop rep = RuleLoop rep (BottomUp rep)
+ Futhark.Optimise.Simplify.Rule: type RuleLoop rep a = a -> Pat (LetDec rep) -> StmAux (ExpDec rep) -> ([(FParam rep, SubExp)], LoopForm rep, Body rep) -> Rule rep
+ Futhark.Optimise.Simplify.Rule: type TopDownRuleLoop rep = RuleLoop rep (TopDown rep)
+ Language.Futhark.Interpreter: instance GHC.Show.Show Language.Futhark.Interpreter.Env
+ Language.Futhark.Interpreter: instance GHC.Show.Show Language.Futhark.Interpreter.Module
+ Language.Futhark.Interpreter: instance GHC.Show.Show Language.Futhark.Interpreter.TermBinding
+ Language.Futhark.Syntax: Loop :: [VName] -> PatBase f vn ParamType -> ExpBase f vn -> LoopFormBase f vn -> ExpBase f vn -> SrcLoc -> AppExpBase f vn
+ Language.Futhark.TypeChecker.Terms.Loop: checkLoop :: (UncheckedExp -> TermTypeM Exp) -> UncheckedLoop -> SrcLoc -> TermTypeM (CheckedLoop, AppRes)
+ Language.Futhark.TypeChecker.Terms.Loop: type CheckedLoop = ([VName], Pat ParamType, Exp, LoopFormBase Info VName, Exp)
+ Language.Futhark.TypeChecker.Terms.Loop: type UncheckedLoop = (UncheckedPat ParamType, UncheckedExp, LoopFormBase NoInfo Name, UncheckedExp)
- Futhark.Analysis.PrimExp: class NumExp t => FloatExp t
+ Futhark.Analysis.PrimExp: class (NumExp t) => FloatExp t
- Futhark.Analysis.PrimExp: class NumExp t => IntExp t
+ Futhark.Analysis.PrimExp: class (NumExp t) => IntExp t
- Futhark.Builder: class ASTRep rep => BuilderOps rep
+ Futhark.Builder: class (ASTRep rep) => BuilderOps rep
- 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: 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 -> Map (Space, Space) (DoLMADCopy op s) -> Bool -> ([BlockItem], [BlockItem]) -> 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: Operations :: WriteScalar op s -> ReadScalar op s -> Allocate op s -> Copy op s -> Map (Space, Space) (DoLMADCopy op s) -> OpCompiler op s -> EntryOutput op s -> EntryInput op s -> Operations op s
- Futhark.CodeGen.ImpCode.OpenCL: LaunchKernel :: KernelSafety -> KernelName -> [KernelArg] -> [Exp] -> [GroupDim] -> OpenCL
+ Futhark.CodeGen.ImpCode.OpenCL: LaunchKernel :: KernelSafety -> KernelName -> Count Bytes (TExp Int64) -> [KernelArg] -> [Exp] -> [GroupDim] -> OpenCL
- Futhark.CodeGen.ImpGen: MemLoc :: VName -> [DimSize] -> IxFun (TExp Int64) -> MemLoc
+ Futhark.CodeGen.ImpGen: MemLoc :: VName -> [DimSize] -> LMAD (TExp Int64) -> MemLoc
- Futhark.CodeGen.ImpGen: dArray :: VName -> PrimType -> ShapeBase SubExp -> VName -> IxFun -> ImpM rep r op ()
+ Futhark.CodeGen.ImpGen: dArray :: VName -> PrimType -> ShapeBase SubExp -> VName -> LMAD -> ImpM rep r op ()
- Futhark.CodeGen.ImpGen: sArray :: String -> PrimType -> ShapeBase SubExp -> VName -> IxFun -> ImpM rep r op VName
+ Futhark.CodeGen.ImpGen: sArray :: String -> PrimType -> ShapeBase SubExp -> VName -> LMAD -> ImpM rep r op VName
- Futhark.IR.Mem: class IsOp op => OpReturns op
+ Futhark.IR.Mem: class (IsOp op) => OpReturns op
- Futhark.IR.Mem.IxFun: LMADDim :: num -> num -> Int -> LMADDim num
+ Futhark.IR.Mem.IxFun: LMADDim :: num -> num -> LMADDim num
- Futhark.IR.Mem.IxFun: flatSlice :: (Eq num, IntegralExp num) => IxFun num -> FlatSlice num -> Maybe (IxFun num)
+ Futhark.IR.Mem.IxFun: flatSlice :: (Eq num, IntegralExp num) => IxFun num -> FlatSlice num -> IxFun num
- Futhark.IR.Mem.IxFun: mkExistential :: Int -> [Int] -> Int -> IxFun (Ext a)
+ Futhark.IR.Mem.IxFun: mkExistential :: Int -> Int -> Int -> IxFun (Ext a)
- Futhark.IR.Mem.LMAD: LMADDim :: num -> num -> Int -> LMADDim num
+ Futhark.IR.Mem.LMAD: LMADDim :: num -> num -> LMADDim num
- Futhark.IR.Mem.LMAD: flatSlice :: IntegralExp num => LMAD num -> FlatSlice num -> Maybe (LMAD num)
+ Futhark.IR.Mem.LMAD: flatSlice :: IntegralExp num => LMAD num -> FlatSlice num -> LMAD num
- Futhark.IR.Mem.LMAD: mkExistential :: [Int] -> Int -> LMAD (Ext a)
+ Futhark.IR.Mem.LMAD: mkExistential :: Int -> Int -> LMAD (Ext a)
- Futhark.IR.Mem.Simplify: simplifyProgGeneric :: SimplifyMemory rep inner => SimpleOps rep -> Prog rep -> PassM (Prog rep)
+ Futhark.IR.Mem.Simplify: simplifyProgGeneric :: SimplifyMemory rep inner => RuleBook (Wise rep) -> SimpleOps rep -> Prog rep -> PassM (Prog rep)
- Futhark.IR.Mem.Simplify: simplifyStmsGeneric :: (HasScope rep m, MonadFreshNames m, SimplifyMemory rep inner) => SimpleOps rep -> Stms rep -> m (Stms rep)
+ Futhark.IR.Mem.Simplify: simplifyStmsGeneric :: (HasScope rep m, MonadFreshNames m, SimplifyMemory rep inner) => RuleBook (Wise rep) -> SimpleOps rep -> Stms rep -> m (Stms rep)
- Futhark.IR.Prop.Aliases: class IsOp op => AliasedOp op
+ Futhark.IR.Prop.Aliases: class (IsOp op) => AliasedOp op
- Futhark.IR.Prop.Names: class FreeIn dec => FreeDec dec
+ Futhark.IR.Prop.Names: class (FreeIn dec) => FreeDec dec
- Futhark.IR.Prop.Types: class FixExt t => DeclExtTyped t
+ Futhark.IR.Prop.Types: class (FixExt t) => DeclExtTyped t
- Futhark.IR.Prop.Types: class FixExt t => ExtTyped t
+ Futhark.IR.Prop.Types: class (FixExt t) => ExtTyped t
- Futhark.IR.Prop.Types: class Typed a => SetType a
+ Futhark.IR.Prop.Types: class (Typed a) => SetType a
- Futhark.MonadFreshNames: class Monad m => MonadFreshNames m
+ Futhark.MonadFreshNames: class (Monad m) => MonadFreshNames m
- Futhark.Optimise.Simplify: SimpleOps :: (SymbolTable (Wise rep) -> Pat (LetDec (Wise rep)) -> Exp (Wise rep) -> SimpleM rep (ExpDec (Wise rep))) -> (SymbolTable (Wise rep) -> Stms (Wise rep) -> Result -> SimpleM rep (Body (Wise rep))) -> Protect (Builder (Wise rep)) -> (Op (Wise rep) -> UsageTable) -> (Pat (LetDec rep) -> Exp (Wise rep) -> SimpleM rep (Pat (LetDec rep))) -> SimplifyOp rep (Op (Wise rep)) -> SimpleOps rep
+ Futhark.Optimise.Simplify: SimpleOps :: (SymbolTable (Wise rep) -> Pat (LetDec (Wise rep)) -> Exp (Wise rep) -> SimpleM rep (ExpDec (Wise rep))) -> (SymbolTable (Wise rep) -> Stms (Wise rep) -> Result -> SimpleM rep (Body (Wise rep))) -> Protect (Builder (Wise rep)) -> (Op (Wise rep) -> UsageTable) -> SimplifyOp rep (Op (Wise rep)) -> SimpleOps rep
- Futhark.Optimise.Simplify.Engine: SimpleOps :: (SymbolTable (Wise rep) -> Pat (LetDec (Wise rep)) -> Exp (Wise rep) -> SimpleM rep (ExpDec (Wise rep))) -> (SymbolTable (Wise rep) -> Stms (Wise rep) -> Result -> SimpleM rep (Body (Wise rep))) -> Protect (Builder (Wise rep)) -> (Op (Wise rep) -> UsageTable) -> (Pat (LetDec rep) -> Exp (Wise rep) -> SimpleM rep (Pat (LetDec rep))) -> SimplifyOp rep (Op (Wise rep)) -> SimpleOps rep
+ Futhark.Optimise.Simplify.Engine: SimpleOps :: (SymbolTable (Wise rep) -> Pat (LetDec (Wise rep)) -> Exp (Wise rep) -> SimpleM rep (ExpDec (Wise rep))) -> (SymbolTable (Wise rep) -> Stms (Wise rep) -> Result -> SimpleM rep (Body (Wise rep))) -> Protect (Builder (Wise rep)) -> (Op (Wise rep) -> UsageTable) -> SimplifyOp rep (Op (Wise rep)) -> SimpleOps rep
- Futhark.Util.IntegralExp: class Num e => IntegralExp e
+ Futhark.Util.IntegralExp: class (Num e) => IntegralExp e
- Language.Futhark.Traversals: ASTMapper :: (ExpBase Info VName -> m (ExpBase Info VName)) -> (VName -> m VName) -> (StructType -> m StructType) -> (ParamType -> m ParamType) -> (ResRetType -> m ResRetType) -> ASTMapper m
+ Language.Futhark.Traversals: ASTMapper :: (ExpBase Info VName -> m (ExpBase Info VName)) -> (QualName VName -> m (QualName VName)) -> (StructType -> m StructType) -> (ParamType -> m ParamType) -> (ResRetType -> m ResRetType) -> ASTMapper m
- Language.Futhark.Traversals: [mapOnName] :: ASTMapper m -> VName -> m VName
+ Language.Futhark.Traversals: [mapOnName] :: ASTMapper m -> QualName VName -> m (QualName VName)
- Language.Futhark.TypeChecker.Monad: class Monad m => MonadTypeChecker m
+ Language.Futhark.TypeChecker.Monad: class (Monad m) => MonadTypeChecker m
- Language.Futhark.TypeChecker.Unify: class Monad m => MonadUnify m
+ Language.Futhark.TypeChecker.Unify: class (Monad m) => MonadUnify m
Files
- docs/c-api.rst +15/−14
- docs/index.rst +4/−3
- docs/man/futhark-hip.rst +128/−0
- docs/usage.rst +1/−1
- futhark.cabal +17/−8
- prelude/array.fut +2/−2
- rts/c/atomics.h +184/−148
- rts/c/backends/cuda.h +241/−144
- rts/c/backends/hip.h +911/−0
- rts/c/backends/opencl.h +301/−199
- rts/c/context_prototypes.h +21/−0
- rts/c/copy.h +262/−0
- rts/c/gpu.h +591/−0
- rts/c/gpu_prototypes.h +12/−0
- rts/c/half.h +3/−3
- rts/c/ispc_util.h +0/−54
- rts/c/scalar.h +2974/−2974
- rts/c/scalar_f16.h +194/−194
- rts/c/util.h +90/−0
- rts/cuda/prelude.cu +102/−0
- rts/opencl/copy.cl +83/−0
- rts/opencl/prelude.cl +54/−0
- rts/opencl/transpose.cl +273/−0
- rts/python/memory.py +132/−0
- rts/python/opencl.py +173/−1
- src/Futhark/AD/Fwd.hs +11/−11
- src/Futhark/AD/Rev.hs +2/−2
- src/Futhark/AD/Rev/Hist.hs +2/−2
- src/Futhark/AD/Rev/Loop.hs +17/−17
- src/Futhark/AD/Rev/Map.hs +1/−1
- src/Futhark/AD/Rev/Monad.hs +2/−2
- src/Futhark/AD/Rev/Reduce.hs +1/−1
- src/Futhark/Actions.hs +36/−3
- src/Futhark/Analysis/Alias.hs +7/−7
- src/Futhark/Analysis/CallGraph.hs +2/−2
- src/Futhark/Analysis/DataDependencies.hs +2/−2
- src/Futhark/Analysis/HORep/MapNest.hs +1/−1
- src/Futhark/Analysis/HORep/SOAC.hs +5/−5
- src/Futhark/Analysis/Interference.hs +26/−26
- src/Futhark/Analysis/LastUse.hs +15/−15
- src/Futhark/Analysis/MemAlias.hs +1/−1
- src/Futhark/Analysis/Metrics.hs +11/−11
- src/Futhark/Analysis/PrimExp.hs +21/−21
- src/Futhark/Analysis/PrimExp/Convert.hs +6/−6
- src/Futhark/Analysis/PrimExp/Simplify.hs +3/−3
- src/Futhark/Analysis/SymbolTable.hs +14/−14
- src/Futhark/Analysis/UsageTable.hs +5/−5
- src/Futhark/Bench.hs +1/−1
- src/Futhark/Builder.hs +9/−9
- src/Futhark/Builder/Class.hs +11/−11
- src/Futhark/CLI/Dataset.hs +1/−1
- src/Futhark/CLI/Dev.hs +1/−1
- src/Futhark/CLI/Eval.hs +1/−1
- src/Futhark/CLI/HIP.hs +17/−0
- src/Futhark/CLI/Main.hs +2/−0
- src/Futhark/CLI/REPL.hs +1/−1
- src/Futhark/CLI/Run.hs +1/−1
- src/Futhark/CLI/Test.hs +3/−3
- src/Futhark/CodeGen/Backends/CCUDA.hs +74/−335
- src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs +0/−132
- src/Futhark/CodeGen/Backends/COpenCL.hs +131/−329
- src/Futhark/CodeGen/Backends/COpenCL/Boilerplate.hs +0/−320
- src/Futhark/CodeGen/Backends/GPU.hs +440/−0
- src/Futhark/CodeGen/Backends/GenericC.hs +50/−14
- src/Futhark/CodeGen/Backends/GenericC/Code.hs +126/−57
- src/Futhark/CodeGen/Backends/GenericC/Fun.hs +8/−4
- src/Futhark/CodeGen/Backends/GenericC/Monad.hs +23/−4
- src/Futhark/CodeGen/Backends/GenericC/Types.hs +12/−6
- src/Futhark/CodeGen/Backends/GenericPython.hs +149/−57
- src/Futhark/CodeGen/Backends/GenericPython/AST.hs +19/−9
- src/Futhark/CodeGen/Backends/HIP.hs +130/−0
- src/Futhark/CodeGen/Backends/MulticoreC.hs +7/−7
- src/Futhark/CodeGen/Backends/MulticoreISPC.hs +27/−40
- src/Futhark/CodeGen/Backends/MulticoreWASM.hs +1/−1
- src/Futhark/CodeGen/Backends/PyOpenCL.hs +103/−87
- src/Futhark/CodeGen/Backends/SequentialC.hs +1/−1
- src/Futhark/CodeGen/Backends/SequentialPython.hs +1/−1
- src/Futhark/CodeGen/Backends/SequentialWASM.hs +1/−1
- src/Futhark/CodeGen/ImpCode.hs +52/−34
- src/Futhark/CodeGen/ImpCode/OpenCL.hs +2/−3
- src/Futhark/CodeGen/ImpGen.hs +68/−211
- src/Futhark/CodeGen/ImpGen/CUDA.hs +1/−1
- src/Futhark/CodeGen/ImpGen/GPU.hs +8/−335
- src/Futhark/CodeGen/ImpGen/GPU/Base.hs +42/−29
- src/Futhark/CodeGen/ImpGen/GPU/Copy.hs +0/−81
- src/Futhark/CodeGen/ImpGen/GPU/Group.hs +57/−44
- src/Futhark/CodeGen/ImpGen/GPU/SegHist.hs +2/−2
- src/Futhark/CodeGen/ImpGen/GPU/SegRed.hs +6/−8
- src/Futhark/CodeGen/ImpGen/GPU/SegScan.hs +34/−4
- src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs +30/−23
- src/Futhark/CodeGen/ImpGen/GPU/SegScan/TwoPass.hs +2/−4
- src/Futhark/CodeGen/ImpGen/GPU/ToOpenCL.hs +82/−207
- src/Futhark/CodeGen/ImpGen/GPU/Transpose.hs +0/−425
- src/Futhark/CodeGen/ImpGen/HIP.hs +17/−0
- src/Futhark/CodeGen/ImpGen/Multicore.hs +1/−1
- src/Futhark/CodeGen/ImpGen/Multicore/Base.hs +1/−1
- src/Futhark/CodeGen/ImpGen/Multicore/SegRed.hs +1/−1
- src/Futhark/CodeGen/ImpGen/OpenCL.hs +1/−1
- src/Futhark/CodeGen/ImpGen/Sequential.hs +1/−1
- src/Futhark/CodeGen/ImpGen/Transpose.hs +0/−219
- src/Futhark/CodeGen/RTS/C.hs +24/−0
- src/Futhark/CodeGen/RTS/CUDA.hs +12/−0
- src/Futhark/CodeGen/RTS/OpenCL.hs +27/−0
- src/Futhark/Compiler.hs +4/−4
- src/Futhark/Compiler/Program.hs +3/−3
- src/Futhark/Construct.hs +32/−32
- src/Futhark/Error.hs +3/−3
- src/Futhark/IR/Aliases.hs +14/−14
- src/Futhark/IR/GPU/Op.hs +9/−9
- src/Futhark/IR/GPU/Simplify.hs +2/−2
- src/Futhark/IR/GPUMem.hs +2/−2
- src/Futhark/IR/MC/Op.hs +6/−6
- src/Futhark/IR/MCMem.hs +1/−1
- src/Futhark/IR/Mem.hs +36/−32
- src/Futhark/IR/Mem/Interval.hs +1/−1
- src/Futhark/IR/Mem/IxFun.hs +35/−136
- src/Futhark/IR/Mem/LMAD.hs +83/−219
- src/Futhark/IR/Mem/Simplify.hs +15/−10
- src/Futhark/IR/Parse.hs +4/−5
- src/Futhark/IR/Pretty.hs +33/−27
- src/Futhark/IR/Prop.hs +5/−5
- src/Futhark/IR/Prop/Aliases.hs +8/−8
- src/Futhark/IR/Prop/Constants.hs +1/−1
- src/Futhark/IR/Prop/Names.hs +23/−23
- src/Futhark/IR/Prop/Patterns.hs +7/−7
- src/Futhark/IR/Prop/Rearrange.hs +2/−2
- src/Futhark/IR/Prop/Reshape.hs +5/−5
- src/Futhark/IR/Prop/Scope.hs +9/−9
- src/Futhark/IR/Prop/TypeOf.hs +6/−6
- src/Futhark/IR/Prop/Types.hs +25/−25
- src/Futhark/IR/Rephrase.hs +11/−11
- src/Futhark/IR/RetType.hs +2/−2
- src/Futhark/IR/SOACS.hs +1/−1
- src/Futhark/IR/SOACS/SOAC.hs +88/−58
- src/Futhark/IR/SOACS/Simplify.hs +5/−5
- src/Futhark/IR/SegOp.hs +61/−54
- src/Futhark/IR/SeqMem.hs +1/−1
- src/Futhark/IR/Syntax.hs +20/−20
- src/Futhark/IR/Syntax/Core.hs +3/−3
- src/Futhark/IR/Traversals.hs +16/−16
- src/Futhark/IR/TypeCheck.hs +65/−66
- src/Futhark/Internalise/Bindings.hs +3/−3
- src/Futhark/Internalise/Defunctionalise.hs +10/−10
- src/Futhark/Internalise/Defunctorise.hs +6/−9
- src/Futhark/Internalise/Exps.hs +5/−5
- src/Futhark/Internalise/FullNormalise.hs +6/−6
- src/Futhark/Internalise/LiftLambdas.hs +12/−3
- src/Futhark/Internalise/Monad.hs +1/−1
- src/Futhark/Internalise/Monomorphise.hs +7/−7
- src/Futhark/Internalise/ReplaceRecords.hs +1/−1
- src/Futhark/Internalise/TypesValues.hs +1/−1
- src/Futhark/MonadFreshNames.hs +14/−14
- src/Futhark/Optimise/ArrayShortCircuiting.hs +2/−2
- src/Futhark/Optimise/ArrayShortCircuiting/ArrayCoalescing.hs +39/−41
- src/Futhark/Optimise/ArrayShortCircuiting/MemRefAggreg.hs +10/−11
- src/Futhark/Optimise/ArrayShortCircuiting/TopdownAnalysis.hs +7/−8
- src/Futhark/Optimise/BlkRegTiling.hs +3/−5
- src/Futhark/Optimise/CSE.hs +4/−4
- src/Futhark/Optimise/DoubleBuffer.hs +18/−18
- src/Futhark/Optimise/EntryPointMem.hs +4/−4
- src/Futhark/Optimise/Fusion.hs +3/−3
- src/Futhark/Optimise/Fusion/Composing.hs +4/−4
- src/Futhark/Optimise/Fusion/GraphRep.hs +16/−16
- src/Futhark/Optimise/Fusion/TryFusion.hs +1/−1
- src/Futhark/Optimise/GenRedOpt.hs +1/−1
- src/Futhark/Optimise/HistAccs.hs +2/−2
- src/Futhark/Optimise/InPlaceLowering.hs +10/−10
- src/Futhark/Optimise/InPlaceLowering/LowerIntoStm.hs +5/−5
- src/Futhark/Optimise/InPlaceLowering/SubstituteIndices.hs +3/−3
- src/Futhark/Optimise/InliningDeadFun.hs +8/−8
- src/Futhark/Optimise/MemoryBlockMerging.hs +8/−8
- src/Futhark/Optimise/MemoryBlockMerging/GreedyColoring.hs +2/−2
- src/Futhark/Optimise/MergeGPUBodies.hs +5/−5
- src/Futhark/Optimise/ReduceDeviceSyncs.hs +3/−3
- src/Futhark/Optimise/ReduceDeviceSyncs/MigrationTable.hs +14/−14
- src/Futhark/Optimise/ReduceDeviceSyncs/MigrationTable/Graph.hs +2/−2
- src/Futhark/Optimise/Simplify.hs +1/−1
- src/Futhark/Optimise/Simplify/Engine.hs +58/−64
- src/Futhark/Optimise/Simplify/Rep.hs +20/−20
- src/Futhark/Optimise/Simplify/Rule.hs +14/−14
- src/Futhark/Optimise/Simplify/Rules.hs +7/−7
- src/Futhark/Optimise/Simplify/Rules/BasicOp.hs +18/−11
- src/Futhark/Optimise/Simplify/Rules/ClosedForm.hs +1/−1
- src/Futhark/Optimise/Simplify/Rules/Index.hs +1/−1
- src/Futhark/Optimise/Simplify/Rules/Loop.hs +15/−17
- src/Futhark/Optimise/Simplify/Rules/Match.hs +4/−4
- src/Futhark/Optimise/Sink.hs +12/−12
- src/Futhark/Optimise/TileLoops.hs +9/−9
- src/Futhark/Optimise/TileLoops/Shared.hs +3/−3
- src/Futhark/Optimise/Unstream.hs +7/−7
- src/Futhark/Pass.hs +1/−1
- src/Futhark/Pass/ExpandAllocations.hs +64/−66
- src/Futhark/Pass/ExplicitAllocations.hs +26/−51
- src/Futhark/Pass/ExplicitAllocations/GPU.hs +19/−13
- src/Futhark/Pass/ExplicitAllocations/SegOp.hs +7/−8
- src/Futhark/Pass/ExtractKernels.hs +8/−8
- src/Futhark/Pass/ExtractKernels/BlockedKernel.hs +2/−2
- src/Futhark/Pass/ExtractKernels/DistributeNests.hs +13/−13
- src/Futhark/Pass/ExtractKernels/Distribution.hs +7/−7
- src/Futhark/Pass/ExtractKernels/ISRWIM.hs +1/−1
- src/Futhark/Pass/ExtractKernels/Interchange.hs +1/−1
- src/Futhark/Pass/ExtractKernels/Intragroup.hs +22/−8
- src/Futhark/Pass/ExtractKernels/StreamKernel.hs +1/−1
- src/Futhark/Pass/ExtractMulticore.hs +4/−4
- src/Futhark/Pass/FirstOrderTransform.hs +1/−1
- src/Futhark/Pass/KernelBabysitting.hs +4/−4
- src/Futhark/Pass/LiftAllocations.hs +2/−2
- src/Futhark/Pass/LowerAllocations.hs +2/−2
- src/Futhark/Pipeline.hs +3/−3
- src/Futhark/Pkg/Info.hs +5/−5
- src/Futhark/Pkg/Solve.hs +1/−1
- src/Futhark/Script.hs +2/−2
- src/Futhark/Test.hs +8/−8
- src/Futhark/Test/Values.hs +1/−1
- src/Futhark/Transform/CopyPropagate.hs +1/−1
- src/Futhark/Transform/FirstOrderTransform.hs +9/−9
- src/Futhark/Transform/Rename.hs +19/−19
- src/Futhark/Transform/Substitute.hs +22/−22
- src/Futhark/Util.hs +5/−5
- src/Futhark/Util/IntegralExp.hs +4/−4
- src/Futhark/Util/Log.hs +4/−4
- src/Futhark/Util/Options.hs +1/−1
- src/Futhark/Util/Pretty.hs +6/−6
- src/Language/Futhark/Core.hs +2/−2
- src/Language/Futhark/FreeVars.hs +1/−1
- src/Language/Futhark/Interpreter.hs +76/−28
- src/Language/Futhark/Interpreter/Values.hs +3/−3
- src/Language/Futhark/Parser/Lexer/Tokens.hs +8/−8
- src/Language/Futhark/Parser/Monad.hs +2/−2
- src/Language/Futhark/Parser/Parser.y +2/−2
- src/Language/Futhark/Pretty.hs +42/−27
- src/Language/Futhark/Primitive.hs +6/−6
- src/Language/Futhark/Prop.hs +3/−3
- src/Language/Futhark/Query.hs +3/−3
- src/Language/Futhark/Syntax.hs +22/−22
- src/Language/Futhark/Traversals.hs +33/−46
- src/Language/Futhark/TypeChecker.hs +11/−7
- src/Language/Futhark/TypeChecker/Consumption.hs +38/−18
- src/Language/Futhark/TypeChecker/Modules.hs +5/−4
- src/Language/Futhark/TypeChecker/Monad.hs +16/−13
- src/Language/Futhark/TypeChecker/Terms.hs +45/−26
- src/Language/Futhark/TypeChecker/Terms/DoLoop.hs +0/−288
- src/Language/Futhark/TypeChecker/Terms/Loop.hs +288/−0
- src/Language/Futhark/TypeChecker/Terms/Monad.hs +8/−5
- src/Language/Futhark/TypeChecker/Terms/Pat.hs +3/−1
- src/Language/Futhark/TypeChecker/Types.hs +14/−14
- src/Language/Futhark/TypeChecker/Unify.hs +46/−39
- unittests/Futhark/IR/Mem/IxFun/Alg.hs +11/−30
- unittests/Futhark/IR/Mem/IxFunTests.hs +100/−146
- unittests/Futhark/IR/Mem/IxFunWrapper.hs +8/−7
- unittests/Language/Futhark/SyntaxTests.hs +1/−1
docs/c-api.rst view
@@ -60,6 +60,7 @@ :c:func:`futhark_context_new`. A configuration object must not be freed before any context objects for which it is used. The same configuration may *not* be used for multiple concurrent contexts.+Configuration objects are cheap to create and destroy. .. c:struct:: futhark_context_config @@ -274,8 +275,9 @@ .. c:function:: int futhark_values_i32_1d(struct futhark_context *ctx, struct futhark_i32_1d *arr, int32_t *data) Asynchronously copy data from the value into ``data``, which must- be of sufficient size. Multi-dimensional arrays are written in- row-major form.+ point to free memory, allocated by the caller, with sufficient+ space to store the full array. Multi-dimensional arrays are+ written in row-major form. .. c:function:: const int64_t *futhark_shape_i32_1d(struct futhark_context *ctx, struct futhark_i32_1d *arr) @@ -439,8 +441,8 @@ GPU --- -The following API functions are available when using the ``opencl`` or-``cuda`` backends.+The following API functions are available when using the ``opencl``,+``cuda``, or ``hip`` backends. .. c:function:: void futhark_context_config_set_device(struct futhark_context_config *cfg, const char *s) @@ -469,15 +471,15 @@ Set the default tile size used when executing kernels that have been block tiled. -.. c:function:: void futhark_context_config_dump_program_to(struct futhark_context_config *cfg, const char *path)+.. c:function:: const char* futhark_context_config_get_program(struct futhark_context_config *cfg) - During :c:func:`futhark_context_new`, dump the OpenCL or CUDA- program source to the given file.+ Retrieve the embedded GPU program. The context configuration keeps+ ownership, so don't free the string. -.. c:function:: void futhark_context_config_load_program_from(struct futhark_context_config *cfg, const char *path)+.. c:function:: void futhark_context_config_set_program(struct futhark_context_config *cfg, const char *program) - During :c:func:`futhark_context_new`, read OpenCL or CUDA program- source from the given file instead of using the embedded program.+ Instead of using the embedded GPU program, use the provided string,+ which is copied by this function. OpenCL ------@@ -520,10 +522,9 @@ Add a build option to the OpenCL kernel compiler. See the OpenCL specification for `clBuildProgram` for available options. -.. c:function:: void futhark_context_config_dump_binary_to(struct futhark_context_config *cfg, const char *path)+.. c:function:: cl_program futhark_context_get_program(struct futhark_context_config *cfg) - During :c:func:`futhark_context_new`, dump the compiled OpenCL- binary to the given file.+ Retrieve the compiled OpenCL program. .. c:function:: void futhark_context_config_load_binary_from(struct futhark_context_config *cfg, const char *path) @@ -547,7 +548,7 @@ Add a build option to the NVRTC compiler. See the CUDA documentation for ``nvrtcCompileProgram`` for available options. -.. c:function:: void futhark_context_config_dump_ptx_to(struct futhark_context_config *cfg, const char *path)+.. c:function:: void futhark_context_dump_ptx_to(struct futhark_context_config *cfg, const char *path) During :c:func:`futhark_context_new`, dump the generated PTX code to the given file.
docs/index.rst view
@@ -45,16 +45,16 @@ :caption: Manual Pages :maxdepth: 1 - man/futhark.rst man/futhark-autotune.rst man/futhark-bench.rst man/futhark-c.rst man/futhark-cuda.rst man/futhark-dataset.rst man/futhark-doc.rst+ man/futhark-hip.rst+ man/futhark-ispc.rst man/futhark-literate.rst man/futhark-multicore.rst- man/futhark-ispc.rst man/futhark-opencl.rst man/futhark-pkg.rst man/futhark-pyopencl.rst@@ -62,5 +62,6 @@ man/futhark-repl.rst man/futhark-run.rst man/futhark-test.rst- man/futhark-wasm.rst man/futhark-wasm-multicore.rst+ man/futhark-wasm.rst+ man/futhark.rst
+ docs/man/futhark-hip.rst view
@@ -0,0 +1,128 @@+.. role:: ref(emphasis)++.. _futhark-hip(1):++==============+futhark-hip+==============++SYNOPSIS+========++futhark hip [options...] <program.fut>++DESCRIPTION+===========+++``futhark hip`` translates a Futhark program to C code invoking HIP+kernels, and either compiles that C code with a C compiler to an+executable binary program, or produces a ``.h`` and ``.c`` file that+can be linked with other code. The standard Futhark optimisation+pipeline is used.++``futhark hip`` uses ``-lhiprtc -lamdhip64`` to link. If using+``--library``, you will need to do the same when linking the final+binary. Although the HIP backend can be made to work on NVIDIA GPUs,+you are probably better off using the very similar+:ref:`futhark-cuda(1)`.++OPTIONS+=======++Accepts the same options as :ref:`futhark-c(1)`.++ENVIRONMENT VARIABLES+=====================++``CC``++ The C compiler used to compile the program. Defaults to ``cc`` if+ unset.++``CFLAGS``++ Space-separated list of options passed to the C compiler. Defaults+ to ``-O -std=c99`` if unset.++EXECUTABLE OPTIONS+==================++Generated executables accept the same options as those generated by+:ref:`futhark-c(1)`. For commonality, the options use OpenCL+nomenclature ("group" instead of "thread block").++The following additional options are accepted.++-h, --help++ Print help text to standard output and exit.++--default-group-size=INT++ The default size of thread blocks that are launched. Capped to the+ hardware limit if necessary.++--default-num-groups=INT++ The default number of thread blocks that are launched.++--default-threshold=INT++ The default parallelism threshold used for comparisons when+ selecting between code versions generated by incremental flattening.+ Intuitively, the amount of parallelism needed to saturate the GPU.++--default-tile-size=INT++ The default tile size used when performing two-dimensional tiling+ (the workgroup size will be the square of the tile size).++--dump-hip=FILE++ Don't run the program, but instead dump the embedded HIP kernels to+ the indicated file. Useful if you want to see what is actually+ being executed.++--load-hip=FILE++ Instead of using the embedded HIP kernels, load them from the+ indicated file.++-n, --no-print-result++ Do not print the program result.++--build-option=OPT++ Add an additional build option to the string passed to the kernel+ compiler (HIPRTC). Refer to the HIP documentation for which options+ are supported. Be careful - some options can easily result in+ invalid results.++--param=ASSIGNMENT++ Set a tuning parameter to the given+ value. ``ASSIGNMENT`` must be of the form ``NAME=INT`` Use+ ``--print-params`` to see which names are available.++--print-params++ Print all tuning parameters that can be set with ``--param`` or+ ``--tuning``.++--tuning=FILE++ Read size=value assignments from the given file.++ENVIRONMENT+===========++If run without ``--library``, ``futhark hip`` will invoke a C+compiler to compile the generated C program into a binary. This only+works if the C compiler can find the necessary HIP libraries.++SEE ALSO+========++:ref:`futhark(1)`
docs/usage.rst view
@@ -158,7 +158,7 @@ ~~~~~~~~~~~ The following options are supported by executables generated with the-GPU backends (``opencl``, ``pyopencl``, and ``cuda``).+GPU backends (``opencl``, ``pyopencl``, ``hip``, and ``cuda``). ``-d/--device DEVICE``
futhark.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: futhark-version: 0.25.2+version: 0.25.3 synopsis: An optimising compiler for a functional, array-oriented language. description: Futhark is a small programming language designed to be compiled to@@ -41,12 +41,16 @@ rts/c/context_prototypes.h rts/c/backends/c.h rts/c/backends/cuda.h+ rts/c/backends/hip.h rts/c/backends/multicore.h rts/c/backends/opencl.h rts/c/lock.h+ rts/c/copy.h rts/c/timing.h rts/c/errors.h rts/c/free_list.h+ rts/c/gpu.h+ rts/c/gpu_prototypes.h rts/c/tuning.h rts/c/values.h rts/c/half.h@@ -58,10 +62,14 @@ rts/c/uniform.h rts/c/util.h rts/c/server.h+ rts/cuda/prelude.cu rts/futhark-doc/style.css rts/javascript/server.js rts/javascript/values.js rts/javascript/wrapperclasses.js+ rts/opencl/copy.cl+ rts/opencl/prelude.cl+ rts/opencl/transpose.cl rts/python/tuning.py rts/python/panic.py rts/python/memory.py@@ -191,6 +199,7 @@ Futhark.CLI.Dev Futhark.CLI.Doc Futhark.CLI.Eval+ Futhark.CLI.HIP Futhark.CLI.Literate Futhark.CLI.LSP Futhark.CLI.Main@@ -208,9 +217,8 @@ Futhark.CLI.Test Futhark.CLI.WASM Futhark.CodeGen.Backends.CCUDA- Futhark.CodeGen.Backends.CCUDA.Boilerplate Futhark.CodeGen.Backends.COpenCL- Futhark.CodeGen.Backends.COpenCL.Boilerplate+ Futhark.CodeGen.Backends.HIP Futhark.CodeGen.Backends.GenericC Futhark.CodeGen.Backends.GenericC.CLI Futhark.CodeGen.Backends.GenericC.Code@@ -225,6 +233,7 @@ Futhark.CodeGen.Backends.GenericPython.AST Futhark.CodeGen.Backends.GenericPython.Options Futhark.CodeGen.Backends.GenericWASM+ Futhark.CodeGen.Backends.GPU Futhark.CodeGen.Backends.MulticoreC Futhark.CodeGen.Backends.MulticoreC.Boilerplate Futhark.CodeGen.Backends.MulticoreISPC@@ -237,6 +246,8 @@ Futhark.CodeGen.Backends.SequentialWASM Futhark.CodeGen.Backends.SimpleRep Futhark.CodeGen.RTS.C+ Futhark.CodeGen.RTS.CUDA+ Futhark.CodeGen.RTS.OpenCL Futhark.CodeGen.RTS.Python Futhark.CodeGen.RTS.JavaScript Futhark.CodeGen.ImpCode@@ -248,7 +259,6 @@ Futhark.CodeGen.ImpGen.CUDA Futhark.CodeGen.ImpGen.GPU Futhark.CodeGen.ImpGen.GPU.Base- Futhark.CodeGen.ImpGen.GPU.Copy Futhark.CodeGen.ImpGen.GPU.Group Futhark.CodeGen.ImpGen.GPU.SegHist Futhark.CodeGen.ImpGen.GPU.SegMap@@ -257,7 +267,7 @@ Futhark.CodeGen.ImpGen.GPU.SegScan.SinglePass Futhark.CodeGen.ImpGen.GPU.SegScan.TwoPass Futhark.CodeGen.ImpGen.GPU.ToOpenCL- Futhark.CodeGen.ImpGen.GPU.Transpose+ Futhark.CodeGen.ImpGen.HIP Futhark.CodeGen.ImpGen.Multicore Futhark.CodeGen.ImpGen.Multicore.Base Futhark.CodeGen.ImpGen.Multicore.SegHist@@ -266,7 +276,6 @@ Futhark.CodeGen.ImpGen.Multicore.SegScan Futhark.CodeGen.ImpGen.OpenCL Futhark.CodeGen.ImpGen.Sequential- Futhark.CodeGen.ImpGen.Transpose Futhark.CodeGen.OpenCL.Heuristics Futhark.Compiler Futhark.Compiler.CLI@@ -449,7 +458,7 @@ Language.Futhark.TypeChecker.Modules Language.Futhark.TypeChecker.Monad Language.Futhark.TypeChecker.Terms- Language.Futhark.TypeChecker.Terms.DoLoop+ Language.Futhark.TypeChecker.Terms.Loop Language.Futhark.TypeChecker.Terms.Monad Language.Futhark.TypeChecker.Terms.Pat Language.Futhark.TypeChecker.Types@@ -472,7 +481,7 @@ , base16-bytestring , binary >=0.8.3 , blaze-html >=0.9.0.1- , bytestring >=0.10.8+ , bytestring >=0.11.2 , bytestring-to-vector >=0.3.0.1 , bmp >=1.2.6.3 , co-log-core
prelude/array.fut view
@@ -197,7 +197,7 @@ -- | Create a value for each point in a two-dimensional index space. ----- **Work:** *O(n ✕ W(f))*+-- **Work:** *O(n ✕ m ✕ W(f))* -- -- **Span:** *O(S(f))* def tabulate_2d 'a (n: i64) (m: i64) (f: i64 -> i64 -> a): *[n][m]a =@@ -205,7 +205,7 @@ -- | Create a value for each point in a three-dimensional index space. ----- **Work:** *O(n ✕ W(f))*+-- **Work:** *O(n ✕ m ✕ o ✕ W(f))* -- -- **Span:** *O(S(f))* def tabulate_3d 'a (n: i64) (m: i64) (o: i64) (f: i64 -> i64 -> i64 -> a): *[n][m][o]a =
rts/c/atomics.h view
@@ -1,82 +1,82 @@ // Start of atomics.h -inline int32_t atomic_xchg_i32_global(volatile __global int32_t *p, int32_t x);-inline int32_t atomic_xchg_i32_local(volatile __local int32_t *p, int32_t x);-inline int32_t atomic_cmpxchg_i32_global(volatile __global int32_t *p,- int32_t cmp, int32_t val);-inline int32_t atomic_cmpxchg_i32_local(volatile __local int32_t *p,- int32_t cmp, int32_t val);-inline int32_t atomic_add_i32_global(volatile __global int32_t *p, int32_t x);-inline int32_t atomic_add_i32_local(volatile __local int32_t *p, int32_t x);-inline float atomic_fadd_f32_global(volatile __global float *p, float x);-inline float atomic_fadd_f32_local(volatile __local float *p, float x);-inline int32_t atomic_smax_i32_global(volatile __global int32_t *p, int32_t x);-inline int32_t atomic_smax_i32_local(volatile __local int32_t *p, int32_t x);-inline int32_t atomic_smin_i32_global(volatile __global int32_t *p, int32_t x);-inline int32_t atomic_smin_i32_local(volatile __local int32_t *p, int32_t x);-inline uint32_t atomic_umax_i32_global(volatile __global uint32_t *p, uint32_t x);-inline uint32_t atomic_umax_i32_local(volatile __local uint32_t *p, uint32_t x);-inline uint32_t atomic_umin_i32_global(volatile __global uint32_t *p, uint32_t x);-inline uint32_t atomic_umin_i32_local(volatile __local uint32_t *p, uint32_t x);-inline int32_t atomic_and_i32_global(volatile __global int32_t *p, int32_t x);-inline int32_t atomic_and_i32_local(volatile __local int32_t *p, int32_t x);-inline int32_t atomic_or_i32_global(volatile __global int32_t *p, int32_t x);-inline int32_t atomic_or_i32_local(volatile __local int32_t *p, int32_t x);-inline int32_t atomic_xor_i32_global(volatile __global int32_t *p, int32_t x);-inline int32_t atomic_xor_i32_local(volatile __local int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_xchg_i32_global(volatile __global int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_xchg_i32_local(volatile __local int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_cmpxchg_i32_global(volatile __global int32_t *p,+ int32_t cmp, int32_t val);+SCALAR_FUN_ATTR int32_t atomic_cmpxchg_i32_local(volatile __local int32_t *p,+ int32_t cmp, int32_t val);+SCALAR_FUN_ATTR int32_t atomic_add_i32_global(volatile __global int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_add_i32_local(volatile __local int32_t *p, int32_t x);+SCALAR_FUN_ATTR float atomic_fadd_f32_global(volatile __global float *p, float x);+SCALAR_FUN_ATTR float atomic_fadd_f32_local(volatile __local float *p, float x);+SCALAR_FUN_ATTR int32_t atomic_smax_i32_global(volatile __global int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_smax_i32_local(volatile __local int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_smin_i32_global(volatile __global int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_smin_i32_local(volatile __local int32_t *p, int32_t x);+SCALAR_FUN_ATTR uint32_t atomic_umax_i32_global(volatile __global uint32_t *p, uint32_t x);+SCALAR_FUN_ATTR uint32_t atomic_umax_i32_local(volatile __local uint32_t *p, uint32_t x);+SCALAR_FUN_ATTR uint32_t atomic_umin_i32_global(volatile __global uint32_t *p, uint32_t x);+SCALAR_FUN_ATTR uint32_t atomic_umin_i32_local(volatile __local uint32_t *p, uint32_t x);+SCALAR_FUN_ATTR int32_t atomic_and_i32_global(volatile __global int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_and_i32_local(volatile __local int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_or_i32_global(volatile __global int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_or_i32_local(volatile __local int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_xor_i32_global(volatile __global int32_t *p, int32_t x);+SCALAR_FUN_ATTR int32_t atomic_xor_i32_local(volatile __local int32_t *p, int32_t x); -inline int32_t atomic_xchg_i32_global(volatile __global int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_xchg_i32_global(volatile __global int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicExch((int32_t*)p, x); #else return atomic_xor(p, x); #endif } -inline int32_t atomic_xchg_i32_local(volatile __local int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_xchg_i32_local(volatile __local int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicExch((int32_t*)p, x); #else return atomic_xor(p, x); #endif } -inline int32_t atomic_cmpxchg_i32_global(volatile __global int32_t *p,- int32_t cmp, int32_t val) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_cmpxchg_i32_global(volatile __global int32_t *p,+ int32_t cmp, int32_t val) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicCAS((int32_t*)p, cmp, val); #else return atomic_cmpxchg(p, cmp, val); #endif } -inline int32_t atomic_cmpxchg_i32_local(volatile __local int32_t *p,- int32_t cmp, int32_t val) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_cmpxchg_i32_local(volatile __local int32_t *p,+ int32_t cmp, int32_t val) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicCAS((int32_t*)p, cmp, val); #else return atomic_cmpxchg(p, cmp, val); #endif } -inline int32_t atomic_add_i32_global(volatile __global int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_add_i32_global(volatile __global int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicAdd((int32_t*)p, x); #else return atomic_add(p, x); #endif } -inline int32_t atomic_add_i32_local(volatile __local int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_add_i32_local(volatile __local int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicAdd((int32_t*)p, x); #else return atomic_add(p, x); #endif } -inline float atomic_fadd_f32_global(volatile __global float *p, float x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR float atomic_fadd_f32_global(volatile __global float *p, float x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicAdd((float*)p, x); #else union { int32_t i; float f; } old;@@ -91,8 +91,8 @@ #endif } -inline float atomic_fadd_f32_local(volatile __local float *p, float x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR float atomic_fadd_f32_local(volatile __local float *p, float x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicAdd((float*)p, x); #else union { int32_t i; float f; } old;@@ -107,112 +107,112 @@ #endif } -inline int32_t atomic_smax_i32_global(volatile __global int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_smax_i32_global(volatile __global int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMax((int32_t*)p, x); #else return atomic_max(p, x); #endif } -inline int32_t atomic_smax_i32_local(volatile __local int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_smax_i32_local(volatile __local int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMax((int32_t*)p, x); #else return atomic_max(p, x); #endif } -inline int32_t atomic_smin_i32_global(volatile __global int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_smin_i32_global(volatile __global int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMin((int32_t*)p, x); #else return atomic_min(p, x); #endif } -inline int32_t atomic_smin_i32_local(volatile __local int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_smin_i32_local(volatile __local int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMin((int32_t*)p, x); #else return atomic_min(p, x); #endif } -inline uint32_t atomic_umax_i32_global(volatile __global uint32_t *p, uint32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR uint32_t atomic_umax_i32_global(volatile __global uint32_t *p, uint32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMax((uint32_t*)p, x); #else return atomic_max(p, x); #endif } -inline uint32_t atomic_umax_i32_local(volatile __local uint32_t *p, uint32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR uint32_t atomic_umax_i32_local(volatile __local uint32_t *p, uint32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMax((uint32_t*)p, x); #else return atomic_max(p, x); #endif } -inline uint32_t atomic_umin_i32_global(volatile __global uint32_t *p, uint32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR uint32_t atomic_umin_i32_global(volatile __global uint32_t *p, uint32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMin((uint32_t*)p, x); #else return atomic_min(p, x); #endif } -inline uint32_t atomic_umin_i32_local(volatile __local uint32_t *p, uint32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR uint32_t atomic_umin_i32_local(volatile __local uint32_t *p, uint32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMin((uint32_t*)p, x); #else return atomic_min(p, x); #endif } -inline int32_t atomic_and_i32_global(volatile __global int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_and_i32_global(volatile __global int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicAnd((int32_t*)p, x); #else return atomic_and(p, x); #endif } -inline int32_t atomic_and_i32_local(volatile __local int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_and_i32_local(volatile __local int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicAnd((int32_t*)p, x); #else return atomic_and(p, x); #endif } -inline int32_t atomic_or_i32_global(volatile __global int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_or_i32_global(volatile __global int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicOr((int32_t*)p, x); #else return atomic_or(p, x); #endif } -inline int32_t atomic_or_i32_local(volatile __local int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_or_i32_local(volatile __local int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicOr((int32_t*)p, x); #else return atomic_or(p, x); #endif } -inline int32_t atomic_xor_i32_global(volatile __global int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_xor_i32_global(volatile __global int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicXor((int32_t*)p, x); #else return atomic_xor(p, x); #endif } -inline int32_t atomic_xor_i32_local(volatile __local int32_t *p, int32_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int32_t atomic_xor_i32_local(volatile __local int32_t *p, int32_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicXor((int32_t*)p, x); #else return atomic_xor(p, x);@@ -221,80 +221,80 @@ // Start of 64 bit atomics -#if defined(FUTHARK_CUDA) || defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics)+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) || defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) -inline int64_t atomic_xchg_i64_global(volatile __global int64_t *p, int64_t x);-inline int64_t atomic_xchg_i64_local(volatile __local int64_t *p, int64_t x);-inline int64_t atomic_cmpxchg_i64_global(volatile __global int64_t *p,- int64_t cmp, int64_t val);-inline int64_t atomic_cmpxchg_i64_local(volatile __local int64_t *p,- int64_t cmp, int64_t val);-inline int64_t atomic_add_i64_global(volatile __global int64_t *p, int64_t x);-inline int64_t atomic_add_i64_local(volatile __local int64_t *p, int64_t x);-inline int64_t atomic_smax_i64_global(volatile __global int64_t *p, int64_t x);-inline int64_t atomic_smax_i64_local(volatile __local int64_t *p, int64_t x);-inline int64_t atomic_smin_i64_global(volatile __global int64_t *p, int64_t x);-inline int64_t atomic_smin_i64_local(volatile __local int64_t *p, int64_t x);-inline uint64_t atomic_umax_i64_global(volatile __global uint64_t *p, uint64_t x);-inline uint64_t atomic_umax_i64_local(volatile __local uint64_t *p, uint64_t x);-inline uint64_t atomic_umin_i64_global(volatile __global uint64_t *p, uint64_t x);-uint64_t atomic_umin_i64_local(volatile __local uint64_t *p, uint64_t x);-inline int64_t atomic_and_i64_global(volatile __global int64_t *p, int64_t x);-inline int64_t atomic_and_i64_local(volatile __local int64_t *p, int64_t x);-inline int64_t atomic_or_i64_global(volatile __global int64_t *p, int64_t x);-inline int64_t atomic_or_i64_local(volatile __local int64_t *p, int64_t x);-inline int64_t atomic_xor_i64_global(volatile __global int64_t *p, int64_t x);-inline int64_t atomic_xor_i64_local(volatile __local int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_xchg_i64_global(volatile __global int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_xchg_i64_local(volatile __local int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_cmpxchg_i64_global(volatile __global int64_t *p,+ int64_t cmp, int64_t val);+SCALAR_FUN_ATTR int64_t atomic_cmpxchg_i64_local(volatile __local int64_t *p,+ int64_t cmp, int64_t val);+SCALAR_FUN_ATTR int64_t atomic_add_i64_global(volatile __global int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_add_i64_local(volatile __local int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_smax_i64_global(volatile __global int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_smax_i64_local(volatile __local int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_smin_i64_global(volatile __global int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_smin_i64_local(volatile __local int64_t *p, int64_t x);+SCALAR_FUN_ATTR uint64_t atomic_umax_i64_global(volatile __global uint64_t *p, uint64_t x);+SCALAR_FUN_ATTR uint64_t atomic_umax_i64_local(volatile __local uint64_t *p, uint64_t x);+SCALAR_FUN_ATTR uint64_t atomic_umin_i64_global(volatile __global uint64_t *p, uint64_t x);+SCALAR_FUN_ATTR uint64_t atomic_umin_i64_local(volatile __local uint64_t *p, uint64_t x);+SCALAR_FUN_ATTR int64_t atomic_and_i64_global(volatile __global int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_and_i64_local(volatile __local int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_or_i64_global(volatile __global int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_or_i64_local(volatile __local int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_xor_i64_global(volatile __global int64_t *p, int64_t x);+SCALAR_FUN_ATTR int64_t atomic_xor_i64_local(volatile __local int64_t *p, int64_t x); #ifdef FUTHARK_F64_ENABLED-inline double atomic_fadd_f64_global(volatile __global double *p, double x);-inline double atomic_fadd_f64_local(volatile __local double *p, double x);+SCALAR_FUN_ATTR double atomic_fadd_f64_global(volatile __global double *p, double x);+SCALAR_FUN_ATTR double atomic_fadd_f64_local(volatile __local double *p, double x); #endif -inline int64_t atomic_xchg_i64_global(volatile __global int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_xchg_i64_global(volatile __global int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicExch((uint64_t*)p, x); #else return atom_xor(p, x); #endif } -inline int64_t atomic_xchg_i64_local(volatile __local int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_xchg_i64_local(volatile __local int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicExch((uint64_t*)p, x); #else return atom_xor(p, x); #endif } -inline int64_t atomic_cmpxchg_i64_global(volatile __global int64_t *p,- int64_t cmp, int64_t val) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_cmpxchg_i64_global(volatile __global int64_t *p,+ int64_t cmp, int64_t val) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicCAS((uint64_t*)p, cmp, val); #else return atom_cmpxchg(p, cmp, val); #endif } -inline int64_t atomic_cmpxchg_i64_local(volatile __local int64_t *p,- int64_t cmp, int64_t val) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_cmpxchg_i64_local(volatile __local int64_t *p,+ int64_t cmp, int64_t val) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicCAS((uint64_t*)p, cmp, val); #else return atom_cmpxchg(p, cmp, val); #endif } -inline int64_t atomic_add_i64_global(volatile __global int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_add_i64_global(volatile __global int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicAdd((uint64_t*)p, x); #else return atom_add(p, x); #endif } -inline int64_t atomic_add_i64_local(volatile __local int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_add_i64_local(volatile __local int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicAdd((uint64_t*)p, x); #else return atom_add(p, x);@@ -303,8 +303,8 @@ #ifdef FUTHARK_F64_ENABLED -inline double atomic_fadd_f64_global(volatile __global double *p, double x) {-#if defined(FUTHARK_CUDA) && __CUDA_ARCH__ >= 600+SCALAR_FUN_ATTR double atomic_fadd_f64_global(volatile __global double *p, double x) {+#if defined(FUTHARK_CUDA) && __CUDA_ARCH__ >= 600 || defined(FUTHARK_HIP) return atomicAdd((double*)p, x); #else union { int64_t i; double f; } old;@@ -319,8 +319,8 @@ #endif } -inline double atomic_fadd_f64_local(volatile __local double *p, double x) {-#if defined(FUTHARK_CUDA) && __CUDA_ARCH__ >= 600+SCALAR_FUN_ATTR double atomic_fadd_f64_local(volatile __local double *p, double x) {+#if defined(FUTHARK_CUDA) && __CUDA_ARCH__ >= 600 || defined(FUTHARK_HIP) return atomicAdd((double*)p, x); #else union { int64_t i; double f; } old;@@ -337,118 +337,154 @@ #endif -inline int64_t atomic_smax_i64_global(volatile __global int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_smax_i64_global(volatile __global int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) return atomicMax((int64_t*)p, x);+#elif defined(FUTHARK_HIP)+ // Currentely missing in HIP; probably a temporary oversight.+ int64_t old = *p, assumed;+ do {+ assumed = old;+ old = smax64(old, x);+ old = atomic_cmpxchg_i64_global((volatile __global int64_t*)p, assumed, old);+ } while (assumed != old);+ return old; #else return atom_max(p, x); #endif } -inline int64_t atomic_smax_i64_local(volatile __local int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_smax_i64_local(volatile __local int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) return atomicMax((int64_t*)p, x);+#elif defined(FUTHARK_HIP)+ // Currentely missing in HIP; probably a temporary oversight.+ int64_t old = *p, assumed;+ do {+ assumed = old;+ old = smax64(old, x);+ old = atomic_cmpxchg_i64_local((volatile __local int64_t*)p, assumed, old);+ } while (assumed != old);+ return old; #else return atom_max(p, x); #endif } -inline int64_t atomic_smin_i64_global(volatile __global int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_smin_i64_global(volatile __global int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) return atomicMin((int64_t*)p, x);+#elif defined(FUTHARK_HIP)+ // Currentely missing in HIP; probably a temporary oversight.+ int64_t old = *p, assumed;+ do {+ assumed = old;+ old = smin64(old, x);+ old = atomic_cmpxchg_i64_global((volatile __global int64_t*)p, assumed, old);+ } while (assumed != old);+ return old; #else return atom_min(p, x); #endif } -inline int64_t atomic_smin_i64_local(volatile __local int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR int64_t atomic_smin_i64_local(volatile __local int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) return atomicMin((int64_t*)p, x);+#elif defined(FUTHARK_HIP)+ // Currentely missing in HIP; probably a temporary oversight.+ int64_t old = *p, assumed;+ do {+ assumed = old;+ old = smin64(old, x);+ old = atomic_cmpxchg_i64_local((volatile __local int64_t*)p, assumed, old);+ } while (assumed != old);+ return old; #else return atom_min(p, x); #endif } -inline uint64_t atomic_umax_i64_global(volatile __global uint64_t *p, uint64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR uint64_t atomic_umax_i64_global(volatile __global uint64_t *p, uint64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMax((uint64_t*)p, x); #else return atom_max(p, x); #endif } -inline uint64_t atomic_umax_i64_local(volatile __local uint64_t *p, uint64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR uint64_t atomic_umax_i64_local(volatile __local uint64_t *p, uint64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMax((uint64_t*)p, x); #else return atom_max(p, x); #endif } -inline uint64_t atomic_umin_i64_global(volatile __global uint64_t *p, uint64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR uint64_t atomic_umin_i64_global(volatile __global uint64_t *p, uint64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMin((uint64_t*)p, x); #else return atom_min(p, x); #endif } -inline uint64_t atomic_umin_i64_local(volatile __local uint64_t *p, uint64_t x) {-#ifdef FUTHARK_CUDA+SCALAR_FUN_ATTR uint64_t atomic_umin_i64_local(volatile __local uint64_t *p, uint64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) return atomicMin((uint64_t*)p, x); #else return atom_min(p, x); #endif } -inline int64_t atomic_and_i64_global(volatile __global int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA- return atomicAnd((int64_t*)p, x);+SCALAR_FUN_ATTR int64_t atomic_and_i64_global(volatile __global int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP)+ return atomicAnd((uint64_t*)p, x); #else return atom_and(p, x); #endif } -inline int64_t atomic_and_i64_local(volatile __local int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA- return atomicAnd((int64_t*)p, x);+SCALAR_FUN_ATTR int64_t atomic_and_i64_local(volatile __local int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP)+ return atomicAnd((uint64_t*)p, x); #else return atom_and(p, x); #endif } -inline int64_t atomic_or_i64_global(volatile __global int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA- return atomicOr((int64_t*)p, x);+SCALAR_FUN_ATTR int64_t atomic_or_i64_global(volatile __global int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP)+ return atomicOr((uint64_t*)p, x); #else return atom_or(p, x); #endif } -inline int64_t atomic_or_i64_local(volatile __local int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA- return atomicOr((int64_t*)p, x);+SCALAR_FUN_ATTR int64_t atomic_or_i64_local(volatile __local int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP)+ return atomicOr((uint64_t*)p, x); #else return atom_or(p, x); #endif } -inline int64_t atomic_xor_i64_global(volatile __global int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA- return atomicXor((int64_t*)p, x);+SCALAR_FUN_ATTR int64_t atomic_xor_i64_global(volatile __global int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP)+ return atomicXor((uint64_t*)p, x); #else return atom_xor(p, x); #endif } -inline int64_t atomic_xor_i64_local(volatile __local int64_t *p, int64_t x) {-#ifdef FUTHARK_CUDA- return atomicXor((int64_t*)p, x);+SCALAR_FUN_ATTR int64_t atomic_xor_i64_local(volatile __local int64_t *p, int64_t x) {+#if defined(FUTHARK_CUDA) || defined(FUTHARK_HIP)+ return atomicXor((uint64_t*)p, x); #else return atom_xor(p, x); #endif } -#endif // defined(FUTHARK_CUDA) || defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics)+#endif // defined(FUTHARK_CUDA) || defined(FUTHARK_HIP) || defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) // End of atomics.h
rts/c/backends/cuda.h view
@@ -87,15 +87,13 @@ const char** tuning_param_classes; // Uniform fields above. + char* program; 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; @@ -115,10 +113,10 @@ cfg->nvrtc_opts = (const char**) malloc(sizeof(const char*)); cfg->nvrtc_opts[0] = NULL; + cfg->program = strconcat(gpu_program);+ 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;@@ -161,12 +159,12 @@ 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;+const char* futhark_context_config_get_program(struct futhark_context_config *cfg) {+ return cfg->program; } -void futhark_context_config_load_program_from(struct futhark_context_config *cfg, const char *path) {- cfg->load_program_from = path;+void futhark_context_config_set_program(struct futhark_context_config *cfg, const char *s) {+ cfg->program = strdup(s); } void futhark_context_config_dump_ptx_to(struct futhark_context_config *cfg, const char *path) {@@ -235,8 +233,7 @@ // A record of something that happened. struct profiling_record { cudaEvent_t *events; // Points to two events.- int *runs;- int64_t *runtime;+ const char *name; }; struct futhark_context {@@ -272,13 +269,13 @@ CUmodule module; CUstream stream; - struct free_list cu_free_list;+ struct free_list gpu_free_list; - size_t max_block_size;+ size_t max_group_size; size_t max_grid_size; size_t max_tile_size; size_t max_threshold;- size_t max_shared_memory;+ size_t max_local_memory; size_t max_bespoke; size_t lockstep_width;@@ -286,6 +283,8 @@ struct profiling_record *profiling_records; int profiling_records_capacity; int profiling_records_used;++ struct builtin_kernels* kernels; }; #define CU_DEV_ATTR(x) (CU_DEVICE_ATTRIBUTE_##x)@@ -331,13 +330,13 @@ name[sizeof(name) - 1] = 0; if (cfg->logging) {- fprintf(stderr, "Device #%d: name=\"%s\", compute capability=%d.%d\n",+ fprintf(ctx->log, "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);+ fprintf(ctx->log, "Device #%d is compute-prohibited, ignoring\n", i); } continue; }@@ -360,31 +359,13 @@ if (chosen == -1) { return 1; } if (cfg->logging) {- fprintf(stderr, "Using device #%d\n", chosen);+ fprintf(ctx->log, "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) { static struct { int major;@@ -467,13 +448,13 @@ } opts[i++] = msgprintf("-D%s=%d", "max_group_size",- (int)ctx->max_block_size);+ (int)ctx->max_group_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);+ opts[i++] = msgprintf("-DMAX_THREADS_PER_BLOCK=%zu", ctx->max_group_size); // Time for the best lines of the code in the entire compiler. if (getenv("CUDA_HOME") != NULL) {@@ -492,6 +473,10 @@ opts[i++] = strdup(extra_opts[j]); } + opts[i++] = msgprintf("-DTR_BLOCK_DIM=%d", TR_BLOCK_DIM);+ opts[i++] = msgprintf("-DTR_TILE_DIM=%d", TR_TILE_DIM);+ opts[i++] = msgprintf("-DTR_ELEMS_PER_THREAD=%d", TR_ELEMS_PER_THREAD);+ *n_opts = i; *opts_out = opts; }@@ -557,13 +542,13 @@ 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 > ctx->max_group_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);+ ctx->max_group_size, cfg->default_block_size); }- cfg->default_block_size = ctx->max_block_size;+ cfg->default_block_size = ctx->max_group_size; } if (cfg->default_grid_size > ctx->max_grid_size) { if (cfg->default_grid_size_changed) {@@ -596,7 +581,7 @@ int64_t max_value = 0, default_value = 0; if (strstr(size_class, "group_size") == size_class) {- max_value = ctx->max_block_size;+ max_value = ctx->max_group_size; default_value = cfg->default_block_size; } else if (strstr(size_class, "num_groups") == size_class) { max_value = ctx->max_grid_size;@@ -631,31 +616,16 @@ } static char* cuda_module_setup(struct futhark_context *ctx,- const char *src_fragments[],+ const char *src, const char *extra_opts[], const char* cache_fname) {- char *ptx = NULL, *src = NULL;+ char *ptx = 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);@@ -695,7 +665,6 @@ if (ptx == NULL) { char* problem = cuda_nvrtc_build(src, (const char**)opts, n_opts, &ptx); if (problem != NULL) {- free(src); return problem; } }@@ -722,18 +691,15 @@ free((char *)opts[i]); } free(opts);- free(ptx);- if (src != NULL) {- free(src);- } return NULL; } // Count up the runtime all the profiling_records that occured during execution. // Also clears the buffer of profiling_records.-static CUresult cuda_tally_profiling_records(struct futhark_context *ctx) {+static CUresult tally_profiling_records(struct futhark_context *ctx,+ struct cost_centres* ccs) { CUresult err; for (int i = 0; i < ctx->profiling_records_used; i++) { struct profiling_record record = ctx->profiling_records[i];@@ -743,9 +709,15 @@ return err; } - // CUDA provides milisecond resolution, but we want microseconds.- *record.runs += 1;- *record.runtime += ms*1000;+ if (ccs) {+ // CUDA provides milisecond resolution, but we want microseconds.+ struct cost_centre c = {+ .name = record.name,+ .runs = 1,+ .runtime = ms*1000+ };+ cost_centres_add(ccs, c);+ } if ((err = cuEventDestroy(record.events[0])) != CUDA_SUCCESS) { return err;@@ -763,7 +735,7 @@ } // Returns pointer to two events.-static cudaEvent_t* cuda_get_events(struct futhark_context *ctx, int *runs, int64_t *runtime) {+static cudaEvent_t* cuda_get_events(struct futhark_context *ctx, const char* name) { if (ctx->profiling_records_used == ctx->profiling_records_capacity) { ctx->profiling_records_capacity *= 2; ctx->profiling_records =@@ -775,79 +747,11 @@ 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[ctx->profiling_records_used].name = name; 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());@@ -880,10 +784,14 @@ return FUTHARK_PROGRAM_ERROR; } }+ CUDA_SUCCEED_OR_RETURN(cuCtxPopCurrent(&ctx->cu_ctx)); return 0; } +struct builtin_kernels* init_builtin_kernels(struct futhark_context* ctx);+void free_builtin_kernels(struct futhark_context* ctx, struct builtin_kernels* kernels);+ int backend_context_setup(struct futhark_context* ctx) { ctx->profiling_records_capacity = 200; ctx->profiling_records_used = 0;@@ -902,18 +810,18 @@ } CUDA_SUCCEED_FATAL(cuCtxCreate(&ctx->cu_ctx, 0, ctx->dev)); - free_list_init(&ctx->cu_free_list);+ free_list_init(&ctx->gpu_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_local_memory = device_query(ctx->dev, MAX_SHARED_MEMORY_PER_BLOCK);+ ctx->max_group_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_tile_size = sqrt(ctx->max_group_size); ctx->max_threshold = 0; ctx->max_bespoke = 0; ctx->lockstep_width = device_query(ctx->dev, WARP_SIZE); CUDA_SUCCEED_FATAL(cuStreamCreate(&ctx->stream, CU_STREAM_DEFAULT)); cuda_size_setup(ctx);- ctx->error = cuda_module_setup(ctx, cuda_program,+ ctx->error = cuda_module_setup(ctx, ctx->cfg->program, ctx->cfg->nvrtc_opts, ctx->cfg->cache_fname); if (ctx->error != NULL) {@@ -925,18 +833,207 @@ 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)));++ if ((ctx->kernels = init_builtin_kernels(ctx)) == NULL) {+ return 1;+ }+ return 0; } void backend_context_teardown(struct futhark_context* ctx) {+ free_builtin_kernels(ctx, ctx->kernels); cuMemFree(ctx->global_failure); cuMemFree(ctx->global_failure_args);- CUDA_SUCCEED_FATAL(cuda_free_all(ctx));- (void)cuda_tally_profiling_records(ctx);+ CUDA_SUCCEED_FATAL(gpu_free_all(ctx));+ (void)tally_profiling_records(ctx, NULL); free(ctx->profiling_records); CUDA_SUCCEED_FATAL(cuStreamDestroy(ctx->stream)); CUDA_SUCCEED_FATAL(cuModuleUnload(ctx->module)); CUDA_SUCCEED_FATAL(cuCtxDestroy(ctx->cu_ctx));+}++// GPU ABSTRACTION LAYER++// Types.++typedef CUfunction gpu_kernel;+typedef CUdeviceptr gpu_mem;++static void gpu_create_kernel(struct futhark_context *ctx,+ gpu_kernel* kernel,+ const char* name) {+ if (ctx->debugging) {+ fprintf(ctx->log, "Creating kernel %s.\n", name);+ }+ CUDA_SUCCEED_FATAL(cuModuleGetFunction(kernel, ctx->module, name));+}++static void gpu_free_kernel(struct futhark_context *ctx,+ gpu_kernel kernel) {+ (void)ctx;+ (void)kernel;+}++static int gpu_scalar_to_device(struct futhark_context* ctx,+ gpu_mem dst, size_t offset, size_t size,+ void *src) {+ CUevent *pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = cuda_get_events(ctx, "copy_scalar_to_dev");+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[0], ctx->stream));+ }+ CUDA_SUCCEED_OR_RETURN(cuMemcpyHtoD(dst + offset, src, size));+ if (pevents != NULL) {+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[1], ctx->stream));+ }+ return FUTHARK_SUCCESS;+}++static int gpu_scalar_from_device(struct futhark_context* ctx,+ void *dst,+ gpu_mem src, size_t offset, size_t size) {+ CUevent *pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = cuda_get_events(ctx, "copy_scalar_from_dev");+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[0], ctx->stream));+ }+ CUDA_SUCCEED_OR_RETURN(cuMemcpyDtoH(dst, src + offset, size));+ if (pevents != NULL) {+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[1], ctx->stream));+ }+ return FUTHARK_SUCCESS;+}++static int gpu_memcpy(struct futhark_context* ctx,+ gpu_mem dst, int64_t dst_offset,+ gpu_mem src, int64_t src_offset,+ int64_t nbytes) {+ CUevent *pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = cuda_get_events(ctx, "copy_dev_to_dev");+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[0], ctx->stream));+ }+ CUDA_SUCCEED_OR_RETURN(cuMemcpy(dst+dst_offset, src+src_offset, nbytes));+ if (pevents != NULL) {+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[1], ctx->stream));+ }+ return FUTHARK_SUCCESS;+}++static int memcpy_host2gpu(struct futhark_context* ctx, bool sync,+ gpu_mem dst, int64_t dst_offset,+ const unsigned char* src, int64_t src_offset,+ int64_t nbytes) {+ if (nbytes > 0) {+ CUevent* pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = cuda_get_events(ctx, "copy_host_to_dev");+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[0], ctx->stream));+ }+ if (sync) {+ CUDA_SUCCEED_OR_RETURN+ (cuMemcpyHtoD(dst + dst_offset, src + src_offset, nbytes));+ } else {+ CUDA_SUCCEED_OR_RETURN+ (cuMemcpyHtoDAsync(dst + dst_offset, src + src_offset, nbytes, ctx->stream));+ }+ if (pevents != NULL) {+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[1], ctx->stream));+ }+ }+ return FUTHARK_SUCCESS;+}++static int memcpy_gpu2host(struct futhark_context* ctx, bool sync,+ unsigned char* dst, int64_t dst_offset,+ gpu_mem src, int64_t src_offset,+ int64_t nbytes) {+ if (nbytes > 0) {+ CUevent* pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = cuda_get_events(ctx, "copy_dev_to_host");+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[0], ctx->stream));+ }+ if (sync) {+ CUDA_SUCCEED_OR_RETURN+ (cuMemcpyDtoH(dst + dst_offset, src + src_offset, nbytes));+ } else {+ CUDA_SUCCEED_OR_RETURN+ (cuMemcpyDtoHAsync(dst + dst_offset, src + src_offset, nbytes, ctx->stream));+ }+ if (sync &&+ ctx->failure_is_an_option &&+ futhark_context_sync(ctx) != 0) {+ return 1;+ }+ }+ return FUTHARK_SUCCESS;+}++static int gpu_launch_kernel(struct futhark_context* ctx,+ gpu_kernel kernel, const char *name,+ const int32_t grid[3],+ const int32_t block[3],+ unsigned int local_mem_bytes,+ int num_args,+ void* args[num_args],+ size_t args_sizes[num_args]) {+ (void) args_sizes;+ int64_t time_start = 0, time_end = 0;+ if (ctx->logging) {+ fprintf(ctx->log,+ "Launching kernel %s with\n"+ " grid=(%d,%d,%d)\n"+ " block=(%d,%d,%d)\n"+ " local memory=%d\n",+ name,+ grid[0], grid[1], grid[2],+ block[0], block[1], block[2],+ local_mem_bytes);+ time_start = get_wall_time();+ }++ CUevent *pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = cuda_get_events(ctx, name);+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[0], ctx->stream));+ }++ CUDA_SUCCEED_OR_RETURN+ (cuLaunchKernel(kernel,+ grid[0], grid[1], grid[2],+ block[0], block[1], block[2],+ local_mem_bytes, ctx->stream,+ args, NULL));++ if (pevents != NULL) {+ CUDA_SUCCEED_FATAL(cuEventRecord(pevents[1], ctx->stream));+ }++ if (ctx->debugging) {+ CUDA_SUCCEED_FATAL(cuCtxSynchronize());+ time_end = get_wall_time();+ long int time_diff = time_end - time_start;+ fprintf(ctx->log, " runtime: %ldus\n\n", time_diff);+ }++ return FUTHARK_SUCCESS;+}++static int gpu_alloc_actual(struct futhark_context *ctx, size_t size, gpu_mem *mem_out) {+ CUresult res = cuMemAlloc(mem_out, size);+ if (res == CUDA_ERROR_OUT_OF_MEMORY) {+ return FUTHARK_OUT_OF_MEMORY;+ }+ CUDA_SUCCEED_OR_RETURN(res);+ return FUTHARK_SUCCESS;+}++static int gpu_free_actual(struct futhark_context *ctx, gpu_mem mem) {+ (void)ctx;+ CUDA_SUCCEED_OR_RETURN(cuMemFree(mem));+ return FUTHARK_SUCCESS; } // End of backends/cuda.h.
+ rts/c/backends/hip.h view
@@ -0,0 +1,911 @@+// Start of backends/hip.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 HIP_SUCCEED_FATAL(x) hip_api_succeed_fatal(x, #x, __FILE__, __LINE__)+#define HIP_SUCCEED_NONFATAL(x) hip_api_succeed_nonfatal(x, #x, __FILE__, __LINE__)+#define HIPRTC_SUCCEED_FATAL(x) hiprtc_api_succeed_fatal(x, #x, __FILE__, __LINE__)+#define HIPRTC_SUCCEED_NONFATAL(x) hiprtc_api_succeed_nonfatal(x, #x, __FILE__, __LINE__)+// Take care not to override an existing error.+#define HIP_SUCCEED_OR_RETURN(e) { \+ char *serror = HIP_SUCCEED_NONFATAL(e); \+ if (serror) { \+ if (!ctx->error) { \+ ctx->error = serror; \+ return bad; \+ } else { \+ free(serror); \+ } \+ } \+ }++// HIP_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 hip_api_succeed_fatal(hipError_t res, const char *call,+ const char *file, int line) {+ if (res != hipSuccess) {+ const char *err_str = hipGetErrorString(res);+ if (err_str == NULL) { err_str = "Unknown"; }+ futhark_panic(-1, "%s:%d: HIP call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, res, err_str);+ }+}++static char* hip_api_succeed_nonfatal(hipError_t res, const char *call,+ const char *file, int line) {+ if (res != hipSuccess) {+ const char *err_str = hipGetErrorString(res);+ if (err_str == NULL) { err_str = "Unknown"; }+ return msgprintf("%s:%d: HIP call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, res, err_str);+ } else {+ return NULL;+ }+}++static inline void hiprtc_api_succeed_fatal(hiprtcResult res, const char *call,+ const char *file, int line) {+ if (res != HIPRTC_SUCCESS) {+ const char *err_str = hiprtcGetErrorString(res);+ futhark_panic(-1, "%s:%d: HIPRTC call\n %s\nfailed with error code %d (%s)\n",+ file, line, call, res, err_str);+ }+}++static char* hiprtc_api_succeed_nonfatal(hiprtcResult res, const char *call,+ const char *file, int line) {+ if (res != HIPRTC_SUCCESS) {+ const char *err_str = hiprtcGetErrorString(res);+ return msgprintf("%s:%d: HIPRTC 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.++ char* program;+ int num_build_opts;+ const char **build_opts;++ const char *preferred_device;+ int preferred_device_num;++ 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_build_opts = 0;+ cfg->build_opts = (const char**) malloc(sizeof(const char*));+ cfg->build_opts[0] = NULL;+ cfg->preferred_device_num = 0;+ cfg->preferred_device = "";+ cfg->program = strconcat(gpu_program);++ 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->build_opts);+ free(cfg->program);+}++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;+}+++const char* futhark_context_config_get_program(struct futhark_context_config *cfg) {+ return cfg->program;+}++void futhark_context_config_set_program(struct futhark_context_config *cfg, const char *s) {+ cfg->program = strdup(s);+}++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 {+ hipEvent_t *events; // Points to two events.+ const char *name;+};++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;+ // Uniform fields above.++ void* global_failure;+ void* 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;++ hipDevice_t dev;+ int dev_id;+ hipModule_t module;+ hipStream_t stream;++ struct free_list gpu_free_list;++ size_t max_group_size;+ size_t max_grid_size;+ size_t max_tile_size;+ size_t max_threshold;+ size_t max_local_memory;+ size_t max_bespoke;++ size_t lockstep_width;++ struct profiling_record *profiling_records;+ int profiling_records_capacity;+ int profiling_records_used;++ struct builtin_kernels* kernels;+};++static int device_query(int dev_id, hipDeviceAttribute_t attr) {+ int val;+ HIP_SUCCEED_FATAL(hipDeviceGetAttribute(&val, attr, dev_id));+ return val;+}++static int function_query(hipFunction_t f, hipFunction_attribute attr) {+ int val;+ HIP_SUCCEED_FATAL(hipFuncGetAttribute(&val, attr, f));+ return val;+}++static int hip_device_setup(struct futhark_context *ctx) {+ struct futhark_context_config *cfg = ctx->cfg;+ int count, chosen = -1;+ hipDevice_t dev;++ HIP_SUCCEED_FATAL(hipGetDeviceCount(&count));+ if (count == 0) { return 1; }++ int num_device_matches = 0;++ for (int i = 0; i < count; i++) {+ hipDeviceProp_t prop;+ hipGetDeviceProperties(&prop, i);++ if (cfg->logging) {+ fprintf(ctx->log, "Device #%d: name=\"%s\"\n", i, prop.name);+ }++ if (strstr(prop.name, cfg->preferred_device) != NULL &&+ num_device_matches++ == cfg->preferred_device_num) {+ chosen = i;+ break;+ }+ }++ if (chosen == -1) { return 1; }++ if (cfg->logging) {+ fprintf(ctx->log, "Using device #%d\n", chosen);+ }++ ctx->dev_id = chosen;+ HIP_SUCCEED_FATAL(hipDeviceGet(&ctx->dev, ctx->dev_id));+ return 0;+}++static void hip_load_code_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 **code, size_t *code_size) {+ 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));+ errno = 0;+ if (cache_restore(cache_fname, h, (unsigned char**)code, code_size) != 0) {+ if (cfg->logging) {+ fprintf(stderr, "Failed to restore cache (errno: %s)\n", strerror(errno));+ }+ }+}++static void hip_size_setup(struct futhark_context *ctx) {+ struct futhark_context_config *cfg = ctx->cfg;+ if (cfg->default_block_size > ctx->max_group_size) {+ if (cfg->default_block_size_changed) {+ fprintf(stderr,+ "Note: Device limits default block size to %zu (down from %zu).\n",+ ctx->max_group_size, cfg->default_block_size);+ }+ cfg->default_block_size = ctx->max_group_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, hipDeviceAttributePhysicalMultiProcessorCount) *+ device_query(ctx->dev, hipDeviceAttributeMaxThreadsPerMultiProcessor))+ / 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_group_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* hiprtc_build(const char *src, const char *opts[], size_t n_opts,+ char **code, size_t *code_size) {+ hiprtcProgram prog;+ char *problem = NULL;++ problem = HIPRTC_SUCCEED_NONFATAL(hiprtcCreateProgram(&prog, src, "futhark-hip", 0, NULL, NULL));++ if (problem) {+ return problem;+ }++ hiprtcResult res = hiprtcCompileProgram(prog, n_opts, opts);+ if (res != HIPRTC_SUCCESS) {+ size_t log_size;+ if (hiprtcGetProgramLogSize(prog, &log_size) == HIPRTC_SUCCESS) {+ char *log = (char*) malloc(log_size+1);+ log[log_size] = 0; // HIPRTC does not zero-terminate.+ if (hiprtcGetProgramLog(prog, log) == HIPRTC_SUCCESS) {+ problem = msgprintf("HIPRTC compilation failed.\n\n%s\n", log);+ } else {+ problem = msgprintf("Could not retrieve compilation log\n");+ }+ free(log);+ }+ return problem;+ }++ HIPRTC_SUCCEED_FATAL(hiprtcGetCodeSize(prog, code_size));+ *code = (char*) malloc(*code_size);+ HIPRTC_SUCCEED_FATAL(hiprtcGetCode(prog, *code));+ HIPRTC_SUCCEED_FATAL(hiprtcDestroyProgram(&prog));+ return NULL;+}++static void hiprtc_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;++ for (num_extra_opts = 0; extra_opts[num_extra_opts] != NULL; num_extra_opts++) {+ if (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) {+ hipDeviceProp_t props;+ HIP_SUCCEED_FATAL(hipGetDeviceProperties(&props, ctx->dev_id));+ opts[i++] = msgprintf("--gpu-architecture=%s", props.gcnArchName);+ }+ if (cfg->debugging) {+ opts[i++] = strdup("-G");+ opts[i++] = strdup("-lineinfo");+ }+ opts[i++] = msgprintf("-D%s=%d",+ "max_group_size",+ (int)ctx->max_group_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_group_size);++ for (int j = 0; extra_opts[j] != NULL; j++) {+ opts[i++] = strdup(extra_opts[j]);+ }++ opts[i++] = msgprintf("-DTR_BLOCK_DIM=%d", TR_BLOCK_DIM);+ opts[i++] = msgprintf("-DTR_TILE_DIM=%d", TR_TILE_DIM);+ opts[i++] = msgprintf("-DTR_ELEMS_PER_THREAD=%d", TR_ELEMS_PER_THREAD);++ *n_opts = i;+ *opts_out = opts;+}++static char* hip_module_setup(struct futhark_context *ctx,+ const char *src,+ const char *extra_opts[],+ const char* cache_fname) {+ char *code = NULL;+ size_t code_size = 0;+ struct futhark_context_config *cfg = ctx->cfg;++ char **opts;+ size_t n_opts;+ hiprtc_mk_build_options(ctx, extra_opts, &opts, &n_opts);++ if (cfg->logging) {+ fprintf(stderr, "HIPRTC build 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_code_from_cache = 0;+ if (cache_fname != NULL) {+ hip_load_code_from_cache(cfg, src, (const char**)opts, n_opts, &h, cache_fname, &code, &code_size);++ if (code != NULL) {+ if (cfg->logging) {+ fprintf(stderr, "Restored compiled code from cache; now loading module...\n");+ }+ if (hipModuleLoadData(&ctx->module, code) == hipSuccess) {+ if (cfg->logging) {+ fprintf(stderr, "Success!\n");+ }+ loaded_code_from_cache = 1;+ } else {+ if (cfg->logging) {+ fprintf(stderr, "Failed!\n");+ }+ free(code);+ code = NULL;+ }+ }+ }++ if (code == NULL) {+ char* problem = hiprtc_build(src, (const char**)opts, n_opts, &code, &code_size);+ if (problem != NULL) {+ return problem;+ }+ }++ if (!loaded_code_from_cache) {+ HIP_SUCCEED_FATAL(hipModuleLoadData(&ctx->module, code));+ }++ if (cache_fname != NULL && !loaded_code_from_cache) {+ if (cfg->logging) {+ fprintf(stderr, "Caching compiled code in %s...\n", cache_fname);+ }+ errno = 0;+ if (cache_store(cache_fname, &h, (const unsigned char*)code, code_size) != 0) {+ fprintf(stderr, "Failed to cache compiled code: %s\n", strerror(errno));+ }+ }++ for (size_t i = 0; i < n_opts; i++) {+ free((char *)opts[i]);+ }+ free(opts);+ free(code);++ return NULL;+}++static int tally_profiling_records(struct futhark_context *ctx,+ struct cost_centres* ccs) {+ hipError_t err;+ for (int i = 0; i < ctx->profiling_records_used; i++) {+ struct profiling_record record = ctx->profiling_records[i];++ float ms;+ if ((err = hipEventElapsedTime(&ms, record.events[0], record.events[1])) != hipSuccess) {+ return err;+ }++ if (ccs) {+ struct cost_centre c = {+ .name = record.name,+ .runs = 1,+ .runtime = ms*1000+ };+ cost_centres_add(ccs, c);+ }++ if ((err = hipEventDestroy(record.events[0])) != hipSuccess) {+ return 1;+ }+ if ((err = hipEventDestroy(record.events[1])) != hipSuccess) {+ return 1;+ }++ free(record.events);+ }++ ctx->profiling_records_used = 0;++ return 0;+}++static hipEvent_t* hip_get_events(struct futhark_context *ctx, const char* name) {+ 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));+ }+ hipEvent_t *events = calloc(2, sizeof(hipEvent_t));+ hipEventCreate(&events[0]);+ hipEventCreate(&events[1]);+ ctx->profiling_records[ctx->profiling_records_used].events = events;+ ctx->profiling_records[ctx->profiling_records_used].name = name;+ ctx->profiling_records_used++;+ return events;+}++int futhark_context_sync(struct futhark_context* ctx) {+ HIP_SUCCEED_OR_RETURN(hipStreamSynchronize(ctx->stream));+ if (ctx->failure_is_an_option) {+ // Check for any delayed error.+ int32_t failure_idx;+ HIP_SUCCEED_OR_RETURN(hipMemcpyDtoH(&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;+ HIP_SUCCEED_OR_RETURN(hipMemcpyHtoD(ctx->global_failure,+ &no_failure,+ sizeof(int32_t)));++ int64_t args[max_failure_args+1];+ HIP_SUCCEED_OR_RETURN(hipMemcpyDtoH(&args,+ ctx->global_failure_args,+ sizeof(args)));++ ctx->error = get_failure_msg(failure_idx, args);++ return FUTHARK_PROGRAM_ERROR;+ }+ }+ return 0;+}++struct builtin_kernels* init_builtin_kernels(struct futhark_context* ctx);+void free_builtin_kernels(struct futhark_context* ctx, struct builtin_kernels* kernels);++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;++ HIP_SUCCEED_FATAL(hipInit(0));+ if (hip_device_setup(ctx) != 0) {+ futhark_panic(-1, "No suitable HIP device found.\n");+ }++ free_list_init(&ctx->gpu_free_list);++ ctx->max_local_memory = device_query(ctx->dev, hipDeviceAttributeMaxSharedMemoryPerBlock);+ ctx->max_group_size = device_query(ctx->dev, hipDeviceAttributeMaxThreadsPerBlock);+ ctx->max_grid_size = device_query(ctx->dev, hipDeviceAttributeMaxGridDimX);+ ctx->max_tile_size = sqrt(ctx->max_group_size);+ ctx->max_threshold = 0;+ ctx->max_bespoke = 0;+ // FIXME: in principle we should query hipDeviceAttributeWarpSize+ // from the device, which will provide 64 on AMD GPUs.+ // Unfortunately, we currently do nasty implicit intra-warp+ // synchronisation in codegen, which does not work when this is 64.+ // Once our codegen properly synchronises intra-warp operations, we+ // can use the actual hardware lockstep width instead.+ ctx->lockstep_width = 32;+ HIP_SUCCEED_FATAL(hipStreamCreate(&ctx->stream));+ hip_size_setup(ctx);+ ctx->error = hip_module_setup(ctx, ctx->cfg->program,+ ctx->cfg->build_opts, ctx->cfg->cache_fname);++ if (ctx->error != NULL) {+ futhark_panic(1, "During HIP initialisation:\n%s\n", ctx->error);+ }++ int32_t no_error = -1;+ HIP_SUCCEED_FATAL(hipMalloc(&ctx->global_failure, sizeof(no_error)));+ HIP_SUCCEED_FATAL(hipMemcpyHtoD(ctx->global_failure, &no_error, sizeof(no_error)));+ // The +1 is to avoid zero-byte allocations.+ HIP_SUCCEED_FATAL(hipMalloc(&ctx->global_failure_args, sizeof(int64_t)*(max_failure_args+1)));++ if ((ctx->kernels = init_builtin_kernels(ctx)) == NULL) {+ return 1;+ }++ return 0;+}++void backend_context_teardown(struct futhark_context* ctx) {+ free_builtin_kernels(ctx, ctx->kernels);+ hipFree(ctx->global_failure);+ hipFree(ctx->global_failure_args);+ HIP_SUCCEED_FATAL(gpu_free_all(ctx));+ (void)tally_profiling_records(ctx, NULL);+ free(ctx->profiling_records);+ HIP_SUCCEED_FATAL(hipStreamDestroy(ctx->stream));+ HIP_SUCCEED_FATAL(hipModuleUnload(ctx->module));+}++// GPU ABSTRACTION LAYER++typedef hipFunction_t gpu_kernel;+typedef hipDeviceptr_t gpu_mem;++static void gpu_create_kernel(struct futhark_context *ctx,+ gpu_kernel* kernel,+ const char* name) {+ if (ctx->debugging) {+ fprintf(ctx->log, "Creating kernel %s.\n", name);+ }+ HIP_SUCCEED_FATAL(hipModuleGetFunction(kernel, ctx->module, name));+}++static void gpu_free_kernel(struct futhark_context *ctx,+ gpu_kernel kernel) {+ (void)ctx;+ (void)kernel;+}++static int gpu_scalar_to_device(struct futhark_context* ctx,+ gpu_mem dst, size_t offset, size_t size,+ void *src) {+ hipEvent_t *pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = hip_get_events(ctx, "copy_scalar_to_dev");+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[0], ctx->stream));+ }+ HIP_SUCCEED_OR_RETURN(hipMemcpyHtoD((unsigned char*)dst + offset, src, size));+ if (pevents != NULL) {+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[1], ctx->stream));+ }+ return FUTHARK_SUCCESS;+}++static int gpu_scalar_from_device(struct futhark_context* ctx,+ void *dst,+ gpu_mem src, size_t offset, size_t size) {+ hipEvent_t *pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = hip_get_events(ctx, "copy_scalar_from_dev");+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[0], ctx->stream));+ }+ HIP_SUCCEED_OR_RETURN(hipMemcpyDtoH(dst, (unsigned char*)src + offset, size));+ if (pevents != NULL) {+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[1], ctx->stream));+ }+ return FUTHARK_SUCCESS;+}++static int gpu_memcpy(struct futhark_context* ctx,+ gpu_mem dst, int64_t dst_offset,+ gpu_mem src, int64_t src_offset,+ int64_t nbytes) {+ hipEvent_t *pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = hip_get_events(ctx, "copy_dev_to_dev");+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[0], ctx->stream));+ }+ HIP_SUCCEED_OR_RETURN(hipMemcpyWithStream((unsigned char*)dst+dst_offset, (unsigned char*)src+src_offset,+ nbytes, hipMemcpyDeviceToDevice ,ctx->stream));+ if (pevents != NULL) {+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[1], ctx->stream));+ }+ return FUTHARK_SUCCESS;+}++static int memcpy_host2gpu(struct futhark_context* ctx, bool sync,+ gpu_mem dst, int64_t dst_offset,+ const unsigned char* src, int64_t src_offset,+ int64_t nbytes) {+ if (nbytes > 0) {+ hipEvent_t* pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = hip_get_events(ctx, "copy_host_to_dev");+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[0], ctx->stream));+ }+ if (sync) {+ HIP_SUCCEED_OR_RETURN+ (hipMemcpyHtoD((unsigned char*)dst + dst_offset,+ (unsigned char*)src + src_offset, nbytes));+ } else {+ HIP_SUCCEED_OR_RETURN+ (hipMemcpyHtoDAsync((unsigned char*)dst + dst_offset,+ (unsigned char*)src + src_offset,+ nbytes, ctx->stream));+ }+ if (pevents != NULL) {+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[1], ctx->stream));+ }+ }+ return FUTHARK_SUCCESS;+}++static int memcpy_gpu2host(struct futhark_context* ctx, bool sync,+ unsigned char* dst, int64_t dst_offset,+ gpu_mem src, int64_t src_offset,+ int64_t nbytes) {+ if (nbytes > 0) {+ hipEvent_t* pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = hip_get_events(ctx, "copy_dev_to_host");+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[0], ctx->stream));+ }+ if (sync) {+ HIP_SUCCEED_OR_RETURN+ (hipMemcpyDtoH(dst + dst_offset,+ (unsigned char*)src + src_offset,+ nbytes));+ } else {+ HIP_SUCCEED_OR_RETURN+ (hipMemcpyDtoHAsync(dst + dst_offset,+ (unsigned char*)src + src_offset,+ nbytes, ctx->stream));+ }+ if (sync &&+ ctx->failure_is_an_option &&+ futhark_context_sync(ctx) != 0) {+ return 1;+ }+ }+ return FUTHARK_SUCCESS;+}++static int gpu_launch_kernel(struct futhark_context* ctx,+ gpu_kernel kernel, const char *name,+ const int32_t grid[3],+ const int32_t block[3],+ unsigned int local_mem_bytes,+ int num_args,+ void* args[num_args],+ size_t args_sizes[num_args]) {+ (void) args_sizes;+ int64_t time_start = 0, time_end = 0;+ if (ctx->logging) {+ fprintf(ctx->log,+ "Launching kernel %s with\n"+ " grid=(%d,%d,%d)\n"+ " block=(%d,%d,%d)\n"+ " local memory=%d\n",+ name,+ grid[0], grid[1], grid[2],+ block[0], block[1], block[2],+ local_mem_bytes);+ time_start = get_wall_time();+ }++ hipEvent_t *pevents = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ pevents = hip_get_events(ctx, name);+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[0], ctx->stream));+ }++ HIP_SUCCEED_OR_RETURN+ (hipModuleLaunchKernel(kernel,+ grid[0], grid[1], grid[2],+ block[0], block[1], block[2],+ local_mem_bytes, ctx->stream,+ args, NULL));++ if (pevents != NULL) {+ HIP_SUCCEED_FATAL(hipEventRecord(pevents[1], ctx->stream));+ }++ if (ctx->debugging) {+ HIP_SUCCEED_FATAL(hipStreamSynchronize(ctx->stream));+ time_end = get_wall_time();+ long int time_diff = time_end - time_start;+ fprintf(ctx->log, " runtime: %ldus\n\n", time_diff);+ }++ return FUTHARK_SUCCESS;+}++static int gpu_alloc_actual(struct futhark_context *ctx, size_t size, gpu_mem *mem_out) {+ hipError_t res = hipMalloc(mem_out, size);+ if (res == hipErrorOutOfMemory) {+ return FUTHARK_OUT_OF_MEMORY;+ }+ HIP_SUCCEED_OR_RETURN(res);+ return FUTHARK_SUCCESS;+}++static int gpu_free_actual(struct futhark_context *ctx, gpu_mem mem) {+ (void)ctx;+ HIP_SUCCEED_OR_RETURN(hipFree(mem));+ return FUTHARK_SUCCESS;+}++// End of backends/hip.h.
rts/c/backends/opencl.h view
@@ -1,5 +1,18 @@ // Start of backends/opencl.h +// Note [32-bit transpositions]+//+// Transposition kernels are much slower when they have to use 64-bit+// arithmetic. I observed about 0.67x slowdown on an A100 GPU when+// transposing four-byte elements (much less when transposing 8-byte+// elements). Unfortunately, 64-bit arithmetic is a requirement for+// large arrays (see #1953 for what happens otherwise). We generate+// both 32- and 64-bit index arithmetic versions of transpositions,+// and dynamically pick between them at runtime. This is an+// unfortunate code bloat, and it would be preferable if we could+// simply optimise the 64-bit version to make this distinction+// unnecessary. Fortunately these kernels are quite small.+ // Forward declarations. struct opencl_device_option; // Invoked by setup_opencl() after the platform and device has been@@ -117,13 +130,12 @@ const char** tuning_param_classes; // Uniform fields above. + char* program; 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; @@ -150,10 +162,9 @@ 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;+ cfg->program = strconcat(gpu_program); // The following are dummy sizes that mean the concrete defaults // will be set during initialisation via hardware-inspection-based@@ -172,6 +183,7 @@ static void backend_context_config_teardown(struct futhark_context_config* cfg) { free(cfg->build_opts);+ free(cfg->program); } void futhark_context_config_add_build_option(struct futhark_context_config* cfg, const char *opt) {@@ -392,12 +404,12 @@ free(devices); } -void futhark_context_config_dump_program_to(struct futhark_context_config *cfg, const char *path) {- cfg->dump_program_to = path;+const char* futhark_context_config_get_program(struct futhark_context_config *cfg) {+ return cfg->program; } -void futhark_context_config_load_program_from(struct futhark_context_config *cfg, const char *path) {- cfg->load_program_from = path;+void futhark_context_config_set_program(struct futhark_context_config *cfg, const char *s) {+ cfg->program = strdup(s); } void futhark_context_config_dump_binary_to(struct futhark_context_config *cfg, const char *path) {@@ -465,8 +477,7 @@ // A record of something that happened. struct profiling_record { cl_event *event;- int *runs;- int64_t *runtime;+ const char* name; }; struct futhark_context {@@ -503,7 +514,7 @@ cl_command_queue queue; cl_program clprogram; - struct free_list cl_free_list;+ struct free_list gpu_free_list; size_t max_group_size; size_t max_num_groups;@@ -517,9 +528,10 @@ int profiling_records_capacity; int profiling_records_used; + struct builtin_kernels* kernels; }; -static cl_build_status build_opencl_program(cl_program program, cl_device_id device, const char* options) {+static cl_build_status build_gpu_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@@ -591,6 +603,10 @@ "%s ", extra_build_opts[i]); } + w += snprintf(compile_opts+w, compile_opts_size-w,+ "-DTR_BLOCK_DIM=%d -DTR_TILE_DIM=%d -DTR_ELEMS_PER_THREAD=%d ",+ TR_BLOCK_DIM, TR_TILE_DIM, TR_ELEMS_PER_THREAD);+ // Oclgrind claims to support cl_khr_fp16, but this is not actually // the case. if (strcmp(device_option.platform_name, "Oclgrind") == 0) {@@ -600,49 +616,49 @@ 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) {+static void tally_profiling_records(struct futhark_context *ctx,+ struct cost_centres* ccs) { 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_SUCCEED_FATAL(clGetEventProfilingInfo(*record.event,+ CL_PROFILING_COMMAND_START,+ sizeof(start_t),+ &start_t,+ NULL)); - // OpenCL provides nanosecond resolution, but we want- // microseconds.- *record.runs += 1;- *record.runtime += (end_t - start_t)/1000;+ OPENCL_SUCCEED_FATAL(clGetEventProfilingInfo(*record.event,+ CL_PROFILING_COMMAND_END,+ sizeof(end_t),+ &end_t,+ NULL)); - if ((err = clReleaseEvent(*record.event)) != CL_SUCCESS) {- return err;+ if (ccs) {+ // Note that OpenCL provides nanosecond resolution, but we want+ // microseconds.+ struct cost_centre c = {+ .name = record.name,+ .runs = 1,+ .runtime = (end_t - start_t)/1000+ };+ cost_centres_add(ccs, c); }++ OPENCL_SUCCEED_FATAL(clReleaseEvent(*record.event)); 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) {+static cl_event* opencl_get_event(struct futhark_context *ctx, const char *name) { if (ctx->profiling_records_used == ctx->profiling_records_capacity) { ctx->profiling_records_capacity *= 2; ctx->profiling_records =@@ -652,130 +668,11 @@ } 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[ctx->profiling_records_used].name = name; 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;@@ -822,12 +719,11 @@ // 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);+ free_list_init(&ctx->gpu_free_list); ctx->queue = queue; OPENCL_SUCCEED_FATAL(clGetCommandQueueInfo(ctx->queue, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx->ctx, NULL));@@ -971,7 +867,7 @@ fprintf(stderr, "OpenCL compiler options: %s\n", compile_opts); } - char *fut_opencl_src = NULL;+ const char* opencl_src = ctx->cfg->program; cl_program prog; error = CL_SUCCESS; @@ -981,40 +877,12 @@ 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, opencl_src, strlen(opencl_src)); cache_hash(&h, compile_opts, strlen(compile_opts)); unsigned char *buf;@@ -1051,7 +919,7 @@ fprintf(stderr, "Creating OpenCL program...\n"); } - const char* src_ptr[] = {fut_opencl_src};+ const char* src_ptr[] = {opencl_src}; prog = clCreateProgramWithSource(ctx->ctx, 1, src_ptr, &src_size, &error); OPENCL_SUCCEED_FATAL(error); }@@ -1077,10 +945,9 @@ if (ctx->cfg->logging) { fprintf(stderr, "Building OpenCL program...\n"); }- OPENCL_SUCCEED_FATAL(build_opencl_program(prog, device_option.device, compile_opts));+ OPENCL_SUCCEED_FATAL(build_gpu_program(prog, device_option.device, compile_opts)); free(compile_opts);- free(fut_opencl_src); size_t binary_size = 0; unsigned char *binary = NULL;@@ -1144,7 +1011,6 @@ } 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);@@ -1173,9 +1039,12 @@ &clCreateCommandQueue_error); OPENCL_SUCCEED_FATAL(clCreateCommandQueue_error); - setup_opencl_with_command_queue(ctx, queue, srcs, extra_build_opts, cache_fname);+ setup_opencl_with_command_queue(ctx, queue, extra_build_opts, cache_fname); } +struct builtin_kernels* init_builtin_kernels(struct futhark_context* ctx);+void free_builtin_kernels(struct futhark_context* ctx, struct builtin_kernels* kernels);+ int backend_context_setup(struct futhark_context* ctx) { ctx->lockstep_width = 0; // Real value set later. ctx->profiling_records_capacity = 200;@@ -1190,9 +1059,9 @@ 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);+ setup_opencl_with_command_queue(ctx, ctx->cfg->queue, ctx->cfg->build_opts, ctx->cfg->cache_fname); } else {- setup_opencl(ctx, opencl_program, ctx->cfg->build_opts, ctx->cfg->cache_fname);+ setup_opencl(ctx, ctx->cfg->build_opts, ctx->cfg->cache_fname); } cl_int error;@@ -1209,15 +1078,23 @@ CL_MEM_READ_WRITE, sizeof(int64_t)*(max_failure_args+1), NULL, &error); OPENCL_SUCCEED_OR_RETURN(error);- return 0;++ if ((ctx->kernels = init_builtin_kernels(ctx)) == NULL) {+ return 1;+ }++ return FUTHARK_SUCCESS; } +static int gpu_free_all(struct futhark_context *ctx);+ void backend_context_teardown(struct futhark_context* ctx) {+ free_builtin_kernels(ctx, ctx->kernels); OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->global_failure)); OPENCL_SUCCEED_FATAL(clReleaseMemObject(ctx->global_failure_args));- (void)opencl_tally_profiling_records(ctx);+ (void)tally_profiling_records(ctx, NULL); free(ctx->profiling_records);- (void)opencl_free_all(ctx);+ (void)gpu_free_all(ctx); (void)clReleaseProgram(ctx->clprogram); (void)clReleaseCommandQueue(ctx->queue); (void)clReleaseContext(ctx->ctx);@@ -1225,6 +1102,231 @@ cl_command_queue futhark_context_get_command_queue(struct futhark_context* ctx) { return ctx->queue;+}++// GPU ABSTRACTION LAYER++// Types.++typedef cl_kernel gpu_kernel;+typedef cl_mem gpu_mem;++static void gpu_create_kernel(struct futhark_context *ctx,+ gpu_kernel* kernel,+ const char* name) {+ if (ctx->debugging) {+ fprintf(ctx->log, "Creating kernel %s.\n", name);+ }+ cl_int error;+ *kernel = clCreateKernel(ctx->clprogram, name, &error);+ OPENCL_SUCCEED_FATAL(error);+}++static void gpu_free_kernel(struct futhark_context *ctx,+ gpu_kernel kernel) {+ (void)ctx;+ clReleaseKernel(kernel);+}++static int gpu_scalar_to_device(struct futhark_context* ctx,+ gpu_mem dst, size_t offset, size_t size,+ void *src) {+ cl_event* event = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ event = opencl_get_event(ctx, "copy_scalar_to_dev");+ }+ OPENCL_SUCCEED_OR_RETURN+ (clEnqueueWriteBuffer+ (ctx->queue, dst, CL_TRUE,+ offset, size, src, 0, NULL, event));+ return 0;+}++static int gpu_scalar_from_device(struct futhark_context* ctx,+ void *dst,+ gpu_mem src, size_t offset, size_t size) {+ cl_event* event = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ event = opencl_get_event(ctx, "copy_scalar_from_dev");+ }+ OPENCL_SUCCEED_OR_RETURN+ (clEnqueueReadBuffer+ (ctx->queue, src, ctx->failure_is_an_option ? CL_FALSE : CL_TRUE,+ offset, size, dst, 0, NULL, event));+ return 0;+}++static int gpu_memcpy(struct futhark_context* ctx,+ gpu_mem dst, int64_t dst_offset,+ gpu_mem src, int64_t src_offset,+ int64_t nbytes) {+ if (nbytes > 0) {+ cl_event* event = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ event = opencl_get_event(ctx, "copy_dev_to_dev");+ }+ // OpenCL swaps the usual order of operands for memcpy()-like+ // functions. The order below is not a typo.+ OPENCL_SUCCEED_OR_RETURN+ (clEnqueueCopyBuffer+ (ctx->queue, src, dst, src_offset, dst_offset, nbytes,+ 0, NULL, event));+ if (ctx->debugging) {+ OPENCL_SUCCEED_FATAL(clFinish(ctx->queue));+ }+ }+ return FUTHARK_SUCCESS;+}++static int memcpy_host2gpu(struct futhark_context* ctx, bool sync,+ gpu_mem dst, int64_t dst_offset,+ const unsigned char* src, int64_t src_offset,+ int64_t nbytes) {+ if (nbytes > 0) {+ cl_event* event = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ event = opencl_get_event(ctx, "copy_host_to_dev");+ }+ OPENCL_SUCCEED_OR_RETURN+ (clEnqueueWriteBuffer(ctx->queue,+ dst,+ sync ? CL_TRUE : CL_FALSE,+ (size_t)dst_offset, (size_t)nbytes,+ src + src_offset,+ 0, NULL, event));+ if (ctx->debugging) {+ OPENCL_SUCCEED_FATAL(clFinish(ctx->queue));+ }+ }+ return FUTHARK_SUCCESS;+}++static int memcpy_gpu2host(struct futhark_context* ctx, bool sync,+ unsigned char* dst, int64_t dst_offset,+ gpu_mem src, int64_t src_offset,+ int64_t nbytes) {+ if (nbytes > 0) {+ cl_event* event = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ event = opencl_get_event(ctx, "copy_dev_to_host");+ }+ OPENCL_SUCCEED_OR_RETURN+ (clEnqueueReadBuffer(ctx->queue, src,+ ctx->failure_is_an_option ? CL_FALSE+ : sync ? CL_TRUE : CL_FALSE,+ src_offset, nbytes,+ dst + dst_offset,+ 0, NULL, event));+ if (sync &&+ ctx->failure_is_an_option &&+ futhark_context_sync(ctx) != 0) {+ return 1;+ }+ }+ return FUTHARK_SUCCESS;+}++static int gpu_launch_kernel(struct futhark_context* ctx,+ gpu_kernel kernel, const char *name,+ const int32_t grid[3],+ const int32_t block[3],+ unsigned int local_mem_bytes,+ int num_args,+ void* args[num_args],+ size_t args_sizes[num_args]) {+ int64_t time_start = 0, time_end = 0;+ if (ctx->logging) {+ fprintf(ctx->log,+ "Launching kernel %s with\n"+ " grid=(%d,%d,%d)\n"+ " block=(%d,%d,%d)\n"+ " local memory=%d\n",+ name,+ grid[0], grid[1], grid[2],+ block[0], block[1], block[2],+ local_mem_bytes);+ time_start = get_wall_time();+ }++ // Some implementations do not work with 0-byte local memory.+ if (local_mem_bytes == 0) {+ local_mem_bytes = 4;+ }++ OPENCL_SUCCEED_OR_RETURN+ (clSetKernelArg(kernel, 0, local_mem_bytes, NULL));+ for (int i = 0; i < num_args; i++) {+ OPENCL_SUCCEED_OR_RETURN+ (clSetKernelArg(kernel, i+1, args_sizes[i], args[i]));+ }++ const size_t global_work_size[3] =+ {(size_t)grid[0]*block[0],+ (size_t)grid[1]*block[1],+ (size_t)grid[2]*block[2]};+ const size_t local_work_size[3] =+ {block[0],+ block[1],+ block[2]};++ cl_event* event = NULL;+ if (ctx->profiling && !ctx->profiling_paused) {+ event = opencl_get_event(ctx, name);+ }++ OPENCL_SUCCEED_OR_RETURN+ (clEnqueueNDRangeKernel(ctx->queue,+ kernel,+ 3, NULL, global_work_size, local_work_size,+ 0, NULL, event));++ if (ctx->debugging) {+ OPENCL_SUCCEED_FATAL(clFinish(ctx->queue));+ time_end = get_wall_time();+ long int time_diff = time_end - time_start;+ fprintf(ctx->log, " runtime: %ldus\n", time_diff);+ }+ if (ctx->logging) {+ printf("\n");+ }++ return FUTHARK_SUCCESS;+}++// 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 gpu_alloc_actual(struct futhark_context *ctx, size_t size, gpu_mem *mem_out) {+ int error;+ *mem_out = clCreateBuffer(ctx->ctx, CL_MEM_READ_WRITE, size, NULL, &error);++ OPENCL_SUCCEED_OR_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.)++ if (error == CL_MEM_OBJECT_ALLOCATION_FAILURE) {+ return FUTHARK_OUT_OF_MEMORY;+ }+ OPENCL_SUCCEED_OR_RETURN(error);+ return FUTHARK_SUCCESS;+}++static int gpu_free_actual(struct futhark_context *ctx, gpu_mem mem) {+ (void)ctx;+ OPENCL_SUCCEED_OR_RETURN(clReleaseMemObject(mem));+ return FUTHARK_SUCCESS; } // End of backends/opencl.h
rts/c/context_prototypes.h view
@@ -20,6 +20,27 @@ // Allocate memory allocated with host_alloc(). static void host_free(struct futhark_context* ctx, size_t size, const char* tag, void* mem); +// Log that a copy has occurred.+static void log_copy(struct futhark_context* ctx,+ const char *kind, int r,+ int64_t dst_offset, int64_t dst_strides[r],+ int64_t src_offset, int64_t src_strides[r],+ int64_t shape[r]);++static void log_transpose(struct futhark_context* ctx,+ int64_t k, int64_t m, int64_t n);++static bool lmad_map_tr(int64_t *num_arrays_out, int64_t *n_out, int64_t *m_out,+ int r,+ const int64_t dst_strides[r],+ const int64_t src_strides[r],+ const int64_t shape[r]);++static bool lmad_contiguous(int r, int64_t strides[r], int64_t shape[r]);++static bool lmad_memcpyable(int r,+ int64_t dst_strides[r], int64_t src_strides[r], int64_t shape[r]);+ // 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);
+ rts/c/copy.h view
@@ -0,0 +1,262 @@+// Start of copy.h++// Cache-oblivious map-transpose function.+#define GEN_MAP_TRANSPOSE(NAME, ELEM_TYPE) \+ static void map_transpose_##NAME \+ (ELEM_TYPE* dst, ELEM_TYPE* src, \+ int64_t k, int64_t m, int64_t n, \+ int64_t cb, int64_t ce, int64_t rb, int64_t re) \+ { \+ int32_t r = re - rb; \+ int32_t c = ce - cb; \+ if (k == 1) { \+ if (r <= 64 && c <= 64) { \+ for (int64_t j = 0; j < c; j++) { \+ for (int64_t i = 0; i < r; i++) { \+ dst[(j + cb) * n + (i + rb)] = src[(i + rb) * m + (j + cb)]; \+ } \+ } \+ } else if (c <= r) { \+ map_transpose_##NAME(dst, src, k, m, n, cb, ce, rb, rb + r/2); \+ map_transpose_##NAME(dst, src, k, m, n, cb, ce, rb + r/2, re); \+ } else { \+ map_transpose_##NAME(dst, src, k, m, n, cb, cb + c/2, rb, re); \+ map_transpose_##NAME(dst, src, k, m, n, cb + c/2, ce, rb, re); \+ } \+ } else { \+ for (int64_t i = 0; i < k; i++) { \+ map_transpose_##NAME(dst + i * m * n, src + i * m * n, 1, m, n, cb, ce, rb, re); \+ }\+} \+}++// Straightforward LMAD copy function.+#define GEN_LMAD_COPY_ELEMENTS(NAME, ELEM_TYPE) \+ static void lmad_copy_elements_##NAME(int r, \+ ELEM_TYPE* dst, int64_t dst_strides[r], \+ ELEM_TYPE *src, int64_t src_strides[r], \+ int64_t shape[r]) { \+ if (r == 1) { \+ for (int i = 0; i < shape[0]; i++) { \+ dst[i*dst_strides[0]] = src[i*src_strides[0]]; \+ } \+ } else if (r > 1) { \+ for (int i = 0; i < shape[0]; i++) { \+ lmad_copy_elements_##NAME(r-1, \+ dst+i*dst_strides[0], dst_strides+1, \+ src+i*src_strides[0], src_strides+1, \+ shape+1); \+ } \+ } \+ } \++// Check whether this LMAD can be seen as a transposed 2D array. This+// is done by checking every possible splitting point.+static bool lmad_is_tr(int64_t *n_out, int64_t *m_out,+ int r,+ const int64_t strides[r],+ const int64_t shape[r]) {+ for (int i = 1; i < r; i++) {+ int n = 1, m = 1;+ bool ok = true;+ int64_t expected = 1;+ // Check strides before 'i'.+ for (int j = i-1; j >= 0; j--) {+ ok = ok && strides[j] == expected;+ expected *= shape[j];+ n *= shape[j];+ }+ // Check strides after 'i'.+ for (int j = r-1; j >= i; j--) {+ ok = ok && strides[j] == expected;+ expected *= shape[j];+ m *= shape[j];+ }+ if (ok) {+ *n_out = n;+ *m_out = m;+ return true;+ }+ }+ return false;+}++// This function determines whether the a 'dst' LMAD is row-major and+// 'src' LMAD is column-major. Both LMADs are for arrays of the same+// shape. Both LMADs are allowed to have additional dimensions "on+// top". Essentially, this function determines whether a copy from+// 'src' to 'dst' is a "map(transpose)" that we know how to implement+// efficiently. The LMADs can have arbitrary rank, and the main+// challenge here is checking whether the src LMAD actually+// corresponds to a 2D column-major layout by morally collapsing+// dimensions. There is a lot of looping here, but the actual trip+// count is going to be very low in practice.+//+// Returns true if this is indeed a map(transpose), and writes the+// number of arrays, and moral array size to appropriate output+// parameters.+static bool lmad_map_tr(int64_t *num_arrays_out, int64_t *n_out, int64_t *m_out,+ int r,+ const int64_t dst_strides[r],+ const int64_t src_strides[r],+ const int64_t shape[r]) {+ int64_t rowmajor_strides[r];+ rowmajor_strides[r-1] = 1;++ for (int i = r-2; i >= 0; i--) {+ rowmajor_strides[i] = rowmajor_strides[i+1] * shape[i+1];+ }++ // map_r will be the number of mapped dimensions on top.+ int map_r = 0;+ int64_t num_arrays = 1;+ for (int i = 0; i < r; i++) {+ if (dst_strides[i] != rowmajor_strides[i] ||+ src_strides[i] != rowmajor_strides[i]) {+ break;+ } else {+ num_arrays *= shape[i];+ map_r++;+ }+ }++ *num_arrays_out = num_arrays;++ if (memcmp(&rowmajor_strides[map_r],+ &dst_strides[map_r],+ sizeof(int64_t)*(r-map_r)) == 0) {+ return lmad_is_tr(n_out, m_out, r-map_r, src_strides+map_r, shape+map_r);+ } else if (memcmp(&rowmajor_strides[map_r],+ &src_strides[map_r],+ sizeof(int64_t)*(r-map_r)) == 0) {+ return lmad_is_tr(m_out, n_out, r-map_r, dst_strides+map_r, shape+map_r);+ }+ return false;+}++// Check if the strides correspond to row-major strides of *any*+// permutation of the shape. This is done by recursive search with+// backtracking. This is worst-case exponential, but hopefully the+// arrays we encounter do not have that many dimensions.+static bool lmad_contiguous_search(int checked, int64_t expected,+ int r,+ int64_t strides[r], int64_t shape[r], bool used[r]) {+ for (int i = 0; i < r; i++) {+ for (int j = 0; j < r; j++) {+ if (!used[j] && strides[j] == expected && strides[j] >= 0) {+ used[j] = true;+ if (checked+1 == r ||+ lmad_contiguous_search(checked+1, expected * shape[j], r, strides, shape, used)) {+ return true;+ }+ used[j] = false;+ }+ }+ }+ return false;+}++// Does this LMAD correspond to an array with positive strides and no+// holes?+static bool lmad_contiguous(int r, int64_t strides[r], int64_t shape[r]) {+ bool used[r];+ for (int i = 0; i < r; i++) {+ used[i] = false;+ }+ return lmad_contiguous_search(0, 1, r, strides, shape, used);+}++// Does this copy correspond to something that could be done with a+// memcpy()-like operation? I.e. do the LMADs actually represent the+// same in-memory layout and are they contiguous?+static bool lmad_memcpyable(int r,+ int64_t dst_strides[r], int64_t src_strides[r], int64_t shape[r]) {+ if (!lmad_contiguous(r, dst_strides, shape)) {+ return false;+ }+ for (int i = 0; i < r; i++) {+ if (dst_strides[i] != src_strides[i] && shape[i] != 1) {+ return false;+ }+ }+ return true;+}+++static void log_copy(struct futhark_context* ctx,+ const char *kind, int r,+ int64_t dst_offset, int64_t dst_strides[r],+ int64_t src_offset, int64_t src_strides[r],+ int64_t shape[r]) {+ if (ctx->logging) {+ fprintf(ctx->log, "\n# Copy %s\n", kind);+ fprintf(ctx->log, "Shape: ");+ for (int i = 0; i < r; i++) { fprintf(ctx->log, "[%ld]", (long int)shape[i]); }+ fprintf(ctx->log, "\n");+ fprintf(ctx->log, "Dst offset: %ld\n", dst_offset);+ fprintf(ctx->log, "Dst strides:");+ for (int i = 0; i < r; i++) { fprintf(ctx->log, " %ld", (long int)dst_strides[i]); }+ fprintf(ctx->log, "\n");+ fprintf(ctx->log, "Src offset: %ld\n", src_offset);+ fprintf(ctx->log, "Src strides:");+ for (int i = 0; i < r; i++) { fprintf(ctx->log, " %ld", (long int)src_strides[i]); }+ fprintf(ctx->log, "\n");+ }+}++static void log_transpose(struct futhark_context* ctx,+ int64_t k, int64_t n, int64_t m) {+ if (ctx->logging) {+ fprintf(ctx->log, "## Transpose\n");+ fprintf(ctx->log, "Arrays : %ld\n", (long int)k);+ fprintf(ctx->log, "X elements : %ld\n", (long int)m);+ fprintf(ctx->log, "Y elements : %ld\n", (long int)n);+ fprintf(ctx->log, "\n");+ }+}++#define GEN_LMAD_COPY(NAME, ELEM_TYPE) \+ static void lmad_copy_##NAME \+ (struct futhark_context *ctx, int r, \+ ELEM_TYPE* dst, int64_t dst_offset, int64_t dst_strides[r], \+ ELEM_TYPE *src, int64_t src_offset, int64_t src_strides[r], \+ int64_t shape[r]) { \+ log_copy(ctx, "CPU to CPU", r, dst_offset, dst_strides, \+ src_offset, src_strides, shape); \+ int64_t size = 1; \+ for (int i = 0; i < r; i++) { size *= shape[i]; } \+ if (size == 0) { return; } \+ int64_t k, n, m; \+ if (lmad_map_tr(&k, &n, &m, \+ r, dst_strides, src_strides, shape)) { \+ log_transpose(ctx, k, n, m); \+ map_transpose_##NAME \+ (dst+dst_offset, src+src_offset, k, n, m, 0, n, 0, m); \+ } else if (lmad_memcpyable(r, dst_strides, src_strides, shape)) { \+ if (ctx->logging) {fprintf(ctx->log, "## Flat copy\n\n");} \+ memcpy(dst+dst_offset, src+src_offset, size*sizeof(*dst)); \+ } else { \+ if (ctx->logging) {fprintf(ctx->log, "## General copy\n\n");} \+ lmad_copy_elements_##NAME \+ (r, \+ dst+dst_offset, dst_strides, \+ src+src_offset, src_strides, shape); \+ } \+ }++GEN_MAP_TRANSPOSE(1b, uint8_t)+GEN_MAP_TRANSPOSE(2b, uint16_t)+GEN_MAP_TRANSPOSE(4b, uint32_t)+GEN_MAP_TRANSPOSE(8b, uint64_t)++GEN_LMAD_COPY_ELEMENTS(1b, uint8_t)+GEN_LMAD_COPY_ELEMENTS(2b, uint16_t)+GEN_LMAD_COPY_ELEMENTS(4b, uint32_t)+GEN_LMAD_COPY_ELEMENTS(8b, uint64_t)++GEN_LMAD_COPY(1b, uint8_t)+GEN_LMAD_COPY(2b, uint16_t)+GEN_LMAD_COPY(4b, uint32_t)+GEN_LMAD_COPY(8b, uint64_t)++// End of copy.h
+ rts/c/gpu.h view
@@ -0,0 +1,591 @@+// Start of gpu.h++// Generic functions that use our tiny GPU abstraction layer. The+// entire context must be defined before this header is included. In+// particular we expect the following functions to be available:++static int gpu_free_actual(struct futhark_context *ctx, gpu_mem mem);+static int gpu_alloc_actual(struct futhark_context *ctx, size_t size, gpu_mem *mem_out);+int gpu_launch_kernel(struct futhark_context* ctx,+ gpu_kernel kernel, const char *name,+ const int32_t grid[3],+ const int32_t block[3],+ unsigned int local_mem_bytes,+ int num_args,+ void* args[num_args],+ size_t args_sizes[num_args]);+int gpu_memcpy(struct futhark_context* ctx,+ gpu_mem dst, int64_t dst_offset,+ gpu_mem src, int64_t src_offset,+ int64_t nbytes);+int gpu_scalar_from_device(struct futhark_context* ctx,+ void *dst,+ gpu_mem src, size_t offset, size_t size);+int gpu_scalar_to_device(struct futhark_context* ctx,+ gpu_mem dst, size_t offset, size_t size,+ void *src);+void gpu_create_kernel(struct futhark_context *ctx,+ gpu_kernel* kernel,+ const char* name);++// Max number of groups we allow along the second or third dimension+// for transpositions.+#define MAX_TR_GROUPS 65535++struct builtin_kernels {+ // We have a lot of ways to transpose arrays.+ gpu_kernel map_transpose_1b;+ gpu_kernel map_transpose_1b_low_height;+ gpu_kernel map_transpose_1b_low_width;+ gpu_kernel map_transpose_1b_small;+ gpu_kernel map_transpose_1b_large;+ gpu_kernel map_transpose_2b;+ gpu_kernel map_transpose_2b_low_height;+ gpu_kernel map_transpose_2b_low_width;+ gpu_kernel map_transpose_2b_small;+ gpu_kernel map_transpose_2b_large;+ gpu_kernel map_transpose_4b;+ gpu_kernel map_transpose_4b_low_height;+ gpu_kernel map_transpose_4b_low_width;+ gpu_kernel map_transpose_4b_small;+ gpu_kernel map_transpose_4b_large;+ gpu_kernel map_transpose_8b;+ gpu_kernel map_transpose_8b_low_height;+ gpu_kernel map_transpose_8b_low_width;+ gpu_kernel map_transpose_8b_small;+ gpu_kernel map_transpose_8b_large;++ // And a few ways of copying.+ gpu_kernel lmad_copy_1b;+ gpu_kernel lmad_copy_2b;+ gpu_kernel lmad_copy_4b;+ gpu_kernel lmad_copy_8b;+};++struct builtin_kernels* init_builtin_kernels(struct futhark_context* ctx) {+ struct builtin_kernels *kernels = malloc(sizeof(struct builtin_kernels));+ gpu_create_kernel(ctx, &kernels->map_transpose_1b, "map_transpose_1b");+ gpu_create_kernel(ctx, &kernels->map_transpose_1b_large, "map_transpose_1b_large");+ gpu_create_kernel(ctx, &kernels->map_transpose_1b_low_height, "map_transpose_1b_low_height");+ gpu_create_kernel(ctx, &kernels->map_transpose_1b_low_width, "map_transpose_1b_low_width");+ gpu_create_kernel(ctx, &kernels->map_transpose_1b_small, "map_transpose_1b_small");++ gpu_create_kernel(ctx, &kernels->map_transpose_2b, "map_transpose_2b");+ gpu_create_kernel(ctx, &kernels->map_transpose_2b_large, "map_transpose_2b_large");+ gpu_create_kernel(ctx, &kernels->map_transpose_2b_low_height, "map_transpose_2b_low_height");+ gpu_create_kernel(ctx, &kernels->map_transpose_2b_low_width, "map_transpose_2b_low_width");+ gpu_create_kernel(ctx, &kernels->map_transpose_2b_small, "map_transpose_2b_small");++ gpu_create_kernel(ctx, &kernels->map_transpose_4b, "map_transpose_4b");+ gpu_create_kernel(ctx, &kernels->map_transpose_4b_large, "map_transpose_4b_large");+ gpu_create_kernel(ctx, &kernels->map_transpose_4b_low_height, "map_transpose_4b_low_height");+ gpu_create_kernel(ctx, &kernels->map_transpose_4b_low_width, "map_transpose_4b_low_width");+ gpu_create_kernel(ctx, &kernels->map_transpose_4b_small, "map_transpose_4b_small");++ gpu_create_kernel(ctx, &kernels->map_transpose_8b, "map_transpose_8b");+ gpu_create_kernel(ctx, &kernels->map_transpose_8b_large, "map_transpose_8b_large");+ gpu_create_kernel(ctx, &kernels->map_transpose_8b_low_height, "map_transpose_8b_low_height");+ gpu_create_kernel(ctx, &kernels->map_transpose_8b_low_width, "map_transpose_8b_low_width");+ gpu_create_kernel(ctx, &kernels->map_transpose_8b_small, "map_transpose_8b_small");++ gpu_create_kernel(ctx, &kernels->lmad_copy_1b, "lmad_copy_1b");+ gpu_create_kernel(ctx, &kernels->lmad_copy_2b, "lmad_copy_2b");+ gpu_create_kernel(ctx, &kernels->lmad_copy_4b, "lmad_copy_4b");+ gpu_create_kernel(ctx, &kernels->lmad_copy_8b, "lmad_copy_8b");++ return kernels;+}++void free_builtin_kernels(struct futhark_context* ctx, struct builtin_kernels* kernels) {+ gpu_free_kernel(ctx, kernels->map_transpose_1b);+ gpu_free_kernel(ctx, kernels->map_transpose_1b_large);+ gpu_free_kernel(ctx, kernels->map_transpose_1b_low_height);+ gpu_free_kernel(ctx, kernels->map_transpose_1b_low_width);+ gpu_free_kernel(ctx, kernels->map_transpose_1b_small);++ gpu_free_kernel(ctx, kernels->map_transpose_2b);+ gpu_free_kernel(ctx, kernels->map_transpose_2b_large);+ gpu_free_kernel(ctx, kernels->map_transpose_2b_low_height);+ gpu_free_kernel(ctx, kernels->map_transpose_2b_low_width);+ gpu_free_kernel(ctx, kernels->map_transpose_2b_small);++ gpu_free_kernel(ctx, kernels->map_transpose_4b);+ gpu_free_kernel(ctx, kernels->map_transpose_4b_large);+ gpu_free_kernel(ctx, kernels->map_transpose_4b_low_height);+ gpu_free_kernel(ctx, kernels->map_transpose_4b_low_width);+ gpu_free_kernel(ctx, kernels->map_transpose_4b_small);++ gpu_free_kernel(ctx, kernels->map_transpose_8b);+ gpu_free_kernel(ctx, kernels->map_transpose_8b_large);+ gpu_free_kernel(ctx, kernels->map_transpose_8b_low_height);+ gpu_free_kernel(ctx, kernels->map_transpose_8b_low_width);+ gpu_free_kernel(ctx, kernels->map_transpose_8b_small);++ gpu_free_kernel(ctx, kernels->lmad_copy_1b);+ gpu_free_kernel(ctx, kernels->lmad_copy_2b);+ gpu_free_kernel(ctx, kernels->lmad_copy_4b);+ gpu_free_kernel(ctx, kernels->lmad_copy_8b);++ free(kernels);+}++static int gpu_alloc(struct futhark_context *ctx, FILE *log,+ size_t min_size, const char *tag,+ gpu_mem *mem_out, size_t *size_out) {+ if (min_size < sizeof(int)) {+ min_size = sizeof(int);+ }++ gpu_mem* memptr;+ if (free_list_find(&ctx->gpu_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 FUTHARK_SUCCESS;+ } else {+ if (ctx->cfg->debugging) {+ fprintf(log, "Found a free block, but it was too small.\n");+ }+ int error = gpu_free_actual(ctx, *memptr);+ free(memptr);+ if (error != FUTHARK_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 = gpu_alloc_actual(ctx, min_size, mem_out);++ while (error == FUTHARK_OUT_OF_MEMORY) {+ if (ctx->cfg->debugging) {+ fprintf(log, "Out of GPU memory: releasing entry from the free list...\n");+ }+ gpu_mem* memptr;+ if (free_list_first(&ctx->gpu_free_list, (fl_mem*)&memptr) == 0) {+ gpu_mem mem = *memptr;+ free(memptr);+ error = gpu_free_actual(ctx, mem);+ if (error != FUTHARK_SUCCESS) {+ return error;+ }+ } else {+ break;+ }+ error = gpu_alloc_actual(ctx, min_size, mem_out);+ }++ return error;+}++static int gpu_free(struct futhark_context *ctx,+ gpu_mem mem, size_t size, const char *tag) {+ gpu_mem* memptr = malloc(sizeof(gpu_mem));+ *memptr = mem;+ free_list_insert(&ctx->gpu_free_list, size, (fl_mem)memptr, tag);+ return FUTHARK_SUCCESS;+}++static int gpu_free_all(struct futhark_context *ctx) {+ free_list_pack(&ctx->gpu_free_list);+ gpu_mem* memptr;+ while (free_list_first(&ctx->gpu_free_list, (fl_mem*)&memptr) == 0) {+ gpu_mem mem = *memptr;+ free(memptr);+ int error = gpu_free_actual(ctx, mem);+ if (error != FUTHARK_SUCCESS) {+ return error;+ }+ }++ return FUTHARK_SUCCESS;+}++static int gpu_map_transpose(struct futhark_context* ctx,+ gpu_kernel kernel_default,+ gpu_kernel kernel_low_height,+ gpu_kernel kernel_low_width,+ gpu_kernel kernel_small,+ gpu_kernel kernel_large,+ const char *name, size_t elem_size,+ gpu_mem dst, int64_t dst_offset,+ gpu_mem src, int64_t src_offset,+ int64_t k, int64_t n, int64_t m) {+ int64_t mulx = TR_BLOCK_DIM / n;+ int64_t muly = TR_BLOCK_DIM / m;+ int32_t mulx32 = mulx;+ int32_t muly32 = muly;+ int32_t k32 = k;+ int32_t n32 = n;+ int32_t m32 = m;++ gpu_kernel kernel = kernel_default;+ int32_t grid[3];+ int32_t block[3];++ void* args[11];+ size_t args_sizes[11] = {+ sizeof(gpu_mem), sizeof(int64_t),+ sizeof(gpu_mem), sizeof(int64_t),+ sizeof(int32_t),+ sizeof(int32_t),+ sizeof(int32_t),+ sizeof(int32_t),+ sizeof(int32_t)+ };++ args[0] = &dst;+ args[1] = &dst_offset;+ args[2] = &src;+ args[3] = &src_offset;+ args[7] = &mulx;+ args[8] = &muly;++ if (dst_offset + k * n * m <= 2147483647L &&+ src_offset + k * n * m <= 2147483647L) {+ if (m <= TR_BLOCK_DIM/2 && n <= TR_BLOCK_DIM/2) {+ if (ctx->logging) { fprintf(ctx->log, "Using small kernel\n"); }+ kernel = kernel_small;+ grid[0] = ((k * n * m) + (TR_BLOCK_DIM*TR_BLOCK_DIM) - 1) / (TR_BLOCK_DIM*TR_BLOCK_DIM);+ grid[1] = 1;+ grid[2] = 1;+ block[0] = TR_BLOCK_DIM*TR_BLOCK_DIM;+ block[1] = 1;+ block[2] = 1;+ } else if (m <= TR_BLOCK_DIM/2 && TR_BLOCK_DIM < n) {+ if (ctx->logging) { fprintf(ctx->log, "Using low-width kernel\n"); }+ kernel = kernel_low_width;+ int64_t x_elems = m;+ int64_t y_elems = (n + muly - 1) / muly;+ grid[0] = (x_elems + TR_BLOCK_DIM - 1) / TR_BLOCK_DIM;+ grid[1] = (y_elems + TR_BLOCK_DIM - 1) / TR_BLOCK_DIM;+ grid[2] = k;+ block[0] = TR_BLOCK_DIM;+ block[1] = TR_BLOCK_DIM;+ block[2] = 1;+ } else if (n <= TR_BLOCK_DIM/2 && TR_BLOCK_DIM < m) {+ if (ctx->logging) { fprintf(ctx->log, "Using low-height kernel\n"); }+ kernel = kernel_low_height;+ int64_t x_elems = (m + mulx - 1) / mulx;+ int64_t y_elems = n;+ grid[0] = (x_elems + TR_BLOCK_DIM - 1) / TR_BLOCK_DIM;+ grid[1] = (y_elems + TR_BLOCK_DIM - 1) / TR_BLOCK_DIM;+ grid[2] = k;+ block[0] = TR_BLOCK_DIM;+ block[1] = TR_BLOCK_DIM;+ block[2] = 1;+ } else {+ if (ctx->logging) { fprintf(ctx->log, "Using default kernel\n"); }+ kernel = kernel_default;+ grid[0] = (m+TR_TILE_DIM-1)/TR_TILE_DIM;+ grid[1] = (n+TR_TILE_DIM-1)/TR_TILE_DIM;+ grid[2] = k;+ block[0] = TR_TILE_DIM;+ block[1] = TR_TILE_DIM/TR_ELEMS_PER_THREAD;+ block[2] = 1;+ }+ args[4] = &k32;+ args[5] = &m32;+ args[6] = &n32;+ args[7] = &mulx32;+ args[8] = &muly32;+ } else {+ if (ctx->logging) { fprintf(ctx->log, "Using large kernel\n"); }+ kernel = kernel_large;+ grid[0] = (m+TR_TILE_DIM-1)/TR_TILE_DIM;+ grid[1] = (n+TR_TILE_DIM-1)/TR_TILE_DIM;+ grid[2] = k;+ block[0] = TR_TILE_DIM;+ block[1] = TR_TILE_DIM/TR_ELEMS_PER_THREAD;+ block[2] = 1;+ args[4] = &k;+ args[5] = &m;+ args[6] = &n;+ args[7] = &mulx;+ args[8] = &muly;+ args_sizes[4] = sizeof(int64_t);+ args_sizes[5] = sizeof(int64_t);+ args_sizes[6] = sizeof(int64_t);+ args_sizes[7] = sizeof(int64_t);+ args_sizes[8] = sizeof(int64_t);+ }++ // Cap the number of groups we launch and figure out how many+ // repeats we need alongside each dimension.+ int32_t repeat_1 = grid[1] / MAX_TR_GROUPS;+ int32_t repeat_2 = grid[2] / MAX_TR_GROUPS;+ grid[1] = repeat_1 > 0 ? MAX_TR_GROUPS : grid[1];+ grid[2] = repeat_2 > 0 ? MAX_TR_GROUPS : grid[2];+ args[9] = &repeat_1;+ args[10] = &repeat_2;+ args_sizes[9] = sizeof(repeat_1);+ args_sizes[10] = sizeof(repeat_2);++ if (ctx->logging) {+ fprintf(ctx->log, "\n");+ }++ return gpu_launch_kernel(ctx, kernel, name, grid, block,+ TR_TILE_DIM*(TR_TILE_DIM+1)*elem_size,+ sizeof(args)/sizeof(args[0]), args, args_sizes);+}++#define GEN_MAP_TRANSPOSE_GPU2GPU(NAME, ELEM_TYPE) \+ static int map_transpose_gpu2gpu_##NAME \+ (struct futhark_context* ctx, \+ gpu_mem dst, int64_t dst_offset, \+ gpu_mem src, int64_t src_offset, \+ int64_t k, int64_t m, int64_t n) \+ { \+ return \+ gpu_map_transpose \+ (ctx, \+ ctx->kernels->map_transpose_##NAME, \+ ctx->kernels->map_transpose_##NAME##_low_height, \+ ctx->kernels->map_transpose_##NAME##_low_width, \+ ctx->kernels->map_transpose_##NAME##_small, \+ ctx->kernels->map_transpose_##NAME##_large, \+ "map_transpose_" #NAME, sizeof(ELEM_TYPE), \+ dst, dst_offset, src, src_offset, \+ k, n, m); \+ }++static int gpu_lmad_copy(struct futhark_context* ctx,+ gpu_kernel kernel, int r,+ gpu_mem dst, int64_t dst_offset, int64_t dst_strides[r],+ gpu_mem src, int64_t src_offset, int64_t src_strides[r],+ int64_t shape[r]) {+ if (r > 8) {+ set_error(ctx, strdup("Futhark runtime limitation:\nCannot copy array of greater than rank 8.\n"));+ return 1;+ }++ int64_t n = 1;+ for (int i = 0; i < r; i++) { n *= shape[i]; }++ void* args[6+(8*3)];+ size_t args_sizes[6+(8*3)];++ args[0] = &dst;+ args_sizes[0] = sizeof(gpu_mem);+ args[1] = &dst_offset;+ args_sizes[1] = sizeof(dst_offset);+ args[2] = &src;+ args_sizes[2] = sizeof(gpu_mem);+ args[3] = &src_offset;+ args_sizes[3] = sizeof(src_offset);+ args[4] = &n;+ args_sizes[4] = sizeof(n);+ args[5] = &r;+ args_sizes[5] = sizeof(r);++ int64_t zero = 0;++ for (int i = 0; i < 8; i++) {+ args_sizes[6+i*3] = sizeof(int64_t);+ args_sizes[6+i*3+1] = sizeof(int64_t);+ args_sizes[6+i*3+2] = sizeof(int64_t);+ if (i < r) {+ args[6+i*3] = &shape[i];+ args[6+i*3+1] = &dst_strides[i];+ args[6+i*3+2] = &src_strides[i];+ } else {+ args[6+i*3] = &zero;+ args[6+i*3+1] = &zero;+ args[6+i*3+2] = &zero;+ }+ }+ const size_t w = 256; // XXX: hardcoded workgroup size.++ return gpu_launch_kernel(ctx, kernel, "copy_lmad_dev_to_dev",+ (const int32_t[3]) {(n+w-1)/w,1,1},+ (const int32_t[3]) {w,1,1},+ 0, 6+(8*3), args, args_sizes);+}++#define GEN_LMAD_COPY_ELEMENTS_GPU2GPU(NAME, ELEM_TYPE) \+ static int lmad_copy_elements_gpu2gpu_##NAME \+ (struct futhark_context* ctx, \+ int r, \+ gpu_mem dst, int64_t dst_offset, int64_t dst_strides[r], \+ gpu_mem src, int64_t src_offset, int64_t src_strides[r], \+ int64_t shape[r]) { \+ return gpu_lmad_copy(ctx, ctx->kernels->lmad_copy_##NAME, r, \+ dst, dst_offset, dst_strides, \+ src, src_offset, src_strides, \+ shape); \+ } \++#define GEN_LMAD_COPY_GPU2GPU(NAME, ELEM_TYPE) \+ static int lmad_copy_gpu2gpu_##NAME \+ (struct futhark_context* ctx, \+ int r, \+ gpu_mem dst, int64_t dst_offset, int64_t dst_strides[r], \+ gpu_mem src, int64_t src_offset, int64_t src_strides[r], \+ int64_t shape[r]) { \+ log_copy(ctx, "GPU to GPU", r, dst_offset, dst_strides, \+ src_offset, src_strides, shape); \+ int64_t size = 1; \+ for (int i = 0; i < r; i++) { size *= shape[i]; } \+ if (size == 0) { return FUTHARK_SUCCESS; } \+ int64_t k, n, m; \+ if (lmad_map_tr(&k, &n, &m, \+ r, dst_strides, src_strides, shape)) { \+ log_transpose(ctx, k, n, m); \+ return map_transpose_gpu2gpu_##NAME \+ (ctx, dst, dst_offset, src, src_offset, k, n, m); \+ } else if (lmad_memcpyable(r, dst_strides, src_strides, shape)) { \+ if (ctx->logging) {fprintf(ctx->log, "## Flat copy\n\n");} \+ return gpu_memcpy(ctx, \+ dst, dst_offset*sizeof(ELEM_TYPE), \+ src, src_offset*sizeof(ELEM_TYPE), \+ size * sizeof(ELEM_TYPE)); \+ } else { \+ if (ctx->logging) {fprintf(ctx->log, "## General copy\n\n");} \+ return lmad_copy_elements_gpu2gpu_##NAME \+ (ctx, r, \+ dst, dst_offset, dst_strides, \+ src, src_offset, src_strides, \+ shape); \+ } \+ }++static int+lmad_copy_elements_host2gpu(struct futhark_context *ctx, size_t elem_size,+ int r,+ gpu_mem dst, int64_t dst_offset, int64_t dst_strides[r],+ unsigned char* src, int64_t src_offset, int64_t src_strides[r],+ int64_t shape[r]) {+ (void)ctx; (void)elem_size; (void)r;+ (void)dst; (void)dst_offset; (void)dst_strides;+ (void)src; (void)src_offset; (void)src_strides;+ (void)shape;+ set_error(ctx, strdup("Futhark runtime limitation:\nCannot copy unstructured array from host to GPU.\n"));+ return 1;+}++static int+lmad_copy_elements_gpu2host (struct futhark_context *ctx, size_t elem_size,+ int r,+ unsigned char* dst, int64_t dst_offset, int64_t dst_strides[r],+ gpu_mem src, int64_t src_offset, int64_t src_strides[r],+ int64_t shape[r]) {+ (void)ctx; (void)elem_size; (void)r;+ (void)dst; (void)dst_offset; (void)dst_strides;+ (void)src; (void)src_offset; (void)src_strides;+ (void)shape;+ set_error(ctx, strdup("Futhark runtime limitation:\nCannot copy unstructured array from GPU to host.\n"));+ return 1;+}++#define GEN_LMAD_COPY_ELEMENTS_HOSTGPU(NAME, ELEM_TYPE) \+ static int lmad_copy_elements_gpu2gpu_##NAME \+ (struct futhark_context* ctx, \+ int r, \+ gpu_mem dst, int64_t dst_offset, int64_t dst_strides[r], \+ gpu_mem src, int64_t src_offset, int64_t src_strides[r], \+ int64_t shape[r]) { \+ return (ctx, ctx->kernels->lmad_copy_##NAME, r, \+ dst, dst_offset, dst_strides, \+ src, src_offset, src_strides, \+ shape); \+ } \+++static int lmad_copy_host2gpu(struct futhark_context* ctx, size_t elem_size, bool sync,+ int r,+ gpu_mem dst, int64_t dst_offset, int64_t dst_strides[r],+ unsigned char* src, int64_t src_offset, int64_t src_strides[r],+ int64_t shape[r]) {+ log_copy(ctx, "Host to GPU", r, dst_offset, dst_strides,+ src_offset, src_strides, shape);+ int64_t size = elem_size;+ for (int i = 0; i < r; i++) { size *= shape[i]; }+ if (size == 0) { return FUTHARK_SUCCESS; }+ int64_t k, n, m;+ if (lmad_memcpyable(r, dst_strides, src_strides, shape)) {+ if (ctx->logging) {fprintf(ctx->log, "## Flat copy\n\n");}+ return memcpy_host2gpu(ctx, sync,+ dst, dst_offset*elem_size,+ src, src_offset*elem_size,+ size);+ } else {+ if (ctx->logging) {fprintf(ctx->log, "## General copy\n\n");}+ int error;+ error = lmad_copy_elements_host2gpu+ (ctx, elem_size, r,+ dst, dst_offset, dst_strides,+ src, src_offset, src_strides,+ shape);+ if (error == 0 && sync) {+ error = futhark_context_sync(ctx);+ }+ return error;+ }+}++static int lmad_copy_gpu2host(struct futhark_context* ctx, size_t elem_size, bool sync,+ int r,+ unsigned char* dst, int64_t dst_offset, int64_t dst_strides[r],+ gpu_mem src, int64_t src_offset, int64_t src_strides[r],+ int64_t shape[r]) {+ log_copy(ctx, "Host to GPU", r, dst_offset, dst_strides,+ src_offset, src_strides, shape);+ int64_t size = elem_size;+ for (int i = 0; i < r; i++) { size *= shape[i]; }+ if (size == 0) { return FUTHARK_SUCCESS; }+ int64_t k, n, m;+ if (lmad_memcpyable(r, dst_strides, src_strides, shape)) {+ if (ctx->logging) {fprintf(ctx->log, "## Flat copy\n\n");}+ return memcpy_gpu2host(ctx, sync,+ dst, dst_offset*elem_size,+ src, src_offset*elem_size,+ size);+ } else {+ if (ctx->logging) {fprintf(ctx->log, "## General copy\n\n");}+ int error;+ error = lmad_copy_elements_gpu2host+ (ctx, elem_size, r,+ dst, dst_offset, dst_strides,+ src, src_offset, src_strides,+ shape);+ if (error == 0 && sync) {+ error = futhark_context_sync(ctx);+ }+ return error;+ }+}++GEN_MAP_TRANSPOSE_GPU2GPU(1b, uint8_t)+GEN_MAP_TRANSPOSE_GPU2GPU(2b, uint16_t)+GEN_MAP_TRANSPOSE_GPU2GPU(4b, uint32_t)+GEN_MAP_TRANSPOSE_GPU2GPU(8b, uint64_t)++GEN_LMAD_COPY_ELEMENTS_GPU2GPU(1b, uint8_t)+GEN_LMAD_COPY_ELEMENTS_GPU2GPU(2b, uint16_t)+GEN_LMAD_COPY_ELEMENTS_GPU2GPU(4b, uint32_t)+GEN_LMAD_COPY_ELEMENTS_GPU2GPU(8b, uint64_t)++GEN_LMAD_COPY_GPU2GPU(1b, uint8_t)+GEN_LMAD_COPY_GPU2GPU(2b, uint16_t)+GEN_LMAD_COPY_GPU2GPU(4b, uint32_t)+GEN_LMAD_COPY_GPU2GPU(8b, uint64_t)++// End of gpu.h
+ rts/c/gpu_prototypes.h view
@@ -0,0 +1,12 @@+// Start of gpu_prototypes.h++// Constants used for transpositions. In principle these should be configurable.+#define TR_BLOCK_DIM 16+#define TR_TILE_DIM (TR_BLOCK_DIM*2)+#define TR_ELEMS_PER_THREAD 8++struct builtin_kernels* init_builtin_kernels(struct futhark_context* ctx);+void free_builtin_kernels(struct futhark_context* ctx, struct builtin_kernels* kernels);+static int gpu_free_all(struct futhark_context *ctx);++// End of gpu_prototypes.h
rts/c/half.h view
@@ -217,7 +217,7 @@ 0, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 0, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 }; -static uint16_t float2halfbits(float value) {+SCALAR_FUN_ATTR uint16_t float2halfbits(float value) { union { float x; uint32_t y; } u; u.x = value; uint32_t bits = u.y;@@ -227,7 +227,7 @@ return hbits; } -static float halfbits2float(uint16_t value) {+SCALAR_FUN_ATTR float halfbits2float(uint16_t value) { uint32_t bits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10]; union { uint32_t x; float y; } u;@@ -235,7 +235,7 @@ return u.y; } -static uint16_t halfbitsnextafter(uint16_t from, uint16_t to) {+SCALAR_FUN_ATTR uint16_t halfbitsnextafter(uint16_t from, uint16_t to) { int fabs = from & 0x7FFF, tabs = to & 0x7FFF; if(fabs > 0x7C00 || tabs > 0x7C00) { return ((from&0x7FFF)>0x7C00) ? (from|0x200) : (to|0x200);
rts/c/ispc_util.h view
@@ -399,58 +399,4 @@ return err; } -// AOS <-> SOA memcpy functions-#define memmove_sized(dim) \-static inline void memmove_##dim(varying uint8 * uniform dst, uniform uint8 * varying src, uniform int64_t n) { \- uniform uint##dim * varying srcp = (uniform uint##dim * varying) src; \- varying uint##dim * uniform dstp = (varying uint##dim * uniform) dst; \- for (uniform int64_t i = 0; i < n / (dim / 8); i++) { \- dstp[i] = srcp[i]; \- } \-} \-static inline void memmove_##dim(uniform uint8 * varying dst, varying uint8 * uniform src, uniform int64_t n) { \- varying uint##dim * uniform srcp = (varying uint##dim * uniform) src; \- uniform uint##dim * varying dstp = (uniform uint##dim * varying) dst; \- for (uniform int64_t i = 0; i < n / (dim / 8); i++) { \- dstp[i] = srcp[i]; \- } \-} \-static inline void memmove_##dim(varying uint8 * uniform dst, varying uint8 * uniform src, uniform int64_t n) { \- varying uint##dim * uniform srcp = (varying uint##dim * uniform) src; \- varying uint##dim * uniform dstp = (varying uint##dim * uniform) dst; \- for (uniform int64_t i = 0; i < n / (dim / 8); i++) { \- dstp[i] = srcp[i]; \- } \-} \-static inline void memmove_##dim(varying uint8 * varying dst, uniform uint8 * varying src, uniform int64_t n) { \- foreach_unique (ptr in dst) { \- memmove_##dim(ptr, src, n); \- } \-} \-static inline void memmove_##dim(uniform uint8 * varying dst, varying uint8 * varying src, uniform int64_t n) { \- foreach_unique (ptr in src) { \- memmove_##dim(dst, ptr, n); \- } \-} \-static inline void memmove_##dim(varying uint8 * varying dst, varying uint8 * uniform src, uniform int64_t n) { \- foreach_unique (ptr in dst) { \- memmove_##dim(ptr, src, n); \- } \-} \-static inline void memmove_##dim(varying uint8 * varying dst, varying uint8 * varying src, uniform int64_t n) { \- if (reduce_equal((varying int64_t)dst)) { \- foreach_unique (ptr in src) { \- memmove_##dim(dst, ptr, n); \- } \- } else { \- foreach_unique (ptr in dst) { \- memmove_##dim(ptr, src, n); \- } \- } \-}-memmove_sized(8)-memmove_sized(16)-memmove_sized(32)-memmove_sized(64)- // End of ispc_util.h.
rts/c/scalar.h view
@@ -17,2980 +17,2980 @@ // Double-precision definitions are only included if the preprocessor // macro FUTHARK_F64_ENABLED is set. -static inline uint8_t add8(uint8_t x, uint8_t y) {- return x + y;-}--static inline uint16_t add16(uint16_t x, uint16_t y) {- return x + y;-}--static inline uint32_t add32(uint32_t x, uint32_t y) {- return x + y;-}--static inline uint64_t add64(uint64_t x, uint64_t y) {- return x + y;-}--static inline uint8_t sub8(uint8_t x, uint8_t y) {- return x - y;-}--static inline uint16_t sub16(uint16_t x, uint16_t y) {- return x - y;-}--static inline uint32_t sub32(uint32_t x, uint32_t y) {- return x - y;-}--static inline uint64_t sub64(uint64_t x, uint64_t y) {- return x - y;-}--static inline uint8_t mul8(uint8_t x, uint8_t y) {- return x * y;-}--static inline uint16_t mul16(uint16_t x, uint16_t y) {- return x * y;-}--static inline uint32_t mul32(uint32_t x, uint32_t y) {- return x * y;-}--static inline uint64_t mul64(uint64_t x, uint64_t y) {- return x * y;-}--#if ISPC--static inline uint8_t udiv8(uint8_t x, uint8_t y) {- // This strange pattern is used to prevent the ISPC compiler from- // causing SIGFPEs and bogus results on divisions where inactive lanes- // have 0-valued divisors. It ensures that any inactive lane instead- // has a divisor of 1. https://github.com/ispc/ispc/issues/2292- uint8_t ys = 1;- foreach_active(i){- ys = y;- }-- return x / ys;-}--static inline uint16_t udiv16(uint16_t x, uint16_t y) {- uint16_t ys = 1;- foreach_active(i){- ys = y;- }- - return x / ys;-}--static inline uint32_t udiv32(uint32_t x, uint32_t y) {- uint32_t ys = 1;- foreach_active(i){- ys = y;- }- -- return x / ys;-}--static inline uint64_t udiv64(uint64_t x, uint64_t y) {- uint64_t ys = 1;- foreach_active(i){- ys = y;- }- -- return x / ys;-}--static inline uint8_t udiv_up8(uint8_t x, uint8_t y) {- uint8_t ys = 1;- foreach_active(i){- ys = y;- }- -- return (x + y - 1) / ys;-}--static inline uint16_t udiv_up16(uint16_t x, uint16_t y) {- uint16_t ys = 1;- foreach_active(i){- ys = y;- }- - return (x + y - 1) / ys;-}--static inline uint32_t udiv_up32(uint32_t x, uint32_t y) {- uint32_t ys = 1;- foreach_active(i){- ys = y;- }- - return (x + y - 1) / ys;-}--static inline uint64_t udiv_up64(uint64_t x, uint64_t y) {- uint64_t ys = 1;- foreach_active(i){- ys = y;- }- - return (x + y - 1) / ys;-}--static inline uint8_t umod8(uint8_t x, uint8_t y) {- uint8_t ys = 1;- foreach_active(i){- ys = y;- }- - return x % ys;-}--static inline uint16_t umod16(uint16_t x, uint16_t y) {- uint16_t ys = 1;- foreach_active(i){- ys = y;- }- -- return x % ys;-}--static inline uint32_t umod32(uint32_t x, uint32_t y) {- uint32_t ys = 1;- foreach_active(i){- ys = y;- }- - return x % ys;-}--static inline uint64_t umod64(uint64_t x, uint64_t y) {- uint64_t ys = 1;- foreach_active(i){- ys = y;- }- - return x % ys;-}--static inline uint8_t udiv_safe8(uint8_t x, uint8_t y) {- uint8_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x / ys;-}--static inline uint16_t udiv_safe16(uint16_t x, uint16_t y) {- uint16_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x / ys;-}--static inline uint32_t udiv_safe32(uint32_t x, uint32_t y) {- uint32_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x / ys;-}--static inline uint64_t udiv_safe64(uint64_t x, uint64_t y) {- uint64_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x / ys;-}--static inline uint8_t udiv_up_safe8(uint8_t x, uint8_t y) {- uint8_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : (x + y - 1) / ys;-}--static inline uint16_t udiv_up_safe16(uint16_t x, uint16_t y) {- uint16_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : (x + y - 1) / ys;-}--static inline uint32_t udiv_up_safe32(uint32_t x, uint32_t y) {- uint32_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : (x + y - 1) / ys;-}--static inline uint64_t udiv_up_safe64(uint64_t x, uint64_t y) {- uint64_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : (x + y - 1) / ys;-}--static inline uint8_t umod_safe8(uint8_t x, uint8_t y) {- uint8_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x % ys;-}--static inline uint16_t umod_safe16(uint16_t x, uint16_t y) {- uint16_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x % ys;-}--static inline uint32_t umod_safe32(uint32_t x, uint32_t y) {- uint32_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x % ys;-}--static inline uint64_t umod_safe64(uint64_t x, uint64_t y) {- uint64_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x % ys;-}--static inline int8_t sdiv8(int8_t x, int8_t y) {- int8_t ys = 1;- foreach_active(i){- ys = y;- }- - int8_t q = x / ys;- int8_t r = x % ys;-- return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int16_t sdiv16(int16_t x, int16_t y) {- int16_t ys = 1;- foreach_active(i){- ys = y;- }- - int16_t q = x / ys;- int16_t r = x % ys;-- return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int32_t sdiv32(int32_t x, int32_t y) {- int32_t ys = 1;- foreach_active(i){- ys = y;- }- int32_t q = x / ys;- int32_t r = x % ys;-- return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int64_t sdiv64(int64_t x, int64_t y) {- int64_t ys = 1;- foreach_active(i){- ys = y;- }- - int64_t q = x / ys;- int64_t r = x % ys;-- return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int8_t sdiv_up8(int8_t x, int8_t y) {- return sdiv8(x + y - 1, y);-}--static inline int16_t sdiv_up16(int16_t x, int16_t y) {- return sdiv16(x + y - 1, y);-}--static inline int32_t sdiv_up32(int32_t x, int32_t y) {- return sdiv32(x + y - 1, y);-}--static inline int64_t sdiv_up64(int64_t x, int64_t y) {- return sdiv64(x + y - 1, y);-}--static inline int8_t smod8(int8_t x, int8_t y) {- int8_t ys = 1;- foreach_active(i){- ys = y;- }- - int8_t r = x % ys;-- return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int16_t smod16(int16_t x, int16_t y) {- int16_t ys = 1;- foreach_active(i){- ys = y;- }- - int16_t r = x % ys;-- return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int32_t smod32(int32_t x, int32_t y) {- int32_t ys = 1;- foreach_active(i){- ys = y;- }- - int32_t r = x % ys;-- return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int64_t smod64(int64_t x, int64_t y) {- int64_t ys = 1;- foreach_active(i){- ys = y;- }- - int64_t r = x % ys;-- return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int8_t sdiv_safe8(int8_t x, int8_t y) {- return y == 0 ? 0 : sdiv8(x, y);-}--static inline int16_t sdiv_safe16(int16_t x, int16_t y) {- return y == 0 ? 0 : sdiv16(x, y);-}--static inline int32_t sdiv_safe32(int32_t x, int32_t y) {- return y == 0 ? 0 : sdiv32(x, y);-}--static inline int64_t sdiv_safe64(int64_t x, int64_t y) {- return y == 0 ? 0 : sdiv64(x, y);-}--static inline int8_t sdiv_up_safe8(int8_t x, int8_t y) {- return sdiv_safe8(x + y - 1, y);-}--static inline int16_t sdiv_up_safe16(int16_t x, int16_t y) {- return sdiv_safe16(x + y - 1, y);-}--static inline int32_t sdiv_up_safe32(int32_t x, int32_t y) {- return sdiv_safe32(x + y - 1, y);-}--static inline int64_t sdiv_up_safe64(int64_t x, int64_t y) {- return sdiv_safe64(x + y - 1, y);-}--static inline int8_t smod_safe8(int8_t x, int8_t y) {- return y == 0 ? 0 : smod8(x, y);-}--static inline int16_t smod_safe16(int16_t x, int16_t y) {- return y == 0 ? 0 : smod16(x, y);-}--static inline int32_t smod_safe32(int32_t x, int32_t y) {- return y == 0 ? 0 : smod32(x, y);-}--static inline int64_t smod_safe64(int64_t x, int64_t y) {- return y == 0 ? 0 : smod64(x, y);-}--static inline int8_t squot8(int8_t x, int8_t y) {- int8_t ys = 1;- foreach_active(i){- ys = y;- }- - return x / ys;-}--static inline int16_t squot16(int16_t x, int16_t y) {- int16_t ys = 1;- foreach_active(i){- ys = y;- }- - return x / ys;-}--static inline int32_t squot32(int32_t x, int32_t y) {- int32_t ys = 1;- foreach_active(i){- ys = y;- }- - return x / ys;-}--static inline int64_t squot64(int64_t x, int64_t y) {- int64_t ys = 1;- foreach_active(i){- ys = y;- }- - return x / ys;-}--static inline int8_t srem8(int8_t x, int8_t y) {- int8_t ys = 1;- foreach_active(i){- ys = y;- }- - return x % ys;-}--static inline int16_t srem16(int16_t x, int16_t y) {- int16_t ys = 1;- foreach_active(i){- ys = y;- }- - return x % ys;-}--static inline int32_t srem32(int32_t x, int32_t y) {- int32_t ys = 1;- foreach_active(i){- ys = y;- }- - return x % ys;-}--static inline int64_t srem64(int64_t x, int64_t y) {- int8_t ys = 1;- foreach_active(i){- ys = y;- }- - return x % ys;-}--static inline int8_t squot_safe8(int8_t x, int8_t y) {- int8_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x / ys;-}--static inline int16_t squot_safe16(int16_t x, int16_t y) {- int16_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x / ys;-}--static inline int32_t squot_safe32(int32_t x, int32_t y) {- int32_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x / ys;-}--static inline int64_t squot_safe64(int64_t x, int64_t y) {- int64_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x / ys;-}--static inline int8_t srem_safe8(int8_t x, int8_t y) {- int8_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x % ys;-}--static inline int16_t srem_safe16(int16_t x, int16_t y) {- int16_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x % ys;-}--static inline int32_t srem_safe32(int32_t x, int32_t y) {- int32_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x % ys;-}--static inline int64_t srem_safe64(int64_t x, int64_t y) {- int64_t ys = 1;- foreach_active(i){- ys = y;- }- - return y == 0 ? 0 : x % ys;-}--#else--static inline uint8_t udiv8(uint8_t x, uint8_t y) {- return x / y;-}--static inline uint16_t udiv16(uint16_t x, uint16_t y) {- return x / y;-}--static inline uint32_t udiv32(uint32_t x, uint32_t y) {- return x / y;-}--static inline uint64_t udiv64(uint64_t x, uint64_t y) {- return x / y;-}--static inline uint8_t udiv_up8(uint8_t x, uint8_t y) {- return (x + y - 1) / y;-}--static inline uint16_t udiv_up16(uint16_t x, uint16_t y) {- return (x + y - 1) / y;-}--static inline uint32_t udiv_up32(uint32_t x, uint32_t y) {- return (x + y - 1) / y;-}--static inline uint64_t udiv_up64(uint64_t x, uint64_t y) {- return (x + y - 1) / y;-}--static inline uint8_t umod8(uint8_t x, uint8_t y) {- return x % y;-}--static inline uint16_t umod16(uint16_t x, uint16_t y) {- return x % y;-}--static inline uint32_t umod32(uint32_t x, uint32_t y) {- return x % y;-}--static inline uint64_t umod64(uint64_t x, uint64_t y) {- return x % y;-}--static inline uint8_t udiv_safe8(uint8_t x, uint8_t y) {- return y == 0 ? 0 : x / y;-}--static inline uint16_t udiv_safe16(uint16_t x, uint16_t y) {- return y == 0 ? 0 : x / y;-}--static inline uint32_t udiv_safe32(uint32_t x, uint32_t y) {- return y == 0 ? 0 : x / y;-}--static inline uint64_t udiv_safe64(uint64_t x, uint64_t y) {- return y == 0 ? 0 : x / y;-}--static inline uint8_t udiv_up_safe8(uint8_t x, uint8_t y) {- return y == 0 ? 0 : (x + y - 1) / y;-}--static inline uint16_t udiv_up_safe16(uint16_t x, uint16_t y) {- return y == 0 ? 0 : (x + y - 1) / y;-}--static inline uint32_t udiv_up_safe32(uint32_t x, uint32_t y) {- return y == 0 ? 0 : (x + y - 1) / y;-}--static inline uint64_t udiv_up_safe64(uint64_t x, uint64_t y) {- return y == 0 ? 0 : (x + y - 1) / y;-}--static inline uint8_t umod_safe8(uint8_t x, uint8_t y) {- return y == 0 ? 0 : x % y;-}--static inline uint16_t umod_safe16(uint16_t x, uint16_t y) {- return y == 0 ? 0 : x % y;-}--static inline uint32_t umod_safe32(uint32_t x, uint32_t y) {- return y == 0 ? 0 : x % y;-}--static inline uint64_t umod_safe64(uint64_t x, uint64_t y) {- return y == 0 ? 0 : x % y;-}--static inline int8_t sdiv8(int8_t x, int8_t y) {- int8_t q = x / y;- int8_t r = x % y;-- return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int16_t sdiv16(int16_t x, int16_t y) {- int16_t q = x / y;- int16_t r = x % y;-- return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int32_t sdiv32(int32_t x, int32_t y) {- int32_t q = x / y;- int32_t r = x % y;-- return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int64_t sdiv64(int64_t x, int64_t y) {- int64_t q = x / y;- int64_t r = x % y;-- return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int8_t sdiv_up8(int8_t x, int8_t y) {- return sdiv8(x + y - 1, y);-}--static inline int16_t sdiv_up16(int16_t x, int16_t y) {- return sdiv16(x + y - 1, y);-}--static inline int32_t sdiv_up32(int32_t x, int32_t y) {- return sdiv32(x + y - 1, y);-}--static inline int64_t sdiv_up64(int64_t x, int64_t y) {- return sdiv64(x + y - 1, y);-}--static inline int8_t smod8(int8_t x, int8_t y) {- int8_t r = x % y;-- return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int16_t smod16(int16_t x, int16_t y) {- int16_t r = x % y;-- return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int32_t smod32(int32_t x, int32_t y) {- int32_t r = x % y;-- return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int64_t smod64(int64_t x, int64_t y) {- int64_t r = x % y;-- return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int8_t sdiv_safe8(int8_t x, int8_t y) {- return y == 0 ? 0 : sdiv8(x, y);-}--static inline int16_t sdiv_safe16(int16_t x, int16_t y) {- return y == 0 ? 0 : sdiv16(x, y);-}--static inline int32_t sdiv_safe32(int32_t x, int32_t y) {- return y == 0 ? 0 : sdiv32(x, y);-}--static inline int64_t sdiv_safe64(int64_t x, int64_t y) {- return y == 0 ? 0 : sdiv64(x, y);-}--static inline int8_t sdiv_up_safe8(int8_t x, int8_t y) {- return sdiv_safe8(x + y - 1, y);-}--static inline int16_t sdiv_up_safe16(int16_t x, int16_t y) {- return sdiv_safe16(x + y - 1, y);-}--static inline int32_t sdiv_up_safe32(int32_t x, int32_t y) {- return sdiv_safe32(x + y - 1, y);-}--static inline int64_t sdiv_up_safe64(int64_t x, int64_t y) {- return sdiv_safe64(x + y - 1, y);-}--static inline int8_t smod_safe8(int8_t x, int8_t y) {- return y == 0 ? 0 : smod8(x, y);-}--static inline int16_t smod_safe16(int16_t x, int16_t y) {- return y == 0 ? 0 : smod16(x, y);-}--static inline int32_t smod_safe32(int32_t x, int32_t y) {- return y == 0 ? 0 : smod32(x, y);-}--static inline int64_t smod_safe64(int64_t x, int64_t y) {- return y == 0 ? 0 : smod64(x, y);-}--static inline int8_t squot8(int8_t x, int8_t y) {- return x / y;-}--static inline int16_t squot16(int16_t x, int16_t y) {- return x / y;-}--static inline int32_t squot32(int32_t x, int32_t y) {- return x / y;-}--static inline int64_t squot64(int64_t x, int64_t y) {- return x / y;-}--static inline int8_t srem8(int8_t x, int8_t y) {- return x % y;-}--static inline int16_t srem16(int16_t x, int16_t y) {- return x % y;-}--static inline int32_t srem32(int32_t x, int32_t y) {- return x % y;-}--static inline int64_t srem64(int64_t x, int64_t y) {- return x % y;-}--static inline int8_t squot_safe8(int8_t x, int8_t y) {- return y == 0 ? 0 : x / y;-}--static inline int16_t squot_safe16(int16_t x, int16_t y) {- return y == 0 ? 0 : x / y;-}--static inline int32_t squot_safe32(int32_t x, int32_t y) {- return y == 0 ? 0 : x / y;-}--static inline int64_t squot_safe64(int64_t x, int64_t y) {- return y == 0 ? 0 : x / y;-}--static inline int8_t srem_safe8(int8_t x, int8_t y) {- return y == 0 ? 0 : x % y;-}--static inline int16_t srem_safe16(int16_t x, int16_t y) {- return y == 0 ? 0 : x % y;-}--static inline int32_t srem_safe32(int32_t x, int32_t y) {- return y == 0 ? 0 : x % y;-}--static inline int64_t srem_safe64(int64_t x, int64_t y) {- return y == 0 ? 0 : x % y;-}--#endif--static inline int8_t smin8(int8_t x, int8_t y) {- return x < y ? x : y;-}--static inline int16_t smin16(int16_t x, int16_t y) {- return x < y ? x : y;-}--static inline int32_t smin32(int32_t x, int32_t y) {- return x < y ? x : y;-}--static inline int64_t smin64(int64_t x, int64_t y) {- return x < y ? x : y;-}--static inline uint8_t umin8(uint8_t x, uint8_t y) {- return x < y ? x : y;-}--static inline uint16_t umin16(uint16_t x, uint16_t y) {- return x < y ? x : y;-}--static inline uint32_t umin32(uint32_t x, uint32_t y) {- return x < y ? x : y;-}--static inline uint64_t umin64(uint64_t x, uint64_t y) {- return x < y ? x : y;-}--static inline int8_t smax8(int8_t x, int8_t y) {- return x < y ? y : x;-}--static inline int16_t smax16(int16_t x, int16_t y) {- return x < y ? y : x;-}--static inline int32_t smax32(int32_t x, int32_t y) {- return x < y ? y : x;-}--static inline int64_t smax64(int64_t x, int64_t y) {- return x < y ? y : x;-}--static inline uint8_t umax8(uint8_t x, uint8_t y) {- return x < y ? y : x;-}--static inline uint16_t umax16(uint16_t x, uint16_t y) {- return x < y ? y : x;-}--static inline uint32_t umax32(uint32_t x, uint32_t y) {- return x < y ? y : x;-}--static inline uint64_t umax64(uint64_t x, uint64_t y) {- return x < y ? y : x;-}--static inline uint8_t shl8(uint8_t x, uint8_t y) {- return (uint8_t)(x << y);-}--static inline uint16_t shl16(uint16_t x, uint16_t y) {- return (uint16_t)(x << y);-}--static inline uint32_t shl32(uint32_t x, uint32_t y) {- return x << y;-}--static inline uint64_t shl64(uint64_t x, uint64_t y) {- return x << y;-}--static inline uint8_t lshr8(uint8_t x, uint8_t y) {- return x >> y;-}--static inline uint16_t lshr16(uint16_t x, uint16_t y) {- return x >> y;-}--static inline uint32_t lshr32(uint32_t x, uint32_t y) {- return x >> y;-}--static inline uint64_t lshr64(uint64_t x, uint64_t y) {- return x >> y;-}--static inline int8_t ashr8(int8_t x, int8_t y) {- return x >> y;-}--static inline int16_t ashr16(int16_t x, int16_t y) {- return x >> y;-}--static inline int32_t ashr32(int32_t x, int32_t y) {- return x >> y;-}--static inline int64_t ashr64(int64_t x, int64_t y) {- return x >> y;-}--static inline uint8_t and8(uint8_t x, uint8_t y) {- return x & y;-}--static inline uint16_t and16(uint16_t x, uint16_t y) {- return x & y;-}--static inline uint32_t and32(uint32_t x, uint32_t y) {- return x & y;-}--static inline uint64_t and64(uint64_t x, uint64_t y) {- return x & y;-}--static inline uint8_t or8(uint8_t x, uint8_t y) {- return x | y;-}--static inline uint16_t or16(uint16_t x, uint16_t y) {- return x | y;-}--static inline uint32_t or32(uint32_t x, uint32_t y) {- return x | y;-}--static inline uint64_t or64(uint64_t x, uint64_t y) {- return x | y;-}--static inline uint8_t xor8(uint8_t x, uint8_t y) {- return x ^ y;-}--static inline uint16_t xor16(uint16_t x, uint16_t y) {- return x ^ y;-}--static inline uint32_t xor32(uint32_t x, uint32_t y) {- return x ^ y;-}--static inline uint64_t xor64(uint64_t x, uint64_t y) {- return x ^ y;-}--static inline bool ult8(uint8_t x, uint8_t y) {- return x < y;-}--static inline bool ult16(uint16_t x, uint16_t y) {- return x < y;-}--static inline bool ult32(uint32_t x, uint32_t y) {- return x < y;-}--static inline bool ult64(uint64_t x, uint64_t y) {- return x < y;-}--static inline bool ule8(uint8_t x, uint8_t y) {- return x <= y;-}--static inline bool ule16(uint16_t x, uint16_t y) {- return x <= y;-}--static inline bool ule32(uint32_t x, uint32_t y) {- return x <= y;-}--static inline bool ule64(uint64_t x, uint64_t y) {- return x <= y;-}--static inline bool slt8(int8_t x, int8_t y) {- return x < y;-}--static inline bool slt16(int16_t x, int16_t y) {- return x < y;-}--static inline bool slt32(int32_t x, int32_t y) {- return x < y;-}--static inline bool slt64(int64_t x, int64_t y) {- return x < y;-}--static inline bool sle8(int8_t x, int8_t y) {- return x <= y;-}--static inline bool sle16(int16_t x, int16_t y) {- return x <= y;-}--static inline bool sle32(int32_t x, int32_t y) {- return x <= y;-}--static inline bool sle64(int64_t x, int64_t y) {- return x <= y;-}--static inline uint8_t pow8(uint8_t x, uint8_t y) {- uint8_t res = 1, rem = y;-- while (rem != 0) {- if (rem & 1)- res *= x;- rem >>= 1;- x *= x;- }- return res;-}--static inline uint16_t pow16(uint16_t x, uint16_t y) {- uint16_t res = 1, rem = y;-- while (rem != 0) {- if (rem & 1)- res *= x;- rem >>= 1;- x *= x;- }- return res;-}--static inline uint32_t pow32(uint32_t x, uint32_t y) {- uint32_t res = 1, rem = y;-- while (rem != 0) {- if (rem & 1)- res *= x;- rem >>= 1;- x *= x;- }- return res;-}--static inline uint64_t pow64(uint64_t x, uint64_t y) {- uint64_t res = 1, rem = y;-- while (rem != 0) {- if (rem & 1)- res *= x;- rem >>= 1;- x *= x;- }- return res;-}--static inline bool itob_i8_bool(int8_t x) {- return x != 0;-}--static inline bool itob_i16_bool(int16_t x) {- return x != 0;-}--static inline bool itob_i32_bool(int32_t x) {- return x != 0;-}--static inline bool itob_i64_bool(int64_t x) {- return x != 0;-}--static inline int8_t btoi_bool_i8(bool x) {- return x;-}--static inline int16_t btoi_bool_i16(bool x) {- return x;-}--static inline int32_t btoi_bool_i32(bool x) {- return x;-}--static inline int64_t btoi_bool_i64(bool x) {- return x;-}--#define sext_i8_i8(x) ((int8_t) (int8_t) (x))-#define sext_i8_i16(x) ((int16_t) (int8_t) (x))-#define sext_i8_i32(x) ((int32_t) (int8_t) (x))-#define sext_i8_i64(x) ((int64_t) (int8_t) (x))-#define sext_i16_i8(x) ((int8_t) (int16_t) (x))-#define sext_i16_i16(x) ((int16_t) (int16_t) (x))-#define sext_i16_i32(x) ((int32_t) (int16_t) (x))-#define sext_i16_i64(x) ((int64_t) (int16_t) (x))-#define sext_i32_i8(x) ((int8_t) (int32_t) (x))-#define sext_i32_i16(x) ((int16_t) (int32_t) (x))-#define sext_i32_i32(x) ((int32_t) (int32_t) (x))-#define sext_i32_i64(x) ((int64_t) (int32_t) (x))-#define sext_i64_i8(x) ((int8_t) (int64_t) (x))-#define sext_i64_i16(x) ((int16_t) (int64_t) (x))-#define sext_i64_i32(x) ((int32_t) (int64_t) (x))-#define sext_i64_i64(x) ((int64_t) (int64_t) (x))-#define zext_i8_i8(x) ((int8_t) (uint8_t) (x))-#define zext_i8_i16(x) ((int16_t) (uint8_t) (x))-#define zext_i8_i32(x) ((int32_t) (uint8_t) (x))-#define zext_i8_i64(x) ((int64_t) (uint8_t) (x))-#define zext_i16_i8(x) ((int8_t) (uint16_t) (x))-#define zext_i16_i16(x) ((int16_t) (uint16_t) (x))-#define zext_i16_i32(x) ((int32_t) (uint16_t) (x))-#define zext_i16_i64(x) ((int64_t) (uint16_t) (x))-#define zext_i32_i8(x) ((int8_t) (uint32_t) (x))-#define zext_i32_i16(x) ((int16_t) (uint32_t) (x))-#define zext_i32_i32(x) ((int32_t) (uint32_t) (x))-#define zext_i32_i64(x) ((int64_t) (uint32_t) (x))-#define zext_i64_i8(x) ((int8_t) (uint64_t) (x))-#define zext_i64_i16(x) ((int16_t) (uint64_t) (x))-#define zext_i64_i32(x) ((int32_t) (uint64_t) (x))-#define zext_i64_i64(x) ((int64_t) (uint64_t) (x))--static int8_t abs8(int8_t x) {- return (int8_t)abs(x);-}--static int16_t abs16(int16_t x) {- return (int16_t)abs(x);-}--static int32_t abs32(int32_t x) {- return abs(x);-}--static int64_t abs64(int64_t x) {-#if defined(__OPENCL_VERSION__) || defined(ISPC)- return abs(x);-#else- return llabs(x);-#endif-}--#if defined(__OPENCL_VERSION__)-static int32_t futrts_popc8(int8_t x) {- return popcount(x);-}--static int32_t futrts_popc16(int16_t x) {- return popcount(x);-}--static int32_t futrts_popc32(int32_t x) {- return popcount(x);-}--static int32_t futrts_popc64(int64_t x) {- return popcount(x);-}-#elif defined(__CUDA_ARCH__)--static int32_t futrts_popc8(int8_t x) {- return __popc(zext_i8_i32(x));-}--static int32_t futrts_popc16(int16_t x) {- return __popc(zext_i16_i32(x));-}--static int32_t futrts_popc32(int32_t x) {- return __popc(x);-}--static int32_t futrts_popc64(int64_t x) {- return __popcll(x);-}--#else // Not OpenCL or CUDA, but plain C.--static int32_t futrts_popc8(uint8_t x) {- int c = 0;- for (; x; ++c) { x &= x - 1; }- return c;-}--static int32_t futrts_popc16(uint16_t x) {- int c = 0;- for (; x; ++c) { x &= x - 1; }- return c;-}--static int32_t futrts_popc32(uint32_t x) {- int c = 0;- for (; x; ++c) { x &= x - 1; }- return c;-}--static int32_t futrts_popc64(uint64_t x) {- int c = 0;- for (; x; ++c) { x &= x - 1; }- return c;-}-#endif--#if defined(__OPENCL_VERSION__)-static uint8_t futrts_umul_hi8 ( uint8_t a, uint8_t b) { return mul_hi(a, b); }-static uint16_t futrts_umul_hi16(uint16_t a, uint16_t b) { return mul_hi(a, b); }-static uint32_t futrts_umul_hi32(uint32_t a, uint32_t b) { return mul_hi(a, b); }-static uint64_t futrts_umul_hi64(uint64_t a, uint64_t b) { return mul_hi(a, b); }-static uint8_t futrts_smul_hi8 ( int8_t a, int8_t b) { return mul_hi(a, b); }-static uint16_t futrts_smul_hi16(int16_t a, int16_t b) { return mul_hi(a, b); }-static uint32_t futrts_smul_hi32(int32_t a, int32_t b) { return mul_hi(a, b); }-static uint64_t futrts_smul_hi64(int64_t a, int64_t b) { return mul_hi(a, b); }-#elif defined(__CUDA_ARCH__)-static uint8_t futrts_umul_hi8(uint8_t a, uint8_t b) { return ((uint16_t)a) * ((uint16_t)b) >> 8; }-static uint16_t futrts_umul_hi16(uint16_t a, uint16_t b) { return ((uint32_t)a) * ((uint32_t)b) >> 16; }-static uint32_t futrts_umul_hi32(uint32_t a, uint32_t b) { return __umulhi(a, b); }-static uint64_t futrts_umul_hi64(uint64_t a, uint64_t b) { return __umul64hi(a, b); }-static uint8_t futrts_smul_hi8 ( int8_t a, int8_t b) { return ((int16_t)a) * ((int16_t)b) >> 8; }-static uint16_t futrts_smul_hi16(int16_t a, int16_t b) { return ((int32_t)a) * ((int32_t)b) >> 16; }-static uint32_t futrts_smul_hi32(int32_t a, int32_t b) { return __mulhi(a, b); }-static uint64_t futrts_smul_hi64(int64_t a, int64_t b) { return __mul64hi(a, b); }-#elif ISPC-static uint8_t futrts_umul_hi8(uint8_t a, uint8_t b) { return ((uint16_t)a) * ((uint16_t)b) >> 8; }-static uint16_t futrts_umul_hi16(uint16_t a, uint16_t b) { return ((uint32_t)a) * ((uint32_t)b) >> 16; }-static uint32_t futrts_umul_hi32(uint32_t a, uint32_t b) { return ((uint64_t)a) * ((uint64_t)b) >> 32; }-static uint64_t futrts_umul_hi64(uint64_t a, uint64_t b) {- uint64_t ah = a >> 32;- uint64_t al = a & 0xffffffff;- uint64_t bh = b >> 32;- uint64_t bl = b & 0xffffffff;-- uint64_t p1 = al * bl;- uint64_t p2 = al * bh;- uint64_t p3 = ah * bl;- uint64_t p4 = ah * bh;-- uint64_t p1h = p1 >> 32;- uint64_t p2h = p2 >> 32;- uint64_t p3h = p3 >> 32;- uint64_t p2l = p2 & 0xffffffff;- uint64_t p3l = p3 & 0xffffffff;-- uint64_t l = p1h + p2l + p3l;- uint64_t m = (p2 >> 32) + (p3 >> 32);- uint64_t h = (l >> 32) + m + p4;-- return h;-}-static int8_t futrts_smul_hi8 ( int8_t a, int8_t b) { return ((uint16_t)a) * ((uint16_t)b) >> 8; }-static int16_t futrts_smul_hi16(int16_t a, int16_t b) { return ((uint32_t)a) * ((uint32_t)b) >> 16; }-static int32_t futrts_smul_hi32(int32_t a, int32_t b) { return ((uint64_t)a) * ((uint64_t)b) >> 32; }-static int64_t futrts_smul_hi64(int64_t a, int64_t b) {- uint64_t ah = a >> 32;- uint64_t al = a & 0xffffffff;- uint64_t bh = b >> 32;- uint64_t bl = b & 0xffffffff;-- uint64_t p1 = al * bl;- int64_t p2 = al * bh;- int64_t p3 = ah * bl;- uint64_t p4 = ah * bh;-- uint64_t p1h = p1 >> 32;- uint64_t p2h = p2 >> 32;- uint64_t p3h = p3 >> 32;- uint64_t p2l = p2 & 0xffffffff;- uint64_t p3l = p3 & 0xffffffff;-- uint64_t l = p1h + p2l + p3l;- uint64_t m = (p2 >> 32) + (p3 >> 32);- uint64_t h = (l >> 32) + m + p4;-- return h;-}--#else // Not OpenCL, ISPC, or CUDA, but plain C.-static uint8_t futrts_umul_hi8(uint8_t a, uint8_t b) { return ((uint16_t)a) * ((uint16_t)b) >> 8; }-static uint16_t futrts_umul_hi16(uint16_t a, uint16_t b) { return ((uint32_t)a) * ((uint32_t)b) >> 16; }-static uint32_t futrts_umul_hi32(uint32_t a, uint32_t b) { return ((uint64_t)a) * ((uint64_t)b) >> 32; }-static uint64_t futrts_umul_hi64(uint64_t a, uint64_t b) { return ((__uint128_t)a) * ((__uint128_t)b) >> 64; }-static int8_t futrts_smul_hi8(int8_t a, int8_t b) { return ((int16_t)a) * ((int16_t)b) >> 8; }-static int16_t futrts_smul_hi16(int16_t a, int16_t b) { return ((int32_t)a) * ((int32_t)b) >> 16; }-static int32_t futrts_smul_hi32(int32_t a, int32_t b) { return ((int64_t)a) * ((int64_t)b) >> 32; }-static int64_t futrts_smul_hi64(int64_t a, int64_t b) { return ((__int128_t)a) * ((__int128_t)b) >> 64; }-#endif--#if defined(__OPENCL_VERSION__)-static uint8_t futrts_umad_hi8 ( uint8_t a, uint8_t b, uint8_t c) { return mad_hi(a, b, c); }-static uint16_t futrts_umad_hi16(uint16_t a, uint16_t b, uint16_t c) { return mad_hi(a, b, c); }-static uint32_t futrts_umad_hi32(uint32_t a, uint32_t b, uint32_t c) { return mad_hi(a, b, c); }-static uint64_t futrts_umad_hi64(uint64_t a, uint64_t b, uint64_t c) { return mad_hi(a, b, c); }-static uint8_t futrts_smad_hi8( int8_t a, int8_t b, int8_t c) { return mad_hi(a, b, c); }-static uint16_t futrts_smad_hi16(int16_t a, int16_t b, int16_t c) { return mad_hi(a, b, c); }-static uint32_t futrts_smad_hi32(int32_t a, int32_t b, int32_t c) { return mad_hi(a, b, c); }-static uint64_t futrts_smad_hi64(int64_t a, int64_t b, int64_t c) { return mad_hi(a, b, c); }-#else // Not OpenCL--static uint8_t futrts_umad_hi8( uint8_t a, uint8_t b, uint8_t c) { return futrts_umul_hi8(a, b) + c; }-static uint16_t futrts_umad_hi16(uint16_t a, uint16_t b, uint16_t c) { return futrts_umul_hi16(a, b) + c; }-static uint32_t futrts_umad_hi32(uint32_t a, uint32_t b, uint32_t c) { return futrts_umul_hi32(a, b) + c; }-static uint64_t futrts_umad_hi64(uint64_t a, uint64_t b, uint64_t c) { return futrts_umul_hi64(a, b) + c; }-static uint8_t futrts_smad_hi8 ( int8_t a, int8_t b, int8_t c) { return futrts_smul_hi8(a, b) + c; }-static uint16_t futrts_smad_hi16(int16_t a, int16_t b, int16_t c) { return futrts_smul_hi16(a, b) + c; }-static uint32_t futrts_smad_hi32(int32_t a, int32_t b, int32_t c) { return futrts_smul_hi32(a, b) + c; }-static uint64_t futrts_smad_hi64(int64_t a, int64_t b, int64_t c) { return futrts_smul_hi64(a, b) + c; }-#endif--#if defined(__OPENCL_VERSION__)-static int32_t futrts_clzz8(int8_t x) {- return clz(x);-}--static int32_t futrts_clzz16(int16_t x) {- return clz(x);-}--static int32_t futrts_clzz32(int32_t x) {- return clz(x);-}--static int32_t futrts_clzz64(int64_t x) {- return clz(x);-}--#elif defined(__CUDA_ARCH__)--static int32_t futrts_clzz8(int8_t x) {- return __clz(zext_i8_i32(x)) - 24;-}--static int32_t futrts_clzz16(int16_t x) {- return __clz(zext_i16_i32(x)) - 16;-}--static int32_t futrts_clzz32(int32_t x) {- return __clz(x);-}--static int32_t futrts_clzz64(int64_t x) {- return __clzll(x);-}--#elif ISPC--static int32_t futrts_clzz8(int8_t x) {- return count_leading_zeros((int32_t)(uint8_t)x)-24;-}--static int32_t futrts_clzz16(int16_t x) {- return count_leading_zeros((int32_t)(uint16_t)x)-16;-}--static int32_t futrts_clzz32(int32_t x) {- return count_leading_zeros(x);-}--static int32_t futrts_clzz64(int64_t x) {- return count_leading_zeros(x);-}--#else // Not OpenCL, ISPC or CUDA, but plain C.--static int32_t futrts_clzz8(int8_t x) {- return x == 0 ? 8 : __builtin_clz((uint32_t)zext_i8_i32(x)) - 24;-}--static int32_t futrts_clzz16(int16_t x) {- return x == 0 ? 16 : __builtin_clz((uint32_t)zext_i16_i32(x)) - 16;-}--static int32_t futrts_clzz32(int32_t x) {- return x == 0 ? 32 : __builtin_clz((uint32_t)x);-}--static int32_t futrts_clzz64(int64_t x) {- return x == 0 ? 64 : __builtin_clzll((uint64_t)x);-}-#endif--#if defined(__OPENCL_VERSION__)-static int32_t futrts_ctzz8(int8_t x) {- int i = 0;- for (; i < 8 && (x & 1) == 0; i++, x >>= 1)- ;- return i;-}--static int32_t futrts_ctzz16(int16_t x) {- int i = 0;- for (; i < 16 && (x & 1) == 0; i++, x >>= 1)- ;- return i;-}--static int32_t futrts_ctzz32(int32_t x) {- int i = 0;- for (; i < 32 && (x & 1) == 0; i++, x >>= 1)- ;- return i;-}--static int32_t futrts_ctzz64(int64_t x) {- int i = 0;- for (; i < 64 && (x & 1) == 0; i++, x >>= 1)- ;- return i;-}--#elif defined(__CUDA_ARCH__)--static int32_t futrts_ctzz8(int8_t x) {- int y = __ffs(x);- return y == 0 ? 8 : y - 1;-}--static int32_t futrts_ctzz16(int16_t x) {- int y = __ffs(x);- return y == 0 ? 16 : y - 1;-}--static int32_t futrts_ctzz32(int32_t x) {- int y = __ffs(x);- return y == 0 ? 32 : y - 1;-}--static int32_t futrts_ctzz64(int64_t x) {- int y = __ffsll(x);- return y == 0 ? 64 : y - 1;-}--#elif ISPC--static int32_t futrts_ctzz8(int8_t x) {- return x == 0 ? 8 : count_trailing_zeros((int32_t)x);-}--static int32_t futrts_ctzz16(int16_t x) {- return x == 0 ? 16 : count_trailing_zeros((int32_t)x);-}--static int32_t futrts_ctzz32(int32_t x) {- return count_trailing_zeros(x);-}--static int32_t futrts_ctzz64(int64_t x) {- return count_trailing_zeros(x);-}--#else // Not OpenCL or CUDA, but plain C.--static int32_t futrts_ctzz8(int8_t x) {- return x == 0 ? 8 : __builtin_ctz((uint32_t)x);-}--static int32_t futrts_ctzz16(int16_t x) {- return x == 0 ? 16 : __builtin_ctz((uint32_t)x);-}--static int32_t futrts_ctzz32(int32_t x) {- return x == 0 ? 32 : __builtin_ctz((uint32_t)x);-}--static int32_t futrts_ctzz64(int64_t x) {- return x == 0 ? 64 : __builtin_ctzll((uint64_t)x);-}-#endif--static inline float fdiv32(float x, float y) {- return x / y;-}--static inline float fadd32(float x, float y) {- return x + y;-}--static inline float fsub32(float x, float y) {- return x - y;-}--static inline float fmul32(float x, float y) {- return x * y;-}--static inline bool cmplt32(float x, float y) {- return x < y;-}--static inline bool cmple32(float x, float y) {- return x <= y;-}--static inline float sitofp_i8_f32(int8_t x) {- return (float) x;-}--static inline float sitofp_i16_f32(int16_t x) {- return (float) x;-}--static inline float sitofp_i32_f32(int32_t x) {- return (float) x;-}--static inline float sitofp_i64_f32(int64_t x) {- return (float) x;-}--static inline float uitofp_i8_f32(uint8_t x) {- return (float) x;-}--static inline float uitofp_i16_f32(uint16_t x) {- return (float) x;-}--static inline float uitofp_i32_f32(uint32_t x) {- return (float) x;-}--static inline float uitofp_i64_f32(uint64_t x) {- return (float) x;-}--#ifdef __OPENCL_VERSION__-static inline float fabs32(float x) {- return fabs(x);-}--static inline float fmax32(float x, float y) {- return fmax(x, y);-}--static inline float fmin32(float x, float y) {- return fmin(x, y);-}--static inline float fpow32(float x, float y) {- return pow(x, y);-}--#elif ISPC--static inline float fabs32(float x) {- return abs(x);-}--static inline float fmax32(float x, float y) {- return isnan(x) ? y : isnan(y) ? x : max(x, y);-}--static inline float fmin32(float x, float y) {- return isnan(x) ? y : isnan(y) ? x : min(x, y);-}--static inline float fpow32(float a, float b) {- float ret;- foreach_active (i) {- uniform float r = __stdlib_powf(extract(a, i), extract(b, i));- ret = insert(ret, i, r);- }- return ret;-}--#else // Not OpenCL, but CUDA or plain C.--static inline float fabs32(float x) {- return fabsf(x);-}--static inline float fmax32(float x, float y) {- return fmaxf(x, y);-}--static inline float fmin32(float x, float y) {- return fminf(x, y);-}--static inline float fpow32(float x, float y) {- return powf(x, y);-}-#endif--static inline bool futrts_isnan32(float x) {- return isnan(x);-}--#if ISPC--static inline bool futrts_isinf32(float x) {- return !isnan(x) && isnan(x - x);-}--static inline bool futrts_isfinite32(float x) {- return !isnan(x) && !futrts_isinf32(x);-}--#else--static inline bool futrts_isinf32(float x) {- return isinf(x);-}--#endif--static inline int8_t fptosi_f32_i8(float x) {- if (futrts_isnan32(x) || futrts_isinf32(x)) {- return 0;- } else {- return (int8_t) x;- }-}--static inline int16_t fptosi_f32_i16(float x) {- if (futrts_isnan32(x) || futrts_isinf32(x)) {- return 0;- } else {- return (int16_t) x;- }-}--static inline int32_t fptosi_f32_i32(float x) {- if (futrts_isnan32(x) || futrts_isinf32(x)) {- return 0;- } else {- return (int32_t) x;- }-}--static inline int64_t fptosi_f32_i64(float x) {- if (futrts_isnan32(x) || futrts_isinf32(x)) {- return 0;- } else {- return (int64_t) x;- };-}--static inline uint8_t fptoui_f32_i8(float x) {- if (futrts_isnan32(x) || futrts_isinf32(x)) {- return 0;- } else {- return (uint8_t) (int8_t) x;- }-}--static inline uint16_t fptoui_f32_i16(float x) {- if (futrts_isnan32(x) || futrts_isinf32(x)) {- return 0;- } else {- return (uint16_t) (int16_t) x;- }-}--static inline uint32_t fptoui_f32_i32(float x) {- if (futrts_isnan32(x) || futrts_isinf32(x)) {- return 0;- } else {- return (uint32_t) (int32_t) x;- }-}--static inline uint64_t fptoui_f32_i64(float x) {- if (futrts_isnan32(x) || futrts_isinf32(x)) {- return 0;- } else {- return (uint64_t) (int64_t) x;- }-}--static inline bool ftob_f32_bool(float x) {- return x != 0;-}--static inline float btof_bool_f32(bool x) {- return x ? 1 : 0;-}--#ifdef __OPENCL_VERSION__-static inline float futrts_log32(float x) {- return log(x);-}--static inline float futrts_log2_32(float x) {- return log2(x);-}--static inline float futrts_log10_32(float x) {- return log10(x);-}--static inline float futrts_log1p_32(float x) {- return log1p(x);-}--static inline float futrts_sqrt32(float x) {- return sqrt(x);-}--static inline float futrts_cbrt32(float x) {- return cbrt(x);-}--static inline float futrts_exp32(float x) {- return exp(x);-}--static inline float futrts_cos32(float x) {- return cos(x);-}--static inline float futrts_sin32(float x) {- return sin(x);-}--static inline float futrts_tan32(float x) {- return tan(x);-}--static inline float futrts_acos32(float x) {- return acos(x);-}--static inline float futrts_asin32(float x) {- return asin(x);-}--static inline float futrts_atan32(float x) {- return atan(x);-}--static inline float futrts_cosh32(float x) {- return cosh(x);-}--static inline float futrts_sinh32(float x) {- return sinh(x);-}--static inline float futrts_tanh32(float x) {- return tanh(x);-}--static inline float futrts_acosh32(float x) {- return acosh(x);-}--static inline float futrts_asinh32(float x) {- return asinh(x);-}--static inline float futrts_atanh32(float x) {- return atanh(x);-}--static inline float futrts_atan2_32(float x, float y) {- return atan2(x, y);-}--static inline float futrts_hypot32(float x, float y) {- return hypot(x, y);-}--static inline float futrts_gamma32(float x) {- return tgamma(x);-}--static inline float futrts_lgamma32(float x) {- return lgamma(x);-}--static inline float futrts_erf32(float x) {- return erf(x);-}--static inline float futrts_erfc32(float x) {- return erfc(x);-}--static inline float fmod32(float x, float y) {- return fmod(x, y);-}--static inline float futrts_round32(float x) {- return rint(x);-}--static inline float futrts_floor32(float x) {- return floor(x);-}--static inline float futrts_ceil32(float x) {- return ceil(x);-}--static inline float futrts_nextafter32(float x, float y) {- return nextafter(x, y);-}--static inline float futrts_lerp32(float v0, float v1, float t) {- return mix(v0, v1, t);-}--static inline float futrts_mad32(float a, float b, float c) {- return mad(a, b, c);-}--static inline float futrts_fma32(float a, float b, float c) {- return fma(a, b, c);-}--#elif ISPC--static inline float futrts_log32(float x) {- return futrts_isfinite32(x) || (futrts_isinf32(x) && x < 0)? log(x) : x;-}--static inline float futrts_log2_32(float x) {- return futrts_log32(x) / log(2.0f);-}--static inline float futrts_log10_32(float x) {- 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);-}--extern "C" unmasked uniform float cbrtf(uniform float);-static inline float futrts_cbrt32(float x) {- float res;- foreach_active (i) {- uniform float r = cbrtf(extract(x, i));- res = insert(res, i, r);- }- return res;-}--static inline float futrts_exp32(float x) {- return exp(x);-}--static inline float futrts_cos32(float x) {- return cos(x);-}--static inline float futrts_sin32(float x) {- return sin(x);-}--static inline float futrts_tan32(float x) {- return tan(x);-}--static inline float futrts_acos32(float x) {- return acos(x);-}--static inline float futrts_asin32(float x) {- return asin(x);-}--static inline float futrts_atan32(float x) {- return atan(x);-}--static inline float futrts_cosh32(float x) {- return (exp(x)+exp(-x)) / 2.0f;-}--static inline float futrts_sinh32(float x) {- return (exp(x)-exp(-x)) / 2.0f;-}--static inline float futrts_tanh32(float x) {- return futrts_sinh32(x)/futrts_cosh32(x);-}--static inline float futrts_acosh32(float x) {- float f = x+sqrt(x*x-1);- if(futrts_isfinite32(f)) return log(f);- return f;-}--static inline float futrts_asinh32(float x) {- float f = x+sqrt(x*x+1);- if(futrts_isfinite32(f)) return log(f);- return f;--}--static inline float futrts_atanh32(float x) {- float f = (1+x)/(1-x);- if(futrts_isfinite32(f)) return log(f)/2.0f;- return f;--}--static inline float futrts_atan2_32(float x, float y) {- return (x == 0.0f && y == 0.0f) ? 0.0f : atan2(x, y);-}--static inline float futrts_hypot32(float x, float y) {- if (futrts_isfinite32(x) && futrts_isfinite32(y)) {- x = abs(x);- y = abs(y);- float a;- float b;- if (x >= y){- a = x;- b = y;- } else {- a = y;- b = x;- }- if(b == 0){- return a;- }-- int e;- float an;- float bn;- an = frexp (a, &e);- bn = ldexp (b, - e);- float cn;- cn = sqrt (an * an + bn * bn);- return ldexp (cn, e);- } else {- if (futrts_isinf32(x) || futrts_isinf32(y)) return INFINITY;- else return x + y;- }--}--extern "C" unmasked uniform float tgammaf(uniform float x);-static inline float futrts_gamma32(float x) {- float res;- foreach_active (i) {- uniform float r = tgammaf(extract(x, i));- res = insert(res, i, r);- }- return res;-}--extern "C" unmasked uniform float lgammaf(uniform float x);-static inline float futrts_lgamma32(float x) {- float res;- foreach_active (i) {- uniform float r = lgammaf(extract(x, i));- res = insert(res, i, r);- }- return res;-}--extern "C" unmasked uniform float erff(uniform float x);-static inline float futrts_erf32(float x) {- float res;- foreach_active (i) {- uniform float r = erff(extract(x, i));- res = insert(res, i, r);- }- return res;-}--extern "C" unmasked uniform float erfcf(uniform float x);-static inline float futrts_erfc32(float x) {- float res;- foreach_active (i) {- uniform float r = erfcf(extract(x, i));- res = insert(res, i, r);- }- return res;-}--static inline float fmod32(float x, float y) {- return x - y * trunc(x/y);-}--static inline float futrts_round32(float x) {- return round(x);-}--static inline float futrts_floor32(float x) {- return floor(x);-}--static inline float futrts_ceil32(float x) {- return ceil(x);-}--extern "C" unmasked uniform float nextafterf(uniform float x, uniform float y);-static inline float futrts_nextafter32(float x, float y) {- float res;- foreach_active (i) {- uniform float r = nextafterf(extract(x, i), extract(y, i));- res = insert(res, i, r);- }- return res;-}--static inline float futrts_lerp32(float v0, float v1, float t) {- return v0 + (v1 - v0) * t;-}--static inline float futrts_mad32(float a, float b, float c) {- return a * b + c;-}--static inline float futrts_fma32(float a, float b, float c) {- return a * b + c;-}--#else // Not OpenCL or ISPC, but CUDA or plain C.--static inline float futrts_log32(float x) {- return logf(x);-}--static inline float futrts_log2_32(float x) {- return log2f(x);-}--static inline float futrts_log10_32(float x) {- return log10f(x);-}--static inline float futrts_log1p_32(float x) {- return log1pf(x);-}--static inline float futrts_sqrt32(float x) {- return sqrtf(x);-}--static inline float futrts_cbrt32(float x) {- return cbrtf(x);-}--static inline float futrts_exp32(float x) {- return expf(x);-}--static inline float futrts_cos32(float x) {- return cosf(x);-}--static inline float futrts_sin32(float x) {- return sinf(x);-}--static inline float futrts_tan32(float x) {- return tanf(x);-}--static inline float futrts_acos32(float x) {- return acosf(x);-}--static inline float futrts_asin32(float x) {- return asinf(x);-}--static inline float futrts_atan32(float x) {- return atanf(x);-}--static inline float futrts_cosh32(float x) {- return coshf(x);-}--static inline float futrts_sinh32(float x) {- return sinhf(x);-}--static inline float futrts_tanh32(float x) {- return tanhf(x);-}--static inline float futrts_acosh32(float x) {- return acoshf(x);-}--static inline float futrts_asinh32(float x) {- return asinhf(x);-}--static inline float futrts_atanh32(float x) {- return atanhf(x);-}--static inline float futrts_atan2_32(float x, float y) {- return atan2f(x, y);-}--static inline float futrts_hypot32(float x, float y) {- return hypotf(x, y);-}--static inline float futrts_gamma32(float x) {- return tgammaf(x);-}--static inline float futrts_lgamma32(float x) {- return lgammaf(x);-}--static inline float futrts_erf32(float x) {- return erff(x);-}--static inline float futrts_erfc32(float x) {- return erfcf(x);-}--static inline float fmod32(float x, float y) {- return fmodf(x, y);-}--static inline float futrts_round32(float x) {- return rintf(x);-}--static inline float futrts_floor32(float x) {- return floorf(x);-}--static inline float futrts_ceil32(float x) {- return ceilf(x);-}--static inline float futrts_nextafter32(float x, float y) {- return nextafterf(x, y);-}--static inline float futrts_lerp32(float v0, float v1, float t) {- return v0 + (v1 - v0) * t;-}--static inline float futrts_mad32(float a, float b, float c) {- return a * b + c;-}--static inline float futrts_fma32(float a, float b, float c) {- return fmaf(a, b, c);-}-#endif--#if ISPC-static inline int32_t futrts_to_bits32(float x) {- return intbits(x);-}--static inline float futrts_from_bits32(int32_t x) {- return floatbits(x);-}-#else-static inline int32_t futrts_to_bits32(float x) {- union {- float f;- int32_t t;- } p;-- p.f = x;- return p.t;-}--static inline float futrts_from_bits32(int32_t x) {- union {- int32_t f;- float t;- } p;-- p.f = x;- return p.t;-}-#endif--static inline float fsignum32(float x) {- return futrts_isnan32(x) ? x : (x > 0 ? 1 : 0) - (x < 0 ? 1 : 0);-}--#ifdef FUTHARK_F64_ENABLED--#if ISPC-static inline bool futrts_isinf64(float x) {- return !isnan(x) && isnan(x - x);-}--static inline bool futrts_isfinite64(float x) {- return !isnan(x) && !futrts_isinf64(x);-}--static inline double fdiv64(double x, double y) {- return x / y;-}--static inline double fadd64(double x, double y) {- return x + y;-}--static inline double fsub64(double x, double y) {- return x - y;-}--static inline double fmul64(double x, double y) {- return x * y;-}--static inline bool cmplt64(double x, double y) {- return x < y;-}--static inline bool cmple64(double x, double y) {- return x <= y;-}--static inline double sitofp_i8_f64(int8_t x) {- return (double) x;-}--static inline double sitofp_i16_f64(int16_t x) {- return (double) x;-}--static inline double sitofp_i32_f64(int32_t x) {- return (double) x;-}--static inline double sitofp_i64_f64(int64_t x) {- return (double) x;-}--static inline double uitofp_i8_f64(uint8_t x) {- return (double) x;-}--static inline double uitofp_i16_f64(uint16_t x) {- return (double) x;-}--static inline double uitofp_i32_f64(uint32_t x) {- return (double) x;-}--static inline double uitofp_i64_f64(uint64_t x) {- return (double) x;-}--static inline double fabs64(double x) {- return abs(x);-}--static inline double fmax64(double x, double y) {- return isnan(x) ? y : isnan(y) ? x : max(x, y);-}--static inline double fmin64(double x, double y) {- return isnan(x) ? y : isnan(y) ? x : min(x, y);-}--static inline double fpow64(double a, double b) {- float ret;- foreach_active (i) {- uniform float r = __stdlib_powf(extract(a, i), extract(b, i));- ret = insert(ret, i, r);- }- return ret;-}--static inline double futrts_log64(double x) {- return futrts_isfinite64(x) || (futrts_isinf64(x) && x < 0)? log(x) : x;-}--static inline double futrts_log2_64(double x) {- return futrts_log64(x)/log(2.0d);-}--static inline double futrts_log10_64(double x) {- 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);-}--extern "C" unmasked uniform double cbrt(uniform double);-static inline double futrts_cbrt64(double x) {- double res;- foreach_active (i) {- uniform double r = cbrtf(extract(x, i));- res = insert(res, i, r);- }- return res;-}--static inline double futrts_exp64(double x) {- return exp(x);-}--static inline double futrts_cos64(double x) {- return cos(x);-}--static inline double futrts_sin64(double x) {- return sin(x);-}--static inline double futrts_tan64(double x) {- return tan(x);-}--static inline double futrts_acos64(double x) {- return acos(x);-}--static inline double futrts_asin64(double x) {- return asin(x);-}--static inline double futrts_atan64(double x) {- return atan(x);-}--static inline double futrts_cosh64(double x) {- return (exp(x)+exp(-x)) / 2.0d;-}--static inline double futrts_sinh64(double x) {- return (exp(x)-exp(-x)) / 2.0d;-}--static inline double futrts_tanh64(double x) {- return futrts_sinh64(x)/futrts_cosh64(x);-}--static inline double futrts_acosh64(double x) {- double f = x+sqrt(x*x-1.0d);- if(futrts_isfinite64(f)) return log(f);- return f;-}--static inline double futrts_asinh64(double x) {- double f = x+sqrt(x*x+1.0d);- if(futrts_isfinite64(f)) return log(f);- return f;-}--static inline double futrts_atanh64(double x) {- double f = (1.0d+x)/(1.0d-x);- if(futrts_isfinite64(f)) return log(f)/2.0d;- return f;--}--static inline double futrts_atan2_64(double x, double y) {- return atan2(x, y);-}--extern "C" unmasked uniform double hypot(uniform double x, uniform double y);-static inline double futrts_hypot64(double x, double y) {- double res;- foreach_active (i) {- uniform double r = hypot(extract(x, i), extract(y, i));- res = insert(res, i, r);- }- return res;-}--extern "C" unmasked uniform double tgamma(uniform double x);-static inline double futrts_gamma64(double x) {- double res;- foreach_active (i) {- uniform double r = tgamma(extract(x, i));- res = insert(res, i, r);- }- return res;-}--extern "C" unmasked uniform double lgamma(uniform double x);-static inline double futrts_lgamma64(double x) {- double res;- foreach_active (i) {- uniform double r = lgamma(extract(x, i));- res = insert(res, i, r);- }- return res;-}--extern "C" unmasked uniform double erf(uniform double x);-static inline double futrts_erf64(double x) {- double res;- foreach_active (i) {- uniform double r = erf(extract(x, i));- res = insert(res, i, r);- }- return res;-}--extern "C" unmasked uniform double erfc(uniform double x);-static inline double futrts_erfc64(double x) {- double res;- foreach_active (i) {- uniform double r = erfc(extract(x, i));- res = insert(res, i, r);- }- return res;-}--static inline double futrts_fma64(double a, double b, double c) {- return a * b + c;-}--static inline double futrts_round64(double x) {- return round(x);-}--static inline double futrts_ceil64(double x) {- return ceil(x);-}--extern "C" unmasked uniform double nextafter(uniform float x, uniform double y);-static inline float futrts_nextafter64(double x, double y) {- double res;- foreach_active (i) {- uniform double r = nextafter(extract(x, i), extract(y, i));- res = insert(res, i, r);- }- return res;-}--static inline double futrts_floor64(double x) {- return floor(x);-}--static inline bool futrts_isnan64(double x) {- return isnan(x);-}--static inline int8_t fptosi_f64_i8(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (int8_t) x;- }-}--static inline int16_t fptosi_f64_i16(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (int16_t) x;- }-}--static inline int32_t fptosi_f64_i32(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (int32_t) x;- }-}--static inline int64_t fptosi_f64_i64(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (int64_t) x;- }-}--static inline uint8_t fptoui_f64_i8(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (uint8_t) (int8_t) x;- }-}--static inline uint16_t fptoui_f64_i16(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (uint16_t) (int16_t) x;- }-}--static inline uint32_t fptoui_f64_i32(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (uint32_t) (int32_t) x;- }-}--static inline uint64_t fptoui_f64_i64(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (uint64_t) (int64_t) x;- }-}--static inline bool ftob_f64_bool(double x) {- return x != 0.0;-}--static inline double btof_bool_f64(bool x) {- return x ? 1.0 : 0.0;-}--static inline int64_t futrts_to_bits64(double x) {- int64_t res;- foreach_active (i) {- uniform double tmp = extract(x, i);- uniform int64_t r = *((uniform int64_t* uniform)&tmp);- res = insert(res, i, r);- }- return res;-}--static inline double futrts_from_bits64(int64_t x) {- double res;- foreach_active (i) {- uniform int64_t tmp = extract(x, i);- uniform double r = *((uniform double* uniform)&tmp);- res = insert(res, i, r);- }- return res;-}--static inline double fmod64(double x, double y) {- return x - y * trunc(x/y);-}--static inline double fsignum64(double x) {- return futrts_isnan64(x) ? x : (x > 0 ? 1.0d : 0.0d) - (x < 0 ? 1.0d : 0.0d);-}--static inline double futrts_lerp64(double v0, double v1, double t) {- return v0 + (v1 - v0) * t;-}--static inline double futrts_mad64(double a, double b, double c) {- return a * b + c;-}--static inline float fpconv_f32_f32(float x) {- return (float) x;-}--static inline double fpconv_f32_f64(float x) {- return (double) x;-}--static inline float fpconv_f64_f32(double x) {- return (float) x;-}--static inline double fpconv_f64_f64(double x) {- return (double) x;-}--#else--static inline double fdiv64(double x, double y) {- return x / y;-}--static inline double fadd64(double x, double y) {- return x + y;-}--static inline double fsub64(double x, double y) {- return x - y;-}--static inline double fmul64(double x, double y) {- return x * y;-}--static inline bool cmplt64(double x, double y) {- return x < y;-}--static inline bool cmple64(double x, double y) {- return x <= y;-}--static inline double sitofp_i8_f64(int8_t x) {- return (double) x;-}--static inline double sitofp_i16_f64(int16_t x) {- return (double) x;-}--static inline double sitofp_i32_f64(int32_t x) {- return (double) x;-}--static inline double sitofp_i64_f64(int64_t x) {- return (double) x;-}--static inline double uitofp_i8_f64(uint8_t x) {- return (double) x;-}--static inline double uitofp_i16_f64(uint16_t x) {- return (double) x;-}--static inline double uitofp_i32_f64(uint32_t x) {- return (double) x;-}--static inline double uitofp_i64_f64(uint64_t x) {- return (double) x;-}--static inline double fabs64(double x) {- return fabs(x);-}--static inline double fmax64(double x, double y) {- return fmax(x, y);-}--static inline double fmin64(double x, double y) {- return fmin(x, y);-}--static inline double fpow64(double x, double y) {- return pow(x, y);-}--static inline double futrts_log64(double x) {- return log(x);-}--static inline double futrts_log2_64(double x) {- return log2(x);-}--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) {- return sqrt(x);-}--static inline double futrts_cbrt64(double x) {- return cbrt(x);-}--static inline double futrts_exp64(double x) {- return exp(x);-}--static inline double futrts_cos64(double x) {- return cos(x);-}--static inline double futrts_sin64(double x) {- return sin(x);-}--static inline double futrts_tan64(double x) {- return tan(x);-}--static inline double futrts_acos64(double x) {- return acos(x);-}--static inline double futrts_asin64(double x) {- return asin(x);-}--static inline double futrts_atan64(double x) {- return atan(x);-}--static inline double futrts_cosh64(double x) {- return cosh(x);-}--static inline double futrts_sinh64(double x) {- return sinh(x);-}--static inline double futrts_tanh64(double x) {- return tanh(x);-}--static inline double futrts_acosh64(double x) {- return acosh(x);-}--static inline double futrts_asinh64(double x) {- return asinh(x);-}--static inline double futrts_atanh64(double x) {- return atanh(x);-}--static inline double futrts_atan2_64(double x, double y) {- return atan2(x, y);-}--static inline double futrts_hypot64(double x, double y) {- return hypot(x, y);-}--static inline double futrts_gamma64(double x) {- return tgamma(x);-}--static inline double futrts_lgamma64(double x) {- return lgamma(x);-}--static inline double futrts_erf64(double x) {- return erf(x);-}--static inline double futrts_erfc64(double x) {- return erfc(x);-}--static inline double futrts_fma64(double a, double b, double c) {- return fma(a, b, c);-}--static inline double futrts_round64(double x) {- return rint(x);-}--static inline double futrts_ceil64(double x) {- return ceil(x);-}--static inline float futrts_nextafter64(float x, float y) {- return nextafter(x, y);-}--static inline double futrts_floor64(double x) {- return floor(x);-}--static inline bool futrts_isnan64(double x) {- return isnan(x);-}--static inline bool futrts_isinf64(double x) {- return isinf(x);-}--static inline int8_t fptosi_f64_i8(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (int8_t) x;- }-}--static inline int16_t fptosi_f64_i16(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (int16_t) x;- }-}--static inline int32_t fptosi_f64_i32(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (int32_t) x;- }-}--static inline int64_t fptosi_f64_i64(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (int64_t) x;- }-}--static inline uint8_t fptoui_f64_i8(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (uint8_t) (int8_t) x;- }-}--static inline uint16_t fptoui_f64_i16(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (uint16_t) (int16_t) x;- }-}--static inline uint32_t fptoui_f64_i32(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (uint32_t) (int32_t) x;- }-}--static inline uint64_t fptoui_f64_i64(double x) {- if (futrts_isnan64(x) || futrts_isinf64(x)) {- return 0;- } else {- return (uint64_t) (int64_t) x;- }-}--static inline bool ftob_f64_bool(double x) {- return x != 0;-}--static inline double btof_bool_f64(bool x) {- return x ? 1 : 0;-}--static inline int64_t futrts_to_bits64(double x) {- union {- double f;- int64_t t;- } p;-- p.f = x;- return p.t;-}--static inline double futrts_from_bits64(int64_t x) {- union {- int64_t f;- double t;- } p;-- p.f = x;- return p.t;-}--static inline double fmod64(double x, double y) {- return fmod(x, y);-}--static inline double fsignum64(double x) {- return futrts_isnan64(x) ? x : (x > 0) - (x < 0);-}--static inline double futrts_lerp64(double v0, double v1, double t) {-#ifdef __OPENCL_VERSION__- return mix(v0, v1, t);-#else- return v0 + (v1 - v0) * t;-#endif-}--static inline double futrts_mad64(double a, double b, double c) {-#ifdef __OPENCL_VERSION__- return mad(a, b, c);-#else- return a * b + c;-#endif-}--static inline float fpconv_f32_f32(float x) {- return (float) x;-}--static inline double fpconv_f32_f64(float x) {- return (double) x;-}--static inline float fpconv_f64_f32(double x) {- return (float) x;-}--static inline double fpconv_f64_f64(double x) {+SCALAR_FUN_ATTR uint8_t add8(uint8_t x, uint8_t y) {+ return x + y;+}++SCALAR_FUN_ATTR uint16_t add16(uint16_t x, uint16_t y) {+ return x + y;+}++SCALAR_FUN_ATTR uint32_t add32(uint32_t x, uint32_t y) {+ return x + y;+}++SCALAR_FUN_ATTR uint64_t add64(uint64_t x, uint64_t y) {+ return x + y;+}++SCALAR_FUN_ATTR uint8_t sub8(uint8_t x, uint8_t y) {+ return x - y;+}++SCALAR_FUN_ATTR uint16_t sub16(uint16_t x, uint16_t y) {+ return x - y;+}++SCALAR_FUN_ATTR uint32_t sub32(uint32_t x, uint32_t y) {+ return x - y;+}++SCALAR_FUN_ATTR uint64_t sub64(uint64_t x, uint64_t y) {+ return x - y;+}++SCALAR_FUN_ATTR uint8_t mul8(uint8_t x, uint8_t y) {+ return x * y;+}++SCALAR_FUN_ATTR uint16_t mul16(uint16_t x, uint16_t y) {+ return x * y;+}++SCALAR_FUN_ATTR uint32_t mul32(uint32_t x, uint32_t y) {+ return x * y;+}++SCALAR_FUN_ATTR uint64_t mul64(uint64_t x, uint64_t y) {+ return x * y;+}++#if ISPC++SCALAR_FUN_ATTR uint8_t udiv8(uint8_t x, uint8_t y) {+ // This strange pattern is used to prevent the ISPC compiler from+ // causing SIGFPEs and bogus results on divisions where inactive lanes+ // have 0-valued divisors. It ensures that any inactive lane instead+ // has a divisor of 1. https://github.com/ispc/ispc/issues/2292+ uint8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x / ys;+}++SCALAR_FUN_ATTR uint16_t udiv16(uint16_t x, uint16_t y) {+ uint16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x / ys;+}++SCALAR_FUN_ATTR uint32_t udiv32(uint32_t x, uint32_t y) {+ uint32_t ys = 1;+ foreach_active(i){+ ys = y;+ }+++ return x / ys;+}++SCALAR_FUN_ATTR uint64_t udiv64(uint64_t x, uint64_t y) {+ uint64_t ys = 1;+ foreach_active(i){+ ys = y;+ }+++ return x / ys;+}++SCALAR_FUN_ATTR uint8_t udiv_up8(uint8_t x, uint8_t y) {+ uint8_t ys = 1;+ foreach_active(i){+ ys = y;+ }+++ return (x + y - 1) / ys;+}++SCALAR_FUN_ATTR uint16_t udiv_up16(uint16_t x, uint16_t y) {+ uint16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return (x + y - 1) / ys;+}++SCALAR_FUN_ATTR uint32_t udiv_up32(uint32_t x, uint32_t y) {+ uint32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return (x + y - 1) / ys;+}++SCALAR_FUN_ATTR uint64_t udiv_up64(uint64_t x, uint64_t y) {+ uint64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return (x + y - 1) / ys;+}++SCALAR_FUN_ATTR uint8_t umod8(uint8_t x, uint8_t y) {+ uint8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x % ys;+}++SCALAR_FUN_ATTR uint16_t umod16(uint16_t x, uint16_t y) {+ uint16_t ys = 1;+ foreach_active(i){+ ys = y;+ }+++ return x % ys;+}++SCALAR_FUN_ATTR uint32_t umod32(uint32_t x, uint32_t y) {+ uint32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x % ys;+}++SCALAR_FUN_ATTR uint64_t umod64(uint64_t x, uint64_t y) {+ uint64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x % ys;+}++SCALAR_FUN_ATTR uint8_t udiv_safe8(uint8_t x, uint8_t y) {+ uint8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x / ys;+}++SCALAR_FUN_ATTR uint16_t udiv_safe16(uint16_t x, uint16_t y) {+ uint16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x / ys;+}++SCALAR_FUN_ATTR uint32_t udiv_safe32(uint32_t x, uint32_t y) {+ uint32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x / ys;+}++SCALAR_FUN_ATTR uint64_t udiv_safe64(uint64_t x, uint64_t y) {+ uint64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x / ys;+}++SCALAR_FUN_ATTR uint8_t udiv_up_safe8(uint8_t x, uint8_t y) {+ uint8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : (x + y - 1) / ys;+}++SCALAR_FUN_ATTR uint16_t udiv_up_safe16(uint16_t x, uint16_t y) {+ uint16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : (x + y - 1) / ys;+}++SCALAR_FUN_ATTR uint32_t udiv_up_safe32(uint32_t x, uint32_t y) {+ uint32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : (x + y - 1) / ys;+}++SCALAR_FUN_ATTR uint64_t udiv_up_safe64(uint64_t x, uint64_t y) {+ uint64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : (x + y - 1) / ys;+}++SCALAR_FUN_ATTR uint8_t umod_safe8(uint8_t x, uint8_t y) {+ uint8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x % ys;+}++SCALAR_FUN_ATTR uint16_t umod_safe16(uint16_t x, uint16_t y) {+ uint16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x % ys;+}++SCALAR_FUN_ATTR uint32_t umod_safe32(uint32_t x, uint32_t y) {+ uint32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x % ys;+}++SCALAR_FUN_ATTR uint64_t umod_safe64(uint64_t x, uint64_t y) {+ uint64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x % ys;+}++SCALAR_FUN_ATTR int8_t sdiv8(int8_t x, int8_t y) {+ int8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ int8_t q = x / ys;+ int8_t r = x % ys;++ return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++SCALAR_FUN_ATTR int16_t sdiv16(int16_t x, int16_t y) {+ int16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ int16_t q = x / ys;+ int16_t r = x % ys;++ return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++SCALAR_FUN_ATTR int32_t sdiv32(int32_t x, int32_t y) {+ int32_t ys = 1;+ foreach_active(i){+ ys = y;+ }+ int32_t q = x / ys;+ int32_t r = x % ys;++ return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++SCALAR_FUN_ATTR int64_t sdiv64(int64_t x, int64_t y) {+ int64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ int64_t q = x / ys;+ int64_t r = x % ys;++ return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++SCALAR_FUN_ATTR int8_t sdiv_up8(int8_t x, int8_t y) {+ return sdiv8(x + y - 1, y);+}++SCALAR_FUN_ATTR int16_t sdiv_up16(int16_t x, int16_t y) {+ return sdiv16(x + y - 1, y);+}++SCALAR_FUN_ATTR int32_t sdiv_up32(int32_t x, int32_t y) {+ return sdiv32(x + y - 1, y);+}++SCALAR_FUN_ATTR int64_t sdiv_up64(int64_t x, int64_t y) {+ return sdiv64(x + y - 1, y);+}++SCALAR_FUN_ATTR int8_t smod8(int8_t x, int8_t y) {+ int8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ int8_t r = x % ys;++ return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++SCALAR_FUN_ATTR int16_t smod16(int16_t x, int16_t y) {+ int16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ int16_t r = x % ys;++ return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++SCALAR_FUN_ATTR int32_t smod32(int32_t x, int32_t y) {+ int32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ int32_t r = x % ys;++ return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++SCALAR_FUN_ATTR int64_t smod64(int64_t x, int64_t y) {+ int64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ int64_t r = x % ys;++ return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++SCALAR_FUN_ATTR int8_t sdiv_safe8(int8_t x, int8_t y) {+ return y == 0 ? 0 : sdiv8(x, y);+}++SCALAR_FUN_ATTR int16_t sdiv_safe16(int16_t x, int16_t y) {+ return y == 0 ? 0 : sdiv16(x, y);+}++SCALAR_FUN_ATTR int32_t sdiv_safe32(int32_t x, int32_t y) {+ return y == 0 ? 0 : sdiv32(x, y);+}++SCALAR_FUN_ATTR int64_t sdiv_safe64(int64_t x, int64_t y) {+ return y == 0 ? 0 : sdiv64(x, y);+}++SCALAR_FUN_ATTR int8_t sdiv_up_safe8(int8_t x, int8_t y) {+ return sdiv_safe8(x + y - 1, y);+}++SCALAR_FUN_ATTR int16_t sdiv_up_safe16(int16_t x, int16_t y) {+ return sdiv_safe16(x + y - 1, y);+}++SCALAR_FUN_ATTR int32_t sdiv_up_safe32(int32_t x, int32_t y) {+ return sdiv_safe32(x + y - 1, y);+}++SCALAR_FUN_ATTR int64_t sdiv_up_safe64(int64_t x, int64_t y) {+ return sdiv_safe64(x + y - 1, y);+}++SCALAR_FUN_ATTR int8_t smod_safe8(int8_t x, int8_t y) {+ return y == 0 ? 0 : smod8(x, y);+}++SCALAR_FUN_ATTR int16_t smod_safe16(int16_t x, int16_t y) {+ return y == 0 ? 0 : smod16(x, y);+}++SCALAR_FUN_ATTR int32_t smod_safe32(int32_t x, int32_t y) {+ return y == 0 ? 0 : smod32(x, y);+}++SCALAR_FUN_ATTR int64_t smod_safe64(int64_t x, int64_t y) {+ return y == 0 ? 0 : smod64(x, y);+}++SCALAR_FUN_ATTR int8_t squot8(int8_t x, int8_t y) {+ int8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x / ys;+}++SCALAR_FUN_ATTR int16_t squot16(int16_t x, int16_t y) {+ int16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x / ys;+}++SCALAR_FUN_ATTR int32_t squot32(int32_t x, int32_t y) {+ int32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x / ys;+}++SCALAR_FUN_ATTR int64_t squot64(int64_t x, int64_t y) {+ int64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x / ys;+}++SCALAR_FUN_ATTR int8_t srem8(int8_t x, int8_t y) {+ int8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x % ys;+}++SCALAR_FUN_ATTR int16_t srem16(int16_t x, int16_t y) {+ int16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x % ys;+}++SCALAR_FUN_ATTR int32_t srem32(int32_t x, int32_t y) {+ int32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x % ys;+}++SCALAR_FUN_ATTR int64_t srem64(int64_t x, int64_t y) {+ int8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return x % ys;+}++SCALAR_FUN_ATTR int8_t squot_safe8(int8_t x, int8_t y) {+ int8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x / ys;+}++SCALAR_FUN_ATTR int16_t squot_safe16(int16_t x, int16_t y) {+ int16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x / ys;+}++SCALAR_FUN_ATTR int32_t squot_safe32(int32_t x, int32_t y) {+ int32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x / ys;+}++SCALAR_FUN_ATTR int64_t squot_safe64(int64_t x, int64_t y) {+ int64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x / ys;+}++SCALAR_FUN_ATTR int8_t srem_safe8(int8_t x, int8_t y) {+ int8_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x % ys;+}++SCALAR_FUN_ATTR int16_t srem_safe16(int16_t x, int16_t y) {+ int16_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x % ys;+}++SCALAR_FUN_ATTR int32_t srem_safe32(int32_t x, int32_t y) {+ int32_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x % ys;+}++SCALAR_FUN_ATTR int64_t srem_safe64(int64_t x, int64_t y) {+ int64_t ys = 1;+ foreach_active(i){+ ys = y;+ }++ return y == 0 ? 0 : x % ys;+}++#else++SCALAR_FUN_ATTR uint8_t udiv8(uint8_t x, uint8_t y) {+ return x / y;+}++SCALAR_FUN_ATTR uint16_t udiv16(uint16_t x, uint16_t y) {+ return x / y;+}++SCALAR_FUN_ATTR uint32_t udiv32(uint32_t x, uint32_t y) {+ return x / y;+}++SCALAR_FUN_ATTR uint64_t udiv64(uint64_t x, uint64_t y) {+ return x / y;+}++SCALAR_FUN_ATTR uint8_t udiv_up8(uint8_t x, uint8_t y) {+ return (x + y - 1) / y;+}++SCALAR_FUN_ATTR uint16_t udiv_up16(uint16_t x, uint16_t y) {+ return (x + y - 1) / y;+}++SCALAR_FUN_ATTR uint32_t udiv_up32(uint32_t x, uint32_t y) {+ return (x + y - 1) / y;+}++SCALAR_FUN_ATTR uint64_t udiv_up64(uint64_t x, uint64_t y) {+ return (x + y - 1) / y;+}++SCALAR_FUN_ATTR uint8_t umod8(uint8_t x, uint8_t y) {+ return x % y;+}++SCALAR_FUN_ATTR uint16_t umod16(uint16_t x, uint16_t y) {+ return x % y;+}++SCALAR_FUN_ATTR uint32_t umod32(uint32_t x, uint32_t y) {+ return x % y;+}++SCALAR_FUN_ATTR uint64_t umod64(uint64_t x, uint64_t y) {+ return x % y;+}++SCALAR_FUN_ATTR uint8_t udiv_safe8(uint8_t x, uint8_t y) {+ return y == 0 ? 0 : x / y;+}++SCALAR_FUN_ATTR uint16_t udiv_safe16(uint16_t x, uint16_t y) {+ return y == 0 ? 0 : x / y;+}++SCALAR_FUN_ATTR uint32_t udiv_safe32(uint32_t x, uint32_t y) {+ return y == 0 ? 0 : x / y;+}++SCALAR_FUN_ATTR uint64_t udiv_safe64(uint64_t x, uint64_t y) {+ return y == 0 ? 0 : x / y;+}++SCALAR_FUN_ATTR uint8_t udiv_up_safe8(uint8_t x, uint8_t y) {+ return y == 0 ? 0 : (x + y - 1) / y;+}++SCALAR_FUN_ATTR uint16_t udiv_up_safe16(uint16_t x, uint16_t y) {+ return y == 0 ? 0 : (x + y - 1) / y;+}++SCALAR_FUN_ATTR uint32_t udiv_up_safe32(uint32_t x, uint32_t y) {+ return y == 0 ? 0 : (x + y - 1) / y;+}++SCALAR_FUN_ATTR uint64_t udiv_up_safe64(uint64_t x, uint64_t y) {+ return y == 0 ? 0 : (x + y - 1) / y;+}++SCALAR_FUN_ATTR uint8_t umod_safe8(uint8_t x, uint8_t y) {+ return y == 0 ? 0 : x % y;+}++SCALAR_FUN_ATTR uint16_t umod_safe16(uint16_t x, uint16_t y) {+ return y == 0 ? 0 : x % y;+}++SCALAR_FUN_ATTR uint32_t umod_safe32(uint32_t x, uint32_t y) {+ return y == 0 ? 0 : x % y;+}++SCALAR_FUN_ATTR uint64_t umod_safe64(uint64_t x, uint64_t y) {+ return y == 0 ? 0 : x % y;+}++SCALAR_FUN_ATTR int8_t sdiv8(int8_t x, int8_t y) {+ int8_t q = x / y;+ int8_t r = x % y;++ return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++SCALAR_FUN_ATTR int16_t sdiv16(int16_t x, int16_t y) {+ int16_t q = x / y;+ int16_t r = x % y;++ return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++SCALAR_FUN_ATTR int32_t sdiv32(int32_t x, int32_t y) {+ int32_t q = x / y;+ int32_t r = x % y;++ return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++SCALAR_FUN_ATTR int64_t sdiv64(int64_t x, int64_t y) {+ int64_t q = x / y;+ int64_t r = x % y;++ return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++SCALAR_FUN_ATTR int8_t sdiv_up8(int8_t x, int8_t y) {+ return sdiv8(x + y - 1, y);+}++SCALAR_FUN_ATTR int16_t sdiv_up16(int16_t x, int16_t y) {+ return sdiv16(x + y - 1, y);+}++SCALAR_FUN_ATTR int32_t sdiv_up32(int32_t x, int32_t y) {+ return sdiv32(x + y - 1, y);+}++SCALAR_FUN_ATTR int64_t sdiv_up64(int64_t x, int64_t y) {+ return sdiv64(x + y - 1, y);+}++SCALAR_FUN_ATTR int8_t smod8(int8_t x, int8_t y) {+ int8_t r = x % y;++ return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++SCALAR_FUN_ATTR int16_t smod16(int16_t x, int16_t y) {+ int16_t r = x % y;++ return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++SCALAR_FUN_ATTR int32_t smod32(int32_t x, int32_t y) {+ int32_t r = x % y;++ return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++SCALAR_FUN_ATTR int64_t smod64(int64_t x, int64_t y) {+ int64_t r = x % y;++ return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++SCALAR_FUN_ATTR int8_t sdiv_safe8(int8_t x, int8_t y) {+ return y == 0 ? 0 : sdiv8(x, y);+}++SCALAR_FUN_ATTR int16_t sdiv_safe16(int16_t x, int16_t y) {+ return y == 0 ? 0 : sdiv16(x, y);+}++SCALAR_FUN_ATTR int32_t sdiv_safe32(int32_t x, int32_t y) {+ return y == 0 ? 0 : sdiv32(x, y);+}++SCALAR_FUN_ATTR int64_t sdiv_safe64(int64_t x, int64_t y) {+ return y == 0 ? 0 : sdiv64(x, y);+}++SCALAR_FUN_ATTR int8_t sdiv_up_safe8(int8_t x, int8_t y) {+ return sdiv_safe8(x + y - 1, y);+}++SCALAR_FUN_ATTR int16_t sdiv_up_safe16(int16_t x, int16_t y) {+ return sdiv_safe16(x + y - 1, y);+}++SCALAR_FUN_ATTR int32_t sdiv_up_safe32(int32_t x, int32_t y) {+ return sdiv_safe32(x + y - 1, y);+}++SCALAR_FUN_ATTR int64_t sdiv_up_safe64(int64_t x, int64_t y) {+ return sdiv_safe64(x + y - 1, y);+}++SCALAR_FUN_ATTR int8_t smod_safe8(int8_t x, int8_t y) {+ return y == 0 ? 0 : smod8(x, y);+}++SCALAR_FUN_ATTR int16_t smod_safe16(int16_t x, int16_t y) {+ return y == 0 ? 0 : smod16(x, y);+}++SCALAR_FUN_ATTR int32_t smod_safe32(int32_t x, int32_t y) {+ return y == 0 ? 0 : smod32(x, y);+}++SCALAR_FUN_ATTR int64_t smod_safe64(int64_t x, int64_t y) {+ return y == 0 ? 0 : smod64(x, y);+}++SCALAR_FUN_ATTR int8_t squot8(int8_t x, int8_t y) {+ return x / y;+}++SCALAR_FUN_ATTR int16_t squot16(int16_t x, int16_t y) {+ return x / y;+}++SCALAR_FUN_ATTR int32_t squot32(int32_t x, int32_t y) {+ return x / y;+}++SCALAR_FUN_ATTR int64_t squot64(int64_t x, int64_t y) {+ return x / y;+}++SCALAR_FUN_ATTR int8_t srem8(int8_t x, int8_t y) {+ return x % y;+}++SCALAR_FUN_ATTR int16_t srem16(int16_t x, int16_t y) {+ return x % y;+}++SCALAR_FUN_ATTR int32_t srem32(int32_t x, int32_t y) {+ return x % y;+}++SCALAR_FUN_ATTR int64_t srem64(int64_t x, int64_t y) {+ return x % y;+}++SCALAR_FUN_ATTR int8_t squot_safe8(int8_t x, int8_t y) {+ return y == 0 ? 0 : x / y;+}++SCALAR_FUN_ATTR int16_t squot_safe16(int16_t x, int16_t y) {+ return y == 0 ? 0 : x / y;+}++SCALAR_FUN_ATTR int32_t squot_safe32(int32_t x, int32_t y) {+ return y == 0 ? 0 : x / y;+}++SCALAR_FUN_ATTR int64_t squot_safe64(int64_t x, int64_t y) {+ return y == 0 ? 0 : x / y;+}++SCALAR_FUN_ATTR int8_t srem_safe8(int8_t x, int8_t y) {+ return y == 0 ? 0 : x % y;+}++SCALAR_FUN_ATTR int16_t srem_safe16(int16_t x, int16_t y) {+ return y == 0 ? 0 : x % y;+}++SCALAR_FUN_ATTR int32_t srem_safe32(int32_t x, int32_t y) {+ return y == 0 ? 0 : x % y;+}++SCALAR_FUN_ATTR int64_t srem_safe64(int64_t x, int64_t y) {+ return y == 0 ? 0 : x % y;+}++#endif++SCALAR_FUN_ATTR int8_t smin8(int8_t x, int8_t y) {+ return x < y ? x : y;+}++SCALAR_FUN_ATTR int16_t smin16(int16_t x, int16_t y) {+ return x < y ? x : y;+}++SCALAR_FUN_ATTR int32_t smin32(int32_t x, int32_t y) {+ return x < y ? x : y;+}++SCALAR_FUN_ATTR int64_t smin64(int64_t x, int64_t y) {+ return x < y ? x : y;+}++SCALAR_FUN_ATTR uint8_t umin8(uint8_t x, uint8_t y) {+ return x < y ? x : y;+}++SCALAR_FUN_ATTR uint16_t umin16(uint16_t x, uint16_t y) {+ return x < y ? x : y;+}++SCALAR_FUN_ATTR uint32_t umin32(uint32_t x, uint32_t y) {+ return x < y ? x : y;+}++SCALAR_FUN_ATTR uint64_t umin64(uint64_t x, uint64_t y) {+ return x < y ? x : y;+}++SCALAR_FUN_ATTR int8_t smax8(int8_t x, int8_t y) {+ return x < y ? y : x;+}++SCALAR_FUN_ATTR int16_t smax16(int16_t x, int16_t y) {+ return x < y ? y : x;+}++SCALAR_FUN_ATTR int32_t smax32(int32_t x, int32_t y) {+ return x < y ? y : x;+}++SCALAR_FUN_ATTR int64_t smax64(int64_t x, int64_t y) {+ return x < y ? y : x;+}++SCALAR_FUN_ATTR uint8_t umax8(uint8_t x, uint8_t y) {+ return x < y ? y : x;+}++SCALAR_FUN_ATTR uint16_t umax16(uint16_t x, uint16_t y) {+ return x < y ? y : x;+}++SCALAR_FUN_ATTR uint32_t umax32(uint32_t x, uint32_t y) {+ return x < y ? y : x;+}++SCALAR_FUN_ATTR uint64_t umax64(uint64_t x, uint64_t y) {+ return x < y ? y : x;+}++SCALAR_FUN_ATTR uint8_t shl8(uint8_t x, uint8_t y) {+ return (uint8_t)(x << y);+}++SCALAR_FUN_ATTR uint16_t shl16(uint16_t x, uint16_t y) {+ return (uint16_t)(x << y);+}++SCALAR_FUN_ATTR uint32_t shl32(uint32_t x, uint32_t y) {+ return x << y;+}++SCALAR_FUN_ATTR uint64_t shl64(uint64_t x, uint64_t y) {+ return x << y;+}++SCALAR_FUN_ATTR uint8_t lshr8(uint8_t x, uint8_t y) {+ return x >> y;+}++SCALAR_FUN_ATTR uint16_t lshr16(uint16_t x, uint16_t y) {+ return x >> y;+}++SCALAR_FUN_ATTR uint32_t lshr32(uint32_t x, uint32_t y) {+ return x >> y;+}++SCALAR_FUN_ATTR uint64_t lshr64(uint64_t x, uint64_t y) {+ return x >> y;+}++SCALAR_FUN_ATTR int8_t ashr8(int8_t x, int8_t y) {+ return x >> y;+}++SCALAR_FUN_ATTR int16_t ashr16(int16_t x, int16_t y) {+ return x >> y;+}++SCALAR_FUN_ATTR int32_t ashr32(int32_t x, int32_t y) {+ return x >> y;+}++SCALAR_FUN_ATTR int64_t ashr64(int64_t x, int64_t y) {+ return x >> y;+}++SCALAR_FUN_ATTR uint8_t and8(uint8_t x, uint8_t y) {+ return x & y;+}++SCALAR_FUN_ATTR uint16_t and16(uint16_t x, uint16_t y) {+ return x & y;+}++SCALAR_FUN_ATTR uint32_t and32(uint32_t x, uint32_t y) {+ return x & y;+}++SCALAR_FUN_ATTR uint64_t and64(uint64_t x, uint64_t y) {+ return x & y;+}++SCALAR_FUN_ATTR uint8_t or8(uint8_t x, uint8_t y) {+ return x | y;+}++SCALAR_FUN_ATTR uint16_t or16(uint16_t x, uint16_t y) {+ return x | y;+}++SCALAR_FUN_ATTR uint32_t or32(uint32_t x, uint32_t y) {+ return x | y;+}++SCALAR_FUN_ATTR uint64_t or64(uint64_t x, uint64_t y) {+ return x | y;+}++SCALAR_FUN_ATTR uint8_t xor8(uint8_t x, uint8_t y) {+ return x ^ y;+}++SCALAR_FUN_ATTR uint16_t xor16(uint16_t x, uint16_t y) {+ return x ^ y;+}++SCALAR_FUN_ATTR uint32_t xor32(uint32_t x, uint32_t y) {+ return x ^ y;+}++SCALAR_FUN_ATTR uint64_t xor64(uint64_t x, uint64_t y) {+ return x ^ y;+}++SCALAR_FUN_ATTR bool ult8(uint8_t x, uint8_t y) {+ return x < y;+}++SCALAR_FUN_ATTR bool ult16(uint16_t x, uint16_t y) {+ return x < y;+}++SCALAR_FUN_ATTR bool ult32(uint32_t x, uint32_t y) {+ return x < y;+}++SCALAR_FUN_ATTR bool ult64(uint64_t x, uint64_t y) {+ return x < y;+}++SCALAR_FUN_ATTR bool ule8(uint8_t x, uint8_t y) {+ return x <= y;+}++SCALAR_FUN_ATTR bool ule16(uint16_t x, uint16_t y) {+ return x <= y;+}++SCALAR_FUN_ATTR bool ule32(uint32_t x, uint32_t y) {+ return x <= y;+}++SCALAR_FUN_ATTR bool ule64(uint64_t x, uint64_t y) {+ return x <= y;+}++SCALAR_FUN_ATTR bool slt8(int8_t x, int8_t y) {+ return x < y;+}++SCALAR_FUN_ATTR bool slt16(int16_t x, int16_t y) {+ return x < y;+}++SCALAR_FUN_ATTR bool slt32(int32_t x, int32_t y) {+ return x < y;+}++SCALAR_FUN_ATTR bool slt64(int64_t x, int64_t y) {+ return x < y;+}++SCALAR_FUN_ATTR bool sle8(int8_t x, int8_t y) {+ return x <= y;+}++SCALAR_FUN_ATTR bool sle16(int16_t x, int16_t y) {+ return x <= y;+}++SCALAR_FUN_ATTR bool sle32(int32_t x, int32_t y) {+ return x <= y;+}++SCALAR_FUN_ATTR bool sle64(int64_t x, int64_t y) {+ return x <= y;+}++SCALAR_FUN_ATTR uint8_t pow8(uint8_t x, uint8_t y) {+ uint8_t res = 1, rem = y;++ while (rem != 0) {+ if (rem & 1)+ res *= x;+ rem >>= 1;+ x *= x;+ }+ return res;+}++SCALAR_FUN_ATTR uint16_t pow16(uint16_t x, uint16_t y) {+ uint16_t res = 1, rem = y;++ while (rem != 0) {+ if (rem & 1)+ res *= x;+ rem >>= 1;+ x *= x;+ }+ return res;+}++SCALAR_FUN_ATTR uint32_t pow32(uint32_t x, uint32_t y) {+ uint32_t res = 1, rem = y;++ while (rem != 0) {+ if (rem & 1)+ res *= x;+ rem >>= 1;+ x *= x;+ }+ return res;+}++SCALAR_FUN_ATTR uint64_t pow64(uint64_t x, uint64_t y) {+ uint64_t res = 1, rem = y;++ while (rem != 0) {+ if (rem & 1)+ res *= x;+ rem >>= 1;+ x *= x;+ }+ return res;+}++SCALAR_FUN_ATTR bool itob_i8_bool(int8_t x) {+ return x != 0;+}++SCALAR_FUN_ATTR bool itob_i16_bool(int16_t x) {+ return x != 0;+}++SCALAR_FUN_ATTR bool itob_i32_bool(int32_t x) {+ return x != 0;+}++SCALAR_FUN_ATTR bool itob_i64_bool(int64_t x) {+ return x != 0;+}++SCALAR_FUN_ATTR int8_t btoi_bool_i8(bool x) {+ return x;+}++SCALAR_FUN_ATTR int16_t btoi_bool_i16(bool x) {+ return x;+}++SCALAR_FUN_ATTR int32_t btoi_bool_i32(bool x) {+ return x;+}++SCALAR_FUN_ATTR int64_t btoi_bool_i64(bool x) {+ return x;+}++#define sext_i8_i8(x) ((int8_t) (int8_t) (x))+#define sext_i8_i16(x) ((int16_t) (int8_t) (x))+#define sext_i8_i32(x) ((int32_t) (int8_t) (x))+#define sext_i8_i64(x) ((int64_t) (int8_t) (x))+#define sext_i16_i8(x) ((int8_t) (int16_t) (x))+#define sext_i16_i16(x) ((int16_t) (int16_t) (x))+#define sext_i16_i32(x) ((int32_t) (int16_t) (x))+#define sext_i16_i64(x) ((int64_t) (int16_t) (x))+#define sext_i32_i8(x) ((int8_t) (int32_t) (x))+#define sext_i32_i16(x) ((int16_t) (int32_t) (x))+#define sext_i32_i32(x) ((int32_t) (int32_t) (x))+#define sext_i32_i64(x) ((int64_t) (int32_t) (x))+#define sext_i64_i8(x) ((int8_t) (int64_t) (x))+#define sext_i64_i16(x) ((int16_t) (int64_t) (x))+#define sext_i64_i32(x) ((int32_t) (int64_t) (x))+#define sext_i64_i64(x) ((int64_t) (int64_t) (x))+#define zext_i8_i8(x) ((int8_t) (uint8_t) (x))+#define zext_i8_i16(x) ((int16_t) (uint8_t) (x))+#define zext_i8_i32(x) ((int32_t) (uint8_t) (x))+#define zext_i8_i64(x) ((int64_t) (uint8_t) (x))+#define zext_i16_i8(x) ((int8_t) (uint16_t) (x))+#define zext_i16_i16(x) ((int16_t) (uint16_t) (x))+#define zext_i16_i32(x) ((int32_t) (uint16_t) (x))+#define zext_i16_i64(x) ((int64_t) (uint16_t) (x))+#define zext_i32_i8(x) ((int8_t) (uint32_t) (x))+#define zext_i32_i16(x) ((int16_t) (uint32_t) (x))+#define zext_i32_i32(x) ((int32_t) (uint32_t) (x))+#define zext_i32_i64(x) ((int64_t) (uint32_t) (x))+#define zext_i64_i8(x) ((int8_t) (uint64_t) (x))+#define zext_i64_i16(x) ((int16_t) (uint64_t) (x))+#define zext_i64_i32(x) ((int32_t) (uint64_t) (x))+#define zext_i64_i64(x) ((int64_t) (uint64_t) (x))++SCALAR_FUN_ATTR int8_t abs8(int8_t x) {+ return (int8_t)abs(x);+}++SCALAR_FUN_ATTR int16_t abs16(int16_t x) {+ return (int16_t)abs(x);+}++SCALAR_FUN_ATTR int32_t abs32(int32_t x) {+ return abs(x);+}++SCALAR_FUN_ATTR int64_t abs64(int64_t x) {+#if defined(__OPENCL_VERSION__) || defined(ISPC)+ return abs(x);+#else+ return llabs(x);+#endif+}++#if defined(__OPENCL_VERSION__)+SCALAR_FUN_ATTR int32_t futrts_popc8(int8_t x) {+ return popcount(x);+}++SCALAR_FUN_ATTR int32_t futrts_popc16(int16_t x) {+ return popcount(x);+}++SCALAR_FUN_ATTR int32_t futrts_popc32(int32_t x) {+ return popcount(x);+}++SCALAR_FUN_ATTR int32_t futrts_popc64(int64_t x) {+ return popcount(x);+}+#elif defined(__CUDA_ARCH__)++SCALAR_FUN_ATTR int32_t futrts_popc8(int8_t x) {+ return __popc(zext_i8_i32(x));+}++SCALAR_FUN_ATTR int32_t futrts_popc16(int16_t x) {+ return __popc(zext_i16_i32(x));+}++SCALAR_FUN_ATTR int32_t futrts_popc32(int32_t x) {+ return __popc(x);+}++SCALAR_FUN_ATTR int32_t futrts_popc64(int64_t x) {+ return __popcll(x);+}++#else // Not OpenCL or CUDA, but plain C.++SCALAR_FUN_ATTR int32_t futrts_popc8(uint8_t x) {+ int c = 0;+ for (; x; ++c) { x &= x - 1; }+ return c;+}++SCALAR_FUN_ATTR int32_t futrts_popc16(uint16_t x) {+ int c = 0;+ for (; x; ++c) { x &= x - 1; }+ return c;+}++SCALAR_FUN_ATTR int32_t futrts_popc32(uint32_t x) {+ int c = 0;+ for (; x; ++c) { x &= x - 1; }+ return c;+}++SCALAR_FUN_ATTR int32_t futrts_popc64(uint64_t x) {+ int c = 0;+ for (; x; ++c) { x &= x - 1; }+ return c;+}+#endif++#if defined(__OPENCL_VERSION__)+SCALAR_FUN_ATTR uint8_t futrts_umul_hi8 ( uint8_t a, uint8_t b) { return mul_hi(a, b); }+SCALAR_FUN_ATTR uint16_t futrts_umul_hi16(uint16_t a, uint16_t b) { return mul_hi(a, b); }+SCALAR_FUN_ATTR uint32_t futrts_umul_hi32(uint32_t a, uint32_t b) { return mul_hi(a, b); }+SCALAR_FUN_ATTR uint64_t futrts_umul_hi64(uint64_t a, uint64_t b) { return mul_hi(a, b); }+SCALAR_FUN_ATTR uint8_t futrts_smul_hi8 ( int8_t a, int8_t b) { return mul_hi(a, b); }+SCALAR_FUN_ATTR uint16_t futrts_smul_hi16(int16_t a, int16_t b) { return mul_hi(a, b); }+SCALAR_FUN_ATTR uint32_t futrts_smul_hi32(int32_t a, int32_t b) { return mul_hi(a, b); }+SCALAR_FUN_ATTR uint64_t futrts_smul_hi64(int64_t a, int64_t b) { return mul_hi(a, b); }+#elif defined(__CUDA_ARCH__)+SCALAR_FUN_ATTR uint8_t futrts_umul_hi8(uint8_t a, uint8_t b) { return ((uint16_t)a) * ((uint16_t)b) >> 8; }+SCALAR_FUN_ATTR uint16_t futrts_umul_hi16(uint16_t a, uint16_t b) { return ((uint32_t)a) * ((uint32_t)b) >> 16; }+SCALAR_FUN_ATTR uint32_t futrts_umul_hi32(uint32_t a, uint32_t b) { return __umulhi(a, b); }+SCALAR_FUN_ATTR uint64_t futrts_umul_hi64(uint64_t a, uint64_t b) { return __umul64hi(a, b); }+SCALAR_FUN_ATTR uint8_t futrts_smul_hi8 ( int8_t a, int8_t b) { return ((int16_t)a) * ((int16_t)b) >> 8; }+SCALAR_FUN_ATTR uint16_t futrts_smul_hi16(int16_t a, int16_t b) { return ((int32_t)a) * ((int32_t)b) >> 16; }+SCALAR_FUN_ATTR uint32_t futrts_smul_hi32(int32_t a, int32_t b) { return __mulhi(a, b); }+SCALAR_FUN_ATTR uint64_t futrts_smul_hi64(int64_t a, int64_t b) { return __mul64hi(a, b); }+#elif ISPC+SCALAR_FUN_ATTR uint8_t futrts_umul_hi8(uint8_t a, uint8_t b) { return ((uint16_t)a) * ((uint16_t)b) >> 8; }+SCALAR_FUN_ATTR uint16_t futrts_umul_hi16(uint16_t a, uint16_t b) { return ((uint32_t)a) * ((uint32_t)b) >> 16; }+SCALAR_FUN_ATTR uint32_t futrts_umul_hi32(uint32_t a, uint32_t b) { return ((uint64_t)a) * ((uint64_t)b) >> 32; }+SCALAR_FUN_ATTR uint64_t futrts_umul_hi64(uint64_t a, uint64_t b) {+ uint64_t ah = a >> 32;+ uint64_t al = a & 0xffffffff;+ uint64_t bh = b >> 32;+ uint64_t bl = b & 0xffffffff;++ uint64_t p1 = al * bl;+ uint64_t p2 = al * bh;+ uint64_t p3 = ah * bl;+ uint64_t p4 = ah * bh;++ uint64_t p1h = p1 >> 32;+ uint64_t p2h = p2 >> 32;+ uint64_t p3h = p3 >> 32;+ uint64_t p2l = p2 & 0xffffffff;+ uint64_t p3l = p3 & 0xffffffff;++ uint64_t l = p1h + p2l + p3l;+ uint64_t m = (p2 >> 32) + (p3 >> 32);+ uint64_t h = (l >> 32) + m + p4;++ return h;+}+SCALAR_FUN_ATTR int8_t futrts_smul_hi8 ( int8_t a, int8_t b) { return ((uint16_t)a) * ((uint16_t)b) >> 8; }+SCALAR_FUN_ATTR int16_t futrts_smul_hi16(int16_t a, int16_t b) { return ((uint32_t)a) * ((uint32_t)b) >> 16; }+SCALAR_FUN_ATTR int32_t futrts_smul_hi32(int32_t a, int32_t b) { return ((uint64_t)a) * ((uint64_t)b) >> 32; }+SCALAR_FUN_ATTR int64_t futrts_smul_hi64(int64_t a, int64_t b) {+ uint64_t ah = a >> 32;+ uint64_t al = a & 0xffffffff;+ uint64_t bh = b >> 32;+ uint64_t bl = b & 0xffffffff;++ uint64_t p1 = al * bl;+ int64_t p2 = al * bh;+ int64_t p3 = ah * bl;+ uint64_t p4 = ah * bh;++ uint64_t p1h = p1 >> 32;+ uint64_t p2h = p2 >> 32;+ uint64_t p3h = p3 >> 32;+ uint64_t p2l = p2 & 0xffffffff;+ uint64_t p3l = p3 & 0xffffffff;++ uint64_t l = p1h + p2l + p3l;+ uint64_t m = (p2 >> 32) + (p3 >> 32);+ uint64_t h = (l >> 32) + m + p4;++ return h;+}++#else // Not OpenCL, ISPC, or CUDA, but plain C.+SCALAR_FUN_ATTR uint8_t futrts_umul_hi8(uint8_t a, uint8_t b) { return ((uint16_t)a) * ((uint16_t)b) >> 8; }+SCALAR_FUN_ATTR uint16_t futrts_umul_hi16(uint16_t a, uint16_t b) { return ((uint32_t)a) * ((uint32_t)b) >> 16; }+SCALAR_FUN_ATTR uint32_t futrts_umul_hi32(uint32_t a, uint32_t b) { return ((uint64_t)a) * ((uint64_t)b) >> 32; }+SCALAR_FUN_ATTR uint64_t futrts_umul_hi64(uint64_t a, uint64_t b) { return ((__uint128_t)a) * ((__uint128_t)b) >> 64; }+SCALAR_FUN_ATTR int8_t futrts_smul_hi8(int8_t a, int8_t b) { return ((int16_t)a) * ((int16_t)b) >> 8; }+SCALAR_FUN_ATTR int16_t futrts_smul_hi16(int16_t a, int16_t b) { return ((int32_t)a) * ((int32_t)b) >> 16; }+SCALAR_FUN_ATTR int32_t futrts_smul_hi32(int32_t a, int32_t b) { return ((int64_t)a) * ((int64_t)b) >> 32; }+SCALAR_FUN_ATTR int64_t futrts_smul_hi64(int64_t a, int64_t b) { return ((__int128_t)a) * ((__int128_t)b) >> 64; }+#endif++#if defined(__OPENCL_VERSION__)+SCALAR_FUN_ATTR uint8_t futrts_umad_hi8 ( uint8_t a, uint8_t b, uint8_t c) { return mad_hi(a, b, c); }+SCALAR_FUN_ATTR uint16_t futrts_umad_hi16(uint16_t a, uint16_t b, uint16_t c) { return mad_hi(a, b, c); }+SCALAR_FUN_ATTR uint32_t futrts_umad_hi32(uint32_t a, uint32_t b, uint32_t c) { return mad_hi(a, b, c); }+SCALAR_FUN_ATTR uint64_t futrts_umad_hi64(uint64_t a, uint64_t b, uint64_t c) { return mad_hi(a, b, c); }+SCALAR_FUN_ATTR uint8_t futrts_smad_hi8( int8_t a, int8_t b, int8_t c) { return mad_hi(a, b, c); }+SCALAR_FUN_ATTR uint16_t futrts_smad_hi16(int16_t a, int16_t b, int16_t c) { return mad_hi(a, b, c); }+SCALAR_FUN_ATTR uint32_t futrts_smad_hi32(int32_t a, int32_t b, int32_t c) { return mad_hi(a, b, c); }+SCALAR_FUN_ATTR uint64_t futrts_smad_hi64(int64_t a, int64_t b, int64_t c) { return mad_hi(a, b, c); }+#else // Not OpenCL++SCALAR_FUN_ATTR uint8_t futrts_umad_hi8( uint8_t a, uint8_t b, uint8_t c) { return futrts_umul_hi8(a, b) + c; }+SCALAR_FUN_ATTR uint16_t futrts_umad_hi16(uint16_t a, uint16_t b, uint16_t c) { return futrts_umul_hi16(a, b) + c; }+SCALAR_FUN_ATTR uint32_t futrts_umad_hi32(uint32_t a, uint32_t b, uint32_t c) { return futrts_umul_hi32(a, b) + c; }+SCALAR_FUN_ATTR uint64_t futrts_umad_hi64(uint64_t a, uint64_t b, uint64_t c) { return futrts_umul_hi64(a, b) + c; }+SCALAR_FUN_ATTR uint8_t futrts_smad_hi8 ( int8_t a, int8_t b, int8_t c) { return futrts_smul_hi8(a, b) + c; }+SCALAR_FUN_ATTR uint16_t futrts_smad_hi16(int16_t a, int16_t b, int16_t c) { return futrts_smul_hi16(a, b) + c; }+SCALAR_FUN_ATTR uint32_t futrts_smad_hi32(int32_t a, int32_t b, int32_t c) { return futrts_smul_hi32(a, b) + c; }+SCALAR_FUN_ATTR uint64_t futrts_smad_hi64(int64_t a, int64_t b, int64_t c) { return futrts_smul_hi64(a, b) + c; }+#endif++#if defined(__OPENCL_VERSION__)+SCALAR_FUN_ATTR int32_t futrts_clzz8(int8_t x) {+ return clz(x);+}++SCALAR_FUN_ATTR int32_t futrts_clzz16(int16_t x) {+ return clz(x);+}++SCALAR_FUN_ATTR int32_t futrts_clzz32(int32_t x) {+ return clz(x);+}++SCALAR_FUN_ATTR int32_t futrts_clzz64(int64_t x) {+ return clz(x);+}++#elif defined(__CUDA_ARCH__)++SCALAR_FUN_ATTR int32_t futrts_clzz8(int8_t x) {+ return __clz(zext_i8_i32(x)) - 24;+}++SCALAR_FUN_ATTR int32_t futrts_clzz16(int16_t x) {+ return __clz(zext_i16_i32(x)) - 16;+}++SCALAR_FUN_ATTR int32_t futrts_clzz32(int32_t x) {+ return __clz(x);+}++SCALAR_FUN_ATTR int32_t futrts_clzz64(int64_t x) {+ return __clzll(x);+}++#elif ISPC++SCALAR_FUN_ATTR int32_t futrts_clzz8(int8_t x) {+ return count_leading_zeros((int32_t)(uint8_t)x)-24;+}++SCALAR_FUN_ATTR int32_t futrts_clzz16(int16_t x) {+ return count_leading_zeros((int32_t)(uint16_t)x)-16;+}++SCALAR_FUN_ATTR int32_t futrts_clzz32(int32_t x) {+ return count_leading_zeros(x);+}++SCALAR_FUN_ATTR int32_t futrts_clzz64(int64_t x) {+ return count_leading_zeros(x);+}++#else // Not OpenCL, ISPC or CUDA, but plain C.++SCALAR_FUN_ATTR int32_t futrts_clzz8(int8_t x) {+ return x == 0 ? 8 : __builtin_clz((uint32_t)zext_i8_i32(x)) - 24;+}++SCALAR_FUN_ATTR int32_t futrts_clzz16(int16_t x) {+ return x == 0 ? 16 : __builtin_clz((uint32_t)zext_i16_i32(x)) - 16;+}++SCALAR_FUN_ATTR int32_t futrts_clzz32(int32_t x) {+ return x == 0 ? 32 : __builtin_clz((uint32_t)x);+}++SCALAR_FUN_ATTR int32_t futrts_clzz64(int64_t x) {+ return x == 0 ? 64 : __builtin_clzll((uint64_t)x);+}+#endif++#if defined(__OPENCL_VERSION__)+SCALAR_FUN_ATTR int32_t futrts_ctzz8(int8_t x) {+ int i = 0;+ for (; i < 8 && (x & 1) == 0; i++, x >>= 1)+ ;+ return i;+}++SCALAR_FUN_ATTR int32_t futrts_ctzz16(int16_t x) {+ int i = 0;+ for (; i < 16 && (x & 1) == 0; i++, x >>= 1)+ ;+ return i;+}++SCALAR_FUN_ATTR int32_t futrts_ctzz32(int32_t x) {+ int i = 0;+ for (; i < 32 && (x & 1) == 0; i++, x >>= 1)+ ;+ return i;+}++SCALAR_FUN_ATTR int32_t futrts_ctzz64(int64_t x) {+ int i = 0;+ for (; i < 64 && (x & 1) == 0; i++, x >>= 1)+ ;+ return i;+}++#elif defined(__CUDA_ARCH__)++SCALAR_FUN_ATTR int32_t futrts_ctzz8(int8_t x) {+ int y = __ffs(x);+ return y == 0 ? 8 : y - 1;+}++SCALAR_FUN_ATTR int32_t futrts_ctzz16(int16_t x) {+ int y = __ffs(x);+ return y == 0 ? 16 : y - 1;+}++SCALAR_FUN_ATTR int32_t futrts_ctzz32(int32_t x) {+ int y = __ffs(x);+ return y == 0 ? 32 : y - 1;+}++SCALAR_FUN_ATTR int32_t futrts_ctzz64(int64_t x) {+ int y = __ffsll(x);+ return y == 0 ? 64 : y - 1;+}++#elif ISPC++SCALAR_FUN_ATTR int32_t futrts_ctzz8(int8_t x) {+ return x == 0 ? 8 : count_trailing_zeros((int32_t)x);+}++SCALAR_FUN_ATTR int32_t futrts_ctzz16(int16_t x) {+ return x == 0 ? 16 : count_trailing_zeros((int32_t)x);+}++SCALAR_FUN_ATTR int32_t futrts_ctzz32(int32_t x) {+ return count_trailing_zeros(x);+}++SCALAR_FUN_ATTR int32_t futrts_ctzz64(int64_t x) {+ return count_trailing_zeros(x);+}++#else // Not OpenCL or CUDA, but plain C.++SCALAR_FUN_ATTR int32_t futrts_ctzz8(int8_t x) {+ return x == 0 ? 8 : __builtin_ctz((uint32_t)x);+}++SCALAR_FUN_ATTR int32_t futrts_ctzz16(int16_t x) {+ return x == 0 ? 16 : __builtin_ctz((uint32_t)x);+}++SCALAR_FUN_ATTR int32_t futrts_ctzz32(int32_t x) {+ return x == 0 ? 32 : __builtin_ctz((uint32_t)x);+}++SCALAR_FUN_ATTR int32_t futrts_ctzz64(int64_t x) {+ return x == 0 ? 64 : __builtin_ctzll((uint64_t)x);+}+#endif++SCALAR_FUN_ATTR float fdiv32(float x, float y) {+ return x / y;+}++SCALAR_FUN_ATTR float fadd32(float x, float y) {+ return x + y;+}++SCALAR_FUN_ATTR float fsub32(float x, float y) {+ return x - y;+}++SCALAR_FUN_ATTR float fmul32(float x, float y) {+ return x * y;+}++SCALAR_FUN_ATTR bool cmplt32(float x, float y) {+ return x < y;+}++SCALAR_FUN_ATTR bool cmple32(float x, float y) {+ return x <= y;+}++SCALAR_FUN_ATTR float sitofp_i8_f32(int8_t x) {+ return (float) x;+}++SCALAR_FUN_ATTR float sitofp_i16_f32(int16_t x) {+ return (float) x;+}++SCALAR_FUN_ATTR float sitofp_i32_f32(int32_t x) {+ return (float) x;+}++SCALAR_FUN_ATTR float sitofp_i64_f32(int64_t x) {+ return (float) x;+}++SCALAR_FUN_ATTR float uitofp_i8_f32(uint8_t x) {+ return (float) x;+}++SCALAR_FUN_ATTR float uitofp_i16_f32(uint16_t x) {+ return (float) x;+}++SCALAR_FUN_ATTR float uitofp_i32_f32(uint32_t x) {+ return (float) x;+}++SCALAR_FUN_ATTR float uitofp_i64_f32(uint64_t x) {+ return (float) x;+}++#ifdef __OPENCL_VERSION__+SCALAR_FUN_ATTR float fabs32(float x) {+ return fabs(x);+}++SCALAR_FUN_ATTR float fmax32(float x, float y) {+ return fmax(x, y);+}++SCALAR_FUN_ATTR float fmin32(float x, float y) {+ return fmin(x, y);+}++SCALAR_FUN_ATTR float fpow32(float x, float y) {+ return pow(x, y);+}++#elif ISPC++SCALAR_FUN_ATTR float fabs32(float x) {+ return abs(x);+}++SCALAR_FUN_ATTR float fmax32(float x, float y) {+ return isnan(x) ? y : isnan(y) ? x : max(x, y);+}++SCALAR_FUN_ATTR float fmin32(float x, float y) {+ return isnan(x) ? y : isnan(y) ? x : min(x, y);+}++SCALAR_FUN_ATTR float fpow32(float a, float b) {+ float ret;+ foreach_active (i) {+ uniform float r = __stdlib_powf(extract(a, i), extract(b, i));+ ret = insert(ret, i, r);+ }+ return ret;+}++#else // Not OpenCL, but CUDA or plain C.++SCALAR_FUN_ATTR float fabs32(float x) {+ return fabsf(x);+}++SCALAR_FUN_ATTR float fmax32(float x, float y) {+ return fmaxf(x, y);+}++SCALAR_FUN_ATTR float fmin32(float x, float y) {+ return fminf(x, y);+}++SCALAR_FUN_ATTR float fpow32(float x, float y) {+ return powf(x, y);+}+#endif++SCALAR_FUN_ATTR bool futrts_isnan32(float x) {+ return isnan(x);+}++#if ISPC++SCALAR_FUN_ATTR bool futrts_isinf32(float x) {+ return !isnan(x) && isnan(x - x);+}++SCALAR_FUN_ATTR bool futrts_isfinite32(float x) {+ return !isnan(x) && !futrts_isinf32(x);+}++#else++SCALAR_FUN_ATTR bool futrts_isinf32(float x) {+ return isinf(x);+}++#endif++SCALAR_FUN_ATTR int8_t fptosi_f32_i8(float x) {+ if (futrts_isnan32(x) || futrts_isinf32(x)) {+ return 0;+ } else {+ return (int8_t) x;+ }+}++SCALAR_FUN_ATTR int16_t fptosi_f32_i16(float x) {+ if (futrts_isnan32(x) || futrts_isinf32(x)) {+ return 0;+ } else {+ return (int16_t) x;+ }+}++SCALAR_FUN_ATTR int32_t fptosi_f32_i32(float x) {+ if (futrts_isnan32(x) || futrts_isinf32(x)) {+ return 0;+ } else {+ return (int32_t) x;+ }+}++SCALAR_FUN_ATTR int64_t fptosi_f32_i64(float x) {+ if (futrts_isnan32(x) || futrts_isinf32(x)) {+ return 0;+ } else {+ return (int64_t) x;+ };+}++SCALAR_FUN_ATTR uint8_t fptoui_f32_i8(float x) {+ if (futrts_isnan32(x) || futrts_isinf32(x)) {+ return 0;+ } else {+ return (uint8_t) (int8_t) x;+ }+}++SCALAR_FUN_ATTR uint16_t fptoui_f32_i16(float x) {+ if (futrts_isnan32(x) || futrts_isinf32(x)) {+ return 0;+ } else {+ return (uint16_t) (int16_t) x;+ }+}++SCALAR_FUN_ATTR uint32_t fptoui_f32_i32(float x) {+ if (futrts_isnan32(x) || futrts_isinf32(x)) {+ return 0;+ } else {+ return (uint32_t) (int32_t) x;+ }+}++SCALAR_FUN_ATTR uint64_t fptoui_f32_i64(float x) {+ if (futrts_isnan32(x) || futrts_isinf32(x)) {+ return 0;+ } else {+ return (uint64_t) (int64_t) x;+ }+}++SCALAR_FUN_ATTR bool ftob_f32_bool(float x) {+ return x != 0;+}++SCALAR_FUN_ATTR float btof_bool_f32(bool x) {+ return x ? 1 : 0;+}++#ifdef __OPENCL_VERSION__+SCALAR_FUN_ATTR float futrts_log32(float x) {+ return log(x);+}++SCALAR_FUN_ATTR float futrts_log2_32(float x) {+ return log2(x);+}++SCALAR_FUN_ATTR float futrts_log10_32(float x) {+ return log10(x);+}++SCALAR_FUN_ATTR float futrts_log1p_32(float x) {+ return log1p(x);+}++SCALAR_FUN_ATTR float futrts_sqrt32(float x) {+ return sqrt(x);+}++SCALAR_FUN_ATTR float futrts_cbrt32(float x) {+ return cbrt(x);+}++SCALAR_FUN_ATTR float futrts_exp32(float x) {+ return exp(x);+}++SCALAR_FUN_ATTR float futrts_cos32(float x) {+ return cos(x);+}++SCALAR_FUN_ATTR float futrts_sin32(float x) {+ return sin(x);+}++SCALAR_FUN_ATTR float futrts_tan32(float x) {+ return tan(x);+}++SCALAR_FUN_ATTR float futrts_acos32(float x) {+ return acos(x);+}++SCALAR_FUN_ATTR float futrts_asin32(float x) {+ return asin(x);+}++SCALAR_FUN_ATTR float futrts_atan32(float x) {+ return atan(x);+}++SCALAR_FUN_ATTR float futrts_cosh32(float x) {+ return cosh(x);+}++SCALAR_FUN_ATTR float futrts_sinh32(float x) {+ return sinh(x);+}++SCALAR_FUN_ATTR float futrts_tanh32(float x) {+ return tanh(x);+}++SCALAR_FUN_ATTR float futrts_acosh32(float x) {+ return acosh(x);+}++SCALAR_FUN_ATTR float futrts_asinh32(float x) {+ return asinh(x);+}++SCALAR_FUN_ATTR float futrts_atanh32(float x) {+ return atanh(x);+}++SCALAR_FUN_ATTR float futrts_atan2_32(float x, float y) {+ return atan2(x, y);+}++SCALAR_FUN_ATTR float futrts_hypot32(float x, float y) {+ return hypot(x, y);+}++SCALAR_FUN_ATTR float futrts_gamma32(float x) {+ return tgamma(x);+}++SCALAR_FUN_ATTR float futrts_lgamma32(float x) {+ return lgamma(x);+}++SCALAR_FUN_ATTR float futrts_erf32(float x) {+ return erf(x);+}++SCALAR_FUN_ATTR float futrts_erfc32(float x) {+ return erfc(x);+}++SCALAR_FUN_ATTR float fmod32(float x, float y) {+ return fmod(x, y);+}++SCALAR_FUN_ATTR float futrts_round32(float x) {+ return rint(x);+}++SCALAR_FUN_ATTR float futrts_floor32(float x) {+ return floor(x);+}++SCALAR_FUN_ATTR float futrts_ceil32(float x) {+ return ceil(x);+}++SCALAR_FUN_ATTR float futrts_nextafter32(float x, float y) {+ return nextafter(x, y);+}++SCALAR_FUN_ATTR float futrts_lerp32(float v0, float v1, float t) {+ return mix(v0, v1, t);+}++SCALAR_FUN_ATTR float futrts_mad32(float a, float b, float c) {+ return mad(a, b, c);+}++SCALAR_FUN_ATTR float futrts_fma32(float a, float b, float c) {+ return fma(a, b, c);+}++#elif ISPC++SCALAR_FUN_ATTR float futrts_log32(float x) {+ return futrts_isfinite32(x) || (futrts_isinf32(x) && x < 0)? log(x) : x;+}++SCALAR_FUN_ATTR float futrts_log2_32(float x) {+ return futrts_log32(x) / log(2.0f);+}++SCALAR_FUN_ATTR float futrts_log10_32(float x) {+ return futrts_log32(x) / log(10.0f);+}++SCALAR_FUN_ATTR 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;+}++SCALAR_FUN_ATTR float futrts_sqrt32(float x) {+ return sqrt(x);+}++extern "C" unmasked uniform float cbrtf(uniform float);+SCALAR_FUN_ATTR float futrts_cbrt32(float x) {+ float res;+ foreach_active (i) {+ uniform float r = cbrtf(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++SCALAR_FUN_ATTR float futrts_exp32(float x) {+ return exp(x);+}++SCALAR_FUN_ATTR float futrts_cos32(float x) {+ return cos(x);+}++SCALAR_FUN_ATTR float futrts_sin32(float x) {+ return sin(x);+}++SCALAR_FUN_ATTR float futrts_tan32(float x) {+ return tan(x);+}++SCALAR_FUN_ATTR float futrts_acos32(float x) {+ return acos(x);+}++SCALAR_FUN_ATTR float futrts_asin32(float x) {+ return asin(x);+}++SCALAR_FUN_ATTR float futrts_atan32(float x) {+ return atan(x);+}++SCALAR_FUN_ATTR float futrts_cosh32(float x) {+ return (exp(x)+exp(-x)) / 2.0f;+}++SCALAR_FUN_ATTR float futrts_sinh32(float x) {+ return (exp(x)-exp(-x)) / 2.0f;+}++SCALAR_FUN_ATTR float futrts_tanh32(float x) {+ return futrts_sinh32(x)/futrts_cosh32(x);+}++SCALAR_FUN_ATTR float futrts_acosh32(float x) {+ float f = x+sqrt(x*x-1);+ if(futrts_isfinite32(f)) return log(f);+ return f;+}++SCALAR_FUN_ATTR float futrts_asinh32(float x) {+ float f = x+sqrt(x*x+1);+ if(futrts_isfinite32(f)) return log(f);+ return f;++}++SCALAR_FUN_ATTR float futrts_atanh32(float x) {+ float f = (1+x)/(1-x);+ if(futrts_isfinite32(f)) return log(f)/2.0f;+ return f;++}++SCALAR_FUN_ATTR float futrts_atan2_32(float x, float y) {+ return (x == 0.0f && y == 0.0f) ? 0.0f : atan2(x, y);+}++SCALAR_FUN_ATTR float futrts_hypot32(float x, float y) {+ if (futrts_isfinite32(x) && futrts_isfinite32(y)) {+ x = abs(x);+ y = abs(y);+ float a;+ float b;+ if (x >= y){+ a = x;+ b = y;+ } else {+ a = y;+ b = x;+ }+ if(b == 0){+ return a;+ }++ int e;+ float an;+ float bn;+ an = frexp (a, &e);+ bn = ldexp (b, - e);+ float cn;+ cn = sqrt (an * an + bn * bn);+ return ldexp (cn, e);+ } else {+ if (futrts_isinf32(x) || futrts_isinf32(y)) return INFINITY;+ else return x + y;+ }++}++extern "C" unmasked uniform float tgammaf(uniform float x);+SCALAR_FUN_ATTR float futrts_gamma32(float x) {+ float res;+ foreach_active (i) {+ uniform float r = tgammaf(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++extern "C" unmasked uniform float lgammaf(uniform float x);+SCALAR_FUN_ATTR float futrts_lgamma32(float x) {+ float res;+ foreach_active (i) {+ uniform float r = lgammaf(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++extern "C" unmasked uniform float erff(uniform float x);+SCALAR_FUN_ATTR float futrts_erf32(float x) {+ float res;+ foreach_active (i) {+ uniform float r = erff(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++extern "C" unmasked uniform float erfcf(uniform float x);+SCALAR_FUN_ATTR float futrts_erfc32(float x) {+ float res;+ foreach_active (i) {+ uniform float r = erfcf(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++SCALAR_FUN_ATTR float fmod32(float x, float y) {+ return x - y * trunc(x/y);+}++SCALAR_FUN_ATTR float futrts_round32(float x) {+ return round(x);+}++SCALAR_FUN_ATTR float futrts_floor32(float x) {+ return floor(x);+}++SCALAR_FUN_ATTR float futrts_ceil32(float x) {+ return ceil(x);+}++extern "C" unmasked uniform float nextafterf(uniform float x, uniform float y);+SCALAR_FUN_ATTR float futrts_nextafter32(float x, float y) {+ float res;+ foreach_active (i) {+ uniform float r = nextafterf(extract(x, i), extract(y, i));+ res = insert(res, i, r);+ }+ return res;+}++SCALAR_FUN_ATTR float futrts_lerp32(float v0, float v1, float t) {+ return v0 + (v1 - v0) * t;+}++SCALAR_FUN_ATTR float futrts_mad32(float a, float b, float c) {+ return a * b + c;+}++SCALAR_FUN_ATTR float futrts_fma32(float a, float b, float c) {+ return a * b + c;+}++#else // Not OpenCL or ISPC, but CUDA or plain C.++SCALAR_FUN_ATTR float futrts_log32(float x) {+ return logf(x);+}++SCALAR_FUN_ATTR float futrts_log2_32(float x) {+ return log2f(x);+}++SCALAR_FUN_ATTR float futrts_log10_32(float x) {+ return log10f(x);+}++SCALAR_FUN_ATTR float futrts_log1p_32(float x) {+ return log1pf(x);+}++SCALAR_FUN_ATTR float futrts_sqrt32(float x) {+ return sqrtf(x);+}++SCALAR_FUN_ATTR float futrts_cbrt32(float x) {+ return cbrtf(x);+}++SCALAR_FUN_ATTR float futrts_exp32(float x) {+ return expf(x);+}++SCALAR_FUN_ATTR float futrts_cos32(float x) {+ return cosf(x);+}++SCALAR_FUN_ATTR float futrts_sin32(float x) {+ return sinf(x);+}++SCALAR_FUN_ATTR float futrts_tan32(float x) {+ return tanf(x);+}++SCALAR_FUN_ATTR float futrts_acos32(float x) {+ return acosf(x);+}++SCALAR_FUN_ATTR float futrts_asin32(float x) {+ return asinf(x);+}++SCALAR_FUN_ATTR float futrts_atan32(float x) {+ return atanf(x);+}++SCALAR_FUN_ATTR float futrts_cosh32(float x) {+ return coshf(x);+}++SCALAR_FUN_ATTR float futrts_sinh32(float x) {+ return sinhf(x);+}++SCALAR_FUN_ATTR float futrts_tanh32(float x) {+ return tanhf(x);+}++SCALAR_FUN_ATTR float futrts_acosh32(float x) {+ return acoshf(x);+}++SCALAR_FUN_ATTR float futrts_asinh32(float x) {+ return asinhf(x);+}++SCALAR_FUN_ATTR float futrts_atanh32(float x) {+ return atanhf(x);+}++SCALAR_FUN_ATTR float futrts_atan2_32(float x, float y) {+ return atan2f(x, y);+}++SCALAR_FUN_ATTR float futrts_hypot32(float x, float y) {+ return hypotf(x, y);+}++SCALAR_FUN_ATTR float futrts_gamma32(float x) {+ return tgammaf(x);+}++SCALAR_FUN_ATTR float futrts_lgamma32(float x) {+ return lgammaf(x);+}++SCALAR_FUN_ATTR float futrts_erf32(float x) {+ return erff(x);+}++SCALAR_FUN_ATTR float futrts_erfc32(float x) {+ return erfcf(x);+}++SCALAR_FUN_ATTR float fmod32(float x, float y) {+ return fmodf(x, y);+}++SCALAR_FUN_ATTR float futrts_round32(float x) {+ return rintf(x);+}++SCALAR_FUN_ATTR float futrts_floor32(float x) {+ return floorf(x);+}++SCALAR_FUN_ATTR float futrts_ceil32(float x) {+ return ceilf(x);+}++SCALAR_FUN_ATTR float futrts_nextafter32(float x, float y) {+ return nextafterf(x, y);+}++SCALAR_FUN_ATTR float futrts_lerp32(float v0, float v1, float t) {+ return v0 + (v1 - v0) * t;+}++SCALAR_FUN_ATTR float futrts_mad32(float a, float b, float c) {+ return a * b + c;+}++SCALAR_FUN_ATTR float futrts_fma32(float a, float b, float c) {+ return fmaf(a, b, c);+}+#endif++#if ISPC+SCALAR_FUN_ATTR int32_t futrts_to_bits32(float x) {+ return intbits(x);+}++SCALAR_FUN_ATTR float futrts_from_bits32(int32_t x) {+ return floatbits(x);+}+#else+SCALAR_FUN_ATTR int32_t futrts_to_bits32(float x) {+ union {+ float f;+ int32_t t;+ } p;++ p.f = x;+ return p.t;+}++SCALAR_FUN_ATTR float futrts_from_bits32(int32_t x) {+ union {+ int32_t f;+ float t;+ } p;++ p.f = x;+ return p.t;+}+#endif++SCALAR_FUN_ATTR float fsignum32(float x) {+ return futrts_isnan32(x) ? x : (x > 0 ? 1 : 0) - (x < 0 ? 1 : 0);+}++#ifdef FUTHARK_F64_ENABLED++#if ISPC+SCALAR_FUN_ATTR bool futrts_isinf64(float x) {+ return !isnan(x) && isnan(x - x);+}++SCALAR_FUN_ATTR bool futrts_isfinite64(float x) {+ return !isnan(x) && !futrts_isinf64(x);+}++SCALAR_FUN_ATTR double fdiv64(double x, double y) {+ return x / y;+}++SCALAR_FUN_ATTR double fadd64(double x, double y) {+ return x + y;+}++SCALAR_FUN_ATTR double fsub64(double x, double y) {+ return x - y;+}++SCALAR_FUN_ATTR double fmul64(double x, double y) {+ return x * y;+}++SCALAR_FUN_ATTR bool cmplt64(double x, double y) {+ return x < y;+}++SCALAR_FUN_ATTR bool cmple64(double x, double y) {+ return x <= y;+}++SCALAR_FUN_ATTR double sitofp_i8_f64(int8_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double sitofp_i16_f64(int16_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double sitofp_i32_f64(int32_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double sitofp_i64_f64(int64_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double uitofp_i8_f64(uint8_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double uitofp_i16_f64(uint16_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double uitofp_i32_f64(uint32_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double uitofp_i64_f64(uint64_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double fabs64(double x) {+ return abs(x);+}++SCALAR_FUN_ATTR double fmax64(double x, double y) {+ return isnan(x) ? y : isnan(y) ? x : max(x, y);+}++SCALAR_FUN_ATTR double fmin64(double x, double y) {+ return isnan(x) ? y : isnan(y) ? x : min(x, y);+}++SCALAR_FUN_ATTR double fpow64(double a, double b) {+ float ret;+ foreach_active (i) {+ uniform float r = __stdlib_powf(extract(a, i), extract(b, i));+ ret = insert(ret, i, r);+ }+ return ret;+}++SCALAR_FUN_ATTR double futrts_log64(double x) {+ return futrts_isfinite64(x) || (futrts_isinf64(x) && x < 0)? log(x) : x;+}++SCALAR_FUN_ATTR double futrts_log2_64(double x) {+ return futrts_log64(x)/log(2.0d);+}++SCALAR_FUN_ATTR double futrts_log10_64(double x) {+ return futrts_log64(x)/log(10.0d);+}++SCALAR_FUN_ATTR 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;+}++SCALAR_FUN_ATTR double futrts_sqrt64(double x) {+ return sqrt(x);+}++extern "C" unmasked uniform double cbrt(uniform double);+SCALAR_FUN_ATTR double futrts_cbrt64(double x) {+ double res;+ foreach_active (i) {+ uniform double r = cbrtf(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++SCALAR_FUN_ATTR double futrts_exp64(double x) {+ return exp(x);+}++SCALAR_FUN_ATTR double futrts_cos64(double x) {+ return cos(x);+}++SCALAR_FUN_ATTR double futrts_sin64(double x) {+ return sin(x);+}++SCALAR_FUN_ATTR double futrts_tan64(double x) {+ return tan(x);+}++SCALAR_FUN_ATTR double futrts_acos64(double x) {+ return acos(x);+}++SCALAR_FUN_ATTR double futrts_asin64(double x) {+ return asin(x);+}++SCALAR_FUN_ATTR double futrts_atan64(double x) {+ return atan(x);+}++SCALAR_FUN_ATTR double futrts_cosh64(double x) {+ return (exp(x)+exp(-x)) / 2.0d;+}++SCALAR_FUN_ATTR double futrts_sinh64(double x) {+ return (exp(x)-exp(-x)) / 2.0d;+}++SCALAR_FUN_ATTR double futrts_tanh64(double x) {+ return futrts_sinh64(x)/futrts_cosh64(x);+}++SCALAR_FUN_ATTR double futrts_acosh64(double x) {+ double f = x+sqrt(x*x-1.0d);+ if(futrts_isfinite64(f)) return log(f);+ return f;+}++SCALAR_FUN_ATTR double futrts_asinh64(double x) {+ double f = x+sqrt(x*x+1.0d);+ if(futrts_isfinite64(f)) return log(f);+ return f;+}++SCALAR_FUN_ATTR double futrts_atanh64(double x) {+ double f = (1.0d+x)/(1.0d-x);+ if(futrts_isfinite64(f)) return log(f)/2.0d;+ return f;++}++SCALAR_FUN_ATTR double futrts_atan2_64(double x, double y) {+ return atan2(x, y);+}++extern "C" unmasked uniform double hypot(uniform double x, uniform double y);+SCALAR_FUN_ATTR double futrts_hypot64(double x, double y) {+ double res;+ foreach_active (i) {+ uniform double r = hypot(extract(x, i), extract(y, i));+ res = insert(res, i, r);+ }+ return res;+}++extern "C" unmasked uniform double tgamma(uniform double x);+SCALAR_FUN_ATTR double futrts_gamma64(double x) {+ double res;+ foreach_active (i) {+ uniform double r = tgamma(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++extern "C" unmasked uniform double lgamma(uniform double x);+SCALAR_FUN_ATTR double futrts_lgamma64(double x) {+ double res;+ foreach_active (i) {+ uniform double r = lgamma(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++extern "C" unmasked uniform double erf(uniform double x);+SCALAR_FUN_ATTR double futrts_erf64(double x) {+ double res;+ foreach_active (i) {+ uniform double r = erf(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++extern "C" unmasked uniform double erfc(uniform double x);+SCALAR_FUN_ATTR double futrts_erfc64(double x) {+ double res;+ foreach_active (i) {+ uniform double r = erfc(extract(x, i));+ res = insert(res, i, r);+ }+ return res;+}++SCALAR_FUN_ATTR double futrts_fma64(double a, double b, double c) {+ return a * b + c;+}++SCALAR_FUN_ATTR double futrts_round64(double x) {+ return round(x);+}++SCALAR_FUN_ATTR double futrts_ceil64(double x) {+ return ceil(x);+}++extern "C" unmasked uniform double nextafter(uniform float x, uniform double y);+SCALAR_FUN_ATTR float futrts_nextafter64(double x, double y) {+ double res;+ foreach_active (i) {+ uniform double r = nextafter(extract(x, i), extract(y, i));+ res = insert(res, i, r);+ }+ return res;+}++SCALAR_FUN_ATTR double futrts_floor64(double x) {+ return floor(x);+}++SCALAR_FUN_ATTR bool futrts_isnan64(double x) {+ return isnan(x);+}++SCALAR_FUN_ATTR int8_t fptosi_f64_i8(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (int8_t) x;+ }+}++SCALAR_FUN_ATTR int16_t fptosi_f64_i16(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (int16_t) x;+ }+}++SCALAR_FUN_ATTR int32_t fptosi_f64_i32(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (int32_t) x;+ }+}++SCALAR_FUN_ATTR int64_t fptosi_f64_i64(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (int64_t) x;+ }+}++SCALAR_FUN_ATTR uint8_t fptoui_f64_i8(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (uint8_t) (int8_t) x;+ }+}++SCALAR_FUN_ATTR uint16_t fptoui_f64_i16(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (uint16_t) (int16_t) x;+ }+}++SCALAR_FUN_ATTR uint32_t fptoui_f64_i32(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (uint32_t) (int32_t) x;+ }+}++SCALAR_FUN_ATTR uint64_t fptoui_f64_i64(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (uint64_t) (int64_t) x;+ }+}++SCALAR_FUN_ATTR bool ftob_f64_bool(double x) {+ return x != 0.0;+}++SCALAR_FUN_ATTR double btof_bool_f64(bool x) {+ return x ? 1.0 : 0.0;+}++SCALAR_FUN_ATTR int64_t futrts_to_bits64(double x) {+ int64_t res;+ foreach_active (i) {+ uniform double tmp = extract(x, i);+ uniform int64_t r = *((uniform int64_t* uniform)&tmp);+ res = insert(res, i, r);+ }+ return res;+}++SCALAR_FUN_ATTR double futrts_from_bits64(int64_t x) {+ double res;+ foreach_active (i) {+ uniform int64_t tmp = extract(x, i);+ uniform double r = *((uniform double* uniform)&tmp);+ res = insert(res, i, r);+ }+ return res;+}++SCALAR_FUN_ATTR double fmod64(double x, double y) {+ return x - y * trunc(x/y);+}++SCALAR_FUN_ATTR double fsignum64(double x) {+ return futrts_isnan64(x) ? x : (x > 0 ? 1.0d : 0.0d) - (x < 0 ? 1.0d : 0.0d);+}++SCALAR_FUN_ATTR double futrts_lerp64(double v0, double v1, double t) {+ return v0 + (v1 - v0) * t;+}++SCALAR_FUN_ATTR double futrts_mad64(double a, double b, double c) {+ return a * b + c;+}++SCALAR_FUN_ATTR float fpconv_f32_f32(float x) {+ return (float) x;+}++SCALAR_FUN_ATTR double fpconv_f32_f64(float x) {+ return (double) x;+}++SCALAR_FUN_ATTR float fpconv_f64_f32(double x) {+ return (float) x;+}++SCALAR_FUN_ATTR double fpconv_f64_f64(double x) {+ return (double) x;+}++#else++SCALAR_FUN_ATTR double fdiv64(double x, double y) {+ return x / y;+}++SCALAR_FUN_ATTR double fadd64(double x, double y) {+ return x + y;+}++SCALAR_FUN_ATTR double fsub64(double x, double y) {+ return x - y;+}++SCALAR_FUN_ATTR double fmul64(double x, double y) {+ return x * y;+}++SCALAR_FUN_ATTR bool cmplt64(double x, double y) {+ return x < y;+}++SCALAR_FUN_ATTR bool cmple64(double x, double y) {+ return x <= y;+}++SCALAR_FUN_ATTR double sitofp_i8_f64(int8_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double sitofp_i16_f64(int16_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double sitofp_i32_f64(int32_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double sitofp_i64_f64(int64_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double uitofp_i8_f64(uint8_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double uitofp_i16_f64(uint16_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double uitofp_i32_f64(uint32_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double uitofp_i64_f64(uint64_t x) {+ return (double) x;+}++SCALAR_FUN_ATTR double fabs64(double x) {+ return fabs(x);+}++SCALAR_FUN_ATTR double fmax64(double x, double y) {+ return fmax(x, y);+}++SCALAR_FUN_ATTR double fmin64(double x, double y) {+ return fmin(x, y);+}++SCALAR_FUN_ATTR double fpow64(double x, double y) {+ return pow(x, y);+}++SCALAR_FUN_ATTR double futrts_log64(double x) {+ return log(x);+}++SCALAR_FUN_ATTR double futrts_log2_64(double x) {+ return log2(x);+}++SCALAR_FUN_ATTR double futrts_log10_64(double x) {+ return log10(x);+}++SCALAR_FUN_ATTR double futrts_log1p_64(double x) {+ return log1p(x);+}++SCALAR_FUN_ATTR double futrts_sqrt64(double x) {+ return sqrt(x);+}++SCALAR_FUN_ATTR double futrts_cbrt64(double x) {+ return cbrt(x);+}++SCALAR_FUN_ATTR double futrts_exp64(double x) {+ return exp(x);+}++SCALAR_FUN_ATTR double futrts_cos64(double x) {+ return cos(x);+}++SCALAR_FUN_ATTR double futrts_sin64(double x) {+ return sin(x);+}++SCALAR_FUN_ATTR double futrts_tan64(double x) {+ return tan(x);+}++SCALAR_FUN_ATTR double futrts_acos64(double x) {+ return acos(x);+}++SCALAR_FUN_ATTR double futrts_asin64(double x) {+ return asin(x);+}++SCALAR_FUN_ATTR double futrts_atan64(double x) {+ return atan(x);+}++SCALAR_FUN_ATTR double futrts_cosh64(double x) {+ return cosh(x);+}++SCALAR_FUN_ATTR double futrts_sinh64(double x) {+ return sinh(x);+}++SCALAR_FUN_ATTR double futrts_tanh64(double x) {+ return tanh(x);+}++SCALAR_FUN_ATTR double futrts_acosh64(double x) {+ return acosh(x);+}++SCALAR_FUN_ATTR double futrts_asinh64(double x) {+ return asinh(x);+}++SCALAR_FUN_ATTR double futrts_atanh64(double x) {+ return atanh(x);+}++SCALAR_FUN_ATTR double futrts_atan2_64(double x, double y) {+ return atan2(x, y);+}++SCALAR_FUN_ATTR double futrts_hypot64(double x, double y) {+ return hypot(x, y);+}++SCALAR_FUN_ATTR double futrts_gamma64(double x) {+ return tgamma(x);+}++SCALAR_FUN_ATTR double futrts_lgamma64(double x) {+ return lgamma(x);+}++SCALAR_FUN_ATTR double futrts_erf64(double x) {+ return erf(x);+}++SCALAR_FUN_ATTR double futrts_erfc64(double x) {+ return erfc(x);+}++SCALAR_FUN_ATTR double futrts_fma64(double a, double b, double c) {+ return fma(a, b, c);+}++SCALAR_FUN_ATTR double futrts_round64(double x) {+ return rint(x);+}++SCALAR_FUN_ATTR double futrts_ceil64(double x) {+ return ceil(x);+}++SCALAR_FUN_ATTR float futrts_nextafter64(float x, float y) {+ return nextafter(x, y);+}++SCALAR_FUN_ATTR double futrts_floor64(double x) {+ return floor(x);+}++SCALAR_FUN_ATTR bool futrts_isnan64(double x) {+ return isnan(x);+}++SCALAR_FUN_ATTR bool futrts_isinf64(double x) {+ return isinf(x);+}++SCALAR_FUN_ATTR int8_t fptosi_f64_i8(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (int8_t) x;+ }+}++SCALAR_FUN_ATTR int16_t fptosi_f64_i16(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (int16_t) x;+ }+}++SCALAR_FUN_ATTR int32_t fptosi_f64_i32(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (int32_t) x;+ }+}++SCALAR_FUN_ATTR int64_t fptosi_f64_i64(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (int64_t) x;+ }+}++SCALAR_FUN_ATTR uint8_t fptoui_f64_i8(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (uint8_t) (int8_t) x;+ }+}++SCALAR_FUN_ATTR uint16_t fptoui_f64_i16(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (uint16_t) (int16_t) x;+ }+}++SCALAR_FUN_ATTR uint32_t fptoui_f64_i32(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (uint32_t) (int32_t) x;+ }+}++SCALAR_FUN_ATTR uint64_t fptoui_f64_i64(double x) {+ if (futrts_isnan64(x) || futrts_isinf64(x)) {+ return 0;+ } else {+ return (uint64_t) (int64_t) x;+ }+}++SCALAR_FUN_ATTR bool ftob_f64_bool(double x) {+ return x != 0;+}++SCALAR_FUN_ATTR double btof_bool_f64(bool x) {+ return x ? 1 : 0;+}++SCALAR_FUN_ATTR int64_t futrts_to_bits64(double x) {+ union {+ double f;+ int64_t t;+ } p;++ p.f = x;+ return p.t;+}++SCALAR_FUN_ATTR double futrts_from_bits64(int64_t x) {+ union {+ int64_t f;+ double t;+ } p;++ p.f = x;+ return p.t;+}++SCALAR_FUN_ATTR double fmod64(double x, double y) {+ return fmod(x, y);+}++SCALAR_FUN_ATTR double fsignum64(double x) {+ return futrts_isnan64(x) ? x : (x > 0) - (x < 0);+}++SCALAR_FUN_ATTR double futrts_lerp64(double v0, double v1, double t) {+#ifdef __OPENCL_VERSION__+ return mix(v0, v1, t);+#else+ return v0 + (v1 - v0) * t;+#endif+}++SCALAR_FUN_ATTR double futrts_mad64(double a, double b, double c) {+#ifdef __OPENCL_VERSION__+ return mad(a, b, c);+#else+ return a * b + c;+#endif+}++SCALAR_FUN_ATTR float fpconv_f32_f32(float x) {+ return (float) x;+}++SCALAR_FUN_ATTR double fpconv_f32_f64(float x) {+ return (double) x;+}++SCALAR_FUN_ATTR float fpconv_f64_f32(double x) {+ return (float) x;+}++SCALAR_FUN_ATTR double fpconv_f64_f64(double x) { return (double) x; }
rts/c/scalar_f16.h view
@@ -39,396 +39,396 @@ // Some of these functions convert to single precision because half // precision versions are not available. -static inline f16 fadd16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fadd16(f16 x, f16 y) { return x + y; } -static inline f16 fsub16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fsub16(f16 x, f16 y) { return x - y; } -static inline f16 fmul16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmul16(f16 x, f16 y) { return x * y; } -static inline bool cmplt16(f16 x, f16 y) {+SCALAR_FUN_ATTR bool cmplt16(f16 x, f16 y) { return x < y; } -static inline bool cmple16(f16 x, f16 y) {+SCALAR_FUN_ATTR bool cmple16(f16 x, f16 y) { return x <= y; } -static inline f16 sitofp_i8_f16(int8_t x) {+SCALAR_FUN_ATTR f16 sitofp_i8_f16(int8_t x) { return (f16) x; } -static inline f16 sitofp_i16_f16(int16_t x) {+SCALAR_FUN_ATTR f16 sitofp_i16_f16(int16_t x) { return (f16) x; } -static inline f16 sitofp_i32_f16(int32_t x) {+SCALAR_FUN_ATTR f16 sitofp_i32_f16(int32_t x) { return (f16) x; } -static inline f16 sitofp_i64_f16(int64_t x) {+SCALAR_FUN_ATTR f16 sitofp_i64_f16(int64_t x) { return (f16) x; } -static inline f16 uitofp_i8_f16(uint8_t x) {+SCALAR_FUN_ATTR f16 uitofp_i8_f16(uint8_t x) { return (f16) x; } -static inline f16 uitofp_i16_f16(uint16_t x) {+SCALAR_FUN_ATTR f16 uitofp_i16_f16(uint16_t x) { return (f16) x; } -static inline f16 uitofp_i32_f16(uint32_t x) {+SCALAR_FUN_ATTR f16 uitofp_i32_f16(uint32_t x) { return (f16) x; } -static inline f16 uitofp_i64_f16(uint64_t x) {+SCALAR_FUN_ATTR f16 uitofp_i64_f16(uint64_t x) { return (f16) x; } -static inline int8_t fptosi_f16_i8(f16 x) {+SCALAR_FUN_ATTR int8_t fptosi_f16_i8(f16 x) { return (int8_t) (float) x; } -static inline int16_t fptosi_f16_i16(f16 x) {+SCALAR_FUN_ATTR int16_t fptosi_f16_i16(f16 x) { return (int16_t) x; } -static inline int32_t fptosi_f16_i32(f16 x) {+SCALAR_FUN_ATTR int32_t fptosi_f16_i32(f16 x) { return (int32_t) x; } -static inline int64_t fptosi_f16_i64(f16 x) {+SCALAR_FUN_ATTR int64_t fptosi_f16_i64(f16 x) { return (int64_t) x; } -static inline uint8_t fptoui_f16_i8(f16 x) {+SCALAR_FUN_ATTR uint8_t fptoui_f16_i8(f16 x) { return (uint8_t) (float) x; } -static inline uint16_t fptoui_f16_i16(f16 x) {+SCALAR_FUN_ATTR uint16_t fptoui_f16_i16(f16 x) { return (uint16_t) x; } -static inline uint32_t fptoui_f16_i32(f16 x) {+SCALAR_FUN_ATTR uint32_t fptoui_f16_i32(f16 x) { return (uint32_t) x; } -static inline uint64_t fptoui_f16_i64(f16 x) {+SCALAR_FUN_ATTR uint64_t fptoui_f16_i64(f16 x) { return (uint64_t) x; } -static inline bool ftob_f16_bool(f16 x) {+SCALAR_FUN_ATTR bool ftob_f16_bool(f16 x) { return x != (f16)0; } -static inline f16 btof_bool_f16(bool x) {+SCALAR_FUN_ATTR f16 btof_bool_f16(bool x) { return x ? 1 : 0; } #ifndef EMULATE_F16-static inline bool futrts_isnan16(f16 x) {+SCALAR_FUN_ATTR bool futrts_isnan16(f16 x) { return isnan((float)x); } #ifdef __OPENCL_VERSION__ -static inline f16 fabs16(f16 x) {+SCALAR_FUN_ATTR f16 fabs16(f16 x) { return fabs(x); } -static inline f16 fmax16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmax16(f16 x, f16 y) { return fmax(x, y); } -static inline f16 fmin16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmin16(f16 x, f16 y) { return fmin(x, y); } -static inline f16 fpow16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fpow16(f16 x, f16 y) { return pow(x, y); } #elif ISPC-static inline f16 fabs16(f16 x) {+SCALAR_FUN_ATTR f16 fabs16(f16 x) { return abs(x); } -static inline f16 fmax16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmax16(f16 x, f16 y) { return futrts_isnan16(x) ? y : futrts_isnan16(y) ? x : max(x, y); } -static inline f16 fmin16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmin16(f16 x, f16 y) { return futrts_isnan16(x) ? y : futrts_isnan16(y) ? x : min(x, y); } -static inline f16 fpow16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fpow16(f16 x, f16 y) { return pow(x, y); } #else // Assuming CUDA. -static inline f16 fabs16(f16 x) {+SCALAR_FUN_ATTR f16 fabs16(f16 x) { return fabsf(x); } -static inline f16 fmax16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmax16(f16 x, f16 y) { return fmaxf(x, y); } -static inline f16 fmin16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmin16(f16 x, f16 y) { return fminf(x, y); } -static inline f16 fpow16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fpow16(f16 x, f16 y) { return powf(x, y); } #endif #if ISPC-static inline bool futrts_isinf16(float x) {+SCALAR_FUN_ATTR bool futrts_isinf16(float x) { return !futrts_isnan16(x) && futrts_isnan16(x - x); }-static inline bool futrts_isfinite16(float x) {+SCALAR_FUN_ATTR bool futrts_isfinite16(float x) { return !futrts_isnan16(x) && !futrts_isinf16(x); } #else -static inline bool futrts_isinf16(f16 x) {+SCALAR_FUN_ATTR bool futrts_isinf16(f16 x) { return isinf((float)x); } #endif #ifdef __OPENCL_VERSION__-static inline f16 futrts_log16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log16(f16 x) { return log(x); } -static inline f16 futrts_log2_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log2_16(f16 x) { return log2(x); } -static inline f16 futrts_log10_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log10_16(f16 x) { return log10(x); } -static inline f16 futrts_log1p_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log1p_16(f16 x) { return log1p(x); } -static inline f16 futrts_sqrt16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sqrt16(f16 x) { return sqrt(x); } -static inline f16 futrts_cbrt16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cbrt16(f16 x) { return cbrt(x); } -static inline f16 futrts_exp16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_exp16(f16 x) { return exp(x); } -static inline f16 futrts_cos16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cos16(f16 x) { return cos(x); } -static inline f16 futrts_sin16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sin16(f16 x) { return sin(x); } -static inline f16 futrts_tan16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_tan16(f16 x) { return tan(x); } -static inline f16 futrts_acos16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_acos16(f16 x) { return acos(x); } -static inline f16 futrts_asin16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_asin16(f16 x) { return asin(x); } -static inline f16 futrts_atan16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_atan16(f16 x) { return atan(x); } -static inline f16 futrts_cosh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cosh16(f16 x) { return cosh(x); } -static inline f16 futrts_sinh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sinh16(f16 x) { return sinh(x); } -static inline f16 futrts_tanh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_tanh16(f16 x) { return tanh(x); } -static inline f16 futrts_acosh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_acosh16(f16 x) { return acosh(x); } -static inline f16 futrts_asinh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_asinh16(f16 x) { return asinh(x); } -static inline f16 futrts_atanh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_atanh16(f16 x) { return atanh(x); } -static inline f16 futrts_atan2_16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_atan2_16(f16 x, f16 y) { return atan2(x, y); } -static inline f16 futrts_hypot16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_hypot16(f16 x, f16 y) { return hypot(x, y); } -static inline f16 futrts_gamma16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_gamma16(f16 x) { return tgamma(x); } -static inline f16 futrts_lgamma16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_lgamma16(f16 x) { return lgamma(x); } -static inline f16 futrts_erf16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_erf16(f16 x) { return erf(x); } -static inline f16 futrts_erfc16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_erfc16(f16 x) { return erfc(x); } -static inline f16 fmod16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmod16(f16 x, f16 y) { return fmod(x, y); } -static inline f16 futrts_round16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_round16(f16 x) { return rint(x); } -static inline f16 futrts_floor16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_floor16(f16 x) { return floor(x); } -static inline f16 futrts_ceil16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_ceil16(f16 x) { return ceil(x); } -static inline f16 futrts_nextafter16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_nextafter16(f16 x, f16 y) { return nextafter(x, y); } -static inline f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {+SCALAR_FUN_ATTR f16 futrts_lerp16(f16 v0, f16 v1, f16 t) { return mix(v0, v1, t); } -static inline f16 futrts_mad16(f16 a, f16 b, f16 c) {+SCALAR_FUN_ATTR f16 futrts_mad16(f16 a, f16 b, f16 c) { return mad(a, b, c); } -static inline f16 futrts_fma16(f16 a, f16 b, f16 c) {+SCALAR_FUN_ATTR f16 futrts_fma16(f16 a, f16 b, f16 c) { return fma(a, b, c); } #elif ISPC -static inline f16 futrts_log16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log16(f16 x) { return futrts_isfinite16(x) || (futrts_isinf16(x) && x < 0) ? log(x) : x; } -static inline f16 futrts_log2_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log2_16(f16 x) { return futrts_log16(x) / log(2.0f16); } -static inline f16 futrts_log10_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log10_16(f16 x) { return futrts_log16(x) / log(10.0f16); } -static inline f16 futrts_log1p_16(f16 x) {+SCALAR_FUN_ATTR 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) {+SCALAR_FUN_ATTR f16 futrts_sqrt16(f16 x) { return (float16)sqrt((float)x); } -static inline f16 futrts_exp16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_exp16(f16 x) { return exp(x); } -static inline f16 futrts_cos16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cos16(f16 x) { return (float16)cos((float)x); } -static inline f16 futrts_sin16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sin16(f16 x) { return (float16)sin((float)x); } -static inline f16 futrts_tan16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_tan16(f16 x) { return (float16)tan((float)x); } -static inline f16 futrts_acos16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_acos16(f16 x) { return (float16)acos((float)x); } -static inline f16 futrts_asin16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_asin16(f16 x) { return (float16)asin((float)x); } -static inline f16 futrts_atan16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_atan16(f16 x) { return (float16)atan((float)x); } -static inline f16 futrts_cosh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cosh16(f16 x) { return (exp(x)+exp(-x)) / 2.0f16; } -static inline f16 futrts_sinh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sinh16(f16 x) { return (exp(x)-exp(-x)) / 2.0f16; } -static inline f16 futrts_tanh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_tanh16(f16 x) { return futrts_sinh16(x)/futrts_cosh16(x); } -static inline f16 futrts_acosh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_acosh16(f16 x) { float16 f = x+(float16)sqrt((float)(x*x-1)); if(futrts_isfinite16(f)) return log(f); return f; } -static inline f16 futrts_asinh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_asinh16(f16 x) { float16 f = x+(float16)sqrt((float)(x*x+1)); if(futrts_isfinite16(f)) return log(f); return f; } -static inline f16 futrts_atanh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_atanh16(f16 x) { float16 f = (1+x)/(1-x); if(futrts_isfinite16(f)) return log(f)/2.0f16; return f; } -static inline f16 futrts_atan2_16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_atan2_16(f16 x, f16 y) { return (float16)atan2((float)x, (float)y); } -static inline f16 futrts_hypot16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_hypot16(f16 x, f16 y) { return (float16)futrts_hypot32((float)x, (float)y); } extern "C" unmasked uniform float tgammaf(uniform float x);-static inline f16 futrts_gamma16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_gamma16(f16 x) { f16 res; foreach_active (i) { uniform f16 r = (f16)tgammaf(extract((float)x, i));@@ -438,7 +438,7 @@ } extern "C" unmasked uniform float lgammaf(uniform float x);-static inline f16 futrts_lgamma16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_lgamma16(f16 x) { f16 res; foreach_active (i) { uniform f16 r = (f16)lgammaf(extract((float)x, i));@@ -447,184 +447,184 @@ return res; } -static inline f16 futrts_cbrt16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cbrt16(f16 x) { f16 res = (f16)futrts_cbrt32((float)x); return res; } -static inline f16 futrts_erf16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_erf16(f16 x) { f16 res = (f16)futrts_erf32((float)x); return res; } -static inline f16 futrts_erfc16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_erfc16(f16 x) { f16 res = (f16)futrts_erfc32((float)x); return res; } -static inline f16 fmod16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmod16(f16 x, f16 y) { return x - y * (float16)trunc((float) (x/y)); } -static inline f16 futrts_round16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_round16(f16 x) { return (float16)round((float)x); } -static inline f16 futrts_floor16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_floor16(f16 x) { return (float16)floor((float)x); } -static inline f16 futrts_ceil16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_ceil16(f16 x) { return (float16)ceil((float)x); } -static inline f16 futrts_nextafter16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_nextafter16(f16 x, f16 y) { return (float16)futrts_nextafter32((float)x, (float) y); } -static inline f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {+SCALAR_FUN_ATTR f16 futrts_lerp16(f16 v0, f16 v1, f16 t) { return v0 + (v1 - v0) * t; } -static inline f16 futrts_mad16(f16 a, f16 b, f16 c) {+SCALAR_FUN_ATTR f16 futrts_mad16(f16 a, f16 b, f16 c) { return a * b + c; } -static inline f16 futrts_fma16(f16 a, f16 b, f16 c) {+SCALAR_FUN_ATTR f16 futrts_fma16(f16 a, f16 b, f16 c) { return a * b + c; } #else // Assume CUDA. -static inline f16 futrts_log16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log16(f16 x) { return hlog(x); } -static inline f16 futrts_log2_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log2_16(f16 x) { return hlog2(x); } -static inline f16 futrts_log10_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log10_16(f16 x) { return hlog10(x); } -static inline f16 futrts_log1p_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log1p_16(f16 x) { return (f16)log1pf((float)x); } -static inline f16 futrts_sqrt16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sqrt16(f16 x) { return hsqrt(x); } -static inline f16 futrts_cbrt16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cbrt16(f16 x) { return cbrtf(x); } -static inline f16 futrts_exp16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_exp16(f16 x) { return hexp(x); } -static inline f16 futrts_cos16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cos16(f16 x) { return hcos(x); } -static inline f16 futrts_sin16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sin16(f16 x) { return hsin(x); } -static inline f16 futrts_tan16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_tan16(f16 x) { return tanf(x); } -static inline f16 futrts_acos16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_acos16(f16 x) { return acosf(x); } -static inline f16 futrts_asin16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_asin16(f16 x) { return asinf(x); } -static inline f16 futrts_atan16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_atan16(f16 x) { return atanf(x); } -static inline f16 futrts_cosh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cosh16(f16 x) { return coshf(x); } -static inline f16 futrts_sinh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sinh16(f16 x) { return sinhf(x); } -static inline f16 futrts_tanh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_tanh16(f16 x) { return tanhf(x); } -static inline f16 futrts_acosh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_acosh16(f16 x) { return acoshf(x); } -static inline f16 futrts_asinh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_asinh16(f16 x) { return asinhf(x); } -static inline f16 futrts_atanh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_atanh16(f16 x) { return atanhf(x); } -static inline f16 futrts_atan2_16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_atan2_16(f16 x, f16 y) { return atan2f(x, y); } -static inline f16 futrts_hypot16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_hypot16(f16 x, f16 y) { return hypotf(x, y); } -static inline f16 futrts_gamma16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_gamma16(f16 x) { return tgammaf(x); } -static inline f16 futrts_lgamma16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_lgamma16(f16 x) { return lgammaf(x); } -static inline f16 futrts_erf16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_erf16(f16 x) { return erff(x); } -static inline f16 futrts_erfc16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_erfc16(f16 x) { return erfcf(x); } -static inline f16 fmod16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmod16(f16 x, f16 y) { return fmodf(x, y); } -static inline f16 futrts_round16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_round16(f16 x) { return rintf(x); } -static inline f16 futrts_floor16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_floor16(f16 x) { return hfloor(x); } -static inline f16 futrts_ceil16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_ceil16(f16 x) { return hceil(x); } -static inline f16 futrts_nextafter16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_nextafter16(f16 x, f16 y) { return __ushort_as_half(halfbitsnextafter(__half_as_ushort(x), __half_as_ushort(y))); } -static inline f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {+SCALAR_FUN_ATTR f16 futrts_lerp16(f16 v0, f16 v1, f16 t) { return v0 + (v1 - v0) * t; } -static inline f16 futrts_mad16(f16 a, f16 b, f16 c) {+SCALAR_FUN_ATTR f16 futrts_mad16(f16 a, f16 b, f16 c) { return a * b + c; } -static inline f16 futrts_fma16(f16 a, f16 b, f16 c) {+SCALAR_FUN_ATTR f16 futrts_fma16(f16 a, f16 b, f16 c) { return fmaf(a, b, c); } @@ -633,25 +633,25 @@ // The CUDA __half type cannot be put in unions for some reason, so we // use bespoke conversion functions instead. #ifdef __CUDA_ARCH__-static inline int16_t futrts_to_bits16(f16 x) {+SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) { return __half_as_ushort(x); }-static inline f16 futrts_from_bits16(int16_t x) {+SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) { return __ushort_as_half(x); } #elif ISPC -static inline int16_t futrts_to_bits16(f16 x) {+SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) { varying int16_t y = *((varying int16_t * uniform)&x); return y; } -static inline f16 futrts_from_bits16(int16_t x) {+SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) { varying f16 y = *((varying f16 * uniform)&x); return y; } #else-static inline int16_t futrts_to_bits16(f16 x) {+SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) { union { f16 f; int16_t t;@@ -661,7 +661,7 @@ return p.t; } -static inline f16 futrts_from_bits16(int16_t x) {+SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) { union { int16_t f; f16 t;@@ -674,159 +674,159 @@ #else // No native f16 - emulate. -static inline f16 fabs16(f16 x) {+SCALAR_FUN_ATTR f16 fabs16(f16 x) { return fabs32(x); } -static inline f16 fmax16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmax16(f16 x, f16 y) { return fmax32(x, y); } -static inline f16 fmin16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmin16(f16 x, f16 y) { return fmin32(x, y); } -static inline f16 fpow16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fpow16(f16 x, f16 y) { return fpow32(x, y); } -static inline bool futrts_isnan16(f16 x) {+SCALAR_FUN_ATTR bool futrts_isnan16(f16 x) { return futrts_isnan32(x); } -static inline bool futrts_isinf16(f16 x) {+SCALAR_FUN_ATTR bool futrts_isinf16(f16 x) { return futrts_isinf32(x); } -static inline f16 futrts_log16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log16(f16 x) { return futrts_log32(x); } -static inline f16 futrts_log2_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log2_16(f16 x) { return futrts_log2_32(x); } -static inline f16 futrts_log10_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log10_16(f16 x) { return futrts_log10_32(x); } -static inline f16 futrts_log1p_16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_log1p_16(f16 x) { return futrts_log1p_32(x); } -static inline f16 futrts_sqrt16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sqrt16(f16 x) { return futrts_sqrt32(x); } -static inline f16 futrts_cbrt16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cbrt16(f16 x) { return futrts_cbrt32(x); } -static inline f16 futrts_exp16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_exp16(f16 x) { return futrts_exp32(x); } -static inline f16 futrts_cos16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cos16(f16 x) { return futrts_cos32(x); } -static inline f16 futrts_sin16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sin16(f16 x) { return futrts_sin32(x); } -static inline f16 futrts_tan16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_tan16(f16 x) { return futrts_tan32(x); } -static inline f16 futrts_acos16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_acos16(f16 x) { return futrts_acos32(x); } -static inline f16 futrts_asin16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_asin16(f16 x) { return futrts_asin32(x); } -static inline f16 futrts_atan16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_atan16(f16 x) { return futrts_atan32(x); } -static inline f16 futrts_cosh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_cosh16(f16 x) { return futrts_cosh32(x); } -static inline f16 futrts_sinh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_sinh16(f16 x) { return futrts_sinh32(x); } -static inline f16 futrts_tanh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_tanh16(f16 x) { return futrts_tanh32(x); } -static inline f16 futrts_acosh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_acosh16(f16 x) { return futrts_acosh32(x); } -static inline f16 futrts_asinh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_asinh16(f16 x) { return futrts_asinh32(x); } -static inline f16 futrts_atanh16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_atanh16(f16 x) { return futrts_atanh32(x); } -static inline f16 futrts_atan2_16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_atan2_16(f16 x, f16 y) { return futrts_atan2_32(x, y); } -static inline f16 futrts_hypot16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_hypot16(f16 x, f16 y) { return futrts_hypot32(x, y); } -static inline f16 futrts_gamma16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_gamma16(f16 x) { return futrts_gamma32(x); } -static inline f16 futrts_lgamma16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_lgamma16(f16 x) { return futrts_lgamma32(x); } -static inline f16 futrts_erf16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_erf16(f16 x) { return futrts_erf32(x); } -static inline f16 futrts_erfc16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_erfc16(f16 x) { return futrts_erfc32(x); } -static inline f16 fmod16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 fmod16(f16 x, f16 y) { return fmod32(x, y); } -static inline f16 futrts_round16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_round16(f16 x) { return futrts_round32(x); } -static inline f16 futrts_floor16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_floor16(f16 x) { return futrts_floor32(x); } -static inline f16 futrts_ceil16(f16 x) {+SCALAR_FUN_ATTR f16 futrts_ceil16(f16 x) { return futrts_ceil32(x); } -static inline f16 futrts_nextafter16(f16 x, f16 y) {+SCALAR_FUN_ATTR f16 futrts_nextafter16(f16 x, f16 y) { return halfbits2float(halfbitsnextafter(float2halfbits(x), float2halfbits(y))); } -static inline f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {+SCALAR_FUN_ATTR f16 futrts_lerp16(f16 v0, f16 v1, f16 t) { return futrts_lerp32(v0, v1, t); } -static inline f16 futrts_mad16(f16 a, f16 b, f16 c) {+SCALAR_FUN_ATTR f16 futrts_mad16(f16 a, f16 b, f16 c) { return futrts_mad32(a, b, c); } -static inline f16 futrts_fma16(f16 a, f16 b, f16 c) {+SCALAR_FUN_ATTR f16 futrts_fma16(f16 a, f16 b, f16 c) { return futrts_fma32(a, b, c); } @@ -836,28 +836,28 @@ // float. Similarly for vstore_half. #ifdef __OPENCL_VERSION__ -static inline int16_t futrts_to_bits16(f16 x) {+SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) { int16_t y; // Violating strict aliasing here. vstore_half((float)x, 0, (half*)&y); return y; } -static inline f16 futrts_from_bits16(int16_t x) {+SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) { return (f16)vload_half(0, (half*)&x); } #else -static inline int16_t futrts_to_bits16(f16 x) {+SCALAR_FUN_ATTR int16_t futrts_to_bits16(f16 x) { return (int16_t)float2halfbits(x); } -static inline f16 futrts_from_bits16(int16_t x) {+SCALAR_FUN_ATTR f16 futrts_from_bits16(int16_t x) { return halfbits2float((uint16_t)x); } -static inline f16 fsignum16(f16 x) {+SCALAR_FUN_ATTR f16 fsignum16(f16 x) { return futrts_isnan16(x) ? x : (x > 0 ? 1 : 0) - (x < 0 ? 1 : 0); } @@ -865,30 +865,30 @@ #endif -static inline float fpconv_f16_f16(f16 x) {+SCALAR_FUN_ATTR float fpconv_f16_f16(f16 x) { return x; } -static inline float fpconv_f16_f32(f16 x) {+SCALAR_FUN_ATTR float fpconv_f16_f32(f16 x) { return x; } -static inline f16 fpconv_f32_f16(float x) {+SCALAR_FUN_ATTR f16 fpconv_f32_f16(float x) { return (f16) x; } #ifdef FUTHARK_F64_ENABLED -static inline double fpconv_f16_f64(f16 x) {+SCALAR_FUN_ATTR double fpconv_f16_f64(f16 x) { return (double) x; } #if ISPC-static inline f16 fpconv_f64_f16(double x) {+SCALAR_FUN_ATTR f16 fpconv_f64_f16(double x) { return (f16) ((float)x); } #else-static inline f16 fpconv_f64_f16(double x) {+SCALAR_FUN_ATTR f16 fpconv_f64_f16(double x) { return (f16) x; } #endif
rts/c/util.h view
@@ -136,7 +136,78 @@ b->used += needed; } +struct cost_centre {+ const char *name;+ int64_t runs;+ int64_t runtime;+}; +// Dynamic dictionary for tallying cost centres when aggregating+// profiling information. Not performance-critical.+struct cost_centres {+ size_t capacity;+ size_t used;+ struct cost_centre* centres;+};++static struct cost_centres *cost_centres_new() {+ struct cost_centres *ccs = malloc(sizeof(struct cost_centres));+ ccs->capacity = 100;+ ccs->used = 0;+ ccs->centres = calloc(ccs->capacity, sizeof(struct cost_centre));+ return ccs;+}++static void cost_centres_free(struct cost_centres* ccs) {+ free(ccs->centres);+ free(ccs);+}++static void cost_centres_init(struct cost_centres* ccs, const char *name) {+ if (ccs->used == ccs->capacity) {+ ccs->capacity *= 2;+ ccs->centres = realloc(ccs->centres, ccs->capacity*sizeof(struct cost_centre));+ }+ ccs->centres[ccs->used].name = name;+ ccs->centres[ccs->used].runs = 0;+ ccs->centres[ccs->used].runtime = 0;+ ccs->used++;+}++static void cost_centres_add(struct cost_centres* ccs, struct cost_centre c) {+ size_t i = 0;+ for (i = 0; i < ccs->used; i++) {+ if (strcmp(c.name, ccs->centres[i].name) == 0) {+ ccs->centres[i].runs += c.runs;+ ccs->centres[i].runtime += c.runtime;+ return;+ }+ }+ if (i == ccs->capacity) {+ ccs->capacity *= 2;+ ccs->centres = realloc(ccs->centres, ccs->capacity*sizeof(struct cost_centre));+ }+ ccs->centres[i] = c;+ ccs->used++;+}++static void cost_centre_report(struct cost_centres* ccs, struct str_builder *b) {+ int64_t total_runs = 0;+ int64_t total_runtime = 0;+ for (size_t i = 0; i < ccs->used; i++) {+ struct cost_centre c = ccs->centres[i];+ str_builder(b,+ "%-40s ran %5d times; avg %8ldus; total: %8ldus\n",+ c.name,+ c.runs, c.runs == 0 ? 0 : c.runtime/c.runs, c.runtime);+ total_runs += c.runs;+ total_runtime += c.runtime;+ }+ str_builder(b,+ "%d operations with cumulative runtime: %6ldus\n",+ total_runs, total_runtime);+}+ static char *strclone(const char *str) { size_t size = strlen(str) + 1; char *copy = (char*) malloc(size);@@ -146,6 +217,25 @@ memcpy(copy, str, size); return copy;+}++// Assumes NULL-terminated.+static char *strconcat(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; } // End of util.h.
+ rts/cuda/prelude.cu view
@@ -0,0 +1,102 @@+// start of prelude.cu++#define SCALAR_FUN_ATTR __device__ static inline+#define FUTHARK_FUN_ATTR __device__ static+#define FUTHARK_F64_ENABLED++typedef char int8_t;+typedef short int16_t;+typedef int int32_t;+typedef long long int64_t;+typedef unsigned char uint8_t;+typedef unsigned short uint16_t;+typedef unsigned int uint32_t;+typedef unsigned long long uint64_t;++#define __global+#define __local+#define __private+#define __constant+#define __write_only+#define __read_only++static inline __device__ int get_group_id(int d) {+ switch (d) {+ case 0: return blockIdx.x;+ case 1: return blockIdx.y;+ case 2: return blockIdx.z;+ default: return 0;+ }+}++static inline __device__ int get_num_groups(int d) {+ switch(d) {+ case 0: return gridDim.x;+ case 1: return gridDim.y;+ case 2: return gridDim.z;+ default: return 0;+ }+}++static inline __device__ int get_global_id(int d) {+ switch (d) {+ case 0: return threadIdx.x + blockIdx.x * blockDim.x;+ case 1: return threadIdx.y + blockIdx.y * blockDim.y;+ case 2: return threadIdx.z + blockIdx.z * blockDim.z;+ default: return 0;+ }+}++static inline __device__ int get_local_id(int d) {+ switch (d) {+ case 0: return threadIdx.x;+ case 1: return threadIdx.y;+ case 2: return threadIdx.z;+ default: return 0;+ }+}++static inline __device__ int get_local_size(int d) {+ switch (d) {+ case 0: return blockDim.x;+ case 1: return blockDim.y;+ case 2: return blockDim.z;+ default: return 0;+ }+}++static inline __device__ int get_global_size(int d) {+ switch (d) {+ case 0: return gridDim.x * blockDim.x;+ case 1: return gridDim.y * blockDim.y;+ case 2: return gridDim.z * blockDim.z;+ default: return 0;+ }+}+++#define CLK_LOCAL_MEM_FENCE 1+#define CLK_GLOBAL_MEM_FENCE 2+static inline __device__ void barrier(int x) {+ __syncthreads();+}+static inline __device__ void mem_fence_local() {+ __threadfence_block();+}+static inline __device__ void mem_fence_global() {+ __threadfence();+}++static inline __device__ void barrier_local() {+ __syncthreads();+}++#define NAN (0.0/0.0)+#define INFINITY (1.0/0.0)+extern volatile __shared__ unsigned char local_mem[];++#define LOCAL_MEM_PARAM+#define FUTHARK_KERNEL extern "C" __global__ __launch_bounds__(MAX_THREADS_PER_BLOCK)+#define FUTHARK_KERNEL_SIZED(a,b,c) extern "C" __global__ __launch_bounds__(a*b*c)++// End of prelude.cu
+ rts/opencl/copy.cl view
@@ -0,0 +1,83 @@+// Start of copy.cl++#define GEN_COPY_KERNEL(NAME, ELEM_TYPE) \+FUTHARK_KERNEL void lmad_copy_##NAME(LOCAL_MEM_PARAM \+ __global ELEM_TYPE *dst_mem, \+ int64_t dst_offset, \+ __global ELEM_TYPE *src_mem, \+ int64_t src_offset, \+ int64_t n, \+ int r, \+ int64_t shape0, int64_t dst_stride0, int64_t src_stride0, \+ int64_t shape1, int64_t dst_stride1, int64_t src_stride1, \+ int64_t shape2, int64_t dst_stride2, int64_t src_stride2, \+ int64_t shape3, int64_t dst_stride3, int64_t src_stride3, \+ int64_t shape4, int64_t dst_stride4, int64_t src_stride4, \+ int64_t shape5, int64_t dst_stride5, int64_t src_stride5, \+ int64_t shape6, int64_t dst_stride6, int64_t src_stride6, \+ int64_t shape7, int64_t dst_stride7, int64_t src_stride7) { \+ int64_t gtid = get_global_id(0); \+ int64_t remainder = gtid; \+ \+ if (gtid >= n) { \+ return; \+ } \+ \+ if (r > 0) { \+ int64_t i = remainder % shape0; \+ dst_offset += i * dst_stride0; \+ src_offset += i * src_stride0; \+ remainder /= shape0; \+ } \+ if (r > 1) { \+ int64_t i = remainder % shape1; \+ dst_offset += i * dst_stride1; \+ src_offset += i * src_stride1; \+ remainder /= shape1; \+ } \+ if (r > 2) { \+ int64_t i = remainder % shape2; \+ dst_offset += i * dst_stride2; \+ src_offset += i * src_stride2; \+ remainder /= shape2; \+ } \+ if (r > 3) { \+ int64_t i = remainder % shape3; \+ dst_offset += i * dst_stride3; \+ src_offset += i * src_stride3; \+ remainder /= shape3; \+ } \+ if (r > 4) { \+ int64_t i = remainder % shape4; \+ dst_offset += i * dst_stride4; \+ src_offset += i * src_stride4; \+ remainder /= shape4; \+ } \+ if (r > 5) { \+ int64_t i = remainder % shape5; \+ dst_offset += i * dst_stride5; \+ src_offset += i * src_stride5; \+ remainder /= shape5; \+ } \+ if (r > 6) { \+ int64_t i = remainder % shape6; \+ dst_offset += i * dst_stride6; \+ src_offset += i * src_stride6; \+ remainder /= shape6; \+ } \+ if (r > 7) { \+ int64_t i = remainder % shape7; \+ dst_offset += i * dst_stride7; \+ src_offset += i * src_stride7; \+ remainder /= shape7; \+ } \+ \+ dst_mem[dst_offset] = src_mem[src_offset]; \+}++GEN_COPY_KERNEL(1b, uint8_t)+GEN_COPY_KERNEL(2b, uint16_t)+GEN_COPY_KERNEL(4b, uint32_t)+GEN_COPY_KERNEL(8b, uint64_t)++// End of copy.cl
+ rts/opencl/prelude.cl view
@@ -0,0 +1,54 @@+// Start of prelude.cl++#define SCALAR_FUN_ATTR static inline+#define FUTHARK_FUN_ATTR static++typedef char int8_t;+typedef short int16_t;+typedef int int32_t;+typedef long int64_t;++typedef uchar uint8_t;+typedef ushort uint16_t;+typedef uint uint32_t;+typedef ulong uint64_t;+++// Clang-based OpenCL implementations need this for 'static' to work.+#ifdef cl_clang_storage_class_specifiers+#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable+#endif+#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable++#ifdef FUTHARK_F64_ENABLED+#pragma OPENCL EXTENSION cl_khr_fp64 : enable+#endif++#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable+#pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable++// NVIDIAs OpenCL does not create device-wide memory fences (see #734), so we+// use inline assembly if we detect we are on an NVIDIA GPU.+#ifdef cl_nv_pragma_unroll+static inline void mem_fence_global() {+ asm("membar.gl;");+}+#else+static inline void mem_fence_global() {+ mem_fence(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);+}+#endif+static inline void mem_fence_local() {+ mem_fence(CLK_LOCAL_MEM_FENCE);+}++static inline void barrier_local() {+ barrier(CLK_LOCAL_MEM_FENCE);+}++// Important for this to be int64_t so it has proper alignment for any type.+#define LOCAL_MEM_PARAM __local uint64_t* local_mem,+#define FUTHARK_KERNEL __kernel+#define FUTHARK_KERNEL_SIZED(a,b,c) __attribute__((reqd_work_group_size(a, b, c))) __kernel++// End of prelude.cl
+ rts/opencl/transpose.cl view
@@ -0,0 +1,273 @@+// Start of transpose.cl++#define GEN_TRANSPOSE_KERNELS(NAME, ELEM_TYPE) \+FUTHARK_KERNEL_SIZED(TR_BLOCK_DIM*2, TR_TILE_DIM/TR_ELEMS_PER_THREAD, 1)\+void map_transpose_##NAME(LOCAL_MEM_PARAM \+ __global ELEM_TYPE *dst_mem, \+ int64_t dst_offset, \+ __global ELEM_TYPE *src_mem, \+ int64_t src_offset, \+ int32_t num_arrays, \+ int32_t x_elems, \+ int32_t y_elems, \+ int32_t mulx, \+ int32_t muly, \+ int32_t repeat_1, \+ int32_t repeat_2) { \+ (void)mulx; (void)muly; \+ __local ELEM_TYPE* block = (__local ELEM_TYPE*)local_mem; \+ int group_id_0 = get_group_id(0); \+ int global_id_0 = get_global_id(0); \+ int group_id_1 = get_group_id(1); \+ int global_id_1 = get_global_id(1); \+ for (int i1 = 0; i1 <= repeat_1; i1++) { \+ int group_id_2 = get_group_id(2); \+ int global_id_2 = get_global_id(2); \+ for (int i2 = 0; i2 <= repeat_2; i2++) { \+ int32_t our_array_offset = group_id_2 * x_elems * y_elems; \+ int32_t odata_offset = dst_offset + our_array_offset; \+ int32_t idata_offset = src_offset + our_array_offset; \+ int32_t x_index = global_id_0; \+ int32_t y_index = group_id_1 * TR_TILE_DIM + get_local_id(1); \+ if (x_index < x_elems) { \+ for (int32_t j = 0; j < TR_ELEMS_PER_THREAD; j++) { \+ int32_t index_i = (y_index + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD)) * x_elems + x_index; \+ if (y_index + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD) < y_elems) { \+ block[(get_local_id(1) + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD)) * (TR_TILE_DIM+1) + \+ get_local_id(0)] = \+ src_mem[idata_offset + index_i]; \+ } \+ } \+ } \+ barrier_local(); \+ x_index = group_id_1 * TR_TILE_DIM + get_local_id(0); \+ y_index = group_id_0 * TR_TILE_DIM + get_local_id(1); \+ if (x_index < y_elems) { \+ for (int32_t j = 0; j < TR_ELEMS_PER_THREAD; j++) { \+ int32_t index_out = (y_index + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD)) * y_elems + x_index; \+ if (y_index + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD) < x_elems) { \+ dst_mem[(odata_offset + index_out)] = \+ block[get_local_id(0) * (TR_TILE_DIM+1) + \+ get_local_id(1) + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD)]; \+ } \+ } \+ } \+ group_id_2 += get_num_groups(2); \+ global_id_2 += get_global_size(2); \+ } \+ group_id_1 += get_num_groups(1); \+ global_id_1 += get_global_size(1); \+ } \+} \+ \+FUTHARK_KERNEL_SIZED(TR_BLOCK_DIM, TR_BLOCK_DIM, 1) \+void map_transpose_##NAME##_low_height(LOCAL_MEM_PARAM \+ __global ELEM_TYPE *dst_mem, \+ int64_t dst_offset, \+ __global ELEM_TYPE *src_mem, \+ int64_t src_offset, \+ int32_t num_arrays, \+ int32_t x_elems, \+ int32_t y_elems, \+ int32_t mulx, \+ int32_t muly, \+ int32_t repeat_1, \+ int32_t repeat_2) { \+ __local ELEM_TYPE* block = (__local ELEM_TYPE*)local_mem; \+ int group_id_0 = get_group_id(0); \+ int global_id_0 = get_global_id(0); \+ int group_id_1 = get_group_id(1); \+ int global_id_1 = get_global_id(1); \+ for (int i1 = 0; i1 <= repeat_1; i1++) { \+ int group_id_2 = get_group_id(2); \+ int global_id_2 = get_global_id(2); \+ for (int i2 = 0; i2 <= repeat_2; i2++) { \+ int32_t our_array_offset = group_id_2 * x_elems * y_elems; \+ int32_t odata_offset = dst_offset + our_array_offset; \+ int32_t idata_offset = src_offset + our_array_offset; \+ int32_t x_index = \+ group_id_0 * TR_BLOCK_DIM * mulx + \+ get_local_id(0) + \+ get_local_id(1)%mulx * TR_BLOCK_DIM; \+ int32_t y_index = group_id_1 * TR_BLOCK_DIM + get_local_id(1)/mulx; \+ int32_t index_in = y_index * x_elems + x_index; \+ if (x_index < x_elems && y_index < y_elems) { \+ block[get_local_id(1) * (TR_BLOCK_DIM+1) + get_local_id(0)] = \+ src_mem[idata_offset + index_in]; \+ } \+ barrier_local(); \+ x_index = group_id_1 * TR_BLOCK_DIM + get_local_id(0)/mulx; \+ y_index = \+ group_id_0 * TR_BLOCK_DIM * mulx + \+ get_local_id(1) + \+ (get_local_id(0)%mulx) * TR_BLOCK_DIM; \+ int32_t index_out = y_index * y_elems + x_index; \+ if (x_index < y_elems && y_index < x_elems) { \+ dst_mem[odata_offset + index_out] = \+ block[get_local_id(0) * (TR_BLOCK_DIM+1) + get_local_id(1)]; \+ } \+ group_id_2 += get_num_groups(2); \+ global_id_2 += get_global_size(2); \+ } \+ group_id_1 += get_num_groups(1); \+ global_id_1 += get_global_size(1); \+ } \+} \+ \+FUTHARK_KERNEL_SIZED(TR_BLOCK_DIM, TR_BLOCK_DIM, 1) \+void map_transpose_##NAME##_low_width(LOCAL_MEM_PARAM \+ __global ELEM_TYPE *dst_mem, \+ int64_t dst_offset, \+ __global ELEM_TYPE *src_mem, \+ int64_t src_offset, \+ int32_t num_arrays, \+ int32_t x_elems, \+ int32_t y_elems, \+ int32_t mulx, \+ int32_t muly, \+ int32_t repeat_1, \+ int32_t repeat_2) { \+ __local ELEM_TYPE* block = (__local ELEM_TYPE*)local_mem; \+ int group_id_0 = get_group_id(0); \+ int global_id_0 = get_global_id(0); \+ int group_id_1 = get_group_id(1); \+ int global_id_1 = get_global_id(1); \+ for (int i1 = 0; i1 <= repeat_1; i1++) { \+ int group_id_2 = get_group_id(2); \+ int global_id_2 = get_global_id(2); \+ for (int i2 = 0; i2 <= repeat_2; i2++) { \+ int32_t our_array_offset = group_id_2 * x_elems * y_elems; \+ int32_t odata_offset = dst_offset + our_array_offset; \+ int32_t idata_offset = src_offset + our_array_offset; \+ int32_t x_index = group_id_0 * TR_BLOCK_DIM + get_local_id(0)/muly; \+ int32_t y_index = \+ group_id_1 * TR_BLOCK_DIM * muly + \+ get_local_id(1) + (get_local_id(0)%muly) * TR_BLOCK_DIM; \+ int32_t index_in = y_index * x_elems + x_index; \+ if (x_index < x_elems && y_index < y_elems) { \+ block[get_local_id(1) * (TR_BLOCK_DIM+1) + get_local_id(0)] = \+ src_mem[idata_offset + index_in]; \+ } \+ barrier_local(); \+ x_index = group_id_1 * TR_BLOCK_DIM * muly + \+ get_local_id(0) + (get_local_id(1)%muly) * TR_BLOCK_DIM; \+ y_index = group_id_0 * TR_BLOCK_DIM + get_local_id(1)/muly; \+ int32_t index_out = y_index * y_elems + x_index; \+ if (x_index < y_elems && y_index < x_elems) { \+ dst_mem[odata_offset + index_out] = \+ block[get_local_id(0) * (TR_BLOCK_DIM+1) + get_local_id(1)]; \+ } \+ group_id_2 += get_num_groups(2); \+ global_id_2 += get_num_groups(2) * get_local_size(2); \+ } \+ group_id_1 += get_num_groups(1); \+ global_id_1 += get_num_groups(1) * get_local_size(1); \+ } \+} \+ \+FUTHARK_KERNEL_SIZED(TR_BLOCK_DIM*TR_BLOCK_DIM, 1, 1) \+void map_transpose_##NAME##_small(LOCAL_MEM_PARAM \+ __global ELEM_TYPE *dst_mem, \+ int64_t dst_offset, \+ __global ELEM_TYPE *src_mem, \+ int64_t src_offset, \+ int32_t num_arrays, \+ int32_t x_elems, \+ int32_t y_elems, \+ int32_t mulx, \+ int32_t muly, \+ int32_t repeat_1, \+ int32_t repeat_2) { \+ (void)mulx; (void)muly; \+ __local ELEM_TYPE* block = (__local ELEM_TYPE*)local_mem; \+ int group_id_0 = get_group_id(0); \+ int global_id_0 = get_global_id(0); \+ int group_id_1 = get_group_id(1); \+ int global_id_1 = get_global_id(1); \+ for (int i1 = 0; i1 <= repeat_1; i1++) { \+ int group_id_2 = get_group_id(2); \+ int global_id_2 = get_global_id(2); \+ for (int i2 = 0; i2 <= repeat_2; i2++) { \+ int32_t our_array_offset = global_id_0/(y_elems * x_elems) * y_elems * x_elems; \+ int32_t x_index = (global_id_0 % (y_elems * x_elems))/y_elems; \+ int32_t y_index = global_id_0%y_elems; \+ int32_t odata_offset = dst_offset + our_array_offset; \+ int32_t idata_offset = src_offset + our_array_offset; \+ int32_t index_in = y_index * x_elems + x_index; \+ int32_t index_out = x_index * y_elems + y_index; \+ if (global_id_0 < x_elems * y_elems * num_arrays) { \+ dst_mem[odata_offset + index_out] = src_mem[idata_offset + index_in]; \+ } \+ group_id_2 += get_num_groups(2); \+ global_id_2 += get_global_size(2); \+ } \+ group_id_1 += get_num_groups(1); \+ global_id_1 += get_global_size(1); \+ } \+} \+ \+FUTHARK_KERNEL_SIZED(TR_BLOCK_DIM*2, TR_TILE_DIM/TR_ELEMS_PER_THREAD, 1)\+void map_transpose_##NAME##_large(LOCAL_MEM_PARAM \+ __global ELEM_TYPE *dst_mem, \+ int64_t dst_offset, \+ __global ELEM_TYPE *src_mem, \+ int64_t src_offset, \+ int64_t num_arrays, \+ int64_t x_elems, \+ int64_t y_elems, \+ int64_t mulx, \+ int64_t muly, \+ int32_t repeat_1, \+ int32_t repeat_2) { \+ (void)mulx; (void)muly; \+ __local ELEM_TYPE* block = (__local ELEM_TYPE*)local_mem; \+ int group_id_0 = get_group_id(0); \+ int global_id_0 = get_global_id(0); \+ int group_id_1 = get_group_id(1); \+ int global_id_1 = get_global_id(1); \+ for (int i1 = 0; i1 <= repeat_1; i1++) { \+ int group_id_2 = get_group_id(2); \+ int global_id_2 = get_global_id(2); \+ for (int i2 = 0; i2 <= repeat_2; i2++) { \+ int64_t our_array_offset = group_id_2 * x_elems * y_elems; \+ int64_t odata_offset = dst_offset + our_array_offset; \+ int64_t idata_offset = src_offset + our_array_offset; \+ int64_t x_index = global_id_0; \+ int64_t y_index = group_id_1 * TR_TILE_DIM + get_local_id(1); \+ if (x_index < x_elems) { \+ for (int64_t j = 0; j < TR_ELEMS_PER_THREAD; j++) { \+ int64_t index_i = (y_index + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD)) * x_elems + x_index; \+ if (y_index + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD) < y_elems) { \+ block[(get_local_id(1) + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD)) * (TR_TILE_DIM+1) + \+ get_local_id(0)] = \+ src_mem[idata_offset + index_i]; \+ } \+ } \+ } \+ barrier_local(); \+ x_index = group_id_1 * TR_TILE_DIM + get_local_id(0); \+ y_index = group_id_0 * TR_TILE_DIM + get_local_id(1); \+ if (x_index < y_elems) { \+ for (int64_t j = 0; j < TR_ELEMS_PER_THREAD; j++) { \+ int64_t index_out = (y_index + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD)) * y_elems + x_index; \+ if (y_index + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD) < x_elems) { \+ dst_mem[(odata_offset + index_out)] = \+ block[get_local_id(0) * (TR_TILE_DIM+1) + \+ get_local_id(1) + j * (TR_TILE_DIM/TR_ELEMS_PER_THREAD)]; \+ } \+ } \+ } \+ group_id_2 += get_num_groups(2); \+ global_id_2 += get_global_size(2); \+ } \+ group_id_1 += get_num_groups(1); \+ global_id_1 += get_global_size(1); \+ } \+} \++GEN_TRANSPOSE_KERNELS(1b, uint8_t)+GEN_TRANSPOSE_KERNELS(2b, uint16_t)+GEN_TRANSPOSE_KERNELS(4b, uint32_t)+GEN_TRANSPOSE_KERNELS(8b, uint64_t)++// End of transpose.cl
rts/python/memory.py view
@@ -55,4 +55,136 @@ return "<opaque Futhark value of type {}>".format(self.desc) +# LMAD stuff+++def lmad_contiguous_search(checked, expected, strides, shape, used):+ for i in range(len(strides)):+ for j in range(len(strides)):+ if not used[j] and strides[j] == expected and strides[j] >= 0:+ used[j] = True+ if checked + 1 == len(strides) or lmad_contiguous_search(+ checked + 1, expected * shape[j], strides, shape, used+ ):+ return True+ used[j] = False+ return False+++def lmad_contiguous(strides, shape):+ used = len(strides) * [False]+ return lmad_contiguous_search(0, 1, strides, shape, used)+++def lmad_memcpyable(dst_strides, src_strides, shape):+ if not lmad_contiguous(dst_strides, shape):+ return False+ for i in range(len(dst_strides)):+ if dst_strides[i] != src_strides[i] and shape[i] != 1:+ return False+ return True+++def lmad_is_tr(strides, shape):+ r = len(shape)+ for i in range(1, r):+ n = 1+ m = 1+ ok = True+ expected = 1+ # Check strides before 'i'.+ for j in range(i - 1, -1, -1):+ ok = ok and strides[j] == expected+ expected *= shape[j]+ n *= shape[j]+ # Check strides after 'i'.+ for j in range(r - 1, i - 1, -1):+ ok = ok and strides[j] == expected+ expected *= shape[j]+ m *= shape[j]+ if ok:+ return (n, m)+ return None+++def lmad_map_tr(dst_strides, src_strides, shape):+ r = len(dst_strides)+ rowmajor_strides = [0] * r+ rowmajor_strides[r - 1] = 1++ for i in range(r - 2, -1, -1):+ rowmajor_strides[i] = rowmajor_strides[i + 1] * shape[i + 1]++ # map_r will be the number of mapped dimensions on top.+ map_r = 0+ k = 1+ for i in range(r):+ if (+ dst_strides[i] != rowmajor_strides[i]+ or src_strides[i] != rowmajor_strides[i]+ ):+ break+ else:+ k *= shape[i]+ map_r += 1++ if rowmajor_strides[map_r:] == dst_strides[map_r:]:+ r = lmad_is_tr(src_strides[map_r:], shape[map_r:])+ if r is not None:+ (n, m) = r+ return (k, n, m)+ elif rowmajor_strides[map_r:] == src_strides[map_r:]:+ r = lmad_is_tr(dst_strides[map_r:], shape[map_r:])+ if r is not None:+ (n, m) = r+ return (k, m, n) # Sic!+ return None+++def lmad_copy_elements(+ pt, dst, dst_offset, dst_strides, src, src_offset, src_strides, shape+):+ if len(shape) == 1:+ for i in range(shape[0]):+ writeScalarArray(+ dst,+ dst_offset + i * dst_strides[0],+ pt(indexArray(src, src_offset + i * src_strides[0], pt)),+ )+ else:+ for i in range(shape[0]):+ lmad_copy_elements(+ pt,+ dst,+ dst_offset + i * dst_strides[0],+ dst_strides[1:],+ src,+ src_offset + i * src_strides[0],+ src_strides[1:],+ shape[1:],+ )+++def lmad_copy(+ pt, dst, dst_offset, dst_strides, src, src_offset, src_strides, shape+):+ if lmad_memcpyable(dst_strides, src_strides, shape):+ ct.memmove(+ addressOffset(dst, dst_offset * ct.sizeof(pt), ct.c_byte),+ addressOffset(src, src_offset * ct.sizeof(pt), ct.c_byte),+ np.prod(shape) * ct.sizeof(pt),+ )+ else:+ lmad_copy_elements(+ pt,+ dst,+ dst_offset,+ dst_strides,+ src,+ src_offset,+ src_strides,+ shape,+ )++ # End of memory.py.
rts/python/opencl.py view
@@ -10,7 +10,11 @@ % cl.version.VERSION_TEXT ) +TR_BLOCK_DIM = 16+TR_TILE_DIM = TR_BLOCK_DIM * 2+TR_ELEMS_PER_THREAD = 8 + def parse_preferred_device(s): pref_num = 0 if len(s) > 1 and s[0] == "#":@@ -284,9 +288,55 @@ if self.platform.name == "Oclgrind": build_options += ["-DEMULATE_F16"] - return cl.Program(self.ctx, program_src).build(build_options)+ build_options += [+ f"-DTR_BLOCK_DIM={TR_BLOCK_DIM}",+ f"-DTR_TILE_DIM={TR_TILE_DIM}",+ f"-DTR_ELEMS_PER_THREAD={TR_ELEMS_PER_THREAD}",+ ] + program = cl.Program(self.ctx, program_src).build(build_options) + self.transpose_kernels = {+ 1: {+ "default": program.map_transpose_1b,+ "low_height": program.map_transpose_1b_low_height,+ "low_width": program.map_transpose_1b_low_width,+ "small": program.map_transpose_1b_small,+ "large": program.map_transpose_1b_large,+ },+ 2: {+ "default": program.map_transpose_2b,+ "low_height": program.map_transpose_2b_low_height,+ "low_width": program.map_transpose_2b_low_width,+ "small": program.map_transpose_2b_small,+ "large": program.map_transpose_2b_large,+ },+ 4: {+ "default": program.map_transpose_4b,+ "low_height": program.map_transpose_4b_low_height,+ "low_width": program.map_transpose_4b_low_width,+ "small": program.map_transpose_4b_small,+ "large": program.map_transpose_4b_large,+ },+ 8: {+ "default": program.map_transpose_8b,+ "low_height": program.map_transpose_8b_low_height,+ "low_width": program.map_transpose_8b_low_width,+ "small": program.map_transpose_8b_small,+ "large": program.map_transpose_8b_large,+ },+ }++ self.copy_kernels = {+ 1: program.lmad_copy_1b,+ 2: program.lmad_copy_2b,+ 4: program.lmad_copy_4b,+ 8: program.lmad_copy_8b,+ }++ return program++ def opencl_alloc(self, min_size, tag): min_size = 1 if min_size == 0 else min_size assert min_size > 0@@ -323,3 +373,125 @@ ) raise Exception(self.failure_msgs[failure[0]].format(*failure_args))+++def map_transpose_gpu2gpu(+ self, elem_size, dst, dst_offset, src, src_offset, k, n, m+):+ kernels = self.transpose_kernels[elem_size]+ kernel = kernels["default"]+ mulx = TR_BLOCK_DIM / n+ muly = TR_BLOCK_DIM / m++ group_dims = (TR_TILE_DIM, TR_TILE_DIM // TR_ELEMS_PER_THREAD, 1)+ dims = (+ (m + TR_TILE_DIM - 1) // TR_TILE_DIM * group_dims[0],+ (n + TR_TILE_DIM - 1) // TR_TILE_DIM * group_dims[1],+ k,+ )++ k32 = np.int32(k)+ n32 = np.int32(n)+ m32 = np.int32(m)+ mulx32 = np.int32(mulx)+ muly32 = np.int32(muly)++ kernel.set_args(+ cl.LocalMemory(TR_TILE_DIM * (TR_TILE_DIM + 1) * elem_size),+ dst,+ dst_offset,+ src,+ src_offset,+ k32,+ m32,+ n32,+ mulx32,+ muly32,+ np.int32(0),+ np.int32(0),+ )+ cl.enqueue_nd_range_kernel(self.queue, kernel, dims, group_dims)+++def copy_elements_gpu2gpu(+ self,+ elem_size,+ dst,+ dst_offset,+ dst_strides,+ src,+ src_offset,+ src_strides,+ shape,+):+ r = len(shape)+ if r > 8:+ raise Exception(+ "Futhark runtime limitation:\nCannot copy array of greater than rank 8.\n"+ )++ n = np.product(shape)+ zero = np.int64(0)+ layout_args = [None] * (8 * 3)+ for i in range(8):+ if i < r:+ layout_args[i * 3 + 0] = shape[i]+ layout_args[i * 3 + 1] = dst_strides[i]+ layout_args[i * 3 + 2] = src_strides[i]+ else:+ layout_args[i * 3 + 0] = zero+ layout_args[i * 3 + 1] = zero+ layout_args[i * 3 + 2] = zero++ kernel = self.copy_kernels[elem_size]+ kernel.set_args(+ cl.LocalMemory(1),+ dst,+ dst_offset,+ src,+ src_offset,+ n,+ np.int32(r),+ *layout_args,+ )+ w = 256+ dims = ((n + w - 1) // w * w,)+ group_dims = (w,)+ cl.enqueue_nd_range_kernel(self.queue, kernel, dims, group_dims)+++def lmad_copy_gpu2gpu(+ self, pt, dst, dst_offset, dst_strides, src, src_offset, src_strides, shape+):+ elem_size = ct.sizeof(pt)+ nbytes = np.product(shape) * elem_size+ if nbytes == 0:+ return None+ if lmad_memcpyable(dst_strides, src_strides, shape):+ cl.enqueue_copy(+ self.queue,+ dst,+ src,+ dst_offset=dst_offset * elem_size,+ src_offset=src_offset * elem_size,+ byte_count=nbytes,+ )+ else:+ tr = lmad_map_tr(dst_strides, src_strides, shape)+ if tr is not None:+ (k, n, m) = tr+ map_transpose_gpu2gpu(+ self, elem_size, dst, dst_offset, src, src_offset, k, m, n+ )+ else:+ copy_elements_gpu2gpu(+ self,+ elem_size,+ dst,+ dst_offset,+ dst_strides,+ src,+ src_offset,+ src_strides,+ shape,+ )
src/Futhark/AD/Fwd.hs view
@@ -72,7 +72,7 @@ getNameSource = gets stateNameSource putNameSource src = modify (\env -> env {stateNameSource = src}) -runADM :: MonadFreshNames m => ADM a -> m a+runADM :: (MonadFreshNames m) => ADM a -> m a runADM (ADM m) = modifyNameSource $ \vn -> second stateNameSource $@@ -91,7 +91,7 @@ newTan :: a -> ADM a bundleNew :: a -> ADM [a] -bundleNewList :: TanBuilder a => [a] -> ADM [a]+bundleNewList :: (TanBuilder a) => [a] -> ADM [a] bundleNewList = fmap mconcat . mapM bundleNew instance TanBuilder (PatElem (TypeBase s u)) where@@ -111,10 +111,10 @@ then pure [pe'] else pure [pe, pe'] -newTanPat :: TanBuilder (PatElem t) => Pat t -> ADM (Pat t)+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 :: (TanBuilder (PatElem t)) => Pat t -> ADM (Pat t) bundleNewPat (Pat pes) = Pat <$> bundleNewList pes instance TanBuilder (Param (TypeBase s u)) where@@ -129,7 +129,7 @@ then pure [param'] else pure [param, param'] -instance Tangent a => TanBuilder (Param (TypeBase s u), a) where+instance (Tangent a) => TanBuilder (Param (TypeBase s u), a) where newTan (p, x) = (,) <$> newTan p <*> tangent x bundleNew (p, x) = do b <- bundleNew p@@ -150,7 +150,7 @@ t' <- tangent t pure [t, t'] -bundleTangents :: Tangent a => [a] -> ADM [a]+bundleTangents :: (Tangent a) => [a] -> ADM [a] bundleTangents = (mconcat <$>) . mapM bundleTan instance Tangent VName where@@ -402,21 +402,21 @@ 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+fwdStm (Let pat aux (Loop val_pats loop@(WhileLoop v) body)) = do 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+ addStm $ Let pat' aux $ Loop val_pats' (WhileLoop v) body'+fwdStm (Let pat aux (Loop val_pats loop@(ForLoop i it bound loop_vars) body)) = do 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'+ addStm $ Let pat' aux $ Loop 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 <- mapM tangent arrs@@ -451,7 +451,7 @@ mapM_ fwdStm stms (res <>) <$> mapM tangent res -fwdJVP :: MonadFreshNames m => Scope SOACS -> Lambda SOACS -> m (Lambda SOACS)+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 <- mapM newTan params
src/Futhark/AD/Rev.hs view
@@ -278,7 +278,7 @@ zipWithM_ insAdj branches_free branches_free_adj diffStm (Let pat aux (Op soac)) m = vjpSOAC vjpOps pat aux soac m-diffStm (Let pat aux loop@DoLoop {}) m =+diffStm (Let pat aux loop@Loop {}) m = diffLoop diffStms pat aux loop m -- See Note [Adjoints of accumulators] diffStm stm@(Let pat _aux (WithAcc inputs lam)) m = do@@ -343,7 +343,7 @@ ts' <- mapM lookupType get_adjs_for pure $ Lambda params body' ts' -revVJP :: MonadFreshNames m => Scope SOACS -> Lambda SOACS -> m (Lambda SOACS)+revVJP :: (MonadFreshNames m) => Scope SOACS -> Lambda SOACS -> m (Lambda SOACS) revVJP scope (Lambda params body ts) = runADM . localScope (scope <> scopeOfLParams params) $ do params_adj <- forM (zip (map resSubExp (bodyResult body)) ts) $ \(se, t) ->
src/Futhark/AD/Rev/Hist.hs view
@@ -644,7 +644,7 @@ radixSortStep (map paramName params) types bit n w letTupExp "sorted" $- DoLoop+ Loop (zip params $ map Var xs) (ForLoop i Int64 iters []) loopbody@@ -664,7 +664,7 @@ l <- letTupExp' "log2res" $- DoLoop+ Loop (zip params [cond_init, m, Constant $ blankPrimValue int64]) (WhileLoop $ paramName cond) body
src/Futhark/AD/Rev/Loop.hs view
@@ -21,7 +21,7 @@ -- | A convenience function to bring the components of a for-loop into -- scope and throw an error if the passed 'Exp' is not a for-loop. bindForLoop ::- PrettyRep rep =>+ (PrettyRep rep) => Exp rep -> ( [(Param (FParamInfo rep), SubExp)] -> LoopForm rep ->@@ -33,7 +33,7 @@ a ) -> a-bindForLoop (DoLoop val_pats form@(ForLoop i it bound loop_vars) body) f =+bindForLoop (Loop val_pats form@(ForLoop i it bound loop_vars) body) f = f val_pats form i it bound loop_vars body bindForLoop e _ = error $ "bindForLoop: not a for-loop:\n" <> prettyString e @@ -57,12 +57,12 @@ -- | Is the loop a while-loop? isWhileLoop :: Exp rep -> Bool-isWhileLoop (DoLoop _ WhileLoop {} _) = True+isWhileLoop (Loop _ WhileLoop {} _) = True isWhileLoop _ = False -- | Transforms a 'ForLoop' into a 'ForLoop' with an empty list of -- loop variables.-removeLoopVars :: MonadBuilder m => Exp (Rep m) -> m (Exp (Rep m))+removeLoopVars :: (MonadBuilder m) => Exp (Rep m) -> m (Exp (Rep m)) removeLoopVars loop = bindForLoop loop $ \val_pats form i _it _bound loop_vars body -> do let indexify (x_param, xs) = do@@ -73,11 +73,11 @@ pure (paramName x_param, x') (substs_list, subst_stms) <- collectStms $ mapM indexify loop_vars let Body aux' stms' res' = substituteNames (M.fromList substs_list) body- pure $ DoLoop val_pats form $ Body aux' (subst_stms <> stms') res'+ pure $ Loop val_pats form $ Body aux' (subst_stms <> stms') res' -- | Augments a while-loop to also compute the number of iterations. computeWhileIters :: Exp SOACS -> ADM SubExp-computeWhileIters (DoLoop val_pats (WhileLoop b) body) = do+computeWhileIters (Loop val_pats (WhileLoop b) body) = do bound_v <- newVName "bound" let t = Prim $ IntType Int64 bound_param = Param mempty bound_v t@@ -89,17 +89,17 @@ in letSubExp "bound+1" $ BasicOp $ BinOp (Add Int64 OverflowUndef) (Var bound_v) one addStms $ bodyStms body pure (pure (subExpRes bound_plus_one) <> bodyResult body)- res <- letTupExp' "loop" $ DoLoop ((bound_param, bound_init) : val_pats) (WhileLoop b) body'+ res <- letTupExp' "loop" $ Loop ((bound_param, bound_init) : val_pats) (WhileLoop b) body' pure $ head res computeWhileIters e = error $ "convertWhileIters: not a while-loop:\n" <> prettyString e -- | Converts a 'WhileLoop' into a 'ForLoop'. Requires that the--- surrounding 'DoLoop' is annotated with a @#[bound(n)]@ attribute,+-- surrounding 'Loop' is annotated with a @#[bound(n)]@ attribute, -- where @n@ is an upper bound on the number of iterations of the -- while-loop. The resulting for-loop will execute for @n@ iterations on -- all inputs, so the tighter the bound the better. convertWhileLoop :: SubExp -> Exp SOACS -> ADM (Exp SOACS)-convertWhileLoop bound_se (DoLoop val_pats (WhileLoop cond) body) =+convertWhileLoop bound_se (Loop val_pats (WhileLoop cond) body) = localScope (scopeOfFParams $ map fst val_pats) $ do i <- newVName "i" body' <-@@ -109,7 +109,7 @@ (pure body) (resultBodyM $ map (Var . paramName . fst) val_pats) ]- pure $ DoLoop val_pats (ForLoop i Int64 bound_se mempty) body'+ pure $ Loop val_pats (ForLoop i Int64 bound_se mempty) body' convertWhileLoop _ e = error $ "convertWhileLoopBound: not a while-loop:\n" <> prettyString e -- | @nestifyLoop n bound loop@ transforms a loop into a depth-@n@ loop nest@@ -149,12 +149,12 @@ =<< nestifyLoop' offset' (n - 1)- (DoLoop val_pats'' (ForLoop i' it' bound_se loop_vars') inner_body)+ (Loop val_pats'' (ForLoop i' it' bound_se loop_vars') inner_body) pure $ varsRes inner_loop pure $- DoLoop val_pats (ForLoop i it bound_se loop_vars) outer_body+ Loop val_pats (ForLoop i it bound_se loop_vars) outer_body | n == 1 =- pure $ DoLoop val_pats (ForLoop i it bound_se loop_vars) body+ pure $ Loop val_pats (ForLoop i it bound_se loop_vars) body | otherwise = pure loop -- | @stripmine n pat loop@ stripmines a loop into a depth-@n@ loop nest.@@ -185,7 +185,7 @@ let loop_params_rem = map fst val_pats' loop_inits_rem = map (Var . patElemName) $ patElems pat' val_pats_rem = zip loop_params_rem loop_inits_rem- remain_loop = DoLoop val_pats_rem (ForLoop i' it' remain_iters loop_vars') remain_body+ remain_loop = Loop val_pats_rem (ForLoop i' it' remain_iters loop_vars') remain_body collectStms_ $ do letBind pat' mined_loop letBind pat remain_loop@@ -194,7 +194,7 @@ -- expression is a for-loop with a @#[stripmine(n)]@ attribute, where -- @n@ is the nesting depth. stripmineStm :: Stm SOACS -> ADM (Stms SOACS)-stripmineStm stm@(Let pat aux loop@(DoLoop _ ForLoop {} _)) =+stripmineStm stm@(Let pat aux loop@(Loop _ ForLoop {} _)) = case nums of (n : _) -> stripmine n pat loop _ -> pure $ oneStm stm@@ -256,7 +256,7 @@ let pat' = pat <> Pat saved_pats val_pats' = val_pats <> zip saved_params empty_saved_array- addStm $ Let pat' aux $ DoLoop val_pats' form body'+ addStm $ Let pat' aux $ Loop val_pats' form body' -- | Construct a loop value-pattern for the adjoint of the -- given variable.@@ -420,7 +420,7 @@ adjs' <- letTupExp "loop_adj" $ substituteNames (restore_true_deps <> var_array_substs) $- DoLoop val_pat_adjs_list form' body_adj+ Loop val_pat_adjs_list form' body_adj let (loop_res_adjs, loop_free_var_val_adjs) = splitAt (length $ loopRes loop_adjs) adjs' (loop_free_adjs, loop_var_val_adjs) =
src/Futhark/AD/Rev/Map.hs view
@@ -50,7 +50,7 @@ (xs, ys, zs) = partitionAdjVars fvs buildRenamedBody ::- MonadBuilder m =>+ (MonadBuilder m) => m (Result, a) -> m (Body (Rep m), a) buildRenamedBody m = do
src/Futhark/AD/Rev/Monad.hs view
@@ -125,7 +125,7 @@ substituteNames m (AdjVal (Var v)) = AdjVal $ Var $ substituteNames m v substituteNames _ adj = adj -zeroArray :: MonadBuilder m => Shape -> Type -> m VName+zeroArray :: (MonadBuilder m) => Shape -> Type -> m VName zeroArray shape t | shapeRank shape == 0 = letExp "zero" $ zeroExp t@@ -217,7 +217,7 @@ getNameSource = gets stateNameSource putNameSource src = modify (\env -> env {stateNameSource = src}) -runADM :: MonadFreshNames m => ADM a -> m a+runADM :: (MonadFreshNames m) => ADM a -> m a runADM (ADM m) = modifyNameSource $ \vn -> second stateNameSource $
src/Futhark/AD/Rev/Reduce.hs view
@@ -16,7 +16,7 @@ import Futhark.Tools import Futhark.Transform.Rename -eReverse :: MonadBuilder m => VName -> m VName+eReverse :: (MonadBuilder m) => VName -> m VName eReverse arr = do arr_t <- lookupType arr let w = arraySize 0 arr_t
src/Futhark/Actions.hs view
@@ -16,6 +16,7 @@ compileCtoWASMAction, compileOpenCLAction, compileCUDAAction,+ compileHIPAction, compileMulticoreAction, compileMulticoreToISPCAction, compileMulticoreToWASMAction,@@ -40,6 +41,7 @@ import Futhark.Analysis.Metrics import Futhark.CodeGen.Backends.CCUDA qualified as CCUDA import Futhark.CodeGen.Backends.COpenCL qualified as COpenCL+import Futhark.CodeGen.Backends.HIP qualified as HIP import Futhark.CodeGen.Backends.MulticoreC qualified as MulticoreC import Futhark.CodeGen.Backends.MulticoreISPC qualified as MulticoreISPC import Futhark.CodeGen.Backends.MulticoreWASM qualified as MulticoreWASM@@ -65,7 +67,7 @@ import System.Info qualified -- | Print the result to stdout.-printAction :: ASTRep rep => Action rep+printAction :: (ASTRep rep) => Action rep printAction = Action { actionName = "Prettyprint",@@ -74,7 +76,7 @@ } -- | Print the result to stdout, alias annotations.-printAliasesAction :: AliasableRep rep => Action rep+printAliasesAction :: (AliasableRep rep) => Action rep printAliasesAction = Action { actionName = "Prettyprint",@@ -141,7 +143,7 @@ } -- | Print metrics about AST node counts to stdout.-metricsAction :: OpMetrics (Op rep) => Action rep+metricsAction :: (OpMetrics (Op rep)) => Action rep metricsAction = Action { actionName = "Compute metrics",@@ -365,6 +367,37 @@ runCC cpath outpath ["-O", "-std=c99"] ("-lm" : extra_options) ToServer -> do liftIO $ T.writeFile cpath $ cPrependHeader $ CCUDA.asServer cprog+ runCC cpath outpath ["-O", "-std=c99"] ("-lm" : extra_options)++-- | The @futhark hip@ action.+compileHIPAction :: FutharkConfig -> CompilerMode -> FilePath -> Action GPUMem+compileHIPAction fcfg mode outpath =+ Action+ { actionName = "Compile to HIP",+ actionDescription = "Compile to HIP",+ actionProcedure = helper+ }+ where+ helper prog = do+ cprog <- handleWarnings fcfg $ HIP.compileProg versionString prog+ let cpath = outpath `addExtension` "c"+ hpath = outpath `addExtension` "h"+ jsonpath = outpath `addExtension` "json"+ extra_options =+ [ "-lamdhip64",+ "-lhiprtc"+ ]+ case mode of+ ToLibrary -> do+ let (header, impl, manifest) = HIP.asLibrary cprog+ liftIO $ T.writeFile hpath $ cPrependHeader header+ liftIO $ T.writeFile cpath $ cPrependHeader impl+ liftIO $ T.writeFile jsonpath manifest+ ToExecutable -> do+ liftIO $ T.writeFile cpath $ cPrependHeader $ HIP.asExecutable cprog+ runCC cpath outpath ["-O", "-std=c99"] ("-lm" : extra_options)+ ToServer -> do+ liftIO $ T.writeFile cpath $ cPrependHeader $ HIP.asServer cprog runCC cpath outpath ["-O", "-std=c99"] ("-lm" : extra_options) -- | The @futhark multicore@ action.
src/Futhark/Analysis/Alias.hs view
@@ -28,7 +28,7 @@ -- | Perform alias analysis on a Futhark program. aliasAnalysis ::- AliasableRep rep =>+ (AliasableRep rep) => Prog rep -> Prog (Aliases rep) aliasAnalysis prog =@@ -39,7 +39,7 @@ -- | Perform alias analysis on function. analyseFun ::- AliasableRep rep =>+ (AliasableRep rep) => FunDef rep -> FunDef (Aliases rep) analyseFun (FunDef entry attrs fname restype params body) =@@ -49,7 +49,7 @@ -- | Perform alias analysis on Body. analyseBody ::- AliasableRep rep =>+ (AliasableRep rep) => AliasTable -> Body rep -> Body (Aliases rep)@@ -59,7 +59,7 @@ -- | Perform alias analysis on statements. analyseStms ::- AliasableRep rep =>+ (AliasableRep rep) => AliasTable -> Stms rep -> (Stms (Aliases rep), AliasesAndConsumed)@@ -78,7 +78,7 @@ -- | Perform alias analysis on statement. analyseStm ::- AliasableRep rep =>+ (AliasableRep rep) => AliasTable -> Stm rep -> Stm (Aliases rep)@@ -90,7 +90,7 @@ -- | Perform alias analysis on expression. analyseExp ::- AliasableRep rep =>+ (AliasableRep rep) => AliasTable -> Exp rep -> Exp (Aliases rep)@@ -130,7 +130,7 @@ -- | Perform alias analysis on lambda. analyseLambda ::- AliasableRep rep =>+ (AliasableRep rep) => AliasTable -> Lambda rep -> Lambda (Aliases rep)
src/Futhark/Analysis/CallGraph.hs view
@@ -88,8 +88,8 @@ <> fcAllCalled cg ftable = buildFunctionTable prog -count :: Ord k => [k] -> M.Map k Int-count ks = M.fromListWith (+) $ zip ks $ repeat 1+count :: (Ord k) => [k] -> M.Map k Int+count ks = M.fromListWith (+) $ map (,1) ks -- | Produce a mapping of the number of occurences in the call graph -- of each function. Only counts functions that are called at least
src/Futhark/Analysis/DataDependencies.hs view
@@ -17,11 +17,11 @@ type Dependencies = M.Map VName Names -- | Compute the data dependencies for an entire body.-dataDependencies :: ASTRep rep => Body rep -> Dependencies+dataDependencies :: (ASTRep rep) => Body rep -> Dependencies dataDependencies = dataDependencies' M.empty dataDependencies' ::- ASTRep rep =>+ (ASTRep rep) => Dependencies -> Body rep -> Dependencies
src/Futhark/Analysis/HORep/MapNest.hs view
@@ -164,7 +164,7 @@ pure $ SOAC.Screma w (Futhark.mapSOAC outerlam) inps fixInputs ::- MonadFreshNames m =>+ (MonadFreshNames m) => SubExp -> [(VName, SOAC.Input)] -> [(VName, SOAC.Input)] ->
src/Futhark/Analysis/HORep/SOAC.hs view
@@ -266,7 +266,7 @@ (substituteNames substs t) -- | Create a plain array variable input with no transformations.-varInput :: HasScope t f => VName -> f Input+varInput :: (HasScope t f) => VName -> f Input varInput v = withType <$> lookupType v where withType = Input (ArrayTransforms Seq.empty) v@@ -301,7 +301,7 @@ addInitialTransforms :: ArrayTransforms -> Input -> Input addInitialTransforms ts (Input ots a t) = Input (ts <> ots) a t -applyTransform :: MonadBuilder m => ArrayTransform -> VName -> m VName+applyTransform :: (MonadBuilder m) => ArrayTransform -> VName -> m VName applyTransform tr ia = do (cs, e) <- transformToExp tr ia certifying cs $ letExp s e@@ -313,7 +313,7 @@ ReshapeOuter {} -> "reshape_outer" ReshapeInner {} -> "reshape_inner" -applyTransforms :: MonadBuilder m => ArrayTransforms -> VName -> m VName+applyTransforms :: (MonadBuilder m) => ArrayTransforms -> VName -> m VName applyTransforms (ArrayTransforms ts) a = foldlM (flip applyTransform) a ts -- | Convert SOAC inputs to the corresponding expressions.@@ -416,7 +416,7 @@ f e (Replicate cs ne) = "replicate" <> pretty cs <> PP.apply [pretty ne, e] -instance PrettyRep rep => PP.Pretty (SOAC rep) where+instance (PrettyRep rep) => PP.Pretty (SOAC rep) where pretty (Screma w form arrs) = Futhark.ppScrema w arrs form pretty (Hist len ops bucket_fun imgs) = Futhark.ppHist len imgs ops bucket_fun pretty (Stream w lam nes arrs) = Futhark.ppStream w arrs nes lam@@ -499,7 +499,7 @@ toExp soac = Op <$> toSOAC soac -- | Convert a SOAC to a Futhark-level SOAC.-toSOAC :: MonadBuilder m => SOAC (Rep m) -> m (Futhark.SOAC (Rep m))+toSOAC :: (MonadBuilder m) => SOAC (Rep m) -> m (Futhark.SOAC (Rep m)) toSOAC (Stream w lam nes inps) = Futhark.Stream w <$> inputsToSubExps inps <*> pure nes <*> pure lam toSOAC (Scatter w lam ivs dests) =
src/Futhark/Analysis/Interference.hs view
@@ -34,13 +34,13 @@ type Graph a = Set (a, a) -- | Insert an edge between two values into the graph.-makeEdge :: Ord a => a -> a -> Graph a+makeEdge :: (Ord a) => a -> a -> Graph a makeEdge v1 v2 | v1 == v2 = mempty | otherwise = S.singleton (min v1 v2, max v1 v2) analyseStm ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> Stm GPUMem ->@@ -86,7 +86,7 @@ (namesToList $ inuse_outside <> inuse <> lus <> last_use_mems) ) --- We conservatively treat all memory arguments to a DoLoop to+-- We conservatively treat all memory arguments to a Loop to -- interfere with each other, as well as anything used inside the -- loop. This could potentially be improved by looking at the -- interference computed by the loop body wrt. the loop arguments, but@@ -104,7 +104,7 @@ isMemArg _ = Nothing analyseExp ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> Exp GPUMem ->@@ -115,7 +115,7 @@ fmap mconcat $ mapM (analyseBody lumap inuse_outside) $ defbody : map caseBody cases- DoLoop merge _ body ->+ Loop merge _ body -> analyseLoopParams merge <$> analyseBody lumap inuse_outside body Op (Inner (SegOp segop)) -> do analyseSegOp lumap inuse_outside segop@@ -123,7 +123,7 @@ pure mempty analyseKernelBody ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> KernelBody GPUMem ->@@ -131,7 +131,7 @@ analyseKernelBody lumap inuse body = analyseStms lumap inuse $ kernelBodyStms body analyseBody ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> Body GPUMem ->@@ -139,7 +139,7 @@ analyseBody lumap inuse body = analyseStms lumap inuse $ bodyStms body analyseStms ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> Stms GPUMem ->@@ -152,7 +152,7 @@ pure (inuse', lus' <> lus, graph' <> graph) analyseSegOp ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> SegOp lvl GPUMem ->@@ -169,7 +169,7 @@ pure (inuse'', lus' <> lus'', graph <> graph') segWithBinOps ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> [SegBinOp GPUMem] ->@@ -185,7 +185,7 @@ pure (inuse'', lus' <> lus'', graph <> graph') analyseSegBinOp ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> SegBinOp GPUMem ->@@ -194,7 +194,7 @@ analyseLambda lumap inuse lambda analyseHistOp ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> HistOp GPUMem ->@@ -203,7 +203,7 @@ analyseLambda lumap inuse (histOp histop) analyseLambda ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> InUse -> Lambda GPUMem ->@@ -238,7 +238,7 @@ -- triple of the names currently in use, names that hit their last use somewhere -- within, and the resulting graph. analyseGPU ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> Stms GPUMem -> m (Graph VName)@@ -264,16 +264,16 @@ -- | Return a mapping from memory blocks to their element sizes in the given -- statements.-memSizes :: LocalScope GPUMem m => Stms GPUMem -> m (Map VName Int)+memSizes :: (LocalScope GPUMem m) => Stms GPUMem -> m (Map VName Int) memSizes stms = inScopeOf stms $ fmap mconcat <$> mapM memSizesStm $ stmsToList stms where- memSizesStm :: LocalScope GPUMem m => Stm GPUMem -> m (Map VName Int)+ memSizesStm :: (LocalScope GPUMem m) => Stm GPUMem -> m (Map VName Int) memSizesStm (Let pat _ e) = do arraySizes <- fmap mconcat <$> mapM memElemSize $ patNames pat arraySizes' <- memSizesExp e pure $ arraySizes <> arraySizes'- memSizesExp :: LocalScope GPUMem m => Exp GPUMem -> m (Map VName Int)+ memSizesExp :: (LocalScope GPUMem m) => Exp GPUMem -> m (Map VName Int) memSizesExp (Op (Inner (SegOp segop))) = let body = segBody segop in inScopeOf (kernelBodyStms body)@@ -283,12 +283,12 @@ $ kernelBodyStms body memSizesExp (Match _ cases defbody _) = do mconcat <$> mapM (memSizes . bodyStms) (defbody : map caseBody cases)- memSizesExp (DoLoop _ _ body) =+ memSizesExp (Loop _ _ body) = memSizes $ bodyStms body memSizesExp _ = pure mempty -- | Return a mapping from memory blocks to the space they are allocated in.-memSpaces :: LocalScope GPUMem m => Stms GPUMem -> m (Map VName Space)+memSpaces :: (LocalScope GPUMem m) => Stms GPUMem -> m (Map VName Space) memSpaces stms = pure $ foldMap getSpacesStm stms where@@ -300,12 +300,12 @@ foldMap getSpacesStm $ kernelBodyStms $ segBody segop getSpacesStm (Let _ _ (Match _ cases defbody _)) = foldMap (foldMap getSpacesStm . bodyStms) $ defbody : map caseBody cases- getSpacesStm (Let _ _ (DoLoop _ _ body)) =+ getSpacesStm (Let _ _ (Loop _ _ body)) = foldMap getSpacesStm (bodyStms body) getSpacesStm _ = mempty analyseGPU' ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => LUTabFun -> Stms GPUMem -> m (InUse, LastUsed, Graph VName)@@ -313,7 +313,7 @@ mconcat . toList <$> mapM helper stms where helper ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => Stm GPUMem -> m (InUse, LastUsed, Graph VName) helper stm@Let {stmExp = Op (Inner (SegOp segop))} =@@ -322,14 +322,14 @@ inScopeOf stm $ mconcat <$> mapM (analyseGPU' lumap . bodyStms) (defbody : map caseBody cases)- helper stm@Let {stmExp = DoLoop merge _ body} =+ helper stm@Let {stmExp = Loop merge _ body} = fmap (analyseLoopParams merge) . inScopeOf stm $ analyseGPU' lumap $ bodyStms body helper stm = inScopeOf stm $ pure mempty -nameInfoToMemInfo :: Mem rep inner => NameInfo rep -> MemBound NoUniqueness+nameInfoToMemInfo :: (Mem rep inner) => NameInfo rep -> MemBound NoUniqueness nameInfoToMemInfo info = case info of FParamName summary -> noUniquenessReturns summary@@ -337,7 +337,7 @@ LetName summary -> letDecMem summary IndexName it -> MemPrim $ IntType it -memInfo :: LocalScope GPUMem m => VName -> m (Maybe VName)+memInfo :: (LocalScope GPUMem m) => VName -> m (Maybe VName) memInfo vname = do summary <- asksScope (fmap nameInfoToMemInfo . M.lookup vname) case summary of@@ -349,7 +349,7 @@ -- | Returns a mapping from memory block to element size. The input is the -- `VName` of a variable (supposedly an array), and the result is a mapping from -- the memory block of that array to element size of the array.-memElemSize :: LocalScope GPUMem m => VName -> m (Map VName Int)+memElemSize :: (LocalScope GPUMem m) => VName -> m (Map VName Int) memElemSize vname = do summary <- asksScope (fmap nameInfoToMemInfo . M.lookup vname) case summary of
src/Futhark/Analysis/LastUse.hs view
@@ -62,10 +62,10 @@ MonadState AliasTab ) -instance RepTypes (Aliases rep) => HasScope (Aliases rep) (LastUseM rep) where+instance (RepTypes (Aliases rep)) => HasScope (Aliases rep) (LastUseM rep) where askScope = asks scope -instance RepTypes (Aliases rep) => LocalScope (Aliases rep) (LastUseM rep) where+instance (RepTypes (Aliases rep)) => LocalScope (Aliases rep) (LastUseM rep) where localScope sc (LastUseM m) = LastUseM $ do local (\rd -> rd {scope = scope rd <> sc}) m @@ -84,7 +84,7 @@ gets $ fromMaybe mempty . M.lookup vname lastUseProg ::- Constraints rep =>+ (Constraints rep) => Prog (Aliases rep) -> LastUseM rep LUTabProg lastUseProg prog =@@ -100,7 +100,7 @@ pure (consts_lu, M.fromList $ zip (map funDefName funs) lus) lastUseFun ::- Constraints rep =>+ (Constraints rep) => Names -> FunDef (Aliases rep) -> LastUseM rep LUTabFun@@ -126,7 +126,7 @@ -- difference between the free-variables in that stmt and the set of variables -- known to be used after that statement. lastUseBody ::- Constraints rep =>+ (Constraints rep) => -- | The body of statements Body (Aliases rep) -> -- | The current last-use table, tupled with the known set of already used names@@ -156,7 +156,7 @@ -- difference between the free-variables in that stmt and the set of variables -- known to be used after that statement. lastUseKernelBody ::- Constraints rep =>+ (Constraints rep) => -- | The body of statements KernelBody (Aliases rep) -> -- | The current last-use table, tupled with the known set of already used names@@ -177,7 +177,7 @@ pure (lutab', used_nms <> used_in_body) lastUseStms ::- Constraints rep =>+ (Constraints rep) => Stms (Aliases rep) -> (LUTabFun, Names) -> [VName] ->@@ -199,7 +199,7 @@ pure (lutab'', nms'') lastUseStm ::- Constraints rep =>+ (Constraints rep) => Stm (Aliases rep) -> (LUTabFun, Names) -> LastUseM rep (LUTabFun, Names)@@ -229,7 +229,7 @@ -- | Last-Use Analysis for an expression. lastUseExp ::- Constraints rep =>+ (Constraints rep) => -- | The expression to analyse Exp (Aliases rep) -> -- | The set of used names "after" this expression@@ -253,7 +253,7 @@ 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+lastUseExp (Loop 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@@ -304,7 +304,7 @@ lastUseMemOp onInner (Inner op) used_nms = onInner op used_nms lastUseSegOp ::- Constraints rep =>+ (Constraints rep) => SegOp lvl (Aliases rep) -> Names -> LastUseM rep (LUTabFun, Names, Names)@@ -356,7 +356,7 @@ ) lastUseSegBinOp ::- Constraints rep =>+ (Constraints rep) => [SegBinOp (Aliases rep)] -> Names -> LastUseM rep (LUTabFun, Names, Names)@@ -370,7 +370,7 @@ pure (body_lutab, lu_vars, used_nms'') lastUseHistOp ::- Constraints rep =>+ (Constraints rep) => [HistOp (Aliases rep)] -> Names -> LastUseM rep (LUTabFun, Names, Names)@@ -430,7 +430,7 @@ -- | 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 =>+ (AliasesOf dec) => -- | Extra names that all 'PatElem' should alias. Names -> -- | Pattern to process@@ -439,7 +439,7 @@ updateAliasing extra_aliases = mapM_ update . patElems where- update :: AliasesOf dec => PatElem dec -> LastUseM rep ()+ update :: (AliasesOf dec) => PatElem dec -> LastUseM rep () update (PatElem name dec) = do let aliases = aliasesOf dec aliases' <- aliasTransitiveClosure $ extra_aliases <> aliases
src/Futhark/Analysis/MemAlias.hs view
@@ -95,7 +95,7 @@ & mapMaybe (filterFun m') & foldr (uncurry addAlias) m' & pure-analyzeStm m (Let pat _ (DoLoop params _ body)) = do+analyzeStm m (Let pat _ (Loop params _ body)) = do let m_init = map snd params & zip (patNames pat)
src/Futhark/Analysis/Metrics.hs view
@@ -29,7 +29,7 @@ class OpMetrics op where opMetrics :: op -> MetricsM () -instance OpMetrics a => OpMetrics (Maybe a) where+instance (OpMetrics a) => OpMetrics (Maybe a) where opMetrics Nothing = pure () opMetrics (Just x) = opMetrics x @@ -78,7 +78,7 @@ addWhat' (ctx, k) = (what : ctx, k) -- | Compute the metrics for a program.-progMetrics :: OpMetrics (Op rep) => Prog rep -> AstMetrics+progMetrics :: (OpMetrics (Op rep)) => Prog rep -> AstMetrics progMetrics prog = actualMetrics $ execWriter $@@ -86,24 +86,24 @@ mapM_ funDefMetrics $ progFuns prog mapM_ stmMetrics $ progConsts prog -funDefMetrics :: OpMetrics (Op rep) => FunDef rep -> MetricsM ()+funDefMetrics :: (OpMetrics (Op rep)) => FunDef rep -> MetricsM () funDefMetrics = bodyMetrics . funDefBody -- | Compute metrics for this body.-bodyMetrics :: OpMetrics (Op rep) => Body rep -> MetricsM ()+bodyMetrics :: (OpMetrics (Op rep)) => Body rep -> MetricsM () bodyMetrics = mapM_ stmMetrics . bodyStms -- | Compute metrics for this statement.-stmMetrics :: OpMetrics (Op rep) => Stm rep -> MetricsM ()+stmMetrics :: (OpMetrics (Op rep)) => Stm rep -> MetricsM () stmMetrics = expMetrics . stmExp -expMetrics :: OpMetrics (Op rep) => Exp rep -> MetricsM ()+expMetrics :: (OpMetrics (Op rep)) => Exp rep -> MetricsM () expMetrics (BasicOp op) = seen "BasicOp" >> basicOpMetrics op-expMetrics (DoLoop _ ForLoop {} body) =- inside "DoLoop" $ seen "ForLoop" >> bodyMetrics body-expMetrics (DoLoop _ WhileLoop {} body) =- inside "DoLoop" $ seen "WhileLoop" >> bodyMetrics body+expMetrics (Loop _ ForLoop {} body) =+ inside "Loop" $ seen "ForLoop" >> bodyMetrics body+expMetrics (Loop _ WhileLoop {} body) =+ inside "Loop" $ seen "WhileLoop" >> bodyMetrics body expMetrics (Match _ [Case [Just (BoolValue True)] tb] fb _) = inside "If" $ do inside "True" $ bodyMetrics tb@@ -143,5 +143,5 @@ basicOpMetrics UpdateAcc {} = seen "UpdateAcc" -- | Compute metrics for this lambda.-lambdaMetrics :: OpMetrics (Op rep) => Lambda rep -> MetricsM ()+lambdaMetrics :: (OpMetrics (Op rep)) => Lambda rep -> MetricsM () lambdaMetrics = bodyMetrics . lambdaBody
src/Futhark/Analysis/PrimExp.hs view
@@ -118,7 +118,7 @@ traverse f (FunExp h args t) = FunExp h <$> traverse (traverse f) args <*> pure t -instance FreeIn v => FreeIn (PrimExp v) where+instance (FreeIn v) => FreeIn (PrimExp v) where freeIn' = foldMap freeIn' -- | A 'PrimExp' tagged with a phantom type used to provide type-safe@@ -136,7 +136,7 @@ instance Traversable (TPrimExp t) where traverse f (TPrimExp e) = TPrimExp <$> traverse f e -instance FreeIn v => FreeIn (TPrimExp t v) where+instance (FreeIn v) => FreeIn (TPrimExp t v) where freeIn' = freeIn' . untyped -- | This expression is of type t'Int8'.@@ -246,7 +246,7 @@ ValueExp $ IntValue $ intValue it (0 :: Integer) constFoldPrimExp e = e -constFoldCmpExp :: Eq v => PrimExp v -> PrimExp v+constFoldCmpExp :: (Eq v) => PrimExp v -> PrimExp v constFoldCmpExp (CmpOpExp (CmpEq _) x y) | x == y = untyped true@@ -267,7 +267,7 @@ -- | The class of integer types that can be used for constructing -- 'TPrimExp's.-class NumExp t => IntExp t where+class (NumExp t) => IntExp t where -- | The type of an expression, known to be an integer type. expIntType :: TPrimExp t v -> IntType @@ -301,7 +301,7 @@ -- | The class of floating-point types that can be used for -- constructing 'TPrimExp's.-class NumExp t => FloatExp t where+class (NumExp t) => FloatExp t where -- | Construct a typed expression from a rational. fromRational' :: Rational -> TPrimExp t v @@ -378,7 +378,7 @@ fromRational = fromRational' -instance Pretty v => Floating (TPrimExp Half v) where+instance (Pretty v) => Floating (TPrimExp Half v) where x ** y = isF16 $ BinOpExp (FPow Float16) (untyped x) (untyped y) pi = isF16 $ ValueExp $ FloatValue $ Float16Value pi exp x = isF16 $ FunExp "exp16" [untyped x] $ FloatType Float16@@ -396,7 +396,7 @@ acosh x = isF16 $ FunExp "acosh16" [untyped x] $ FloatType Float16 atanh x = isF16 $ FunExp "atanh16" [untyped x] $ FloatType Float16 -instance Pretty v => Floating (TPrimExp Float v) where+instance (Pretty v) => Floating (TPrimExp Float v) where x ** y = isF32 $ BinOpExp (FPow Float32) (untyped x) (untyped y) pi = isF32 $ ValueExp $ FloatValue $ Float32Value pi exp x = isF32 $ FunExp "exp32" [untyped x] $ FloatType Float32@@ -414,7 +414,7 @@ acosh x = isF32 $ FunExp "acosh32" [untyped x] $ FloatType Float32 atanh x = isF32 $ FunExp "atanh32" [untyped x] $ FloatType Float32 -instance Pretty v => Floating (TPrimExp Double v) where+instance (Pretty v) => Floating (TPrimExp Double v) where x ** y = isF64 $ BinOpExp (FPow Float64) (untyped x) (untyped y) pi = isF64 $ ValueExp $ FloatValue $ Float64Value pi exp x = isF64 $ FunExp "exp64" [untyped x] $ FloatType Float64@@ -476,16 +476,16 @@ sgn _ = Nothing -- | Lifted logical conjunction.-(.&&.) :: Eq v => TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v+(.&&.) :: (Eq v) => TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v TPrimExp x .&&. TPrimExp y = TPrimExp $ constFoldPrimExp $ BinOpExp LogAnd x y -- | Lifted logical conjunction.-(.||.) :: Eq v => TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v+(.||.) :: (Eq v) => TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v TPrimExp x .||. TPrimExp y = TPrimExp $ constFoldPrimExp $ BinOpExp LogOr x y -- | Lifted relational operators; assuming signed numbers in case of -- integers.-(.<.), (.>.), (.<=.), (.>=.), (.==.) :: Eq v => TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v+(.<.), (.>.), (.<=.), (.>=.), (.==.) :: (Eq v) => TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v TPrimExp x .<. TPrimExp y = TPrimExp $ constFoldCmpExp $ CmpOpExp cmp x y where@@ -508,8 +508,8 @@ x .>=. y = y .<=. x -- | Lifted bitwise operators. The right-shift is logical, *not* arithmetic.-(.&.), (.|.), (.^.), (.>>.), (.<<.) :: Eq v => TPrimExp t v -> TPrimExp t v -> TPrimExp t v-bitPrimExp :: Eq v => (IntType -> BinOp) -> TPrimExp t v -> TPrimExp t v -> TPrimExp t v+(.&.), (.|.), (.^.), (.>>.), (.<<.) :: (Eq v) => TPrimExp t v -> TPrimExp t v -> TPrimExp t v+bitPrimExp :: (Eq v) => (IntType -> BinOp) -> TPrimExp t v -> TPrimExp t v -> TPrimExp t v bitPrimExp op (TPrimExp x) (TPrimExp y) = TPrimExp $ constFoldPrimExp $@@ -552,7 +552,7 @@ | FloatType t <- primExpType x = Just $ BinOpExp (f t) x y | otherwise = Nothing -numBad :: Pretty a => String -> a -> b+numBad :: (Pretty a) => String -> a -> b numBad s x = error $ "Invalid argument to PrimExp method " ++ s ++ ": " ++ prettyString x @@ -661,19 +661,19 @@ sMin64 x y = TPrimExp $ BinOpExp (SMin Int64) (untyped x) (untyped y) -- | Sign-extend to 32 bit integer.-sExt32 :: IntExp t => TPrimExp t v -> TPrimExp Int32 v+sExt32 :: (IntExp t) => TPrimExp t v -> TPrimExp Int32 v sExt32 = isInt32 . sExt Int32 . untyped -- | Sign-extend to 64 bit integer.-sExt64 :: IntExp t => TPrimExp t v -> TPrimExp Int64 v+sExt64 :: (IntExp t) => TPrimExp t v -> TPrimExp Int64 v sExt64 = isInt64 . sExt Int64 . untyped -- | Zero-extend to 32 bit integer.-zExt32 :: IntExp t => TPrimExp t v -> TPrimExp Int32 v+zExt32 :: (IntExp t) => TPrimExp t v -> TPrimExp Int32 v zExt32 = isInt32 . zExt Int32 . untyped -- | Zero-extend to 64 bit integer.-zExt64 :: IntExp t => TPrimExp t v -> TPrimExp Int64 v+zExt64 :: (IntExp t) => TPrimExp t v -> TPrimExp Int64 v zExt64 = isInt64 . zExt Int64 . untyped -- | 16-bit float minimum.@@ -711,7 +711,7 @@ -- Prettyprinting instances -instance Pretty v => Pretty (PrimExp v) where+instance (Pretty v) => Pretty (PrimExp v) where pretty (LeafExp v _) = pretty v pretty (ValueExp v) = pretty v pretty (BinOpExp op x y) = pretty op <+> parens (pretty x) <+> parens (pretty y)@@ -720,12 +720,12 @@ pretty (UnOpExp op x) = pretty op <+> parens (pretty x) pretty (FunExp h args _) = pretty h <+> parens (commasep $ map pretty args) -instance Pretty v => Pretty (TPrimExp t v) where+instance (Pretty v) => Pretty (TPrimExp t v) where pretty = pretty . untyped -- | Produce a mapping from the leaves of the 'PrimExp' to their -- designated types.-leafExpTypes :: Ord a => PrimExp a -> S.Set (a, PrimType)+leafExpTypes :: (Ord a) => PrimExp a -> S.Set (a, PrimType) leafExpTypes (LeafExp x ptp) = S.singleton (x, ptp) leafExpTypes (ValueExp _) = S.empty leafExpTypes (UnOpExp _ e) = leafExpTypes e
src/Futhark/Analysis/PrimExp/Convert.hs view
@@ -33,7 +33,7 @@ import Futhark.Construct import Futhark.IR -instance ToExp v => ToExp (PrimExp v) where+instance (ToExp v) => ToExp (PrimExp v) where toExp (BinOpExp op x y) = BasicOp <$> (BinOp op <$> toSubExp "binop_x" x <*> toSubExp "binop_y" y) toExp (CmpOpExp op x y) =@@ -54,7 +54,7 @@ toExp (LeafExp v _) = toExp v -instance ToExp v => ToExp (TPrimExp t v) where+instance (ToExp v) => ToExp (TPrimExp t v) where toExp = toExp . untyped -- | Convert an expression to a 'PrimExp'. The provided function is@@ -83,7 +83,7 @@ primExpFromExp _ _ = fail "Not a PrimExp" -- | Like 'primExpFromExp', but for a t'SubExp'.-primExpFromSubExpM :: Applicative m => (VName -> m (PrimExp v)) -> SubExp -> m (PrimExp v)+primExpFromSubExpM :: (Applicative m) => (VName -> m (PrimExp v)) -> SubExp -> m (PrimExp v) primExpFromSubExpM f (Var v) = f v primExpFromSubExpM _ (Constant v) = pure $ ValueExp v @@ -126,7 +126,7 @@ -- | Applying a monadic transformation to the leaves in a 'PrimExp'. replaceInPrimExpM ::- Monad m =>+ (Monad m) => (a -> PrimType -> m (PrimExp b)) -> PrimExp a -> m (PrimExp b)@@ -157,7 +157,7 @@ -- | Substituting names in a PrimExp with other PrimExps substituteInPrimExp ::- Ord v =>+ (Ord v) => M.Map v (PrimExp v) -> PrimExp v -> PrimExp v@@ -169,5 +169,5 @@ primExpSlice = fmap pe64 -- | Convert a 'PrimExp' slice to a t'SubExp' slice.-subExpSlice :: MonadBuilder m => Slice (TPrimExp Int64 VName) -> m (Slice SubExp)+subExpSlice :: (MonadBuilder m) => Slice (TPrimExp Int64 VName) -> m (Slice SubExp) subExpSlice = traverse $ toSubExp "slice"
src/Futhark/Analysis/PrimExp/Simplify.hs view
@@ -9,7 +9,7 @@ -- refers to a name that is a 'Constant', the node turns into a -- 'ValueExp'. simplifyPrimExp ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => PrimExp VName -> SimpleM rep (PrimExp VName) simplifyPrimExp = simplifyAnyPrimExp onLeaf@@ -22,7 +22,7 @@ -- | Like 'simplifyPrimExp', but where leaves may be 'Ext's. simplifyExtPrimExp ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => PrimExp (Ext VName) -> SimpleM rep (PrimExp (Ext VName)) simplifyExtPrimExp = simplifyAnyPrimExp onLeaf@@ -35,7 +35,7 @@ onLeaf (Ext i) pt = pure $ LeafExp (Ext i) pt simplifyAnyPrimExp ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => (a -> PrimType -> SimpleM rep (PrimExp a)) -> PrimExp a -> SimpleM rep (PrimExp a)
src/Futhark/Analysis/SymbolTable.hs view
@@ -93,7 +93,7 @@ empty :: SymbolTable rep empty = SymbolTable 0 M.empty mempty False -fromScope :: ASTRep rep => Scope rep -> SymbolTable rep+fromScope :: (ASTRep rep) => Scope rep -> SymbolTable rep fromScope = M.foldlWithKey' insertFreeVar' empty where insertFreeVar' m k dec = insertFreeVar k dec m@@ -182,7 +182,7 @@ freeVarIndex :: VName -> IndexArray } -instance ASTRep rep => Typed (Entry rep) where+instance (ASTRep rep) => Typed (Entry rep) where typeOf = typeOf . entryInfo entryInfo :: Entry rep -> NameInfo rep@@ -239,10 +239,10 @@ Just (BasicOp e, cs) -> Just (e, cs) _ -> Nothing -lookupType :: ASTRep rep => VName -> SymbolTable rep -> Maybe Type+lookupType :: (ASTRep rep) => VName -> SymbolTable rep -> Maybe Type lookupType name vtable = typeOf <$> lookup name vtable -lookupSubExpType :: ASTRep rep => SubExp -> SymbolTable rep -> Maybe Type+lookupSubExpType :: (ASTRep rep) => SubExp -> SymbolTable rep -> Maybe Type lookupSubExpType (Var v) = lookupType v lookupSubExpType (Constant v) = const $ Just $ Prim $ primValueType v @@ -288,7 +288,7 @@ subExpAvailable Constant {} = const True index ::- ASTRep rep =>+ (ASTRep rep) => VName -> [SubExp] -> SymbolTable rep ->@@ -405,11 +405,11 @@ pat_elem <- patElems pat pure $ defBndEntry vtable pat_elem (Aliases.aliasesOf pat_elem) stm -adjustSeveral :: Ord k => (v -> v) -> [k] -> M.Map k v -> M.Map k v+adjustSeveral :: (Ord k) => (v -> v) -> [k] -> M.Map k v -> M.Map k v adjustSeveral f = flip $ foldl' $ flip $ M.adjust f insertEntry ::- ASTRep rep =>+ (ASTRep rep) => VName -> EntryType rep -> SymbolTable rep ->@@ -433,7 +433,7 @@ } insertEntries ::- ASTRep rep =>+ (ASTRep rep) => [(VName, EntryType rep)] -> SymbolTable rep -> SymbolTable rep@@ -495,7 +495,7 @@ mconcat . map (`lookupAliases` vtable) . namesToList $ names insertFParam ::- ASTRep rep =>+ (ASTRep rep) => AST.FParam rep -> SymbolTable rep -> SymbolTable rep@@ -511,13 +511,13 @@ } insertFParams ::- ASTRep rep =>+ (ASTRep rep) => [AST.FParam rep] -> SymbolTable rep -> SymbolTable rep insertFParams fparams symtable = foldl' (flip insertFParam) symtable fparams -insertLParam :: ASTRep rep => LParam rep -> SymbolTable rep -> SymbolTable rep+insertLParam :: (ASTRep rep) => LParam rep -> SymbolTable rep -> SymbolTable rep insertLParam param = insertEntry name bind where bind =@@ -537,7 +537,7 @@ -- used to help some loop optimisations detect invariant loop -- parameters. insertLoopMerge ::- ASTRep rep =>+ (ASTRep rep) => [(AST.FParam rep, SubExp, SubExpRes)] -> SymbolTable rep -> SymbolTable rep@@ -552,7 +552,7 @@ fparamMerge = Just (initial, res) } -insertLoopVar :: ASTRep rep => VName -> IntType -> SubExp -> SymbolTable rep -> SymbolTable rep+insertLoopVar :: (ASTRep rep) => VName -> IntType -> SubExp -> SymbolTable rep -> SymbolTable rep insertLoopVar name it bound = insertEntry name bind where bind =@@ -562,7 +562,7 @@ loopVarBound = bound } -insertFreeVar :: ASTRep rep => VName -> NameInfo rep -> SymbolTable rep -> SymbolTable rep+insertFreeVar :: (ASTRep rep) => VName -> NameInfo rep -> SymbolTable rep -> SymbolTable rep insertFreeVar name dec = insertEntry name entry where entry =
src/Futhark/Analysis/UsageTable.hs view
@@ -148,12 +148,12 @@ withoutU :: Usages -> Usages -> Usages withoutU (Usages x) (Usages y) = Usages $ x .&. complement y -usageInBody :: Aliased rep => Body rep -> UsageTable+usageInBody :: (Aliased rep) => Body rep -> UsageTable usageInBody = foldMap consumedUsage . namesToList . consumedInBody -- | Produce a usage table reflecting the use of the free variables in -- a single statement.-usageInStm :: Aliased rep => Stm rep -> UsageTable+usageInStm :: (Aliased rep) => Stm rep -> UsageTable usageInStm (Let pat rep e) = mconcat [ usageInPat pat `without` patNames pat,@@ -165,17 +165,17 @@ -- | Usage table reflecting use in pattern. In particular, free -- variables in the decorations are considered used as sizes, even if -- they are also bound in this pattern.-usageInPat :: FreeIn t => Pat t -> UsageTable+usageInPat :: (FreeIn t) => Pat t -> UsageTable usageInPat = sizeUsages . foldMap freeIn . patElems -usageInExp :: Aliased rep => Exp rep -> UsageTable+usageInExp :: (Aliased rep) => Exp rep -> UsageTable usageInExp (Apply _ args _ _) = mconcat [ mconcat $ map consumedUsage $ namesToList $ subExpAliases arg | (arg, d) <- args, d == Consume ]-usageInExp e@DoLoop {} =+usageInExp e@Loop {} = foldMap consumedUsage $ namesToList $ consumedInExp e usageInExp (Match _ cases defbody _) = foldMap (usageInBody . caseBody) cases <> usageInBody defbody
src/Futhark/Bench.hs view
@@ -359,7 +359,7 @@ -- | Compile and produce reference datasets. prepareBenchmarkProgram ::- MonadIO m =>+ (MonadIO m) => Maybe Int -> CompileOptions -> FilePath ->
src/Futhark/Builder.hs view
@@ -38,7 +38,7 @@ -- | A 'BuilderT' (and by extension, a 'Builder') is only an instance of -- 'MonadBuilder' for representations that implement this type class, -- which contains methods for constructing statements.-class ASTRep rep => BuilderOps rep where+class (ASTRep rep) => BuilderOps rep where mkExpDecB :: (MonadBuilder m, Rep m ~ rep) => Pat (LetDec rep) ->@@ -91,7 +91,7 @@ -- | The most commonly used binder monad. type Builder rep = BuilderT rep (State VNameSource) -instance MonadFreshNames m => MonadFreshNames (BuilderT rep m) where+instance (MonadFreshNames m) => MonadFreshNames (BuilderT rep m) where getNameSource = lift getNameSource putNameSource = lift . putNameSource @@ -141,7 +141,7 @@ -- | Run a binder action given an initial scope, returning a value and -- the statements added ('addStm') during the action. runBuilderT ::- MonadFreshNames m =>+ (MonadFreshNames m) => BuilderT rep m a -> Scope rep -> m (a, Stms rep)@@ -151,7 +151,7 @@ -- | Like 'runBuilderT', but return only the statements. runBuilderT_ ::- MonadFreshNames m =>+ (MonadFreshNames m) => BuilderT rep m () -> Scope rep -> m (Stms rep)@@ -228,7 +228,7 @@ -- UndecidableInstances, but save on typing elsewhere. mapInner ::- Monad m =>+ (Monad m) => ( m (a, (Stms rep, Scope rep)) -> m (b, (Stms rep, Scope rep)) ) ->@@ -240,15 +240,15 @@ put s' pure x -instance MonadReader r m => MonadReader r (BuilderT rep m) where+instance (MonadReader r m) => MonadReader r (BuilderT rep m) where ask = BuilderT $ lift ask local f = mapInner $ local f -instance MonadState s m => MonadState s (BuilderT rep m) where+instance (MonadState s m) => MonadState s (BuilderT rep m) where get = BuilderT $ lift get put = BuilderT . lift . put -instance MonadWriter w m => MonadWriter w (BuilderT rep m) where+instance (MonadWriter w m) => MonadWriter w (BuilderT rep m) where tell = BuilderT . lift . tell pass = mapInner $ \m -> pass $ do ((x, f), s) <- m@@ -257,7 +257,7 @@ ((x, s), y) <- listen m pure ((x, y), s) -instance MonadError e m => MonadError e (BuilderT rep m) where+instance (MonadError e m) => MonadError e (BuilderT rep m) where throwError = lift . throwError catchError (BuilderT m) f = BuilderT $ catchError m $ unBuilder . f
src/Futhark/Builder/Class.hs view
@@ -93,7 +93,7 @@ -- | Apply a function to the statements added by this action. censorStms ::- MonadBuilder m =>+ (MonadBuilder m) => (Stms (Rep m) -> Stms (Rep m)) -> m a -> m a@@ -103,7 +103,7 @@ pure x -- | Add the given attributes to any statements added by this action.-attributing :: MonadBuilder m => Attrs -> m a -> m a+attributing :: (MonadBuilder m) => Attrs -> m a -> m a attributing attrs = censorStms $ fmap onStm where onStm (Let pat aux e) =@@ -111,7 +111,7 @@ -- | Add the certificates and attributes to any statements added by -- this action.-auxing :: MonadBuilder m => StmAux anyrep -> m a -> m a+auxing :: (MonadBuilder m) => StmAux anyrep -> m a -> m a auxing (StmAux cs attrs _) = censorStms $ fmap onStm where onStm (Let pat aux e) =@@ -125,7 +125,7 @@ -- | Add a statement with the given pattern and expression. letBind ::- MonadBuilder m =>+ (MonadBuilder m) => Pat (LetDec (Rep m)) -> Exp (Rep m) -> m ()@@ -134,7 +134,7 @@ -- | Construct a 'Stm' from identifiers for the context- and value -- part of the pattern, as well as the expression.-mkLet :: Buildable rep => [Ident] -> Exp rep -> Stm rep+mkLet :: (Buildable rep) => [Ident] -> Exp rep -> Stm rep mkLet ids e = let pat = mkExpPat ids e dec = mkExpDec pat e@@ -142,7 +142,7 @@ -- | Like mkLet, but also take attributes and certificates from the -- given 'StmAux'.-mkLet' :: Buildable rep => [Ident] -> StmAux a -> Exp rep -> Stm rep+mkLet' :: (Buildable rep) => [Ident] -> StmAux a -> Exp rep -> Stm rep mkLet' ids (StmAux cs attrs _) e = let pat = mkExpPat ids e dec = mkExpDec pat e@@ -150,23 +150,23 @@ -- | Add a statement with the given pattern element names and -- expression.-letBindNames :: MonadBuilder m => [VName] -> Exp (Rep m) -> m ()+letBindNames :: (MonadBuilder m) => [VName] -> Exp (Rep m) -> m () letBindNames names e = addStm =<< mkLetNamesM names e -- | As 'collectStms', but throw away the ordinary result.-collectStms_ :: MonadBuilder m => m a -> m (Stms (Rep m))+collectStms_ :: (MonadBuilder m) => m a -> m (Stms (Rep m)) collectStms_ = fmap snd . collectStms -- | Add the statements of the body, then return the body result.-bodyBind :: MonadBuilder m => Body (Rep m) -> m Result+bodyBind :: (MonadBuilder m) => Body (Rep m) -> m Result bodyBind (Body _ stms res) = do addStms stms pure res -- | Add several bindings at the outermost level of a t'Body'.-insertStms :: Buildable rep => Stms rep -> Body rep -> Body rep+insertStms :: (Buildable rep) => Stms rep -> Body rep -> Body rep insertStms stms1 (Body _ stms2 res) = mkBody (stms1 <> stms2) res -- | Add a single binding at the outermost level of a t'Body'.-insertStm :: Buildable rep => Stm rep -> Body rep -> Body rep+insertStm :: (Buildable rep) => Stm rep -> Body rep -> Body rep insertStm = insertStms . oneStm
src/Futhark/CLI/Dataset.hs view
@@ -141,7 +141,7 @@ ] setRangeOption ::- Read a =>+ (Read a) => String -> (Range a -> RandomConfiguration -> RandomConfiguration) -> FunOptDescr DataOptions
src/Futhark/CLI/Dev.hs view
@@ -241,7 +241,7 @@ "Pass " ++ name ++ " expects MCMem representation, but got " ++ representation rep typedPassOption ::- Checkable torep =>+ (Checkable torep) => (String -> UntypedPassState -> FutharkM (Prog fromrep)) -> (Prog torep -> UntypedPassState) -> Pass fromrep torep ->
src/Futhark/CLI/Eval.hs view
@@ -128,7 +128,7 @@ 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 :: (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
+ src/Futhark/CLI/HIP.hs view
@@ -0,0 +1,17 @@+-- | @futhark hip@+module Futhark.CLI.HIP (main) where++import Futhark.Actions (compileHIPAction)+import Futhark.Compiler.CLI+import Futhark.Passes (gpumemPipeline)++-- | Run @futhark hip@.+main :: String -> [String] -> IO ()+main = compilerMain+ ()+ []+ "Compile HIP"+ "Generate HIP/C code from optimised Futhark program."+ gpumemPipeline+ $ \fcfg () mode outpath prog ->+ actionProcedure (compileHIPAction fcfg mode outpath) prog
src/Futhark/CLI/Main.hs view
@@ -17,6 +17,7 @@ import Futhark.CLI.Dev qualified as Dev import Futhark.CLI.Doc qualified as Doc import Futhark.CLI.Eval qualified as Eval+import Futhark.CLI.HIP qualified as HIP import Futhark.CLI.LSP qualified as LSP import Futhark.CLI.Literate qualified as Literate import Futhark.CLI.Misc qualified as Misc@@ -55,6 +56,7 @@ ("c", (C.main, "Compile to sequential C.")), ("opencl", (OpenCL.main, "Compile to C calling OpenCL.")), ("cuda", (CCUDA.main, "Compile to C calling CUDA.")),+ ("hip", (HIP.main, "Compile to C calling HIP.")), ("multicore", (Multicore.main, "Compile to multicore C.")), ("python", (Python.main, "Compile to sequential Python.")), ("pyopencl", (PyOpenCL.main, "Compile to Python calling PyOpenCL.")),
src/Futhark/CLI/REPL.hs view
@@ -358,7 +358,7 @@ c -runInterpreterNoBreak :: MonadIO m => F I.ExtOp a -> m (Either I.InterpreterError a)+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
src/Futhark/CLI/Run.hs view
@@ -138,7 +138,7 @@ badOnLeft _ (Right x) = pure x badOnLeft p (Left err) = throwError $ p err -runInterpreter' :: MonadIO m => F I.ExtOp a -> m (Either I.InterpreterError a)+runInterpreter' :: (MonadIO m) => F I.ExtOp a -> m (Either I.InterpreterError a) runInterpreter' m = runF m (pure . Right) intOp where intOp (I.ExtOpError err) = pure $ Left err
src/Futhark/CLI/Test.hs view
@@ -42,7 +42,7 @@ eitherToErrors :: Either e a -> Errors e a eitherToErrors = either failure Pure -throwError :: MonadError [e] m => e -> m a+throwError :: (MonadError [e] m) => e -> m a throwError e = E.throwError [e] runTestM :: TestM () -> IO TestResult@@ -57,7 +57,7 @@ [] -> [] (e : es') -> (s <> ":\n" <> e) : es' -context1 :: Monad m => T.Text -> ExceptT T.Text m a -> ExceptT T.Text m a+context1 :: (Monad m) => T.Text -> ExceptT T.Text m a -> ExceptT T.Text m a context1 s = withExceptT $ \e -> s <> ":\n" <> e accErrors :: [TestM a] -> TestM [a]@@ -358,7 +358,7 @@ compareResult entry index program expected res -checkError :: MonadError T.Text m => ExpectedError -> T.Text -> m ()+checkError :: (MonadError T.Text m) => ExpectedError -> T.Text -> m () checkError (ThisError regex_s regex) err | not (match regex $ T.unpack err) = E.throwError $
src/Futhark/CodeGen/Backends/CCUDA.hs view
@@ -10,17 +10,14 @@ ) where -import Control.Monad-import Data.List (unzip4)-import Data.Maybe (catMaybes)+import Data.Map qualified as M import Data.Text qualified as T-import Futhark.CodeGen.Backends.CCUDA.Boilerplate-import Futhark.CodeGen.Backends.COpenCL.Boilerplate (commonOptions, sizeLoggingCode)+import Futhark.CodeGen.Backends.GPU import Futhark.CodeGen.Backends.GenericC qualified as GC import Futhark.CodeGen.Backends.GenericC.Options-import Futhark.CodeGen.Backends.SimpleRep (primStorageType, toStorage) import Futhark.CodeGen.ImpCode.OpenCL import Futhark.CodeGen.ImpGen.CUDA qualified as ImpGen+import Futhark.CodeGen.RTS.C (backendsCudaH) import Futhark.IR.GPUMem hiding ( CmpSizeLe, GetSize,@@ -28,81 +25,60 @@ ) import Futhark.MonadFreshNames import Language.C.Quote.OpenCL qualified as C-import Language.C.Syntax qualified as C import NeatInterpolation (untrimming) --- | Compile the program to C with calls to CUDA.-compileProg :: MonadFreshNames m => T.Text -> Prog GPUMem -> m (ImpGen.Warnings, GC.CParts)-compileProg version prog = do- (ws, Program cuda_code cuda_prelude kernels _ params failures prog') <-- ImpGen.compileProg prog- let cost_centres =- [ copyDevToDev,- copyDevToHost,- copyHostToDev,- copyScalarToDev,- copyScalarFromDev- ]- extra =- generateBoilerplate- cuda_code- cuda_prelude- cost_centres- kernels- failures- (ws,)- <$> GC.compileProg- "cuda"- version- params- operations- extra- cuda_includes- (Space "device", [Space "device", DefaultSpace])- cliOptions- prog'- where- operations :: GC.Operations OpenCL ()- operations =- GC.defaultOperations- { GC.opsWriteScalar = writeCUDAScalar,- GC.opsReadScalar = readCUDAScalar,- GC.opsAllocate = allocateCUDABuffer,- GC.opsDeallocate = deallocateCUDABuffer,- GC.opsCopy = copyCUDAMemory,- GC.opsMemoryType = cudaMemoryType,- GC.opsCompiler = callKernel,- GC.opsFatMemory = True,- GC.opsCritical =- ( [C.citems|CUDA_SUCCEED_FATAL(cuCtxPushCurrent(ctx->cu_ctx));|],- [C.citems|CUDA_SUCCEED_FATAL(cuCtxPopCurrent(&ctx->cu_ctx));|]- )- }- cuda_includes =- [untrimming|- #include <cuda.h>- #include <cuda_runtime.h>- #include <nvrtc.h>- |]+mkBoilerplate ::+ T.Text ->+ M.Map Name KernelSafety ->+ [PrimType] ->+ [FailureMsg] ->+ GC.CompilerM OpenCL () ()+mkBoilerplate cuda_program kernels types failures = do+ generateGPUBoilerplate+ cuda_program+ backendsCudaH+ (M.keys kernels)+ types+ failures + 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|const char* futhark_context_config_get_program(struct futhark_context_config *cfg);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_program(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);|]+ cliOptions :: [Option] cliOptions =- commonOptions+ gpuOptions ++ [ Option { optionLongName = "dump-cuda", optionShortName = Nothing, optionArgument = RequiredArgument "FILE", optionDescription = "Dump the embedded CUDA kernels to the indicated file.", optionAction =- [C.cstm|{futhark_context_config_dump_program_to(cfg, optarg);- entry_point = NULL;}|]+ [C.cstm|{const char* prog = futhark_context_config_get_program(cfg);+ if (dump_file(optarg, prog, strlen(prog)) != 0) {+ fprintf(stderr, "%s: %s\n", optarg, strerror(errno));+ exit(1);+ }+ exit(1);}|] }, Option { optionLongName = "load-cuda", optionShortName = Nothing, optionArgument = RequiredArgument "FILE", optionDescription = "Instead of using the embedded CUDA kernels, load them from the indicated file.",- optionAction = [C.cstm|futhark_context_config_load_program_from(cfg, optarg);|]+ optionAction =+ [C.cstm|{ size_t n; const char *s = slurp_file(optarg, &n);+ if (s == NULL) { fprintf(stderr, "%s: %s\n", optarg, strerror(errno)); exit(1); }+ futhark_context_config_set_program(cfg, s);+ }|] }, Option { optionLongName = "dump-ptx",@@ -136,278 +112,41 @@ } ] --- We detect the special case of writing a constant and turn it into a--- non-blocking write. This may be slightly faster, as it prevents--- unnecessary synchronisation of the context, and writing a constant--- is fairly common. This is only possible because we can give the--- constant infinite lifetime (with 'static'), which is not the case--- for ordinary variables.-writeCUDAScalar :: GC.WriteScalar OpenCL ()-writeCUDAScalar mem idx t "device" _ val@C.Const {} = do- val' <- newVName "write_static"- let (bef, aft) = profilingEnclosure copyScalarToDev- GC.item- [C.citem|{static $ty:t $id:val' = $exp:val;- $items:bef- CUDA_SUCCEED_OR_RETURN(- cuMemcpyHtoDAsync($exp:mem + $exp:idx * sizeof($ty:t),- &$id:val',- sizeof($ty:t),- ctx->stream));- $items:aft- }|]-writeCUDAScalar mem idx t "device" _ val = do- val' <- newVName "write_tmp"- let (bef, aft) = profilingEnclosure copyScalarToDev- GC.item- [C.citem|{$ty:t $id:val' = $exp:val;- $items:bef- CUDA_SUCCEED_OR_RETURN(- cuMemcpyHtoD($exp:mem + $exp:idx * sizeof($ty:t),- &$id:val',- sizeof($ty:t)));- $items:aft- }|]-writeCUDAScalar _ _ _ space _ _ =- error $ "Cannot write to '" ++ space ++ "' memory space."--readCUDAScalar :: GC.ReadScalar OpenCL ()-readCUDAScalar mem idx t "device" _ = do- val <- newVName "read_res"- let (bef, aft) = profilingEnclosure copyScalarFromDev- mapM_- GC.item- [C.citems|- $ty:t $id:val;- {- $items:bef- CUDA_SUCCEED_OR_RETURN(- cuMemcpyDtoH(&$id:val,- $exp:mem + $exp:idx * sizeof($ty:t),- sizeof($ty:t)));- $items:aft- }- |]- GC.stm- [C.cstm|if (ctx->failure_is_an_option && futhark_context_sync(ctx) != 0)- { return 1; }|]- pure [C.cexp|$id:val|]-readCUDAScalar _ _ _ space _ =- error $ "Cannot write to '" ++ space ++ "' memory space."--allocateCUDABuffer :: GC.Allocate OpenCL ()-allocateCUDABuffer mem size tag "device" =- GC.stm- [C.cstm|ctx->error =- CUDA_SUCCEED_NONFATAL(cuda_alloc(ctx, ctx->log,- (size_t)$exp:size, $exp:tag,- &$exp:mem, (size_t*)&$exp:size));|]-allocateCUDABuffer _ _ _ space =- error $ "Cannot allocate in '" ++ space ++ "' memory space."--deallocateCUDABuffer :: GC.Deallocate OpenCL ()-deallocateCUDABuffer mem size tag "device" =- 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."--copyCUDAMemory :: GC.Copy OpenCL ()-copyCUDAMemory b dstmem dstidx dstSpace srcmem srcidx srcSpace nbytes = do- let (copy, prof) = memcpyFun b dstSpace srcSpace- (bef, aft) = profilingEnclosure prof- GC.item- [C.citem|{$items:bef CUDA_SUCCEED_OR_RETURN($exp:copy); $items:aft}|]- where- dst = [C.cexp|$exp:dstmem + $exp:dstidx|]- src = [C.cexp|$exp:srcmem + $exp:srcidx|]- memcpyFun GC.CopyBarrier DefaultSpace (Space "device") =- ([C.cexp|cuMemcpyDtoH($exp:dst, $exp:src, $exp:nbytes)|], copyDevToHost)- memcpyFun GC.CopyBarrier (Space "device") DefaultSpace =- ([C.cexp|cuMemcpyHtoD($exp:dst, $exp:src, $exp:nbytes)|], copyHostToDev)- memcpyFun _ (Space "device") (Space "device") =- ([C.cexp|cuMemcpy($exp:dst, $exp:src, $exp:nbytes)|], copyDevToDev)- memcpyFun GC.CopyNoBarrier DefaultSpace (Space "device") =- ([C.cexp|cuMemcpyDtoHAsync($exp:dst, $exp:src, $exp:nbytes, ctx->stream)|], copyDevToHost)- memcpyFun GC.CopyNoBarrier (Space "device") DefaultSpace =- ([C.cexp|cuMemcpyHtoDAsync($exp:dst, $exp:src, $exp:nbytes, ctx->stream)|], copyHostToDev)- memcpyFun _ _ _ =- error $- "Cannot copy to '"- ++ show dstSpace- ++ "' from '"- ++ show srcSpace- ++ "'."- cudaMemoryType :: GC.MemoryType OpenCL () cudaMemoryType "device" = pure [C.cty|typename CUdeviceptr|]-cudaMemoryType space =- error $ "CUDA backend does not support '" ++ space ++ "' memory space."--kernelConstToExp :: KernelConst -> C.Exp-kernelConstToExp (SizeConst key) =- [C.cexp|*ctx->tuning_params.$id:key|]-kernelConstToExp (SizeMaxConst size_class) =- [C.cexp|ctx->$id:field|]- where- field = "max_" <> cudaSizeClass size_class- cudaSizeClass SizeThreshold {} = "threshold"- cudaSizeClass SizeGroup = "block_size"- cudaSizeClass SizeNumGroups = "grid_size"- cudaSizeClass SizeTile = "tile_size"- cudaSizeClass SizeRegTile = "reg_tile_size"- cudaSizeClass SizeLocalMemory = "shared_memory"- cudaSizeClass (SizeBespoke x _) = prettyString x--compileGroupDim :: GroupDim -> GC.CompilerM op s C.Exp-compileGroupDim (Left e) = GC.compileExp e-compileGroupDim (Right kc) = pure $ kernelConstToExp kc--callKernel :: GC.OpCompiler OpenCL ()-callKernel (GetSize v key) = do- let e = kernelConstToExp $ SizeConst key- GC.stm [C.cstm|$id:v = $exp:e;|]-callKernel (CmpSizeLe v key x) = do- let e = kernelConstToExp $ SizeConst key- x' <- GC.compileExp x- GC.stm [C.cstm|$id:v = $exp:e <= $exp:x';|]- sizeLoggingCode v key x'-callKernel (GetSizeMax v size_class) = do- let e = kernelConstToExp $ SizeMaxConst size_class- GC.stm [C.cstm|$id:v = $exp:e;|]-callKernel (LaunchKernel safety kernel_name args num_blocks block_size) = do- (arg_params, arg_params_inits, call_args, shared_vars) <-- unzip4 <$> zipWithM mkArgs [(0 :: Int) ..] args- let (shared_sizes, shared_offsets) = unzip $ catMaybes shared_vars- shared_offsets_sc = mkOffsets shared_sizes- shared_args = zip shared_offsets shared_offsets_sc- shared_bytes = last shared_offsets_sc- forM_ shared_args $ \(arg, offset) ->- GC.decl [C.cdecl|unsigned int $id:arg = $exp:offset;|]-- (grid_x, grid_y, grid_z) <- mkDims <$> mapM GC.compileExp num_blocks- (block_x, block_y, block_z) <- mkDims <$> mapM compileGroupDim block_size-- let need_perm = length num_blocks == 3- kernel_fname <- genKernelFunction kernel_name safety need_perm arg_params arg_params_inits-- GC.stm- [C.cstm|{- err = $id:kernel_fname(ctx,- $exp:grid_x,$exp:grid_y,$exp:grid_z,- $exp:block_x, $exp:block_y, $exp:block_z,- $exp:shared_bytes,- $args:call_args);- if (err != FUTHARK_SUCCESS) { goto cleanup; }- }|]+cudaMemoryType space = error $ "GPU backend does not support '" ++ space ++ "' memory space." - when (safety >= SafetyFull) $- GC.stm [C.cstm|ctx->failure_is_an_option = 1;|]+-- | Compile the program to C with calls to CUDA.+compileProg :: (MonadFreshNames m) => T.Text -> Prog GPUMem -> m (ImpGen.Warnings, GC.CParts)+compileProg version prog = do+ ( ws,+ Program cuda_code cuda_prelude kernels types params failures prog'+ ) <-+ ImpGen.compileProg prog+ (ws,)+ <$> GC.compileProg+ "cuda"+ version+ params+ operations+ (mkBoilerplate (cuda_prelude <> cuda_code) kernels types failures)+ cuda_includes+ (Space "device", [Space "device", DefaultSpace])+ cliOptions+ prog' where- mkDims [] = ([C.cexp|0|], [C.cexp|0|], [C.cexp|0|])- mkDims [x] = (x, [C.cexp|1|], [C.cexp|1|])- mkDims [x, y] = (x, y, [C.cexp|1|])- mkDims (x : y : z : _) = (x, y, z)- addExp x y = [C.cexp|$exp:x + $exp:y|]- alignExp e = [C.cexp|$exp:e + ((8 - ($exp:e % 8)) % 8)|]- mkOffsets = scanl (\a b -> a `addExp` alignExp b) [C.cexp|0|]- mkArgs i (ValueKArg e t) = do- e' <- GC.compileExp e- pure- ( [C.cparam|$ty:(primStorageType t) $id:("arg" <> show i)|],- [C.cinit|&$id:("arg" <> show i)|],- toStorage t e',- Nothing- )- mkArgs i (MemKArg v) = do- v' <- GC.rawMem v- pure- ( [C.cparam|typename CUdeviceptr $id:("arg" <> show i)|],- [C.cinit|&$id:("arg" <> show i)|],- v',- Nothing- )- mkArgs i (SharedMemoryKArg (Count c)) = do- num_bytes <- GC.compileExp c- size <- newVName "shared_size"- offset <- newVName "shared_offset"- GC.decl [C.cdecl|unsigned int $id:size = $exp:num_bytes;|]- pure- ( [C.cparam|unsigned int $id:("arg" <> show i)|],- [C.cinit|&$id:("arg" <> show i)|],- [C.cexp|$id:offset|],- Just (size, offset)- )--genKernelFunction ::- KernelName ->- KernelSafety ->- Bool ->- [C.Param] ->- [C.Initializer] ->- GC.CompilerM op s Name-genKernelFunction kernel_name safety need_perm arg_params arg_params_inits = do- let kernel_fname = "gpu_kernel_" <> kernel_name- (bef, aft) = profilingEnclosure kernel_name- perm_args- | need_perm = [[C.cinit|&perm[0]|], [C.cinit|&perm[1]|], [C.cinit|&perm[2]|]]- | otherwise = []- failure_args =- take- (numFailureParams safety)- [ [C.cinit|&ctx->global_failure|],- [C.cinit|&ctx->failure_is_an_option|],- [C.cinit|&ctx->global_failure_args|]- ]-- GC.libDecl- [C.cedecl|static int $id:kernel_fname(- struct futhark_context* ctx, unsigned int grid_x, unsigned int grid_y, unsigned int grid_z,- unsigned int block_x, unsigned int block_y, unsigned int block_z,- unsigned int shared_bytes, $params:arg_params) {- if (grid_x * grid_y * grid_z * block_x * block_y * block_z != 0) {- int perm[3] = { 0, 1, 2 };-- if (grid_y >= (1<<16)) {- perm[1] = perm[0];- perm[0] = 1;- }-- if (grid_z >= (1<<16)) {- perm[2] = perm[0];- perm[0] = 2;- }-- size_t grid[3];- grid[perm[0]] = grid_x;- grid[perm[1]] = grid_y;- grid[perm[2]] = grid_z;-- void *all_args[] = { $inits:(perm_args ++ failure_args ++ arg_params_inits) };- typename int64_t time_start = 0, time_end = 0;- if (ctx->debugging) {- fprintf(ctx->log, "Launching %s with grid size [%d, %d, %d] and block size [%d, %d, %d]; shared memory: %d bytes.\n",- $string:(prettyString kernel_name),- grid_x, grid_y, grid_z,- block_x, block_y, block_z,- shared_bytes);- time_start = get_wall_time();- }- $items:bef- CUDA_SUCCEED_OR_RETURN(- cuLaunchKernel(ctx->program->$id:kernel_name,- grid[0], grid[1], grid[2],- block_x, block_y, block_z,- shared_bytes, ctx->stream,- all_args, NULL));- $items:aft- if (ctx->debugging) {- CUDA_SUCCEED_FATAL(cuCtxSynchronize());- time_end = get_wall_time();- fprintf(ctx->log, "Kernel %s runtime: %ldus\n",- $string:(prettyString kernel_name), time_end - time_start);- }- }- return FUTHARK_SUCCESS;- }|]-- pure kernel_fname+ operations :: GC.Operations OpenCL ()+ operations =+ gpuOperations+ { GC.opsMemoryType = cudaMemoryType,+ GC.opsCritical =+ ( [C.citems|CUDA_SUCCEED_FATAL(cuCtxPushCurrent(ctx->cu_ctx));|],+ [C.citems|CUDA_SUCCEED_FATAL(cuCtxPopCurrent(&ctx->cu_ctx));|]+ )+ }+ cuda_includes =+ [untrimming|+ #include <cuda.h>+ #include <cuda_runtime.h>+ #include <nvrtc.h>+ |]
− src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs
@@ -1,132 +0,0 @@-{-# LANGUAGE QuasiQuotes #-}---- | Various boilerplate definitions for the CUDA backend.-module Futhark.CodeGen.Backends.CCUDA.Boilerplate- ( generateBoilerplate,- profilingEnclosure,- module Futhark.CodeGen.Backends.COpenCL.Boilerplate,- )-where--import Control.Monad-import Data.Map qualified as M-import Data.Text qualified as T-import Futhark.CodeGen.Backends.COpenCL.Boilerplate- ( copyDevToDev,- copyDevToHost,- copyHostToDev,- copyScalarFromDev,- copyScalarToDev,- costCentreReport,- failureMsgFunction,- 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 (backendsCudaH)-import Futhark.Util (chunk)-import Language.C.Quote.OpenCL qualified as C-import Language.C.Syntax qualified as C--errorMsgNumArgs :: ErrorMsg a -> Int-errorMsgNumArgs = length . errorMsgArgTypes---- | Block items to put before and after a thing to be profiled.-profilingEnclosure :: Name -> ([C.BlockItem], [C.BlockItem])-profilingEnclosure name =- ( [C.citems|- typename CUevent *pevents = NULL;- if (ctx->profiling && !ctx->profiling_paused) {- pevents = cuda_get_events(ctx,- &ctx->program->$id:(kernelRuns name),- &ctx->program->$id:(kernelRuntime name));- CUDA_SUCCEED_FATAL(cuEventRecord(pevents[0], ctx->stream));- }- |],- [C.citems|- if (pevents != NULL) {- CUDA_SUCCEED_FATAL(cuEventRecord(pevents[1], ctx->stream));- }- |]- )--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 ::- T.Text ->- T.Text ->- [Name] ->- M.Map KernelName KernelSafety ->- [FailureMsg] ->- GC.CompilerM OpenCL () ()-generateBoilerplate cuda_program cuda_prelude cost_centres kernels 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- mapM_- GC.earlyDecl- [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-- generateCUDADecls cost_centres kernels-- 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);|]-- GC.generateProgramStruct-- GC.onClear- [C.citem|if (ctx->error == NULL) {- 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
@@ -10,14 +10,16 @@ ) where -import Control.Monad hiding (mapM)+import Control.Monad.State+import Data.Map qualified as M import Data.Text qualified as T-import Futhark.CodeGen.Backends.COpenCL.Boilerplate+import Futhark.CodeGen.Backends.GPU import Futhark.CodeGen.Backends.GenericC qualified as GC import Futhark.CodeGen.Backends.GenericC.Options-import Futhark.CodeGen.Backends.SimpleRep (primStorageType, toStorage) import Futhark.CodeGen.ImpCode.OpenCL import Futhark.CodeGen.ImpGen.OpenCL qualified as ImpGen+import Futhark.CodeGen.OpenCL.Heuristics+import Futhark.CodeGen.RTS.C (backendsOpenclH) import Futhark.IR.GPUMem hiding ( CmpSizeLe, GetSize,@@ -28,73 +30,90 @@ import Language.C.Syntax qualified as C import NeatInterpolation (untrimming) --- | Compile the program to C with calls to OpenCL.-compileProg :: MonadFreshNames m => T.Text -> Prog GPUMem -> m (ImpGen.Warnings, GC.CParts)-compileProg version prog = do- ( ws,- Program- opencl_code- opencl_prelude- kernels- types- params- failures- prog'- ) <-- ImpGen.compileProg prog- let cost_centres =- [ copyDevToDev,- copyDevToHost,- copyHostToDev,- copyScalarToDev,- copyScalarFromDev- ]- (ws,)- <$> GC.compileProg- "opencl"- version- params- operations- ( generateBoilerplate- opencl_code- opencl_prelude- cost_centres- kernels- types- failures- )- include_opencl_h- (Space "device", [Space "device", DefaultSpace])- cliOptions- prog'+sizeHeuristicsCode :: SizeHeuristic -> C.Stm+sizeHeuristicsCode (SizeHeuristic platform_name device_type which (TPrimExp what)) =+ [C.cstm|+ if ($exp:which' == 0 &&+ strstr(option->platform_name, $string:platform_name) != NULL &&+ (option->device_type & $exp:(clDeviceType device_type)) == $exp:(clDeviceType device_type)) {+ $items:get_size+ }|] where- operations :: GC.Operations OpenCL ()- operations =- GC.defaultOperations- { GC.opsCompiler = callKernel,- GC.opsWriteScalar = writeOpenCLScalar,- GC.opsReadScalar = readOpenCLScalar,- GC.opsAllocate = allocateOpenCLBuffer,- GC.opsDeallocate = deallocateOpenCLBuffer,- GC.opsCopy = copyOpenCLMemory,- GC.opsMemoryType = openclMemoryType,- GC.opsFatMemory = True- }- include_opencl_h =- [untrimming|- #define CL_TARGET_OPENCL_VERSION 120- #define CL_USE_DEPRECATED_OPENCL_1_2_APIS- #ifdef __APPLE__- #define CL_SILENCE_DEPRECATION- #include <OpenCL/cl.h>- #else- #include <CL/cl.h>- #endif- |]+ clDeviceType DeviceGPU = [C.cexp|CL_DEVICE_TYPE_GPU|]+ clDeviceType DeviceCPU = [C.cexp|CL_DEVICE_TYPE_CPU|] + 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|]++ get_size =+ let (e, m) = runState (GC.compilePrimExp onLeaf what) mempty+ in concat (M.elems m) ++ [[C.citem|$exp:which' = $exp:e;|]]++ onLeaf (DeviceInfo s) = do+ let s' = "CL_DEVICE_" ++ s+ v = s ++ "_val"+ m <- get+ case M.lookup s m of+ Nothing ->+ -- XXX: Cheating with the type here; works for the infos we+ -- currently use because we zero-initialise and assume a+ -- little-endian platform, but should be made more+ -- size-aware in the future.+ modify $+ M.insert+ s'+ [C.citems|size_t $id:v = 0;+ clGetDeviceInfo(ctx->device, $id:s',+ sizeof($id:v), &$id:v,+ NULL);|]+ Just _ -> pure ()++ pure [C.cexp|$id:v|]++mkBoilerplate ::+ T.Text ->+ M.Map Name KernelSafety ->+ [PrimType] ->+ [FailureMsg] ->+ GC.CompilerM OpenCL () ()+mkBoilerplate opencl_program kernels types failures = do+ generateGPUBoilerplate+ opencl_program+ backendsOpenclH+ (M.keys kernels)+ types+ failures++ GC.earlyDecl+ [C.cedecl|void post_opencl_setup(struct futhark_context *ctx, struct opencl_device_option *option) {+ $stms:(map sizeHeuristicsCode sizeHeuristicsTable)+ }|]++ 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|const char* futhark_context_config_get_program(struct futhark_context_config *cfg);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_program(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);|]+ cliOptions :: [Option] cliOptions =- commonOptions+ gpuOptions ++ [ Option { optionLongName = "platform", optionShortName = Just 'p',@@ -108,15 +127,23 @@ optionArgument = RequiredArgument "FILE", optionDescription = "Dump the embedded OpenCL program to the indicated file.", optionAction =- [C.cstm|{futhark_context_config_dump_program_to(cfg, optarg);- entry_point = NULL;}|]+ [C.cstm|{const char* prog = futhark_context_config_get_program(cfg);+ if (dump_file(optarg, prog, strlen(prog)) != 0) {+ fprintf(stderr, "%s: %s\n", optarg, strerror(errno));+ exit(1);+ }+ exit(0);}|] }, Option { optionLongName = "load-opencl", optionShortName = Nothing, optionArgument = RequiredArgument "FILE", optionDescription = "Instead of using the embedded OpenCL program, load it from the indicated file.",- optionAction = [C.cstm|futhark_context_config_load_program_from(cfg, optarg);|]+ optionAction =+ [C.cstm|{ size_t n; const char *s = slurp_file(optarg, &n);+ if (s == NULL) { fprintf(stderr, "%s: %s\n", optarg, strerror(errno)); exit(1); }+ futhark_context_config_set_program(cfg, s);+ }|] }, Option { optionLongName = "dump-opencl-binary",@@ -159,267 +186,42 @@ } ] --- We detect the special case of writing a constant and turn it into a--- non-blocking write. This may be slightly faster, as it prevents--- unnecessary synchronisation of the OpenCL command queue, and--- writing a constant is fairly common. This is only possible because--- we can give the constant infinite lifetime (with 'static'), which--- is not the case for ordinary variables.-writeOpenCLScalar :: GC.WriteScalar OpenCL ()-writeOpenCLScalar mem i t "device" _ val = do- val' <- newVName "write_tmp"- let (decl, blocking) =- case val of- C.Const {} -> ([C.citem|static $ty:t $id:val' = $exp:val;|], [C.cexp|CL_FALSE|])- _ -> ([C.citem|$ty:t $id:val' = $exp:val;|], [C.cexp|CL_TRUE|])- GC.stm- [C.cstm|{$item:decl- OPENCL_SUCCEED_OR_RETURN(- clEnqueueWriteBuffer(ctx->queue, $exp:mem, $exp:blocking,- $exp:i * sizeof($ty:t), sizeof($ty:t),- &$id:val',- 0, NULL, $exp:(profilingEvent copyScalarToDev)));- }|]-writeOpenCLScalar _ _ _ space _ _ =- error $ "Cannot write to '" ++ space ++ "' memory space."---- It is often faster to do a blocking clEnqueueReadBuffer() than to--- do an async clEnqueueReadBuffer() followed by a clFinish(), even--- with an in-order command queue. This is safe if and only if there--- are no possible outstanding failures.-readOpenCLScalar :: GC.ReadScalar OpenCL ()-readOpenCLScalar mem i t "device" _ = do- val <- newVName "read_res"- GC.decl [C.cdecl|$ty:t $id:val;|]- GC.stm- [C.cstm|OPENCL_SUCCEED_OR_RETURN(- clEnqueueReadBuffer(ctx->queue, $exp:mem,- ctx->failure_is_an_option ? CL_FALSE : CL_TRUE,- $exp:i * sizeof($ty:t), sizeof($ty:t),- &$id:val,- 0, NULL, $exp:(profilingEvent copyScalarFromDev)));- |]- GC.stm- [C.cstm|if (ctx->failure_is_an_option && futhark_context_sync(ctx) != 0)- { return 1; }|]- pure [C.cexp|$id:val|]-readOpenCLScalar _ _ _ space _ =- error $ "Cannot read from '" ++ space ++ "' memory space."--allocateOpenCLBuffer :: GC.Allocate OpenCL ()-allocateOpenCLBuffer mem size tag "device" =- GC.stm- [C.cstm|ctx->error =- OPENCL_SUCCEED_NONFATAL(opencl_alloc(ctx, ctx->log,- (size_t)$exp:size, $exp:tag,- &$exp:mem, (size_t*)&$exp:size));|]-allocateOpenCLBuffer _ _ _ space =- error $ "Cannot allocate in '" ++ space ++ "' memory space."--deallocateOpenCLBuffer :: GC.Deallocate OpenCL ()-deallocateOpenCLBuffer mem size tag "device" =- 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"--syncArg :: GC.CopyBarrier -> C.Exp-syncArg GC.CopyBarrier = [C.cexp|CL_TRUE|]-syncArg GC.CopyNoBarrier = [C.cexp|CL_FALSE|]--copyOpenCLMemory :: GC.Copy OpenCL ()--- The read/write/copy-buffer functions fail if the given offset is--- out of bounds, even if asked to read zero bytes. We protect with a--- branch to avoid this.-copyOpenCLMemory b destmem destidx DefaultSpace srcmem srcidx (Space "device") nbytes =- GC.stm- [C.cstm|- if ($exp:nbytes > 0) {- typename cl_bool sync_call = $exp:(syncArg b);- OPENCL_SUCCEED_OR_RETURN(- 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,- 0, NULL, $exp:(profilingEvent copyHostToDev)));- if (sync_call &&- ctx->failure_is_an_option &&- futhark_context_sync(ctx) != 0) { return 1; }- }- |]-copyOpenCLMemory b destmem destidx (Space "device") srcmem srcidx DefaultSpace nbytes =- GC.stm- [C.cstm|- if ($exp:nbytes > 0) {- OPENCL_SUCCEED_OR_RETURN(- 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)));- }- |]-copyOpenCLMemory _ destmem destidx (Space "device") srcmem srcidx (Space "device") nbytes =- -- Be aware that OpenCL swaps the usual order of operands for- -- memcpy()-like functions. The order below is not a typo.- GC.stm- [C.cstm|{- if ($exp:nbytes > 0) {- OPENCL_SUCCEED_OR_RETURN(- 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->queue));- }- }- }|]-copyOpenCLMemory _ destmem destidx DefaultSpace srcmem srcidx DefaultSpace nbytes =- GC.copyMemoryDefaultSpace destmem destidx srcmem srcidx nbytes-copyOpenCLMemory _ _ _ destspace _ _ srcspace _ =- error $ "Cannot copy to " ++ show destspace ++ " from " ++ show srcspace- openclMemoryType :: GC.MemoryType OpenCL () openclMemoryType "device" = pure [C.cty|typename cl_mem|]-openclMemoryType space =- error $ "OpenCL backend does not support '" ++ space ++ "' memory space."--kernelConstToExp :: KernelConst -> C.Exp-kernelConstToExp (SizeConst key) =- [C.cexp|*ctx->tuning_params.$id:key|]-kernelConstToExp (SizeMaxConst size_class) =- [C.cexp|ctx->$id:field|]- where- field = "max_" <> prettyString size_class--compileGroupDim :: GroupDim -> GC.CompilerM op s C.Exp-compileGroupDim (Left e) = GC.compileExp e-compileGroupDim (Right kc) = pure $ kernelConstToExp kc--callKernel :: GC.OpCompiler OpenCL ()-callKernel (GetSize v key) = do- let e = kernelConstToExp $ SizeConst key- GC.stm [C.cstm|$id:v = $exp:e;|]-callKernel (CmpSizeLe v key x) = do- let e = kernelConstToExp $ SizeConst key- x' <- GC.compileExp x- GC.stm [C.cstm|$id:v = $exp:e <= $exp:x';|]- sizeLoggingCode v key x'-callKernel (GetSizeMax v size_class) = do- let e = kernelConstToExp $ SizeMaxConst size_class- GC.stm [C.cstm|$id:v = $exp:e;|]-callKernel (LaunchKernel safety name args num_workgroups workgroup_size) = do- -- The other failure args are set automatically when the kernel is- -- first created.- when (safety == SafetyFull) $- GC.stm- [C.cstm|- OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:name, 1,- sizeof(ctx->failure_is_an_option),- &ctx->failure_is_an_option));- |]-- (arg_params, arg_set, call_args) <-- unzip3 <$> zipWithM onArg [(0 :: Int) ..] args-- num_workgroups' <- mapM GC.compileExp num_workgroups- workgroup_size' <- mapM compileGroupDim workgroup_size- local_bytes <- foldM localBytes [C.cexp|0|] args-- kernel_fname <- genKernelFunction name safety arg_params arg_set-- let grid_x : grid_y : grid_z : _ = num_workgroups' ++ repeat [C.cexp|1|]- group_x : group_y : group_z : _ = workgroup_size' ++ repeat [C.cexp|1|]-- GC.stm- [C.cstm|{- err = $id:kernel_fname(ctx,- $exp:grid_x,$exp:grid_y,$exp:grid_z,- $exp:group_x, $exp:group_y, $exp:group_z,- $exp:local_bytes,- $args:call_args);- if (err != FUTHARK_SUCCESS) { goto cleanup; }- }|]-- when (safety >= SafetyFull) $- GC.stm [C.cstm|ctx->failure_is_an_option = 1;|]- where- localBytes cur (SharedMemoryKArg num_bytes) = do- num_bytes' <- GC.compileExp $ unCount num_bytes- pure [C.cexp|$exp:cur + $exp:num_bytes'|]- localBytes cur _ = pure cur-- onArg i (ValueKArg e t) = do- let arg = "arg" <> show i- e' <- GC.compileExp e- pure- ( [C.cparam|$ty:(primStorageType t) $id:arg|],- ([C.cexp|sizeof($id:arg)|], [C.cexp|&$id:arg|]),- toStorage t e'- )- onArg i (MemKArg v) = do- let arg = "arg" <> show i- v' <- GC.rawMem v- pure- ( [C.cparam|typename cl_mem $id:arg|],- ([C.cexp|sizeof($id:arg)|], [C.cexp|&$id:arg|]),- v'- )- onArg i (SharedMemoryKArg (Count c)) = do- let arg = "arg" <> show i- num_bytes <- GC.compileExp c- pure- ( [C.cparam|unsigned int $id:arg|],- ([C.cexp|$id:arg|], [C.cexp|NULL|]),- num_bytes- )--genKernelFunction ::- KernelName ->- KernelSafety ->- [C.Param] ->- [(C.Exp, C.Exp)] ->- GC.CompilerM op s Name-genKernelFunction kernel_name safety arg_params arg_set = do- let kernel_fname = "gpu_kernel_" <> kernel_name- GC.libDecl- [C.cedecl|static int $id:kernel_fname(- struct futhark_context* ctx,- unsigned int grid_x, unsigned int grid_y, unsigned int grid_z,- unsigned int block_x, unsigned int block_y, unsigned int block_z,- unsigned int local_bytes, $params:arg_params) {- (void)local_bytes;- if (grid_x * grid_y * grid_z * block_x * block_y * block_z != 0) {- const size_t global_work_size[3] = {grid_x*block_x, grid_y*block_y, grid_z*block_z};- const size_t local_work_size[3] = {block_x, block_y, block_z};- typename int64_t time_start = 0, time_end = 0;- $stms:set_args- if (ctx->debugging) {- fprintf(ctx->log, "Launching %s with grid size [%d, %d, %d] and group size [%d, %d, %d]; local memory: %d bytes.\n",- $string:(prettyString kernel_name),- grid_x, grid_y, grid_z,- block_x, block_y, block_z,- local_bytes);- time_start = get_wall_time();- }- typename cl_event *pevent = $exp:(profilingEvent kernel_name);- OPENCL_SUCCEED_OR_RETURN(- clEnqueueNDRangeKernel(ctx->queue, ctx->program->$id:kernel_name, 3, NULL,- global_work_size, local_work_size,- 0, NULL, pevent));- if (ctx->debugging) {- OPENCL_SUCCEED_FATAL(clFinish(ctx->queue));- time_end = get_wall_time();- long int time_diff = time_end - time_start;- fprintf(ctx->log, "kernel %s runtime: %ldus\n",- $string:(prettyString kernel_name), time_diff);- }- }- return FUTHARK_SUCCESS;- }|]+openclMemoryType space = error $ "GPU backend does not support '" ++ space ++ "' memory space." - pure kernel_fname+-- | Compile the program to C with calls to OpenCL.+compileProg :: (MonadFreshNames m) => T.Text -> Prog GPUMem -> m (ImpGen.Warnings, GC.CParts)+compileProg version prog = do+ ( ws,+ Program opencl_code opencl_prelude kernels types params failures prog'+ ) <-+ ImpGen.compileProg prog+ (ws,)+ <$> GC.compileProg+ "opencl"+ version+ params+ operations+ (mkBoilerplate (opencl_prelude <> opencl_code) kernels types failures)+ opencl_includes+ (Space "device", [Space "device", DefaultSpace])+ cliOptions+ prog' where- set_args = zipWith setKernelArg [numFailureParams safety ..] arg_set- setKernelArg i (size, e) =- [C.cstm|OPENCL_SUCCEED_OR_RETURN(clSetKernelArg(ctx->program->$id:kernel_name, $int:i, $exp:size, $exp:e));|]+ operations :: GC.Operations OpenCL ()+ operations =+ gpuOperations+ { GC.opsMemoryType = openclMemoryType+ }+ opencl_includes =+ [untrimming|+ #define CL_TARGET_OPENCL_VERSION 120+ #define CL_USE_DEPRECATED_OPENCL_1_2_APIS+ #ifdef __APPLE__+ #define CL_SILENCE_DEPRECATION+ #include <OpenCL/cl.h>+ #else+ #include <CL/cl.h>+ #endif+ |]
− src/Futhark/CodeGen/Backends/COpenCL/Boilerplate.hs
@@ -1,320 +0,0 @@-{-# LANGUAGE QuasiQuotes #-}--module Futhark.CodeGen.Backends.COpenCL.Boilerplate- ( generateBoilerplate,- profilingEvent,- copyDevToDev,- copyDevToHost,- copyHostToDev,- copyScalarToDev,- copyScalarFromDev,- commonOptions,- failureMsgFunction,- costCentreReport,- kernelRuntime,- kernelRuns,- sizeLoggingCode,- )-where--import Control.Monad-import Control.Monad.State-import Data.Map qualified as M-import Data.Text qualified as T-import Futhark.CodeGen.Backends.GenericC qualified as GC-import Futhark.CodeGen.Backends.GenericC.Options-import Futhark.CodeGen.Backends.GenericC.Pretty-import Futhark.CodeGen.ImpCode.OpenCL-import Futhark.CodeGen.OpenCL.Heuristics-import Futhark.CodeGen.RTS.C (backendsOpenclH)-import Futhark.Util (chunk)-import Futhark.Util.Pretty (prettyTextOneLine)-import Language.C.Quote.OpenCL qualified as C-import Language.C.Syntax qualified as C--errorMsgNumArgs :: ErrorMsg a -> Int-errorMsgNumArgs = length . errorMsgArgTypes--failureMsgFunction :: [FailureMsg] -> C.Definition-failureMsgFunction failures =- let printfEscape =- let escapeChar '%' = "%%"- escapeChar c = [c]- in concatMap escapeChar- onPart (ErrorString s) = printfEscape $ T.unpack s- -- FIXME: bogus for non-ints.- onPart ErrorVal {} = "%lld"- 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: {return msgprintf($string:msg, $args:msgargs); break;}|]- failure_cases =- zipWith onFailure [(0 :: Int) ..] failures- 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"-copyDevToHost = "copy_dev_to_host"-copyHostToDev = "copy_host_to_dev"-copyScalarToDev = "copy_scalar_to_dev"-copyScalarFromDev = "copy_scalar_from_dev"--profilingEvent :: Name -> C.Exp-profilingEvent name =- [C.cexp|(ctx->profiling_paused || !ctx->profiling) ? NULL- : opencl_get_event(ctx,- &ctx->program->$id:(kernelRuns name),- &ctx->program->$id:(kernelRuntime name))|]--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->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) {- fprintf(ctx->log, "Created kernel %s.\n", $string:(prettyString name));- }- }|]- where- set_global_failure =- [C.citem|OPENCL_SUCCEED_FATAL(- clSetKernelArg(ctx->program->$id:name, 0, sizeof(typename cl_mem),- &ctx->global_failure));|]- set_global_failure_args =- [C.citem|OPENCL_SUCCEED_FATAL(- 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]--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] ->- [FailureMsg] ->- GC.CompilerM OpenCL () ()-generateBoilerplate opencl_program opencl_prelude cost_centres kernels types 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- 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);|]-- 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")--kernelRuns :: KernelName -> Name-kernelRuns = (<> "_runs")--costCentreReport :: [Name] -> [C.BlockItem]-costCentreReport names = report_kernels ++ [report_total]- where- longest_name = foldl max 0 $ map (length . prettyString) names- report_kernels = concatMap reportKernel names- format_string name =- let padding = replicate (longest_name - length name) ' '- in unwords- [ name ++ padding,- "ran %5d times; avg: %8ldus; total: %8ldus\n"- ]- reportKernel name =- let runs = kernelRuns name- total_runtime = kernelRuntime name- in [ [C.citem|- str_builder(&builder,- $string:(format_string (prettyString name)),- 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->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);|]--sizeHeuristicsCode :: SizeHeuristic -> C.Stm-sizeHeuristicsCode (SizeHeuristic platform_name device_type which (TPrimExp what)) =- [C.cstm|- if ($exp:which' == 0 &&- strstr(option->platform_name, $string:platform_name) != NULL &&- (option->device_type & $exp:(clDeviceType device_type)) == $exp:(clDeviceType device_type)) {- $items:get_size- }|]- where- clDeviceType DeviceGPU = [C.cexp|CL_DEVICE_TYPE_GPU|]- clDeviceType DeviceCPU = [C.cexp|CL_DEVICE_TYPE_CPU|]-- 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|]-- get_size =- let (e, m) = runState (GC.compilePrimExp onLeaf what) mempty- in concat (M.elems m) ++ [[C.citem|$exp:which' = $exp:e;|]]-- onLeaf (DeviceInfo s) = do- let s' = "CL_DEVICE_" ++ s- v = s ++ "_val"- m <- get- case M.lookup s m of- Nothing ->- -- XXX: Cheating with the type here; works for the infos we- -- currently use because we zero-initialise and assume a- -- little-endian platform, but should be made more- -- size-aware in the future.- modify $- M.insert- s'- [C.citems|size_t $id:v = 0;- clGetDeviceInfo(ctx->device, $id:s',- sizeof($id:v), &$id:v,- NULL);|]- Just _ -> pure ()-- pure [C.cexp|$id:v|]---- Output size information if logging is enabled.------ The autotuner depends on the format of this output, so use caution if--- changing it.-sizeLoggingCode :: VName -> Name -> C.Exp -> GC.CompilerM op () ()-sizeLoggingCode v key x' = do- GC.stm- [C.cstm|if (ctx->logging) {- fprintf(ctx->log, "Compared %s <= %ld: %s.\n", $string:(T.unpack (prettyTextOneLine key)), (long)$exp:x', $id:v ? "true" : "false");- }|]---- Options that are common to multiple GPU-like backends.-commonOptions :: [Option]-commonOptions =- [ Option- { optionLongName = "device",- optionShortName = Just 'd',- optionArgument = RequiredArgument "NAME",- optionDescription = "Use the first OpenCL device whose name contains the given string.",- optionAction = [C.cstm|futhark_context_config_set_device(cfg, optarg);|]- },- Option- { optionLongName = "default-group-size",- optionShortName = Nothing,- optionArgument = RequiredArgument "INT",- optionDescription = "The default size of OpenCL workgroups that are launched.",- optionAction = [C.cstm|futhark_context_config_set_default_group_size(cfg, atoi(optarg));|]- },- Option- { optionLongName = "default-num-groups",- optionShortName = Nothing,- optionArgument = RequiredArgument "INT",- optionDescription = "The default number of OpenCL workgroups that are launched.",- optionAction = [C.cstm|futhark_context_config_set_default_num_groups(cfg, atoi(optarg));|]- },- Option- { optionLongName = "default-tile-size",- optionShortName = Nothing,- optionArgument = RequiredArgument "INT",- optionDescription = "The default tile size used when performing two-dimensional tiling.",- optionAction = [C.cstm|futhark_context_config_set_default_tile_size(cfg, atoi(optarg));|]- },- Option- { optionLongName = "default-reg-tile-size",- optionShortName = Nothing,- optionArgument = RequiredArgument "INT",- optionDescription = "The default register tile size used when performing two-dimensional tiling.",- optionAction = [C.cstm|futhark_context_config_set_default_reg_tile_size(cfg, atoi(optarg));|]- },- Option- { optionLongName = "default-threshold",- optionShortName = Nothing,- optionArgument = RequiredArgument "INT",- optionDescription = "The default parallelism threshold.",- optionAction = [C.cstm|futhark_context_config_set_default_threshold(cfg, atoi(optarg));|]- }- ]--{-# NOINLINE generateBoilerplate #-}
+ src/Futhark/CodeGen/Backends/GPU.hs view
@@ -0,0 +1,440 @@+{-# LANGUAGE QuasiQuotes #-}++-- | C code generation for GPU, in general.+--+-- This module generates codes that targets the tiny GPU API+-- abstraction layer we define in the runtime system.+module Futhark.CodeGen.Backends.GPU+ ( gpuOperations,+ gpuOptions,+ generateGPUBoilerplate,+ )+where++import Control.Monad+import Data.Bifunctor (bimap)+import Data.Map qualified as M+import Data.Text qualified as T+import Futhark.CodeGen.Backends.GenericC qualified as GC+import Futhark.CodeGen.Backends.GenericC.Options+import Futhark.CodeGen.Backends.GenericC.Pretty (idText)+import Futhark.CodeGen.Backends.SimpleRep (primStorageType, toStorage)+import Futhark.CodeGen.ImpCode.OpenCL+import Futhark.CodeGen.RTS.C (gpuH, gpuPrototypesH)+import Futhark.MonadFreshNames+import Futhark.Util (chunk)+import Futhark.Util.Pretty (prettyTextOneLine)+import Language.C.Quote.OpenCL qualified as C+import Language.C.Syntax qualified as C++genKernelFunction ::+ KernelName ->+ KernelSafety ->+ [C.Param] ->+ [(C.Exp, C.Exp)] ->+ GC.CompilerM op s Name+genKernelFunction kernel_name safety arg_params arg_set = do+ let kernel_fname = "gpu_kernel_" <> kernel_name+ GC.libDecl+ [C.cedecl|static int $id:kernel_fname+ (struct futhark_context* ctx,+ unsigned int grid_x, unsigned int grid_y, unsigned int grid_z,+ unsigned int block_x, unsigned int block_y, unsigned int block_z,+ unsigned int shared_bytes, $params:arg_params) {+ if (grid_x * grid_y * grid_z * block_x * block_y * block_z != 0) {+ void* args[$int:num_args] = { $inits:(failure_inits<>args_inits) };+ size_t args_sizes[$int:num_args] = { $inits:(failure_sizes<>args_sizes) };+ return gpu_launch_kernel(ctx, ctx->program->$id:kernel_name,+ $string:(prettyString kernel_name),+ (const typename int32_t[]){grid_x, grid_y, grid_z},+ (const typename int32_t[]){block_x, block_y, block_z},+ shared_bytes,+ $int:num_args, args, args_sizes);+ }+ return FUTHARK_SUCCESS;+ }|]++ pure kernel_fname+ where+ num_args = numFailureParams safety + length arg_set+ expToInit e = [C.cinit|$exp:e|]+ (args_sizes, args_inits) = bimap (map expToInit) (map expToInit) $ unzip arg_set+ (failure_inits, failure_sizes) =+ unzip . take (numFailureParams safety) $+ [ ([C.cinit|&ctx->global_failure|], [C.cinit|sizeof(ctx->global_failure)|]),+ ([C.cinit|&ctx->failure_is_an_option|], [C.cinit|sizeof(ctx->failure_is_an_option)|]),+ ([C.cinit|&ctx->global_failure_args|], [C.cinit|sizeof(ctx->global_failure_args)|])+ ]++kernelConstToExp :: KernelConst -> C.Exp+kernelConstToExp (SizeConst key) =+ [C.cexp|*ctx->tuning_params.$id:key|]+kernelConstToExp (SizeMaxConst size_class) =+ [C.cexp|ctx->$id:field|]+ where+ field = "max_" <> prettyString size_class++compileGroupDim :: GroupDim -> GC.CompilerM op s C.Exp+compileGroupDim (Left e) = GC.compileExp e+compileGroupDim (Right kc) = pure $ kernelConstToExp kc++genLaunchKernel ::+ KernelSafety ->+ KernelName ->+ Count Bytes (TExp Int64) ->+ [KernelArg] ->+ [Exp] ->+ [GroupDim] ->+ GC.CompilerM op s ()+genLaunchKernel safety kernel_name local_memory args num_groups group_size = do+ (arg_params, arg_params_inits, call_args) <-+ unzip3 <$> zipWithM mkArgs [(0 :: Int) ..] args++ (grid_x, grid_y, grid_z) <- mkDims <$> mapM GC.compileExp num_groups+ (group_x, group_y, group_z) <- mkDims <$> mapM compileGroupDim group_size++ kernel_fname <- genKernelFunction kernel_name safety arg_params arg_params_inits++ local_memory' <- GC.compileExp $ untyped $ unCount local_memory++ GC.stm+ [C.cstm|{+ err = $id:kernel_fname(ctx,+ $exp:grid_x, $exp:grid_y, $exp:grid_z,+ $exp:group_x, $exp:group_y, $exp:group_z,+ $exp:local_memory',+ $args:call_args);+ if (err != FUTHARK_SUCCESS) { goto cleanup; }+ }|]++ when (safety >= SafetyFull) $+ GC.stm [C.cstm|ctx->failure_is_an_option = 1;|]+ where+ mkDims [] = ([C.cexp|0|], [C.cexp|0|], [C.cexp|0|])+ mkDims [x] = (x, [C.cexp|1|], [C.cexp|1|])+ mkDims [x, y] = (x, y, [C.cexp|1|])+ mkDims (x : y : z : _) = (x, y, z)++ mkArgs i (ValueKArg e t) = do+ let arg = "arg" <> show i+ e' <- GC.compileExp e+ pure+ ( [C.cparam|$ty:(primStorageType t) $id:arg|],+ ([C.cexp|sizeof($id:arg)|], [C.cexp|&$id:arg|]),+ toStorage t e'+ )+ mkArgs i (MemKArg v) = do+ let arg = "arg" <> show i+ v' <- GC.rawMem v+ pure+ ( [C.cparam|typename gpu_mem $id:arg|],+ ([C.cexp|sizeof($id:arg)|], [C.cexp|&$id:arg|]),+ v'+ )++callKernel :: GC.OpCompiler OpenCL ()+callKernel (GetSize v key) = do+ let e = kernelConstToExp $ SizeConst key+ GC.stm [C.cstm|$id:v = $exp:e;|]+callKernel (CmpSizeLe v key x) = do+ let e = kernelConstToExp $ SizeConst key+ x' <- GC.compileExp x+ GC.stm [C.cstm|$id:v = $exp:e <= $exp:x';|]+ -- Output size information if logging is enabled. The autotuner+ -- depends on the format of this output, so use caution if changing+ -- it.+ GC.stm+ [C.cstm|if (ctx->logging) {+ fprintf(ctx->log, "Compared %s <= %ld: %s.\n", $string:(T.unpack (prettyTextOneLine key)), (long)$exp:x', $id:v ? "true" : "false");+ }|]+callKernel (GetSizeMax v size_class) = do+ let e = kernelConstToExp $ SizeMaxConst size_class+ GC.stm [C.cstm|$id:v = $exp:e;|]+callKernel (LaunchKernel safety kernel_name local_memory args num_groups group_size) =+ genLaunchKernel safety kernel_name local_memory args num_groups group_size++copygpu2gpu :: GC.DoLMADCopy op s+copygpu2gpu _ t shape dst (dstoffset, dststride) src (srcoffset, srcstride) = do+ let fname = "lmad_copy_gpu2gpu_" <> show (primByteSize t :: Int) <> "b"+ r = length shape+ dststride_inits = [[C.cinit|$exp:e|] | Count e <- dststride]+ srcstride_inits = [[C.cinit|$exp:e|] | Count e <- srcstride]+ shape_inits = [[C.cinit|$exp:e|] | Count e <- shape]+ GC.stm+ [C.cstm|+ if ((err =+ $id:fname(ctx, $int:r,+ $exp:dst, $exp:(unCount dstoffset),+ (typename int64_t[]){ $inits:dststride_inits },+ $exp:src, $exp:(unCount srcoffset),+ (typename int64_t[]){ $inits:srcstride_inits },+ (typename int64_t[]){ $inits:shape_inits })) != 0) {+ goto cleanup;+ }+ |]++copyhost2gpu :: GC.DoLMADCopy op s+copyhost2gpu sync t shape dst (dstoffset, dststride) src (srcoffset, srcstride) = do+ let r = length shape+ dststride_inits = [[C.cinit|$exp:e|] | Count e <- dststride]+ srcstride_inits = [[C.cinit|$exp:e|] | Count e <- srcstride]+ shape_inits = [[C.cinit|$exp:e|] | Count e <- shape]+ GC.stm+ [C.cstm|+ if ((err =+ lmad_copy_host2gpu+ (ctx, $int:(primByteSize t::Int), $exp:sync', $int:r,+ $exp:dst, $exp:(unCount dstoffset),+ (typename int64_t[]){ $inits:dststride_inits },+ $exp:src, $exp:(unCount srcoffset),+ (typename int64_t[]){ $inits:srcstride_inits },+ (typename int64_t[]){ $inits:shape_inits })) != 0) {+ goto cleanup;+ }+ |]+ where+ sync' = case sync of+ GC.CopyBarrier -> [C.cexp|true|]+ GC.CopyNoBarrier -> [C.cexp|false|]++copygpu2host :: GC.DoLMADCopy op s+copygpu2host sync t shape dst (dstoffset, dststride) src (srcoffset, srcstride) = do+ let r = length shape+ dststride_inits = [[C.cinit|$exp:e|] | Count e <- dststride]+ srcstride_inits = [[C.cinit|$exp:e|] | Count e <- srcstride]+ shape_inits = [[C.cinit|$exp:e|] | Count e <- shape]+ GC.stm+ [C.cstm|+ if ((err =+ lmad_copy_gpu2host+ (ctx, $int:(primByteSize t::Int), $exp:sync', $int:r,+ $exp:dst, $exp:(unCount dstoffset),+ (typename int64_t[]){ $inits:dststride_inits },+ $exp:src, $exp:(unCount srcoffset),+ (typename int64_t[]){ $inits:srcstride_inits },+ (typename int64_t[]){ $inits:shape_inits })) != 0) {+ goto cleanup;+ }+ |]+ where+ sync' = case sync of+ GC.CopyBarrier -> [C.cexp|true|]+ GC.CopyNoBarrier -> [C.cexp|false|]++gpuCopies :: M.Map (Space, Space) (GC.DoLMADCopy op s)+gpuCopies =+ M.fromList+ [ ((Space "device", Space "device"), copygpu2gpu),+ ((Space "device", DefaultSpace), copyhost2gpu),+ ((DefaultSpace, Space "device"), copygpu2host)+ ]++createKernels :: [KernelName] -> GC.CompilerM op s ()+createKernels kernels = forM_ kernels $ \name ->+ GC.contextFieldDyn+ (C.toIdent name mempty)+ [C.cty|typename gpu_kernel|]+ [C.cstm|gpu_create_kernel(ctx, &ctx->program->$id:name, $string:(T.unpack (idText (C.toIdent name mempty))));|]+ [C.cstm|gpu_free_kernel(ctx, ctx->program->$id:name);|]++allocateGPU :: GC.Allocate op ()+allocateGPU mem size tag "device" =+ GC.stm+ [C.cstm|(void)gpu_alloc(ctx, ctx->log,+ (size_t)$exp:size, $exp:tag,+ &$exp:mem, (size_t*)&$exp:size);|]+allocateGPU _ _ _ space =+ error $ "Cannot allocate in '" ++ space ++ "' memory space."++deallocateGPU :: GC.Deallocate op ()+deallocateGPU mem size tag "device" =+ GC.stm [C.cstm|(void)gpu_free(ctx, $exp:mem, $exp:size, $exp:tag);|]+deallocateGPU _ _ _ space =+ error $ "Cannot deallocate in '" ++ space ++ "' space"++-- It is often faster to do a blocking clEnqueueReadBuffer() than to+-- do an async clEnqueueReadBuffer() followed by a clFinish(), even+-- with an in-order command queue. This is safe if and only if there+-- are no possible outstanding failures.+readScalarGPU :: GC.ReadScalar op ()+readScalarGPU mem i t "device" _ = do+ val <- newVName "read_res"+ GC.decl [C.cdecl|$ty:t $id:val;|]+ GC.stm+ [C.cstm|if ((err = gpu_scalar_from_device(ctx, &$id:val, $exp:mem, $exp:i * sizeof($ty:t), sizeof($ty:t))) != 0) { goto cleanup; }|]+ GC.stm+ [C.cstm|if (ctx->failure_is_an_option && futhark_context_sync(ctx) != 0)+ { err = 1; goto cleanup; }|]+ pure [C.cexp|$id:val|]+readScalarGPU _ _ _ space _ =+ error $ "Cannot read from '" ++ space ++ "' memory space."++-- TODO: Optimised special case when the scalar is a constant, in+-- which case we can do the write asynchronously.+writeScalarGPU :: GC.WriteScalar op ()+writeScalarGPU mem i t "device" _ val = do+ val' <- newVName "write_tmp"+ GC.item [C.citem|$ty:t $id:val' = $exp:val;|]+ GC.stm+ [C.cstm|if ((err = gpu_scalar_to_device(ctx, $exp:mem, $exp:i * sizeof($ty:t), sizeof($ty:t), &$id:val')) != 0) { goto cleanup; }|]+writeScalarGPU _ _ _ space _ _ =+ error $ "Cannot write to '" ++ space ++ "' memory space."++syncArg :: GC.CopyBarrier -> C.Exp+syncArg GC.CopyBarrier = [C.cexp|true|]+syncArg GC.CopyNoBarrier = [C.cexp|false|]++copyGPU :: GC.Copy OpenCL ()+copyGPU _ dstmem dstidx (Space "device") srcmem srcidx (Space "device") nbytes =+ GC.stm+ [C.cstm|err = gpu_memcpy(ctx, $exp:dstmem, $exp:dstidx, $exp:srcmem, $exp:srcidx, $exp:nbytes);|]+copyGPU b dstmem dstidx DefaultSpace srcmem srcidx (Space "device") nbytes =+ GC.stm+ [C.cstm|err = memcpy_gpu2host(ctx, $exp:(syncArg b), $exp:dstmem, $exp:dstidx, $exp:srcmem, $exp:srcidx, $exp:nbytes);|]+copyGPU b dstmem dstidx (Space "device") srcmem srcidx DefaultSpace nbytes =+ GC.stm+ [C.cstm|err = memcpy_host2gpu(ctx, $exp:(syncArg b), $exp:dstmem, $exp:dstidx, $exp:srcmem, $exp:srcidx, $exp:nbytes);|]+copyGPU _ _ _ destspace _ _ srcspace _ =+ error $ "Cannot copy to " ++ show destspace ++ " from " ++ show srcspace++gpuOperations :: GC.Operations OpenCL ()+gpuOperations =+ GC.defaultOperations+ { GC.opsCompiler = callKernel,+ GC.opsWriteScalar = writeScalarGPU,+ GC.opsReadScalar = readScalarGPU,+ GC.opsAllocate = allocateGPU,+ GC.opsDeallocate = deallocateGPU,+ GC.opsCopy = copyGPU,+ GC.opsCopies = gpuCopies <> GC.opsCopies GC.defaultOperations,+ GC.opsFatMemory = True+ }++-- | Options that are common to multiple GPU-like backends.+gpuOptions :: [Option]+gpuOptions =+ [ Option+ { optionLongName = "device",+ optionShortName = Just 'd',+ optionArgument = RequiredArgument "NAME",+ optionDescription = "Use the first device whose name contains the given string.",+ optionAction = [C.cstm|futhark_context_config_set_device(cfg, optarg);|]+ },+ Option+ { optionLongName = "default-group-size",+ optionShortName = Nothing,+ optionArgument = RequiredArgument "INT",+ optionDescription = "The default size of workgroups that are launched.",+ optionAction = [C.cstm|futhark_context_config_set_default_group_size(cfg, atoi(optarg));|]+ },+ Option+ { optionLongName = "default-num-groups",+ optionShortName = Nothing,+ optionArgument = RequiredArgument "INT",+ optionDescription = "The default number of workgroups that are launched.",+ optionAction = [C.cstm|futhark_context_config_set_default_num_groups(cfg, atoi(optarg));|]+ },+ Option+ { optionLongName = "default-tile-size",+ optionShortName = Nothing,+ optionArgument = RequiredArgument "INT",+ optionDescription = "The default tile size used when performing two-dimensional tiling.",+ optionAction = [C.cstm|futhark_context_config_set_default_tile_size(cfg, atoi(optarg));|]+ },+ Option+ { optionLongName = "default-reg-tile-size",+ optionShortName = Nothing,+ optionArgument = RequiredArgument "INT",+ optionDescription = "The default register tile size used when performing two-dimensional tiling.",+ optionAction = [C.cstm|futhark_context_config_set_default_reg_tile_size(cfg, atoi(optarg));|]+ },+ Option+ { optionLongName = "default-threshold",+ optionShortName = Nothing,+ optionArgument = RequiredArgument "INT",+ optionDescription = "The default parallelism threshold.",+ optionAction = [C.cstm|futhark_context_config_set_default_threshold(cfg, atoi(optarg));|]+ }+ ]++errorMsgNumArgs :: ErrorMsg a -> Int+errorMsgNumArgs = length . errorMsgArgTypes++failureMsgFunction :: [FailureMsg] -> C.Definition+failureMsgFunction failures =+ let printfEscape =+ let escapeChar '%' = "%%"+ escapeChar c = [c]+ in concatMap escapeChar+ onPart (ErrorString s) = printfEscape $ T.unpack s+ -- FIXME: bogus for non-ints.+ onPart ErrorVal {} = "%lld"+ 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: {return msgprintf($string:msg, $args:msgargs); break;}|]+ failure_cases =+ zipWith onFailure [(0 :: Int) ..] failures+ in [C.cedecl|static char* get_failure_msg(int failure_idx, typename int64_t args[]) {+ (void)args;+ switch (failure_idx) { $stms:failure_cases }+ return strdup("Unknown error. This is a compiler bug.");+ }|]++genProfileReport :: [Name] -> GC.CompilerM op s ()+genProfileReport cost_centres =+ GC.profileReport+ [C.citem|{struct cost_centres* ccs = cost_centres_new();+ $stms:(map initCostCentre (def_cost_centres<>cost_centres))+ tally_profiling_records(ctx, ccs);+ cost_centre_report(ccs, &builder);+ cost_centres_free(ccs);+ }|]+ where+ def_cost_centres =+ [ "copy_dev_to_dev",+ "copy_dev_to_host",+ "copy_host_to_dev",+ "copy_scalar_to_dev",+ "copy_scalar_from_dev"+ ]+ initCostCentre v =+ [C.cstm|cost_centres_init(ccs, $string:(nameToString v));|]++-- | Called after most code has been generated to generate the bulk of+-- the boilerplate.+generateGPUBoilerplate ::+ T.Text ->+ T.Text ->+ [Name] ->+ [PrimType] ->+ [FailureMsg] ->+ GC.CompilerM OpenCL () ()+generateGPUBoilerplate gpu_program backendH kernels types failures = do+ createKernels kernels+ let gpu_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 gpu_program]+ program_fragments = gpu_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+ 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 *gpu_program[] = {$inits:program_fragments};+ $esc:(T.unpack gpuPrototypesH)+ $esc:(T.unpack backendH)+ $esc:(T.unpack gpuH)+ |]+ GC.earlyDecl $ failureMsgFunction failures++ GC.generateProgramStruct++ GC.onClear [C.citem|if (ctx->error == NULL) { gpu_free_all(ctx); }|]++ genProfileReport kernels
src/Futhark/CodeGen/Backends/GenericC.hs view
@@ -37,7 +37,7 @@ import Futhark.CodeGen.Backends.GenericC.Server (serverDefs) import Futhark.CodeGen.Backends.GenericC.Types import Futhark.CodeGen.ImpCode-import Futhark.CodeGen.RTS.C (cacheH, contextH, contextPrototypesH, errorsH, freeListH, halfH, lockH, timingH, utilH)+import Futhark.CodeGen.RTS.C (cacheH, contextH, contextPrototypesH, copyH, errorsH, freeListH, halfH, lockH, timingH, utilH) import Futhark.IR.GPU.Sizes import Futhark.Manifest qualified as Manifest import Futhark.MonadFreshNames@@ -61,6 +61,29 @@ err = FUTHARK_PROGRAM_ERROR; goto cleanup;|] +lmadcopyCPU :: DoLMADCopy op s+lmadcopyCPU _ t shape dst (dstoffset, dststride) src (srcoffset, srcstride) = do+ let fname :: String+ (fname, ty) =+ case primByteSize t :: Int of+ 1 -> ("lmad_copy_1b", [C.cty|typename uint8_t|])+ 2 -> ("lmad_copy_2b", [C.cty|typename uint16_t|])+ 4 -> ("lmad_copy_4b", [C.cty|typename uint32_t|])+ 8 -> ("lmad_copy_8b", [C.cty|typename uint64_t|])+ k -> error $ "lmadcopyCPU: " <> error (show k)+ r = length shape+ dststride_inits = [[C.cinit|$exp:e|] | Count e <- dststride]+ srcstride_inits = [[C.cinit|$exp:e|] | Count e <- srcstride]+ shape_inits = [[C.cinit|$exp:e|] | Count e <- shape]+ stm+ [C.cstm|+ $id:fname(ctx, $int:r,+ ($ty:ty*) $exp:dst, $exp:(unCount dstoffset),+ (typename int64_t[]){ $inits:dststride_inits },+ ($ty:ty*) $exp:src, $exp:(unCount srcoffset),+ (typename int64_t[]){ $inits:srcstride_inits },+ (typename int64_t[]){ $inits:shape_inits });|]+ -- | A set of operations that fail for every operation involving -- non-default memory spaces. Uses plain pointers and @malloc@ for -- memory management.@@ -72,6 +95,7 @@ opsAllocate = defAllocate, opsDeallocate = defDeallocate, opsCopy = defCopy,+ opsCopies = M.singleton (DefaultSpace, DefaultSpace) lmadcopyCPU, opsMemoryType = defMemoryType, opsCompiler = defCompiler, opsFatMemory = True,@@ -174,20 +198,11 @@ return ret; } - long long new_usage = ctx->$id:usagename + size; if (ctx->detail_memory) {- fprintf(ctx->log, "Allocating %lld bytes for %s in %s (then allocated: %lld bytes)",+ fprintf(ctx->log, "Allocating %lld bytes for %s in %s (currently allocated: %lld bytes).\n", (long long) size, desc, $string:spacedesc,- new_usage);- }- if (new_usage > ctx->$id:peakname) {- ctx->$id:peakname = new_usage;- if (ctx->detail_memory) {- fprintf(ctx->log, " (new peak).\n");- }- } else if (ctx->detail_memory) {- fprintf(ctx->log, ".\n");+ ctx->$id:usagename); } $items:alloc@@ -197,7 +212,20 @@ *(block->references) = 1; block->size = size; block->desc = desc;+ long long new_usage = ctx->$id:usagename + size;+ if (ctx->detail_memory) {+ fprintf(ctx->log, "Received block of %lld bytes; now allocated: %lld bytes",+ (long long)block->size, new_usage);+ } ctx->$id:usagename = new_usage;+ if (new_usage > ctx->$id:peakname) {+ ctx->$id:peakname = new_usage;+ if (ctx->detail_memory) {+ fprintf(ctx->log, " (new peak).\n");+ }+ } else if (ctx->detail_memory) {+ fprintf(ctx->log, ".\n");+ } return FUTHARK_SUCCESS; } else { // We are naively assuming that any memory allocation error is due to OOM.@@ -298,11 +326,14 @@ #ifdef __clang__ #pragma clang diagnostic ignored "-Wunused-function" #pragma clang diagnostic ignored "-Wunused-variable"+#pragma clang diagnostic ignored "-Wunused-const-variable" #pragma clang diagnostic ignored "-Wparentheses" #pragma clang diagnostic ignored "-Wunused-label"+#pragma clang diagnostic ignored "-Wunused-but-set-variable" #elif __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable"+#pragma GCC diagnostic ignored "-Wunused-const-variable" #pragma GCC diagnostic ignored "-Wparentheses" #pragma GCC diagnostic ignored "-Wunused-label" #pragma GCC diagnostic ignored "-Wunused-but-set-variable"@@ -332,7 +363,7 @@ map fst $ filter ((fname `S.member`) . snd . snd) $ M.toList m compileProg' ::- MonadFreshNames m =>+ (MonadFreshNames m) => T.Text -> T.Text -> ParamMap ->@@ -404,6 +435,7 @@ #undef NDEBUG #include <assert.h> #include <stdarg.h>+#define SCALAR_FUN_ATTR static inline $utilH $cacheH $halfH@@ -439,6 +471,10 @@ $contextH +$copyH++#define FUTHARK_FUN_ATTR static+ $prototypes $lib_decls@@ -514,7 +550,7 @@ -- | Compile imperative program to a C program. Always uses the -- function named "main" as entry point, so make sure it is defined. compileProg ::- MonadFreshNames m =>+ (MonadFreshNames m) => T.Text -> T.Text -> ParamMap ->
src/Futhark/CodeGen/Backends/GenericC/Code.hs view
@@ -8,6 +8,8 @@ compileCode, compileDest, compileArg,+ compileLMADCopy,+ compileLMADCopyWith, errorMsgString, linearCode, )@@ -15,6 +17,7 @@ import Control.Monad import Control.Monad.Reader (asks)+import Data.Map qualified as M import Data.Maybe import Data.Text qualified as T import Futhark.CodeGen.Backends.GenericC.Monad@@ -55,7 +58,7 @@ compileExp = compilePrimExp $ \v -> pure [C.cexp|$id:v|] -- | Tell me how to compile a @v@, and I'll Compile any @PrimExp v@ for you.-compilePrimExp :: Monad m => (v -> m C.Exp) -> PrimExp v -> m C.Exp+compilePrimExp :: (Monad m) => (v -> m C.Exp) -> PrimExp v -> m C.Exp compilePrimExp _ (ValueExp val) = pure $ C.toExp val mempty compilePrimExp f (LeafExp v _) =@@ -133,6 +136,50 @@ assignmentOperator Mul {} = Just $ \d e -> [C.cexp|$id:d *= $exp:e|] assignmentOperator _ = Nothing +generateRead ::+ C.Exp ->+ C.Exp ->+ PrimType ->+ Space ->+ Volatility ->+ CompilerM op s C.Exp+generateRead _ _ Unit _ _ =+ pure [C.cexp|$exp:(UnitValue)|]+generateRead src iexp _ ScalarSpace {} _ =+ pure [C.cexp|$exp:src[$exp:iexp]|]+generateRead src iexp restype DefaultSpace vol =+ pure . fromStorage restype $+ derefPointer+ src+ iexp+ [C.cty|$tyquals:(volQuals vol) $ty:(primStorageType restype)*|]+generateRead src iexp restype (Space space) vol = do+ reader <- asks (opsReadScalar . envOperations)+ fromStorage restype <$> reader src iexp (primStorageType restype) space vol++generateWrite ::+ C.Exp ->+ C.Exp ->+ PrimType ->+ Space ->+ Volatility ->+ C.Exp ->+ CompilerM op s ()+generateWrite _ _ Unit _ _ _ = pure ()+generateWrite dest idx _ ScalarSpace {} _ elemexp = do+ stm [C.cstm|$exp:dest[$exp:idx] = $exp:elemexp;|]+generateWrite dest idx elemtype DefaultSpace vol elemexp = do+ let deref =+ derefPointer+ dest+ idx+ [C.cty|$tyquals:(volQuals vol) $ty:(primStorageType elemtype)*|]+ elemexp' = toStorage elemtype elemexp+ stm [C.cstm|$exp:deref = $exp:elemexp';|]+generateWrite dest idx elemtype (Space space) vol elemexp = do+ writer <- asks (opsWriteScalar . envOperations)+ writer dest idx (primStorageType elemtype) space vol (toStorage elemtype elemexp)+ compileRead :: VName -> Count u (TPrimExp t VName) ->@@ -140,25 +187,10 @@ Space -> Volatility -> CompilerM op s C.Exp-compileRead _ _ Unit _ _ =- pure [C.cexp|$exp:(UnitValue)|]-compileRead src (Count iexp) restype DefaultSpace vol = do+compileRead src (Count iexp) restype space vol = do src' <- rawMem src- fmap (fromStorage restype) $- derefPointer src'- <$> compileExp (untyped iexp)- <*> pure [C.cty|$tyquals:(volQuals vol) $ty:(primStorageType restype)*|]-compileRead src (Count iexp) restype (Space space) vol =- fmap (fromStorage restype) . join $- asks (opsReadScalar . envOperations)- <*> rawMem src- <*> compileExp (untyped iexp)- <*> pure (primStorageType restype)- <*> pure space- <*> pure vol-compileRead src (Count iexp) _ ScalarSpace {} _ = do- iexp' <- compileExp $ untyped iexp- pure [C.cexp|$id:src[$exp:iexp']|]+ iexp' <- compileExp (untyped iexp)+ generateRead src' iexp' restype space vol memNeedsWrapping :: VName -> CompilerM op s Bool memNeedsWrapping v = do@@ -304,47 +336,26 @@ [C.cstm|if ($exp:cond') { $items:tbranch' } else $stm:x|] _ -> [C.cstm|if ($exp:cond') { $items:tbranch' } else { $items:fbranch' }|]-compileCode (Copy _ dest (Count destoffset) DefaultSpace src (Count srcoffset) DefaultSpace (Count size)) =- join $- copyMemoryDefaultSpace- <$> rawMem dest- <*> compileExp (untyped destoffset)- <*> rawMem src- <*> compileExp (untyped srcoffset)- <*> compileExp (untyped size)-compileCode (Copy _ dest (Count destoffset) destspace src (Count srcoffset) srcspace (Count size)) = do- copy <- asks $ opsCopy . envOperations- join $- copy CopyBarrier- <$> rawMem dest- <*> compileExp (untyped destoffset)- <*> pure destspace- <*> rawMem src- <*> compileExp (untyped srcoffset)- <*> pure srcspace- <*> compileExp (untyped size)+compileCode (LMADCopy t shape (dst, dstspace) (dstoffset, dststrides) (src, srcspace) (srcoffset, srcstrides)) = do+ cp <- asks $ M.lookup (dstspace, srcspace) . opsCopies . envOperations+ case cp of+ Nothing ->+ compileLMADCopy t shape (dst, dstspace) (dstoffset, dststrides) (src, srcspace) (srcoffset, srcstrides)+ Just cp' -> do+ shape' <- traverse (traverse (compileExp . untyped)) shape+ dst' <- rawMem dst+ src' <- rawMem src+ dstoffset' <- traverse (compileExp . untyped) dstoffset+ dststrides' <- traverse (traverse (compileExp . untyped)) dststrides+ srcoffset' <- traverse (compileExp . untyped) srcoffset+ srcstrides' <- traverse (traverse (compileExp . untyped)) srcstrides+ cp' CopyBarrier t shape' dst' (dstoffset', dststrides') src' (srcoffset', srcstrides') compileCode (Write _ _ Unit _ _ _) = pure ()-compileCode (Write dest (Count idx) elemtype DefaultSpace vol elemexp) = do- dest' <- rawMem dest- deref <-- derefPointer dest'- <$> compileExp (untyped idx)- <*> pure [C.cty|$tyquals:(volQuals vol) $ty:(primStorageType elemtype)*|]- elemexp' <- toStorage elemtype <$> compileExp elemexp- stm [C.cstm|$exp:deref = $exp:elemexp';|]-compileCode (Write dest (Count idx) _ ScalarSpace {} _ elemexp) = do+compileCode (Write dst (Count idx) elemtype space vol elemexp) = do+ dst' <- rawMem dst idx' <- compileExp (untyped idx) elemexp' <- compileExp elemexp- stm [C.cstm|$id:dest[$exp:idx'] = $exp:elemexp';|]-compileCode (Write dest (Count idx) elemtype (Space space) vol elemexp) =- join $- asks (opsWriteScalar . envOperations)- <*> rawMem dest- <*> compileExp (untyped idx)- <*> pure (primStorageType elemtype)- <*> pure space- <*> pure vol- <*> (toStorage elemtype <$> compileExp elemexp)+ generateWrite dst' idx' elemtype space vol elemexp' compileCode (Read x src i restype space vol) = do e <- compileRead src i restype space vol stm [C.cstm|$id:x = $exp:e;|]@@ -394,3 +405,61 @@ <*> pure fname <*> mapM compileArg args stms $ mconcat unpack_dest++-- | Compile an 'LMADCopy' using sequential nested loops, but+-- parameterised over how to do the reads and writes.+compileLMADCopyWith ::+ [Count Elements (TExp Int64)] ->+ (C.Exp -> C.Exp -> CompilerM op s ()) ->+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) ->+ (C.Exp -> CompilerM op s C.Exp) ->+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) ->+ CompilerM op s ()+compileLMADCopyWith shape doWrite dst_lmad doRead src_lmad = do+ let (dstoffset, dststrides) = dst_lmad+ (srcoffset, srcstrides) = src_lmad+ shape' <- mapM (compileExp . untyped . unCount) shape+ body <- collect $ do+ dst_i <-+ compileExp . untyped . unCount $+ dstoffset + sum (zipWith (*) is' dststrides)+ src_i <-+ compileExp . untyped . unCount $+ srcoffset + sum (zipWith (*) is' srcstrides)+ doWrite dst_i =<< doRead src_i+ items $ loops (zip is shape') body+ where+ r = length shape+ is = map (VName "i") [0 .. r - 1]+ is' :: [Count Elements (TExp Int64)]+ is' = map (elements . le64) is+ loops [] body = body+ loops ((i, n) : ins) body =+ [C.citems|for (typename int64_t $id:i = 0; $id:i < $exp:n; $id:i++)+ { $items:(loops ins body) }|]++-- | Compile an 'LMADCopy' using sequential nested loops and+-- 'Read'/'Write' of individual scalars. This always works, but can+-- be pretty slow if those reads and writes are costly.+compileLMADCopy ::+ PrimType ->+ [Count Elements (TExp Int64)] ->+ (VName, Space) ->+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) ->+ (VName, Space) ->+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) ->+ CompilerM op s ()+compileLMADCopy t shape (dst, dstspace) dst_lmad (src, srcspace) src_lmad = do+ src' <- rawMem src+ dst' <- rawMem dst+ let doWrite dst_i = generateWrite dst' dst_i t dstspace Nonvolatile+ doRead src_i = generateRead src' src_i t srcspace Nonvolatile+ compileLMADCopyWith shape doWrite dst_lmad doRead src_lmad
src/Futhark/CodeGen/Backends/GenericC/Fun.hs view
@@ -63,10 +63,12 @@ body' <- collect $ compileFunBody out_ptrs outputs body decl_mem <- declAllocatedMem free_mem <- freeAllocatedMem+ let futhark_function =+ C.DeclSpec [] [C.EscTypeQual "FUTHARK_FUN_ATTR" mempty] (C.Tint Nothing mempty) mempty pure- ( [C.cedecl|static int $id:(funName fname)($params:extra, $params:outparams, $params:inparams);|],- [C.cfun|static int $id:(funName fname)($params:extra, $params:outparams, $params:inparams) {+ ( [C.cedecl|$spec:futhark_function $id:(funName fname)($params:extra, $params:outparams, $params:inparams);|],+ [C.cfun|$spec:futhark_function $id:(funName fname)($params:extra, $params:outparams, $params:inparams) { $stms:ignores int err = 0; $items:decl_cached@@ -96,10 +98,12 @@ cachingMemory (lexicalMemoryUsage func) $ \decl_cached free_cached -> do body' <- collect $ compileFunBody out_ptrs outputs body+ let futhark_function =+ C.DeclSpec [] [C.EscTypeQual "FUTHARK_FUN_ATTR" mempty] (C.Tvoid mempty) mempty pure- ( [C.cedecl|static void $id:(funName fname)($params:outparams, $params:inparams);|],- [C.cfun|static void $id:(funName fname)($params:outparams, $params:inparams) {+ ( [C.cedecl|$spec:futhark_function $id:(funName fname)($params:outparams, $params:inparams);|],+ [C.cfun|$spec:futhark_function $id:(funName fname)($params:outparams, $params:inparams) { $items:decl_cached $items:get_constants $items:body'
src/Futhark/CodeGen/Backends/GenericC/Monad.hs view
@@ -18,6 +18,7 @@ Deallocate, CopyBarrier (..), Copy,+ DoLMADCopy, -- * Monadic compiler interface CompilerM,@@ -203,6 +204,22 @@ C.Exp -> CompilerM op s () +-- | Perform an 'LMADCopy'. It is expected that these functions are+-- each specialised on which spaces they operate on, so that is not part of their arguments.+type DoLMADCopy op s =+ CopyBarrier ->+ PrimType ->+ [Count Elements C.Exp] ->+ C.Exp ->+ ( Count Elements C.Exp,+ [Count Elements C.Exp]+ ) ->+ C.Exp ->+ ( Count Elements C.Exp,+ [Count Elements C.Exp]+ ) ->+ CompilerM op s ()+ -- | Call a function. type CallCompiler op s = [VName] -> Name -> [C.Exp] -> CompilerM op s () @@ -216,6 +233,8 @@ opsCompiler :: OpCompiler op s, opsError :: ErrorCompiler op s, opsCall :: CallCompiler op s,+ -- | @(dst,src)@-space mapping to copy functions.+ opsCopies :: M.Map (Space, Space) (DoLMADCopy op s), -- | If true, use reference counting. Otherwise, bare -- pointers. opsFatMemory :: Bool,@@ -351,7 +370,7 @@ fatMemory ScalarSpace {} = pure False fatMemory _ = asks $ opsFatMemory . envOperations -cacheMem :: C.ToExp a => a -> CompilerM op s (Maybe VName)+cacheMem :: (C.ToExp a) => a -> CompilerM op s (Maybe VName) cacheMem a = asks $ M.lookup (C.toExp a noLoc) . envCachedMem -- | Construct a publicly visible definition using the specified name@@ -468,7 +487,7 @@ where fat = asks ((&&) . opsFatMemory . envOperations) <*> (isNothing <$> cacheMem v) -rawMem' :: C.ToExp a => Bool -> a -> C.Exp+rawMem' :: (C.ToExp a) => Bool -> a -> C.Exp rawMem' True e = [C.cexp|$exp:e.mem|] rawMem' False e = [C.cexp|$exp:e|] @@ -518,7 +537,7 @@ ty <- memToCType name space decl [C.cdecl|$ty:ty $id:name;|] -resetMem :: C.ToExp a => a -> Space -> CompilerM op s ()+resetMem :: (C.ToExp a) => a -> Space -> CompilerM op s () resetMem mem space = do refcount <- fatMemory space cached <- isJust <$> cacheMem mem@@ -552,7 +571,7 @@ }|] _ -> stm [C.cstm|$exp:dest = $exp:src;|] -unRefMem :: C.ToExp a => a -> Space -> CompilerM op s ()+unRefMem :: (C.ToExp a) => a -> Space -> CompilerM op s () unRefMem mem space = do refcount <- fatMemory space cached <- isJust <$> cacheMem mem
src/Futhark/CodeGen/Backends/GenericC/Types.hs view
@@ -83,7 +83,7 @@ [C.cexp|arr->mem.mem|] [C.cexp|0|] space- [C.cexp|data|]+ [C.cexp|(const unsigned char*)data|] [C.cexp|0|] DefaultSpace [C.cexp|((size_t)$exp:arr_size) * $int:(primByteSize pt::Int)|]@@ -106,7 +106,7 @@ collect $ copy CopyNoBarrier- [C.cexp|data|]+ [C.cexp|(unsigned char*)data|] [C.cexp|0|] DefaultSpace [C.cexp|arr->mem.mem|]@@ -126,7 +126,7 @@ proto [C.cedecl|$ty:array_type* $id:new_array($ty:ctx_ty *ctx, const $ty:pt' *data, $params:shape_params);|] proto- [C.cedecl|$ty:array_type* $id:new_raw_array($ty:ctx_ty *ctx, const $ty:memty data, typename int64_t offset, $params:shape_params);|]+ [C.cedecl|$ty:array_type* $id:new_raw_array($ty:ctx_ty *ctx, $ty:memty data, typename int64_t offset, $params:shape_params);|] proto [C.cedecl|int $id:free_array($ty:ctx_ty *ctx, $ty:array_type *arr);|] proto@@ -140,17 +140,22 @@ libDecl [C.cunit| $ty:array_type* $id:new_array($ty:ctx_ty *ctx, const $ty:pt' *data, $params:shape_params) {+ int err = 0; $ty:array_type* bad = NULL; $ty:array_type *arr = ($ty:array_type*) malloc(sizeof($ty:array_type)); if (arr == NULL) { return bad; } $items:(criticalSection ops new_body)+ if (err != 0) {+ free(arr);+ return bad;+ } return arr; } - $ty:array_type* $id:new_raw_array($ty:ctx_ty *ctx, const $ty:memty data, typename int64_t offset,- $params:shape_params) {+ $ty:array_type* $id:new_raw_array($ty:ctx_ty *ctx, $ty:memty data, typename int64_t offset, $params:shape_params) {+ int err = 0; $ty:array_type* bad = NULL; $ty:array_type *arr = ($ty:array_type*) malloc(sizeof($ty:array_type)); if (arr == NULL) {@@ -167,8 +172,9 @@ } int $id:values_array($ty:ctx_ty *ctx, $ty:array_type *arr, $ty:pt' *data) {+ int err = 0; $items:(criticalSection ops values_body)- return 0;+ return err; } $ty:memty $id:values_raw_array($ty:ctx_ty *ctx, $ty:array_type *arr) {
src/Futhark/CodeGen/Backends/GenericPython.hs view
@@ -20,6 +20,7 @@ fromStorage, toStorage, Operations (..),+ DoLMADCopy, defaultOperations, unpackDim, CompilerM (..),@@ -42,13 +43,14 @@ where import Control.Monad-import Control.Monad.RWS+import Control.Monad.RWS hiding (reader, writer) import Data.Char (isAlpha, isAlphaNum) import Data.Map qualified as M import Data.Maybe import Data.Text qualified as T import Futhark.CodeGen.Backends.GenericPython.AST import Futhark.CodeGen.Backends.GenericPython.Options+import Futhark.CodeGen.ImpCode (Count (..), Elements, TExp, elements, le64, untyped) import Futhark.CodeGen.ImpCode qualified as Imp import Futhark.CodeGen.RTS.Python import Futhark.Compiler.Config (CompilerMode (..))@@ -102,6 +104,22 @@ PrimType -> CompilerM op s () +-- | Perform an 'Imp.LMADCopy'. It is expected that these functions+-- are each specialised on which spaces they operate on, so that is+-- not part of their arguments.+type DoLMADCopy op s =+ PrimType ->+ [Count Elements PyExp] ->+ PyExp ->+ ( Count Elements PyExp,+ [Count Elements PyExp]+ ) ->+ PyExp ->+ ( Count Elements PyExp,+ [Count Elements PyExp]+ ) ->+ CompilerM op s ()+ -- | Construct the Python array being returned from an entry point. type EntryOutput op s = VName ->@@ -126,6 +144,8 @@ opsReadScalar :: ReadScalar op s, opsAllocate :: Allocate op s, opsCopy :: Copy op s,+ -- | @(dst,src)@-space mapping to copy functions.+ opsCopies :: M.Map (Space, Space) (DoLMADCopy op s), opsCompiler :: OpCompiler op s, opsEntryOutput :: EntryOutput op s, opsEntryInput :: EntryInput op s@@ -141,6 +161,7 @@ opsReadScalar = defReadScalar, opsAllocate = defAllocate, opsCopy = defCopy,+ opsCopies = M.singleton (DefaultSpace, DefaultSpace) lmadcopyCPU, opsCompiler = defCompiler, opsEntryOutput = defEntryOutput, opsEntryInput = defEntryInput@@ -178,9 +199,6 @@ envAllocate :: CompilerEnv op s -> Allocate op s envAllocate = opsAllocate . envOperations -envCopy :: CompilerEnv op s -> Copy op s-envCopy = opsCopy . envOperations- envEntryOutput :: CompilerEnv op s -> EntryOutput op s envEntryOutput = opsEntryOutput . envOperations @@ -366,7 +384,7 @@ Def "__init__" params $ body <> at_init compileProg ::- MonadFreshNames m =>+ (MonadFreshNames m) => CompilerMode -> String -> Constructor ->@@ -1000,7 +1018,7 @@ FSignum {} -> "np.sign" compileBinOpLike ::- Monad m =>+ (Monad m) => (v -> m PyExp) -> Imp.PrimExp v -> Imp.PrimExp v ->@@ -1123,7 +1141,7 @@ 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+compilePrimExp :: (Monad m) => (v -> m PyExp) -> Imp.PrimExp v -> m PyExp compilePrimExp _ (Imp.ValueExp v) = pure $ compilePrimValue v compilePrimExp f (Imp.LeafExp v _) = f v compilePrimExp f (Imp.BinOpExp op x y) = do@@ -1174,6 +1192,96 @@ (formatstrs, formatargs) <- mapAndUnzipM onPart parts pure (mconcat formatstrs, formatargs) +generateRead ::+ PyExp ->+ PyExp ->+ PrimType ->+ Space ->+ CompilerM op s PyExp+generateRead _ _ Unit _ =+ pure (compilePrimValue UnitValue)+generateRead _ _ _ ScalarSpace {} =+ error "GenericPython.generateRead: ScalarSpace"+generateRead src iexp pt DefaultSpace = do+ let pt' = compilePrimType pt+ pure $ fromStorage pt $ simpleCall "indexArray" [src, iexp, Var pt']+generateRead src iexp pt (Space space) = do+ reader <- asks envReadScalar+ reader src iexp pt space++generateWrite ::+ PyExp ->+ PyExp ->+ PrimType ->+ Space ->+ PyExp ->+ CompilerM op s ()+generateWrite _ _ Unit _ _ = pure ()+generateWrite _ _ _ ScalarSpace {} _ = do+ error "GenericPython.generateWrite: ScalarSpace"+generateWrite dst iexp pt (Imp.Space space) elemexp = do+ writer <- asks envWriteScalar+ writer dst iexp pt space elemexp+generateWrite dst iexp pt DefaultSpace elemexp =+ stm $ Exp $ simpleCall "writeScalarArray" [dst, iexp, toStorage pt elemexp]++-- | Compile an 'LMADCopy' using sequential nested loops, but+-- parameterised over how to do the reads and writes.+compileLMADCopyWith ::+ [Count Elements (TExp Int64)] ->+ (PyExp -> PyExp -> CompilerM op s ()) ->+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) ->+ (PyExp -> CompilerM op s PyExp) ->+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) ->+ CompilerM op s ()+compileLMADCopyWith shape doWrite dst_lmad doRead src_lmad = do+ let (dstoffset, dststrides) = dst_lmad+ (srcoffset, srcstrides) = src_lmad+ shape' <- mapM (compileExp . untyped . unCount) shape+ body <- collect $ do+ dst_i <-+ compileExp . untyped . unCount $+ dstoffset + sum (zipWith (*) is' dststrides)+ src_i <-+ compileExp . untyped . unCount $+ srcoffset + sum (zipWith (*) is' srcstrides)+ doWrite dst_i =<< doRead src_i+ mapM_ stm $ loops (zip is shape') body+ where+ r = length shape+ is = map (VName "i") [0 .. r - 1]+ is' :: [Count Elements (TExp Int64)]+ is' = map (elements . le64) is+ loops [] body = body+ loops ((i, n) : ins) body =+ [For (compileName i) (simpleCall "range" [n]) $ loops ins body]++-- | Compile an 'LMADCopy' using sequential nested loops and+-- 'Imp.Read'/'Imp.Write' of individual scalars. This always works,+-- but can be pretty slow if those reads and writes are costly.+compileLMADCopy ::+ PrimType ->+ [Count Elements (TExp Int64)] ->+ (VName, Space) ->+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) ->+ (VName, Space) ->+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) ->+ CompilerM op s ()+compileLMADCopy t shape (dst, dstspace) dst_lmad (src, srcspace) src_lmad = do+ src' <- compileVar src+ dst' <- compileVar dst+ let doWrite dst_i = generateWrite dst' dst_i t dstspace+ doRead src_i = generateRead src' src_i t srcspace+ compileLMADCopyWith shape doWrite dst_lmad doRead src_lmad+ compileCode :: Imp.Code op -> CompilerM op s () compileCode Imp.DebugPrint {} = pure ()@@ -1278,57 +1386,41 @@ stm =<< Assign <$> compileVar name <*> pure allocate' compileCode (Imp.Free name _) = stm =<< Assign <$> compileVar name <*> pure None-compileCode (Imp.Copy _ dest (Imp.Count destoffset) DefaultSpace src (Imp.Count srcoffset) DefaultSpace (Imp.Count size)) = do- destoffset' <- compileExp $ Imp.untyped destoffset- srcoffset' <- compileExp $ Imp.untyped srcoffset- dest' <- compileVar dest- src' <- compileVar src- size' <- compileExp $ Imp.untyped size- let offset_call1 = simpleCall "addressOffset" [dest', destoffset', Var "ct.c_byte"]- let offset_call2 = simpleCall "addressOffset" [src', srcoffset', Var "ct.c_byte"]- stm $ Exp $ simpleCall "ct.memmove" [offset_call1, offset_call2, size']-compileCode (Imp.Copy pt dest (Imp.Count destoffset) destspace src (Imp.Count srcoffset) srcspace (Imp.Count size)) = do- copy <- asks envCopy- join $- copy- <$> compileVar dest- <*> compileExp (Imp.untyped destoffset)- <*> pure destspace- <*> compileVar src- <*> compileExp (Imp.untyped srcoffset)- <*> pure srcspace- <*> compileExp (Imp.untyped size)- <*> pure pt-compileCode (Imp.Write _ _ Unit _ _ _) = pure ()-compileCode (Imp.Write dest (Imp.Count idx) elemtype (Imp.Space space) _ elemexp) =- join $- asks envWriteScalar- <*> compileVar dest- <*> compileExp (Imp.untyped idx)- <*> pure elemtype- <*> pure space- <*> compileExp elemexp-compileCode (Imp.Write dest (Imp.Count idx) elemtype _ _ elemexp) = do+compileCode (Imp.LMADCopy t shape (dst, dstspace) (dstoffset, dststrides) (src, srcspace) (srcoffset, srcstrides)) = do+ cp <- asks $ M.lookup (dstspace, srcspace) . opsCopies . envOperations+ case cp of+ Nothing ->+ compileLMADCopy t shape (dst, dstspace) (dstoffset, dststrides) (src, srcspace) (srcoffset, srcstrides)+ Just cp' -> do+ shape' <- traverse (traverse (compileExp . untyped)) shape+ dst' <- compileVar dst+ src' <- compileVar src+ dstoffset' <- traverse (compileExp . untyped) dstoffset+ dststrides' <- traverse (traverse (compileExp . untyped)) dststrides+ srcoffset' <- traverse (compileExp . untyped) srcoffset+ srcstrides' <- traverse (traverse (compileExp . untyped)) srcstrides+ cp' t shape' dst' (dstoffset', dststrides') src' (srcoffset', srcstrides')+compileCode (Imp.Write dst (Imp.Count idx) pt space _ elemexp) = do+ dst' <- compileVar dst idx' <- compileExp $ Imp.untyped idx- elemexp' <- toStorage elemtype <$> compileExp elemexp- dest' <- compileVar dest- stm $ Exp $ simpleCall "writeScalarArray" [dest', idx', elemexp']-compileCode (Imp.Read x _ _ Unit _ _) =- stm =<< Assign <$> compileVar x <*> pure (compilePrimValue UnitValue)-compileCode (Imp.Read x src (Imp.Count iexp) restype (Imp.Space space) _) = do- x' <- compileVar x- e <-- join $- asks envReadScalar- <*> compileVar src- <*> compileExp (Imp.untyped iexp)- <*> pure restype- <*> pure space- stm $ Assign x' e-compileCode (Imp.Read x src (Imp.Count iexp) bt _ _) = do+ elemexp' <- compileExp elemexp+ generateWrite dst' idx' pt space elemexp'+compileCode (Imp.Read x src (Imp.Count iexp) pt space _) = do x' <- compileVar x- iexp' <- compileExp $ Imp.untyped iexp- let bt' = compilePrimType bt+ iexp' <- compileExp $ untyped iexp src' <- compileVar src- stm $ Assign x' $ fromStorage bt $ simpleCall "indexArray" [src', iexp', Var bt']+ stm . Assign x' =<< generateRead src' iexp' pt space compileCode Imp.Skip = pure ()++lmadcopyCPU :: DoLMADCopy op s+lmadcopyCPU t shape dst (dstoffset, dststride) src (srcoffset, srcstride) =+ stm . Exp . simpleCall "lmad_copy" $+ [ Var (compilePrimType t),+ dst,+ unCount dstoffset,+ List (map unCount dststride),+ src,+ unCount srcoffset,+ List (map unCount srcstride),+ List (map unCount shape)+ ]
src/Futhark/CodeGen/Backends/GenericPython/AST.hs view
@@ -132,21 +132,25 @@ instance Pretty PyStmt where pretty (If cond [] []) = "if"- <+> pretty cond <> ":"+ <+> pretty cond+ <> ":" </> indent 2 "pass" pretty (If cond [] fbranch) = "if"- <+> pretty cond <> ":"+ <+> pretty cond+ <> ":" </> indent 2 "pass" </> "else:" </> indent 2 (stack $ map pretty fbranch) pretty (If cond tbranch []) = "if"- <+> pretty cond <> ":"+ <+> pretty cond+ <> ":" </> indent 2 (stack $ map pretty tbranch) pretty (If cond tbranch fbranch) = "if"- <+> pretty cond <> ":"+ <+> pretty cond+ <> ":" </> indent 2 (stack $ map pretty tbranch) </> "else:" </> indent 2 (stack $ map pretty fbranch)@@ -156,17 +160,20 @@ </> stack (map pretty pyexcepts) pretty (While cond body) = "while"- <+> pretty cond <> ":"+ <+> pretty cond+ <> ":" </> indent 2 (stack $ map pretty body) pretty (For i what body) = "for" <+> pretty i <+> "in"- <+> pretty what <> ":"+ <+> pretty what+ <> ":" </> indent 2 (stack $ map pretty body) pretty (With what body) = "with"- <+> pretty what <> ":"+ <+> pretty what+ <> ":" </> indent 2 (stack $ map pretty body) pretty (Assign e1 e2) = pretty e1 <+> "=" <+> pretty e2 pretty (AssignOp op e1 e2) = pretty e1 <+> pretty (op ++ "=") <+> pretty e2@@ -187,13 +194,16 @@ instance Pretty PyFunDef where pretty (Def fname params body) = "def"- <+> pretty fname <> parens (commasep $ map pretty params) <> ":"+ <+> pretty fname+ <> parens (commasep $ map pretty params)+ <> ":" </> indent 2 (stack (map pretty body)) instance Pretty PyClassDef where pretty (Class cname body) = "class"- <+> pretty cname <> ":"+ <+> pretty cname+ <> ":" </> indent 2 (stack (map pretty body)) instance Pretty PyExcept where
+ src/Futhark/CodeGen/Backends/HIP.hs view
@@ -0,0 +1,130 @@+{-# LANGUAGE QuasiQuotes #-}++-- | Code generation for HIP.+module Futhark.CodeGen.Backends.HIP+ ( compileProg,+ GC.CParts (..),+ GC.asLibrary,+ GC.asExecutable,+ GC.asServer,+ )+where++import Data.Map qualified as M+import Data.Text qualified as T+import Futhark.CodeGen.Backends.GPU+import Futhark.CodeGen.Backends.GenericC qualified as GC+import Futhark.CodeGen.Backends.GenericC.Options+import Futhark.CodeGen.ImpCode.OpenCL+import Futhark.CodeGen.ImpGen.HIP qualified as ImpGen+import Futhark.CodeGen.RTS.C (backendsHipH)+import Futhark.IR.GPUMem hiding+ ( CmpSizeLe,+ GetSize,+ GetSizeMax,+ )+import Futhark.MonadFreshNames+import Language.C.Quote.OpenCL qualified as C+import NeatInterpolation (untrimming)++mkBoilerplate ::+ T.Text ->+ M.Map Name KernelSafety ->+ [PrimType] ->+ [FailureMsg] ->+ GC.CompilerM OpenCL () ()+mkBoilerplate hip_program kernels types failures = do+ generateGPUBoilerplate+ hip_program+ backendsHipH+ (M.keys kernels)+ types+ failures++ 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|const char* futhark_context_config_get_program(struct futhark_context_config *cfg);|]+ GC.headerDecl GC.InitDecl [C.cedecl|void futhark_context_config_set_program(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);|]++cliOptions :: [Option]+cliOptions =+ gpuOptions+ ++ [ Option+ { optionLongName = "dump-hip",+ optionShortName = Nothing,+ optionArgument = RequiredArgument "FILE",+ optionDescription = "Dump the embedded HIP kernels to the indicated file.",+ optionAction =+ [C.cstm|{const char* prog = futhark_context_config_get_program(cfg);+ if (dump_file(optarg, prog, strlen(prog)) != 0) {+ fprintf(stderr, "%s: %s\n", optarg, strerror(errno));+ exit(1);+ }+ exit(0);}|]+ },+ Option+ { optionLongName = "load-hip",+ optionShortName = Nothing,+ optionArgument = RequiredArgument "FILE",+ optionDescription = "Instead of using the embedded HIP kernels, load them from the indicated file.",+ optionAction =+ [C.cstm|{ size_t n; const char *s = slurp_file(optarg, &n);+ if (s == NULL) { fprintf(stderr, "%s: %s\n", optarg, strerror(errno)); exit(1); }+ futhark_context_config_set_program(cfg, s);+ }|]+ },+ Option+ { optionLongName = "build-option",+ optionShortName = Nothing,+ optionArgument = RequiredArgument "OPT",+ optionDescription = "Add an additional build option to the string passed to NVRTC.",+ optionAction = [C.cstm|futhark_context_config_add_build_option(cfg, optarg);|]+ },+ Option+ { optionLongName = "profile",+ optionShortName = Just 'P',+ optionArgument = NoArgument,+ optionDescription = "Gather profiling data while executing and print out a summary at the end.",+ optionAction = [C.cstm|futhark_context_config_set_profiling(cfg, 1);|]+ }+ ]++hipMemoryType :: GC.MemoryType OpenCL ()+hipMemoryType "device" = pure [C.cty|typename hipDeviceptr_t|]+hipMemoryType space = error $ "GPU backend does not support '" ++ space ++ "' memory space."++-- | Compile the program to C with calls to HIP.+compileProg :: (MonadFreshNames m) => T.Text -> Prog GPUMem -> m (ImpGen.Warnings, GC.CParts)+compileProg version prog = do+ ( ws,+ Program hip_code hip_prelude kernels types params failures prog'+ ) <-+ ImpGen.compileProg prog+ (ws,)+ <$> GC.compileProg+ "hip"+ version+ params+ operations+ (mkBoilerplate (hip_prelude <> hip_code) kernels types failures)+ hip_includes+ (Space "device", [Space "device", DefaultSpace])+ cliOptions+ prog'+ where+ operations :: GC.Operations OpenCL ()+ operations =+ gpuOperations+ { GC.opsMemoryType = hipMemoryType+ }+ hip_includes =+ [untrimming|+ #define __HIP_PLATFORM_AMD__+ #include <hip/hip_runtime.h>+ #include <hip/hiprtc.h>+ |]
src/Futhark/CodeGen/Backends/MulticoreC.hs view
@@ -45,7 +45,7 @@ -- | Compile the program to ImpCode with multicore operations. compileProg ::- MonadFreshNames m => T.Text -> Prog MCMem -> m (ImpGen.Warnings, GC.CParts)+ (MonadFreshNames m) => T.Text -> Prog MCMem -> m (ImpGen.Warnings, GC.CParts) compileProg version = traverse ( GC.compileProg@@ -122,7 +122,7 @@ [C.csdecl|$ty:defaultMemBlockType $id:(closureRetvalStructField name);|] compileSetStructValues ::- C.ToIdent a =>+ (C.ToIdent a) => a -> [VName] -> [(C.Type, ValueType)] ->@@ -137,7 +137,7 @@ [C.cstm|$id:struct.$id:(closureFreeStructField name)=$id:name;|] compileSetRetvalStructValues ::- C.ToIdent a =>+ (C.ToIdent a) => a -> [VName] -> [(C.Type, ValueType)] ->@@ -154,7 +154,7 @@ field name (_, RawMem) = [C.cstms|$id:struct.$id:(closureRetvalStructField name)=$id:name;|] -compileGetRetvalStructVals :: C.ToIdent a => a -> [VName] -> [(C.Type, ValueType)] -> [C.InitGroup]+compileGetRetvalStructVals :: (C.ToIdent a) => a -> [VName] -> [(C.Type, ValueType)] -> [C.InitGroup] compileGetRetvalStructVals struct = zipWith field where field name (ty, Prim pt) =@@ -167,7 +167,7 @@ .size = 0, .references = NULL};|] compileGetStructVals ::- C.ToIdent a =>+ (C.ToIdent a) => a -> [VName] -> [(C.Type, ValueType)] ->@@ -183,7 +183,7 @@ .mem = $id:struct->$id:(closureFreeStructField name), .size = 0, .references = NULL};|] -compileWriteBackResVals :: C.ToIdent a => a -> [VName] -> [(C.Type, ValueType)] -> [C.Stm]+compileWriteBackResVals :: (C.ToIdent a) => a -> [VName] -> [(C.Type, ValueType)] -> [C.Stm] compileWriteBackResVals struct = zipWith field where field name (_, Prim pt) =@@ -341,7 +341,7 @@ pure s' generateParLoopFn ::- C.ToIdent a =>+ (C.ToIdent a) => M.Map VName Space -> String -> MCCode ->
src/Futhark/CodeGen/Backends/MulticoreISPC.hs view
@@ -61,7 +61,7 @@ -- | Compile the program to C and ISPC code using multicore operations. compileProg ::- MonadFreshNames m => T.Text -> Prog MCMem -> m (ImpGen.Warnings, (GC.CParts, T.Text))+ (MonadFreshNames m) => T.Text -> Prog MCMem -> m (ImpGen.Warnings, (GC.CParts, T.Text)) compileProg version prog = do -- Dynamic scheduling seems completely broken currently, so we disable it. (ws, defs) <- ImpGen.compileProg prog@@ -101,6 +101,7 @@ typedef unsigned int16 uint16_t; typedef unsigned int8 uint8_t; #define volatile+#define SCALAR_FUN_ATTR static inline $errorsH @@ -122,7 +123,9 @@ operations :: GC.Operations Multicore ISPCState operations = MC.operations- { GC.opsCompiler = compileOp+ { GC.opsCompiler = compileOp,+ -- FIXME: the default codegen for LMAD copies does not work for ISPC.+ GC.opsCopies = mempty } ispcDecl :: C.Definition -> ISPCCompilerM ()@@ -147,26 +150,6 @@ GC.earlyDecl =<< f s' pure s' --- | Copy memory where one of the operands is using an AoS layout.-copyMemoryAOS ::- PrimType ->- C.Exp ->- C.Exp ->- C.Exp ->- C.Exp ->- C.Exp ->- GC.CompilerM op s ()-copyMemoryAOS pt destmem destidx srcmem srcidx nbytes =- GC.stm- [C.cstm|if ($exp:nbytes > 0) {- $id:overload($exp:destmem + $exp:destidx,- $exp:srcmem + $exp:srcidx,- extract($exp:nbytes, 0));- }|]- where- size = show (8 * primByteSize pt :: Integer)- overload = "memmove_" <> size- -- | ISPC has no string literals, so this makes one in C and exposes it via an -- external function, returning the name. makeStringLiteral :: String -> ISPCCompilerM Name@@ -189,7 +172,7 @@ }|] -- | Unref memory in ISPC-unRefMem :: C.ToExp a => a -> Space -> ISPCCompilerM ()+unRefMem :: (C.ToExp a) => a -> Space -> ISPCCompilerM () unRefMem mem space = do cached <- isJust <$> GC.cacheMem mem let mem_s = T.unpack $ expText $ C.toExp mem noLoc@@ -552,16 +535,20 @@ dest' <- GC.rawMem dest idxexp <- compileExp $ constFoldPrimExp $ untyped idx deref <-- GC.derefPointer dest' [C.cexp|($tyquals:([varying]) typename int64_t)$exp:idxexp|]+ GC.derefPointer+ dest'+ [C.cexp|($tyquals:([varying]) typename int64_t)$exp:idxexp|] <$> getMemType dest elemtype elemexp' <- toStorage elemtype <$> compileExp elemexp GC.stm [C.cstm|$exp:deref = $exp:elemexp';|] | otherwise = do dest' <- GC.rawMem dest+ idxexp <- compileExp $ untyped idx deref <-- GC.derefPointer dest'- <$> compileExp (untyped idx)- <*> getMemType dest elemtype+ GC.derefPointer+ dest'+ [C.cexp|($tyquals:([varying]) typename int64_t)$exp:idxexp|]+ <$> getMemType dest elemtype elemexp' <- toStorage elemtype <$> compileExp elemexp GC.stm [C.cstm|$exp:deref = $exp:elemexp';|] where@@ -576,19 +563,19 @@ <$> compileExp (untyped iexp) <*> getMemType src restype GC.stm [C.cstm|$id:x = $exp:e;|]-compileCode code@(Copy pt dest (Count destoffset) DefaultSpace src (Count srcoffset) DefaultSpace (Count size)) = do- dm <- isJust <$> GC.cacheMem dest- sm <- isJust <$> GC.cacheMem src- if dm || sm- then- join $- copyMemoryAOS pt- <$> GC.rawMem dest- <*> compileExp (untyped destoffset)- <*> GC.rawMem src- <*> compileExp (untyped srcoffset)- <*> compileExp (untyped size)- else GC.compileCode code+compileCode (LMADCopy t shape (dst, DefaultSpace) dst_lmad (src, DefaultSpace) src_lmad) = do+ dst' <- GC.rawMem dst+ src' <- GC.rawMem src+ let doWrite dst_i ve = do+ deref <-+ GC.derefPointer+ dst'+ [C.cexp|($tyquals:([varying]) typename int64_t)$exp:dst_i|]+ <$> getMemType dst t+ GC.stm [C.cstm|$exp:deref = $exp:(toStorage t ve);|]+ doRead src_i =+ fromStorage t . GC.derefPointer src' src_i <$> getMemType src t+ GC.compileLMADCopyWith shape doWrite dst_lmad doRead src_lmad compileCode (Free name space) = do cached <- isJust <$> GC.cacheMem name unless cached $ unRefMem name space
src/Futhark/CodeGen/Backends/MulticoreWASM.hs view
@@ -37,7 +37,7 @@ -- -- * Options that should be passed to @emcc@. compileProg ::- MonadFreshNames m =>+ (MonadFreshNames m) => T.Text -> Prog MCMem -> m (ImpGen.Warnings, (GC.CParts, T.Text, [String]))
src/Futhark/CodeGen/Backends/PyOpenCL.hs view
@@ -7,10 +7,12 @@ import Control.Monad import Data.Map qualified as M import Data.Text qualified as T-import Futhark.CodeGen.Backends.GenericPython qualified as Py+import Futhark.CodeGen.Backends.GenericPython hiding (compileProg)+import Futhark.CodeGen.Backends.GenericPython qualified as GP import Futhark.CodeGen.Backends.GenericPython.AST import Futhark.CodeGen.Backends.GenericPython.Options import Futhark.CodeGen.Backends.PyOpenCL.Boilerplate+import Futhark.CodeGen.ImpCode (Count (..)) import Futhark.CodeGen.ImpCode.OpenCL qualified as Imp import Futhark.CodeGen.ImpGen.OpenCL qualified as ImpGen import Futhark.CodeGen.RTS.Python (openclPy)@@ -21,8 +23,8 @@ -- | Compile the program to Python with calls to OpenCL. compileProg ::- MonadFreshNames m =>- Py.CompilerMode ->+ (MonadFreshNames m) =>+ CompilerMode -> String -> Prog GPUMem -> m (ImpGen.Warnings, T.Text)@@ -73,7 +75,7 @@ ] let constructor =- Py.Constructor+ Constructor [ "self", "build_options=build_options", "command_queue=None",@@ -169,7 +171,7 @@ ] (ws,)- <$> Py.compileProg+ <$> GP.compileProg mode class_name constructor@@ -177,26 +179,29 @@ defines operations ()- [Exp $ Py.simpleCall "sync" [Var "self"]]+ [Exp $ simpleCall "sync" [Var "self"]] options prog' where- operations :: Py.Operations Imp.OpenCL ()+ operations :: Operations Imp.OpenCL () operations =- Py.Operations- { Py.opsCompiler = callKernel,- Py.opsWriteScalar = writeOpenCLScalar,- Py.opsReadScalar = readOpenCLScalar,- Py.opsAllocate = allocateOpenCLBuffer,- Py.opsCopy = copyOpenCLMemory,- Py.opsEntryOutput = packArrayOutput,- Py.opsEntryInput = unpackArrayInput+ Operations+ { opsCompiler = callKernel,+ opsWriteScalar = writeOpenCLScalar,+ opsReadScalar = readOpenCLScalar,+ opsAllocate = allocateOpenCLBuffer,+ opsCopy = copyOpenCLMemory,+ opsCopies =+ M.insert (Imp.Space "device", Imp.Space "device") copygpu2gpu $+ opsCopies defaultOperations,+ opsEntryOutput = packArrayOutput,+ opsEntryInput = unpackArrayInput } -- We have many casts to 'long', because PyOpenCL may get confused at -- the 32-bit numbers that ImpCode uses for offsets and the like. asLong :: PyExp -> PyExp-asLong x = Py.simpleCall "np.int64" [x]+asLong x = simpleCall "np.int64" [x] kernelConstToExp :: Imp.KernelConst -> PyExp kernelConstToExp (Imp.SizeConst key) =@@ -204,37 +209,37 @@ kernelConstToExp (Imp.SizeMaxConst size_class) = Var $ "self.max_" <> prettyString size_class -compileGroupDim :: Imp.GroupDim -> Py.CompilerM op s PyExp-compileGroupDim (Left e) = asLong <$> Py.compileExp e+compileGroupDim :: Imp.GroupDim -> CompilerM op s PyExp+compileGroupDim (Left e) = asLong <$> compileExp e compileGroupDim (Right kc) = pure $ kernelConstToExp kc -callKernel :: Py.OpCompiler Imp.OpenCL ()+callKernel :: OpCompiler Imp.OpenCL () callKernel (Imp.GetSize v key) = do- v' <- Py.compileVar v- Py.stm $ Assign v' $ kernelConstToExp $ Imp.SizeConst key+ v' <- compileVar v+ stm $ Assign v' $ kernelConstToExp $ Imp.SizeConst key callKernel (Imp.CmpSizeLe v key x) = do- v' <- Py.compileVar v- x' <- Py.compileExp x- Py.stm $+ v' <- compileVar v+ x' <- compileExp x+ stm $ Assign v' $ BinOp "<=" (kernelConstToExp (Imp.SizeConst key)) x' callKernel (Imp.GetSizeMax v size_class) = do- v' <- Py.compileVar v- Py.stm $ Assign v' $ kernelConstToExp $ Imp.SizeMaxConst size_class-callKernel (Imp.LaunchKernel safety name args num_workgroups workgroup_size) = do- num_workgroups' <- mapM (fmap asLong . Py.compileExp) num_workgroups+ v' <- compileVar v+ stm $ Assign v' $ kernelConstToExp $ Imp.SizeMaxConst size_class+callKernel (Imp.LaunchKernel safety name local_memory args num_workgroups workgroup_size) = do+ num_workgroups' <- mapM (fmap asLong . compileExp) num_workgroups workgroup_size' <- mapM compileGroupDim workgroup_size let kernel_size = zipWith mult_exp num_workgroups' workgroup_size' total_elements = foldl mult_exp (Integer 1) kernel_size cond = BinOp "!=" total_elements (Integer 0)-- body <- Py.collect $ launchKernel name safety kernel_size workgroup_size' args- Py.stm $ If cond body []+ local_memory' <- compileExp $ Imp.untyped $ Imp.unCount local_memory+ body <- collect $ launchKernel name safety kernel_size workgroup_size' local_memory' args+ stm $ If cond body [] when (safety >= Imp.SafetyFull) $- Py.stm $+ stm $ Assign (Var "self.failure_is_an_option") $- Py.compilePrimValue (Imp.IntValue (Imp.Int32Value 1))+ compilePrimValue (Imp.IntValue (Imp.Int32Value 1)) where mult_exp = BinOp "*" @@ -243,9 +248,10 @@ Imp.KernelSafety -> [PyExp] -> [PyExp] ->+ PyExp -> [Imp.KernelArg] ->- Py.CompilerM op s ()-launchKernel kernel_name safety kernel_dims workgroup_dims args = do+ CompilerM op s ()+launchKernel kernel_name safety kernel_dims workgroup_dims local_memory args = do let kernel_dims' = Tuple kernel_dims workgroup_dims' = Tuple workgroup_dims kernel_name' = "self." <> zEncodeText (nameToText kernel_name) <> "_var"@@ -257,45 +263,41 @@ Var "self.failure_is_an_option", Var "self.global_failure_args" ]- Py.stm $- Exp $- Py.simpleCall (T.unpack $ kernel_name' <> ".set_args") $- failure_args ++ args'- Py.stm $- Exp $- Py.simpleCall- "cl.enqueue_nd_range_kernel"- [Var "self.queue", Var (T.unpack kernel_name'), kernel_dims', workgroup_dims']+ stm . Exp $+ simpleCall (T.unpack $ kernel_name' <> ".set_args") $+ [simpleCall "cl.LocalMemory" [simpleCall "max" [local_memory, Integer 1]]]+ ++ failure_args+ ++ args'+ stm . Exp $+ simpleCall+ "cl.enqueue_nd_range_kernel"+ [Var "self.queue", Var (T.unpack kernel_name'), kernel_dims', workgroup_dims'] finishIfSynchronous where- processKernelArg :: Imp.KernelArg -> Py.CompilerM op s PyExp- processKernelArg (Imp.ValueKArg e bt) =- Py.toStorage bt <$> Py.compileExp e- processKernelArg (Imp.MemKArg v) = Py.compileVar v- processKernelArg (Imp.SharedMemoryKArg (Imp.Count num_bytes)) = do- num_bytes' <- Py.compileExp num_bytes- pure $ Py.simpleCall "cl.LocalMemory" [asLong num_bytes']+ processKernelArg :: Imp.KernelArg -> CompilerM op s PyExp+ processKernelArg (Imp.ValueKArg e bt) = toStorage bt <$> compileExp e+ processKernelArg (Imp.MemKArg v) = compileVar v -writeOpenCLScalar :: Py.WriteScalar Imp.OpenCL ()+writeOpenCLScalar :: WriteScalar Imp.OpenCL () writeOpenCLScalar mem i bt "device" val = do let nparr = Call (Var "np.array")- [Arg val, ArgKeyword "dtype" $ Var $ Py.compilePrimType bt]- Py.stm $+ [Arg val, ArgKeyword "dtype" $ Var $ compilePrimType bt]+ stm $ Exp $ Call (Var "cl.enqueue_copy") [ Arg $ Var "self.queue", Arg mem, Arg nparr,- ArgKeyword "device_offset" $ BinOp "*" (asLong i) (Integer $ Imp.primByteSize bt),+ ArgKeyword "dst_offset" $ BinOp "*" (asLong i) (Integer $ Imp.primByteSize bt), ArgKeyword "is_blocking" $ Var "synchronous" ] writeOpenCLScalar _ _ _ space _ = error $ "Cannot write to '" ++ space ++ "' memory space." -readOpenCLScalar :: Py.ReadScalar Imp.OpenCL ()+readOpenCLScalar :: ReadScalar Imp.OpenCL () readOpenCLScalar mem i bt "device" = do val <- newVName "read_res" let val' = Var $ prettyString val@@ -303,38 +305,38 @@ Call (Var "np.empty") [ Arg $ Integer 1,- ArgKeyword "dtype" (Var $ Py.compilePrimType bt)+ ArgKeyword "dtype" (Var $ compilePrimType bt) ]- Py.stm $ Assign val' nparr- Py.stm $+ stm $ Assign val' nparr+ stm $ Exp $ Call (Var "cl.enqueue_copy") [ Arg $ Var "self.queue", Arg val', Arg mem,- ArgKeyword "device_offset" $ BinOp "*" (asLong i) (Integer $ Imp.primByteSize bt),+ ArgKeyword "src_offset" $ BinOp "*" (asLong i) (Integer $ Imp.primByteSize bt), ArgKeyword "is_blocking" $ Var "synchronous" ]- Py.stm $ Exp $ Py.simpleCall "sync" [Var "self"]+ stm $ Exp $ simpleCall "sync" [Var "self"] pure $ Index val' $ IdxExp $ Integer 0 readOpenCLScalar _ _ _ space = error $ "Cannot read from '" ++ space ++ "' memory space." -allocateOpenCLBuffer :: Py.Allocate Imp.OpenCL ()+allocateOpenCLBuffer :: Allocate Imp.OpenCL () allocateOpenCLBuffer mem size "device" =- Py.stm $+ stm $ Assign mem $- Py.simpleCall "opencl_alloc" [Var "self", size, String $ prettyText mem]+ simpleCall "opencl_alloc" [Var "self", size, String $ prettyText mem] allocateOpenCLBuffer _ _ space = error $ "Cannot allocate in '" ++ space ++ "' space" -copyOpenCLMemory :: Py.Copy Imp.OpenCL ()+copyOpenCLMemory :: Copy Imp.OpenCL () copyOpenCLMemory destmem destidx Imp.DefaultSpace srcmem srcidx (Imp.Space "device") nbytes bt = do let divide = BinOp "//" nbytes (Integer $ Imp.primByteSize bt) end = BinOp "+" destidx divide dest = Index destmem (IdxRange destidx end)- Py.stm $+ stm $ ifNotZeroSize nbytes $ Exp $ Call@@ -347,8 +349,8 @@ ] 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 $+ src = Index (simpleCall "createArray" [srcmem, List [nbytes], Var "np.byte"]) (IdxRange srcidx end)+ stm $ ifNotZeroSize nbytes $ Exp $ Call@@ -360,7 +362,7 @@ ArgKeyword "is_blocking" $ Var "synchronous" ] copyOpenCLMemory destmem destidx (Imp.Space "device") srcmem srcidx (Imp.Space "device") nbytes _ = do- Py.stm $+ stm $ ifNotZeroSize nbytes $ Exp $ Call@@ -368,48 +370,48 @@ [ Arg $ Var "self.queue", Arg destmem, Arg srcmem,- ArgKeyword "dest_offset" $ asLong destidx,+ ArgKeyword "dst_offset" $ asLong destidx, ArgKeyword "src_offset" $ asLong srcidx, ArgKeyword "byte_count" $ asLong nbytes ] finishIfSynchronous copyOpenCLMemory destmem destidx Imp.DefaultSpace srcmem srcidx Imp.DefaultSpace nbytes _ =- Py.copyMemoryDefaultSpace destmem destidx srcmem srcidx nbytes+ copyMemoryDefaultSpace destmem destidx srcmem srcidx nbytes copyOpenCLMemory _ _ destspace _ _ srcspace _ _ = error $ "Cannot copy to " ++ show destspace ++ " from " ++ show srcspace -packArrayOutput :: Py.EntryOutput Imp.OpenCL ()+packArrayOutput :: EntryOutput Imp.OpenCL () packArrayOutput mem "device" bt ept dims = do- mem' <- Py.compileVar mem- dims' <- mapM Py.compileDim dims+ mem' <- compileVar mem+ dims' <- mapM compileDim dims pure $ Call (Var "cl.array.Array") [ Arg $ Var "self.queue", Arg $ Tuple $ dims' <> [Integer 0 | bt == Imp.Unit],- Arg $ Var $ Py.compilePrimToExtNp bt ept,+ Arg $ Var $ compilePrimToExtNp bt ept, ArgKeyword "data" mem' ] packArrayOutput _ sid _ _ _ = error $ "Cannot return array from " ++ sid ++ " space." -unpackArrayInput :: Py.EntryInput Imp.OpenCL ()+unpackArrayInput :: EntryInput Imp.OpenCL () unpackArrayInput mem "device" t s dims e = do let type_is_ok = BinOp "and"- (BinOp "in" (Py.simpleCall "type" [e]) (List [Var "np.ndarray", Var "cl.array.Array"]))- (BinOp "==" (Field e "dtype") (Var (Py.compilePrimToExtNp t s)))- Py.stm $ Assert type_is_ok $ String "Parameter has unexpected type"+ (BinOp "in" (simpleCall "type" [e]) (List [Var "np.ndarray", Var "cl.array.Array"]))+ (BinOp "==" (Field e "dtype") (Var (compilePrimToExtNp t s)))+ stm $ Assert type_is_ok $ String "Parameter has unexpected type" - zipWithM_ (Py.unpackDim e) dims [0 ..]+ zipWithM_ (unpackDim e) dims [0 ..] - let memsize' = Py.simpleCall "np.int64" [Field e "nbytes"]+ let memsize' = simpleCall "np.int64" [Field e "nbytes"] pyOpenCLArrayCase = [Assign mem $ Field e "data"]- numpyArrayCase <- Py.collect $ do+ numpyArrayCase <- collect $ do allocateOpenCLBuffer mem memsize' "device"- Py.stm $+ stm $ ifNotZeroSize memsize' $ Exp $ Call@@ -420,9 +422,9 @@ ArgKeyword "is_blocking" $ Var "synchronous" ] - Py.stm $+ stm $ If- (BinOp "==" (Py.simpleCall "type" [e]) (Var "cl.array.Array"))+ (BinOp "==" (simpleCall "type" [e]) (Var "cl.array.Array")) pyOpenCLArrayCase numpyArrayCase unpackArrayInput _ sid _ _ _ _ =@@ -432,6 +434,20 @@ ifNotZeroSize e s = If (BinOp "!=" e (Integer 0)) [s] [] -finishIfSynchronous :: Py.CompilerM op s ()+finishIfSynchronous :: CompilerM op s () finishIfSynchronous =- Py.stm $ If (Var "synchronous") [Exp $ Py.simpleCall "sync" [Var "self"]] []+ stm $ If (Var "synchronous") [Exp $ simpleCall "sync" [Var "self"]] []++copygpu2gpu :: DoLMADCopy op s+copygpu2gpu t shape dst (dstoffset, dststride) src (srcoffset, srcstride) = do+ stm . Exp . simpleCall "lmad_copy_gpu2gpu" $+ [ Var "self",+ Var (compilePrimType t),+ dst,+ unCount dstoffset,+ List (map unCount dststride),+ src,+ unCount srcoffset,+ List (map unCount srcstride),+ List (map unCount shape)+ ]
src/Futhark/CodeGen/Backends/SequentialC.hs view
@@ -20,7 +20,7 @@ import Futhark.MonadFreshNames -- | Compile the program to sequential C.-compileProg :: MonadFreshNames m => T.Text -> Prog SeqMem -> m (ImpGen.Warnings, GC.CParts)+compileProg :: (MonadFreshNames m) => T.Text -> Prog SeqMem -> m (ImpGen.Warnings, GC.CParts) compileProg version = traverse ( GC.compileProg
src/Futhark/CodeGen/Backends/SequentialPython.hs view
@@ -15,7 +15,7 @@ -- | Compile the program to Python. compileProg ::- MonadFreshNames m =>+ (MonadFreshNames m) => GenericPython.CompilerMode -> String -> Prog SeqMem ->
src/Futhark/CodeGen/Backends/SequentialWASM.hs view
@@ -35,7 +35,7 @@ -- file by itself). -- -- * Options that should be passed to @emcc@.-compileProg :: MonadFreshNames m => T.Text -> Prog SeqMem -> m (ImpGen.Warnings, (GC.CParts, T.Text, [String]))+compileProg :: (MonadFreshNames m) => T.Text -> Prog SeqMem -> m (ImpGen.Warnings, (GC.CParts, T.Text, [String])) compileProg version prog = do (ws, prog') <- ImpGen.compileProg prog
src/Futhark/CodeGen/ImpCode.hs view
@@ -28,9 +28,9 @@ -- ImpCode does not have arrays. 'DeclareArray' is for declaring -- constant array literals, not arrays in general. Instead, ImpCode -- deals only with memory. Array operations present in core IR--- programs are turned into 'Write', v'Read', and 'Copy' operations--- that use flat indexes and offsets based on the index function of--- the original array.+-- programs are turned into 'Write', v'Read', and 'LMADCopy'+-- operations that use flat indexes and offsets based on the index+-- function of the original array. -- -- == Scoping --@@ -73,6 +73,7 @@ ArrayContents (..), declaredIn, lexicalMemoryUsage,+ declsFirst, calledFuncs, callGraph, ParamMap,@@ -98,7 +99,7 @@ where import Data.Bifunctor (second)-import Data.List (intersperse)+import Data.List (intersperse, partition) import Data.Map qualified as M import Data.Ord (comparing) import Data.Set qualified as S@@ -279,18 +280,18 @@ -- all memory blocks will be freed with this statement. -- Backends are free to ignore it entirely. Free VName Space- | -- | Element type being copied, destination, offset in- -- destination, destination space, source, offset in source,- -- offset space, number of bytes.- Copy+ | -- | @LMADcopy pt dest dest_lmad src src_lmad shape@+ LMADCopy PrimType- VName- (Count Bytes (TExp Int64))- Space- VName- (Count Bytes (TExp Int64))- Space- (Count Bytes (TExp Int64))+ [Count Elements (TExp Int64)]+ (VName, Space)+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ )+ (VName, Space)+ ( Count Elements (TExp Int64),+ [Count Elements (TExp Int64)]+ ) | -- | @Write mem i t space vol v@ writes the value @v@ to -- @mem@ offset by @i@ elements of type @t@. The -- 'Space' argument is the memory space of @mem@@@ -384,6 +385,21 @@ onArg (MemArg x) = oneName x set x = go set x +-- | Reorder the code such that all declarations appear first. This+-- is always possible, because 'DeclareScalar' and 'DeclareMem' do+-- not depend on any local bindings.+declsFirst :: Code a -> Code a+declsFirst = mconcat . uncurry (<>) . partition isDecl . listify+ where+ listify (c1 :>>: c2) = listify c1 <> listify c2+ listify (If cond c1 c2) = [If cond (declsFirst c1) (declsFirst c2)]+ listify (For i e c) = [For i e (declsFirst c)]+ listify (While cond c) = [While cond (declsFirst c)]+ listify c = [c]+ isDecl (DeclareScalar {}) = True+ isDecl (DeclareMem {}) = True+ isDecl _ = False+ -- | The set of functions that are called by this code. Accepts a -- function for determing function calls in 'Op's. calledFuncs :: (a -> S.Set Name) -> Code a -> S.Set Name@@ -449,17 +465,17 @@ -- Prettyprinting definitions. -instance Pretty op => Pretty (Definitions op) where+instance (Pretty op) => Pretty (Definitions op) where pretty (Definitions types consts funs) = pretty types </> pretty consts </> pretty funs -instance Pretty op => Pretty (Functions op) where+instance (Pretty op) => Pretty (Functions op) where pretty (Functions funs) = stack $ intersperse mempty $ map ppFun funs where ppFun (name, fun) = "Function " <> pretty name <> colon </> indent 2 (pretty fun) -instance Pretty op => Pretty (Constants op) where+instance (Pretty op) => Pretty (Constants op) where pretty (Constants decls code) = "Constants:" </> indent 2 (stack $ map pretty decls)@@ -479,7 +495,7 @@ ppArg ((p, u), t) = pretty p <+> ":" <+> ppRes (u, t) ppRes (u, t) = pretty u <> pretty t -instance Pretty op => Pretty (FunctionT op) where+instance (Pretty op) => Pretty (FunctionT op) where pretty (Function entry outs ins body) = "Inputs:" </> indent 2 (stack $ map pretty ins)@@ -520,7 +536,7 @@ pretty (ArrayValues vs) = braces (commasep $ map pretty vs) pretty (ArrayZeros n) = braces "0" <+> "*" <+> pretty n -instance Pretty op => Pretty (Code op) where+instance (Pretty op) => Pretty (Code op) where pretty (Op op) = pretty op pretty Skip = "skip" pretty (c1 :>>: c2) = pretty c1 </> pretty c2@@ -581,17 +597,19 @@ pretty dest <+> "<-" <+> pretty from <+> "@" <> pretty space pretty (Assert e msg _) = "assert" <> parens (commasep [pretty msg, pretty e])- pretty (Copy t dest destoffset destspace src srcoffset srcspace size) =- "copy"+ pretty (LMADCopy t shape (dst, dstspace) (dstoffset, dststrides) (src, srcspace) (srcoffset, srcstrides)) =+ ("lmadcopy_" <> pretty (length shape) <> "d_" <> pretty t) <> (parens . align)- ( pretty t <> comma- </> ppMemLoc dest destoffset <> pretty destspace <> comma- </> ppMemLoc src srcoffset <> pretty srcspace <> comma- </> pretty size+ ( foldMap (brackets . pretty) shape+ <> ","+ </> p dst dstspace dstoffset dststrides+ <> ","+ </> p src srcspace srcoffset srcstrides ) where- ppMemLoc base offset =- pretty base <+> "+" <+> pretty offset+ p mem space offset strides =+ pretty mem <> pretty space <> "+" <> pretty offset+ <+> foldMap (brackets . pretty) strides pretty (If cond tbranch fbranch) = "if" <+> pretty cond@@ -673,8 +691,8 @@ pure $ Allocate name size s traverse _ (Free name space) = pure $ Free name space- traverse _ (Copy dest pt destoffset destspace src srcoffset srcspace size) =- pure $ Copy dest pt destoffset destspace src srcoffset srcspace size+ traverse _ (LMADCopy t shape (dst, dstspace) (dstoffset, dststrides) (src, srcspace) (srcoffset, srcstrides)) =+ pure $ LMADCopy t shape (dst, dstspace) (dstoffset, dststrides) (src, srcspace) (srcoffset, srcstrides) traverse _ (Write name i bt val space vol) = pure $ Write name i bt val space vol traverse _ (Read x name i bt space vol) =@@ -711,7 +729,7 @@ freeIn' (EntryPoint _ res args) = freeIn' (map snd res) <> freeIn' (map snd args) -instance FreeIn a => FreeIn (Functions a) where+instance (FreeIn a) => FreeIn (Functions a) where freeIn' (Functions fs) = foldMap (onFun . snd) fs where onFun f =@@ -728,7 +746,7 @@ freeIn' (TransparentValue vd) = freeIn' vd freeIn' (OpaqueValue _ vds) = foldMap freeIn' vds -instance FreeIn a => FreeIn (Code a) where+instance (FreeIn a) => FreeIn (Code a) where freeIn' (x :>>: y) = fvBind (declaredIn x) $ freeIn' x <> freeIn' y freeIn' Skip =@@ -747,8 +765,8 @@ freeIn' name <> freeIn' size <> freeIn' space freeIn' (Free name _) = freeIn' name- freeIn' (Copy _ dest x _ src y _ n) =- freeIn' dest <> freeIn' x <> freeIn' src <> freeIn' y <> freeIn' n+ freeIn' (LMADCopy _ shape (dst, _) (dstoffset, dststrides) (src, _) (srcoffset, srcstrides)) =+ freeIn' shape <> freeIn' dst <> freeIn' dstoffset <> freeIn' dststrides <> freeIn' src <> freeIn' srcoffset <> freeIn' srcstrides freeIn' (SetMem x y _) = freeIn' x <> freeIn' y freeIn' (Write v i _ _ _ e) =
src/Futhark/CodeGen/ImpCode/OpenCL.hs view
@@ -64,8 +64,6 @@ ValueKArg Exp PrimType | -- | Pass this pointer as argument. MemKArg VName- | -- | Create this much local memory per workgroup.- SharedMemoryKArg (Count Bytes Exp) deriving (Show) -- | Whether a kernel can potentially fail (because it contains bounds@@ -95,7 +93,7 @@ -- | Host-level OpenCL operation. data OpenCL- = LaunchKernel KernelSafety KernelName [KernelArg] [Exp] [GroupDim]+ = LaunchKernel KernelSafety KernelName (Count Bytes (TExp Int64)) [KernelArg] [Exp] [GroupDim] | GetSize VName Name | CmpSizeLe VName Name Exp | GetSizeMax VName SizeClass@@ -105,6 +103,7 @@ data KernelTarget = TargetOpenCL | TargetCUDA+ | TargetHIP deriving (Eq) instance Pretty OpenCL where
src/Futhark/CodeGen/ImpGen.hs view
@@ -70,10 +70,9 @@ copy, copyDWIM, copyDWIMFix,- copyElementWise,+ lmadCopy, typeSize, inBounds,- isMapTransposeCopy, caseMatch, -- * Constructing code.@@ -108,7 +107,6 @@ sWrite, sUpdate, sLoopNest,- sCopy, sLoopSpace, (<--), (<~~),@@ -137,12 +135,9 @@ ( Bytes, Count, Elements,- bytes, elements,- withElemType, ) import Futhark.CodeGen.ImpCode qualified as Imp-import Futhark.CodeGen.ImpGen.Transpose import Futhark.Construct hiding (ToExp (..)) import Futhark.IR.Mem import Futhark.IR.Mem.IxFun qualified as IxFun@@ -192,7 +187,7 @@ { opsExpCompiler = defCompileExp, opsOpCompiler = opc, opsStmsCompiler = defCompileStms,- opsCopyCompiler = defaultCopy,+ opsCopyCompiler = lmadCopy, opsAllocCompilers = mempty } @@ -200,17 +195,17 @@ data MemLoc = MemLoc { memLocName :: VName, memLocShape :: [Imp.DimSize],- memLocIxFun :: IxFun.IxFun (Imp.TExp Int64)+ memLocLMAD :: LMAD.LMAD (Imp.TExp Int64) } deriving (Eq, Show) sliceMemLoc :: MemLoc -> Slice (Imp.TExp Int64) -> MemLoc-sliceMemLoc (MemLoc mem shape ixfun) slice =- MemLoc mem shape $ IxFun.slice ixfun slice+sliceMemLoc (MemLoc mem shape lmad) slice =+ MemLoc mem shape $ LMAD.slice lmad slice -flatSliceMemLoc :: MemLoc -> FlatSlice (Imp.TExp Int64) -> Maybe MemLoc-flatSliceMemLoc (MemLoc mem shape ixfun) slice =- MemLoc mem shape <$> IxFun.flatSlice ixfun slice+flatSliceMemLoc :: MemLoc -> FlatSlice (Imp.TExp Int64) -> MemLoc+flatSliceMemLoc (MemLoc mem shape lmad) slice =+ MemLoc mem shape $ LMAD.flatSlice lmad slice data ArrayEntry = ArrayEntry { entryArrayLoc :: MemLoc,@@ -411,7 +406,7 @@ warnings ws = modify $ \s -> s {stateWarnings = ws <> stateWarnings s} -- | Emit a warning about something the user should be aware of.-warn :: Located loc => loc -> [loc] -> T.Text -> ImpM rep r op ()+warn :: (Located loc) => loc -> [loc] -> T.Text -> ImpM rep r op () warn loc locs problem = warnings $ singleWarning' (srclocOf loc) (map srclocOf locs) (pretty problem) @@ -427,7 +422,7 @@ let Imp.Functions fs = stateFunctions s in isJust $ lookup fname fs -constsVTable :: Mem rep inner => Stms rep -> VTable rep+constsVTable :: (Mem rep inner) => Stms rep -> VTable rep constsVTable = foldMap stmVtable where stmVtable (Let pat _ e) =@@ -511,7 +506,7 @@ OpaqueRecord fs -> sum $ map (entryPointSize types . snd) fs compileInParam ::- Mem rep inner =>+ (Mem rep inner) => FParam rep -> ImpM rep r op (Either Imp.Param ArrayDecl) compileInParam fparam = case paramDec fparam of@@ -519,8 +514,8 @@ pure $ Left $ Imp.ScalarParam name bt MemMem space -> pure $ Left $ Imp.MemParam name space- MemArray bt shape _ (ArrayIn mem ixfun) ->- pure $ Right $ ArrayDecl name bt $ MemLoc mem (shapeDims shape) ixfun+ MemArray bt shape _ (ArrayIn mem lmad) ->+ pure $ Right $ ArrayDecl name bt $ MemLoc mem (shapeDims shape) $ IxFun.ixfunLMAD lmad MemAcc {} -> error "Functions may not have accumulator parameters." where@@ -529,7 +524,7 @@ data ArrayDecl = ArrayDecl VName PrimType MemLoc compileInParams ::- Mem rep inner =>+ (Mem rep inner) => OpaqueTypes -> [FParam rep] -> Maybe [EntryParam] ->@@ -601,7 +596,7 @@ error "Functions may not return accumulators." compileExternalValues ::- Mem rep inner =>+ (Mem rep inner) => OpaqueTypes -> [RetType rep] -> [EntryResult] ->@@ -621,9 +616,9 @@ mkValueDesc _ signedness (MemArray t shape _ ret) = do (mem, space) <- case ret of- ReturnsNewBlock space j _ixfun ->+ ReturnsNewBlock space j _lmad -> pure (nthOut j, space)- ReturnsInBlock mem _ixfun -> do+ ReturnsInBlock mem _lmad -> do space <- entryMemSpace <$> lookupMemory mem pure (mem, space) pure $ Imp.ArrayValue mem space t signedness $ map f $ shapeDims shape@@ -651,7 +646,7 @@ mkExts (length ctx_rts) orig_epts val_rts compileOutParams ::- Mem rep inner =>+ (Mem rep inner) => OpaqueTypes -> [RetType rep] -> Maybe [EntryResult] ->@@ -665,7 +660,7 @@ pure (evs, catMaybes maybe_params, dests) compileFunDef ::- Mem rep inner =>+ (Mem rep inner) => OpaqueTypes -> FunDef rep -> ImpM rep r op ()@@ -708,7 +703,7 @@ forM_ (zip params ses) $ \(param, SubExpRes _ se) -> copyDWIM (paramName param) [] se [] -compileLoopBody :: Typed dec => [Param dec] -> Body rep -> ImpM rep r op ()+compileLoopBody :: (Typed dec) => [Param dec] -> Body rep -> ImpM rep r op () compileLoopBody mergeparams (Body _ stms ses) = do -- We cannot write the results to the merge parameters immediately, -- as some of the results may actually *be* merge parameters, and@@ -811,7 +806,7 @@ (Var v, Mem {}) -> pure $ Just $ Imp.MemArg v _ -> pure Nothing defCompileExp pat (BasicOp op) = defCompileBasicOp pat op-defCompileExp pat (DoLoop merge form body) = do+defCompileExp pat (Loop merge form body) = do attrs <- askAttrs when ("unroll" `inAttrs` attrs) $ warn (noLoc :: SrcLoc) [] "#[unroll] on loop with unknown number of iterations." -- FIXME: no location.@@ -874,7 +869,7 @@ emit . Imp.TracePrint $ ErrorMsg ["\n"] defCompileBasicOp ::- Mem rep inner =>+ (Mem rep inner) => Pat (LetDec rep) -> BasicOp -> ImpM rep r op ()@@ -932,11 +927,8 @@ defCompileBasicOp (Pat [pe]) (FlatUpdate _ slice v) = do pe_loc <- entryArrayLoc <$> lookupArray (patElemName pe) v_loc <- entryArrayLoc <$> lookupArray v- case flatSliceMemLoc pe_loc slice' of- Just pe_loc' -> copy (elemType (patElemType pe)) pe_loc' v_loc- Nothing -> error "defCompileBasicOp FlatUpdate"- where- slice' = fmap pe64 slice+ let pe_loc' = flatSliceMemLoc pe_loc $ fmap pe64 slice+ copy (elemType (patElemType pe)) pe_loc' v_loc defCompileBasicOp (Pat [pe]) (Replicate shape se) | Acc {} <- patElemType pe = pure () | shape == mempty =@@ -979,7 +971,7 @@ 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]+ LMAD.iota 0 [fromIntegral $ length es] addVar static_array $ MemVar Nothing $ MemEntry DefaultSpace copy t dest_mem static_src | otherwise =@@ -1047,7 +1039,7 @@ -- | Like 'dFParams', but does not create new declarations. -- Note: a hack to be used only for functions.-addFParams :: Mem rep inner => [FParam rep] -> ImpM rep r op ()+addFParams :: (Mem rep inner) => [FParam rep] -> ImpM rep r op () addFParams = mapM_ addFParam where addFParam fparam =@@ -1061,7 +1053,7 @@ addLoopVar i it = addVar i $ ScalarVar Nothing $ ScalarEntry $ IntType it dVars ::- Mem rep inner =>+ (Mem rep inner) => Maybe (Exp rep) -> [PatElem (LetDec rep)] -> ImpM rep r op ()@@ -1069,10 +1061,10 @@ where dVar = dScope e . scopeOfPatElem -dFParams :: Mem rep inner => [FParam rep] -> ImpM rep r op ()+dFParams :: (Mem rep inner) => [FParam rep] -> ImpM rep r op () dFParams = dScope Nothing . scopeOfFParams -dLParams :: Mem rep inner => [LParam rep] -> ImpM rep r op ()+dLParams :: (Mem rep inner) => [LParam rep] -> ImpM rep r op () dLParams = dScope Nothing . scopeOfLParams dPrimVol :: String -> PrimType -> Imp.TExp t -> ImpM rep r op (TV t)@@ -1126,8 +1118,8 @@ MemVar e $ MemEntry space memBoundToVarEntry e (MemAcc acc ispace ts _) = AccVar e (acc, ispace, ts)-memBoundToVarEntry e (MemArray bt shape _ (ArrayIn mem ixfun)) =- let location = MemLoc mem (shapeDims shape) ixfun+memBoundToVarEntry e (MemArray bt shape _ (ArrayIn mem lmad)) =+ let location = MemLoc mem (shapeDims shape) $ IxFun.ixfunLMAD lmad in ArrayVar e ArrayEntry@@ -1136,7 +1128,7 @@ } infoDec ::- Mem rep inner =>+ (Mem rep inner) => NameInfo rep -> MemInfo SubExp NoUniqueness MemBind infoDec (LetName dec) = letDecMem dec@@ -1145,7 +1137,7 @@ infoDec (IndexName it) = MemPrim $ IntType it dInfo ::- Mem rep inner =>+ (Mem rep inner) => Maybe (Exp rep) -> VName -> NameInfo rep ->@@ -1164,18 +1156,17 @@ addVar name entry dScope ::- Mem rep inner =>+ (Mem rep inner) => Maybe (Exp rep) -> Scope rep -> ImpM rep r op () dScope e = mapM_ (uncurry $ dInfo e) . M.toList -dArray :: VName -> PrimType -> ShapeBase SubExp -> VName -> IxFun -> ImpM rep r op ()-dArray name pt shape mem ixfun =+dArray :: VName -> PrimType -> ShapeBase SubExp -> VName -> LMAD -> ImpM rep r op ()+dArray name pt shape mem lmad = addVar name $ ArrayVar Nothing $ ArrayEntry location pt where- location =- MemLoc mem (shapeDims shape) ixfun+ location = MemLoc mem (shapeDims shape) lmad everythingVolatile :: ImpM rep r op a -> ImpM rep r op a everythingVolatile = local $ \env -> env {envVolatility = Imp.Volatile}@@ -1391,12 +1382,12 @@ MemLoc -> [Imp.TExp Int64] -> ImpM rep r op (VName, Imp.Space, Count Elements (Imp.TExp Int64))-fullyIndexArray' (MemLoc mem _ ixfun) indices = do+fullyIndexArray' (MemLoc mem _ lmad) indices = do space <- entryMemSpace <$> lookupMemory mem pure ( mem, space,- elements $ IxFun.index ixfun indices+ elements $ LMAD.index lmad indices ) -- More complicated read/write operations that use index functions.@@ -1404,150 +1395,43 @@ copy :: CopyCompiler rep r op copy bt- dst@(MemLoc dst_name _ dst_ixfn@(IxFun.IxFun dst_lmad _))- src@(MemLoc src_name _ src_ixfn@(IxFun.IxFun src_lmad _)) = do+ dst@(MemLoc dst_name _ dst_ixfn@dst_lmad)+ src@(MemLoc src_name _ src_ixfn@src_lmad) = do -- If we can statically determine that the two index-functions -- are equivalent, don't do anything- unless (dst_name == src_name && dst_ixfn `IxFun.equivalent` src_ixfn)+ unless (dst_name == src_name && dst_ixfn `LMAD.equivalent` src_ixfn) $ -- It's also possible that we can dynamically determine that the two -- index-functions are equivalent. sUnless ( fromBool (dst_name == src_name)- .&&. IxFun.dynamicEqualsLMAD dst_lmad src_lmad+ .&&. LMAD.dynamicEqualsLMAD dst_lmad src_lmad ) $ do -- If none of the above is true, actually do the copy cc <- asks envCopyCompiler cc bt dst src --- | Is this copy really a mapping with transpose? Produce an--- expression that is true if so, as well as other expressions that--- contain information about the transpose in that case (don't trust--- these if the boolean is false).-isMapTransposeCopy ::- PrimType ->- MemLoc ->- MemLoc ->- Maybe- ( Imp.TExp Bool,- ( Imp.TExp Int64,- Imp.TExp Int64,- Imp.TExp Int64,- Imp.TExp Int64,- Imp.TExp Int64- )- )-isMapTransposeCopy pt (MemLoc _ _ destIxFun) (MemLoc _ _ srcIxFun)- | perm <- LMAD.permutation dest_lmad,- LMAD.permutation src_lmad == [0 .. rank - 1],- Just (r1, r2, _) <- isMapTranspose perm =- isOk (IxFun.shape destIxFun) swap r1 r2- | perm <- LMAD.permutation src_lmad,- LMAD.permutation dest_lmad == [0 .. rank - 1],- Just (r1, r2, _) <- isMapTranspose perm =- isOk (IxFun.shape srcIxFun) id r1 r2- | otherwise =- Nothing- where- rank = IxFun.rank destIxFun- swap (x, y) = (y, x)- dest_lmad = IxFun.ixfunLMAD destIxFun- src_lmad = IxFun.ixfunLMAD srcIxFun- dest_offset = LMAD.offset dest_lmad- src_offset = LMAD.offset src_lmad-- isOk shape f r1 r2 =- let (num_arrays, size_x, size_y) = getSizes shape f r1 r2- in Just- ( LMAD.contiguous dest_lmad- .&&. LMAD.contiguous src_lmad,- ( dest_offset * primByteSize pt,- src_offset * primByteSize pt,- num_arrays,- size_x,- size_y- )- )-- getSizes shape f r1 r2 =- let (mapped, notmapped) = splitAt r1 shape- (pretrans, posttrans) = f $ splitAt r2 notmapped- in (product mapped, product pretrans, product posttrans)--mapTransposeName :: PrimType -> String-mapTransposeName bt = "map_transpose_" ++ prettyString bt--mapTransposeForType :: PrimType -> ImpM rep r op Name-mapTransposeForType bt = do- let fname = nameFromString $ "builtin#" <> mapTransposeName bt-- exists <- hasFunction fname- unless exists $ emitFunction fname $ mapTransposeFunction fname bt-- pure fname---- | Use 'sCopy' if possible, otherwise 'copyElementWise'.-defaultCopy :: CopyCompiler rep r op-defaultCopy pt dest src- | Just (is_transpose, (destoffset, srcoffset, num_arrays, size_x, size_y)) <-- isMapTransposeCopy pt dest src = do- fname <- mapTransposeForType pt- sIf- is_transpose- ( emit . Imp.Call [] fname $- transposeArgs- pt- destmem- (bytes destoffset)- srcmem- (bytes srcoffset)- num_arrays- size_x- size_y- )- nontranspose- | otherwise = nontranspose- where- num_elems = Imp.elements $ product $ IxFun.shape $ memLocIxFun src-- MemLoc destmem _ dest_ixfun = dest- MemLoc srcmem _ src_ixfun = src-- isScalarSpace ScalarSpace {} = True- isScalarSpace _ = False-- nontranspose = do- srcspace <- entryMemSpace <$> lookupMemory srcmem- destspace <- entryMemSpace <$> lookupMemory destmem- if isScalarSpace srcspace || isScalarSpace destspace- then copyElementWise pt dest src- else do- let dest_lmad = LMAD.noPermutation $ IxFun.ixfunLMAD dest_ixfun- src_lmad = LMAD.noPermutation $ IxFun.ixfunLMAD src_ixfun- destoffset = elements (LMAD.offset dest_lmad) `withElemType` pt- srcoffset = elements (LMAD.offset src_lmad) `withElemType` pt- sIf- (LMAD.memcpyable dest_lmad src_lmad)- (sCopy destmem destoffset destspace srcmem srcoffset srcspace num_elems pt)- (copyElementWise pt dest src)--copyElementWise :: CopyCompiler rep r op-copyElementWise bt dest src = do- let bounds = IxFun.shape $ memLocIxFun src- is <- replicateM (length bounds) (newVName "i")- let ivars = map Imp.le64 is- (destmem, destspace, destidx) <- fullyIndexArray' dest ivars- (srcmem, srcspace, srcidx) <- fullyIndexArray' src ivars- vol <- asks envVolatility- tmp <- newVName "tmp"+lmadCopy :: CopyCompiler rep r op+lmadCopy t dstloc srcloc = do+ let dstmem = memLocName dstloc+ srcmem = memLocName srcloc+ dstlmad = memLocLMAD dstloc+ srclmad = memLocLMAD srcloc+ srcspace <- entryMemSpace <$> lookupMemory srcmem+ dstspace <- entryMemSpace <$> lookupMemory dstmem emit $- foldl (.) id (zipWith Imp.For is $ map untyped bounds) $- mconcat- [ Imp.DeclareScalar tmp vol bt,- Imp.Read tmp srcmem srcidx bt srcspace vol,- Imp.Write destmem destidx bt destspace vol $ Imp.var tmp bt- ]+ Imp.LMADCopy+ t+ (elements <$> LMAD.shape dstlmad)+ (dstmem, dstspace)+ ( LMAD.offset $ elements <$> dstlmad,+ map LMAD.ldStride $ LMAD.dims $ elements <$> dstlmad+ )+ (srcmem, srcspace)+ ( LMAD.offset $ elements <$> srclmad,+ map LMAD.ldStride $ LMAD.dims $ elements <$> srclmad+ ) -- | Copy from here to there; both destination and source may be -- indexeded.@@ -1737,7 +1621,7 @@ -- @space@, writing the result to @pat@, which must contain a single -- memory-typed element. compileAlloc ::- Mem rep inner => Pat (LetDec rep) -> SubExp -> Space -> ImpM rep r op ()+ (Mem rep inner) => Pat (LetDec rep) -> SubExp -> Space -> ImpM rep r op () compileAlloc (Pat [mem]) e space = do let e' = Imp.bytes $ pe64 e allocator <- asks $ M.lookup space . envAllocCompilers@@ -1837,7 +1721,7 @@ sAlloc_ name' size space pure name' -sArray :: String -> PrimType -> ShapeBase SubExp -> VName -> IxFun -> ImpM rep r op VName+sArray :: String -> PrimType -> ShapeBase SubExp -> VName -> LMAD -> ImpM rep r op VName sArray name bt shape mem ixfun = do name' <- newVName name dArray name' bt shape mem ixfun@@ -1847,7 +1731,7 @@ sArrayInMem :: String -> PrimType -> ShapeBase SubExp -> VName -> ImpM rep r op VName sArrayInMem name pt shape mem = sArray name pt shape mem $- IxFun.iota $+ LMAD.iota 0 $ map (isInt64 . primExpFromSubExp int64) $ shapeDims shape @@ -1856,9 +1740,9 @@ sAllocArrayPerm name pt shape space perm = do let permuted_dims = rearrangeShape perm $ shapeDims shape mem <- sAlloc (name ++ "_mem") (typeSize (Array pt shape NoUniqueness)) space- let iota_ixfun = IxFun.iota $ map (isInt64 . primExpFromSubExp int64) permuted_dims+ let iota_ixfun = LMAD.iota 0 $ map (isInt64 . primExpFromSubExp int64) permuted_dims sArray name pt shape mem $- IxFun.permute iota_ixfun $+ LMAD.permute iota_ixfun $ rearrangeInverse perm -- | Uses linear/iota index function.@@ -1876,7 +1760,7 @@ mem <- newVNameForFun $ name ++ "_mem" emit $ Imp.DeclareArray mem pt vs addVar mem $ MemVar Nothing $ MemEntry DefaultSpace- sArray name pt shape mem $ IxFun.iota [fromIntegral num_elems]+ sArray name pt shape mem $ LMAD.iota 0 [fromIntegral num_elems] sWrite :: VName -> [Imp.TExp Int64] -> Imp.Exp -> ImpM rep r op () sWrite arr is v = do@@ -1904,33 +1788,6 @@ ([Imp.TExp Int64] -> ImpM rep r op ()) -> ImpM rep r op () sLoopNest = sLoopSpace . map pe64 . shapeDims--sCopy ::- VName ->- Count Bytes (Imp.TExp Int64) ->- Space ->- VName ->- Count Bytes (Imp.TExp Int64) ->- Space ->- Count Elements (Imp.TExp Int64) ->- PrimType ->- ImpM rep r op ()-sCopy destmem destoffset destspace srcmem srcoffset srcspace num_elems pt =- if destmem == srcmem- then sUnless (Imp.unCount destoffset .==. Imp.unCount srcoffset) the_copy- else the_copy- where- the_copy =- emit- $ Imp.Copy- pt- destmem- destoffset- destspace- srcmem- srcoffset- srcspace- $ num_elems `withElemType` pt -- | Untyped assignment. (<~~) :: VName -> Imp.Exp -> ImpM rep r op ()
src/Futhark/CodeGen/ImpGen/CUDA.hs view
@@ -13,5 +13,5 @@ import Futhark.MonadFreshNames -- | Compile the program to ImpCode with CUDA kernels.-compileProg :: MonadFreshNames m => Prog GPUMem -> m (Warnings, Program)+compileProg :: (MonadFreshNames m) => Prog GPUMem -> m (Warnings, Program) compileProg prog = second kernelsToCUDA <$> compileProgCUDA prog
src/Futhark/CodeGen/ImpGen/GPU.hs view
@@ -7,13 +7,12 @@ module Futhark.CodeGen.ImpGen.GPU ( compileProgOpenCL, compileProgCUDA,+ compileProgHIP, Warnings, ) where import Control.Monad-import Control.Monad.State-import Data.Foldable (toList) import Data.List (foldl') import Data.Map qualified as M import Data.Maybe@@ -21,25 +20,21 @@ import Futhark.CodeGen.ImpGen hiding (compileProg) import Futhark.CodeGen.ImpGen qualified import Futhark.CodeGen.ImpGen.GPU.Base-import Futhark.CodeGen.ImpGen.GPU.Copy import Futhark.CodeGen.ImpGen.GPU.SegHist import Futhark.CodeGen.ImpGen.GPU.SegMap import Futhark.CodeGen.ImpGen.GPU.SegRed import Futhark.CodeGen.ImpGen.GPU.SegScan-import Futhark.CodeGen.ImpGen.GPU.Transpose import Futhark.Error import Futhark.IR.GPUMem-import Futhark.IR.Mem.IxFun qualified as IxFun-import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.MonadFreshNames-import Futhark.Util.IntegralExp (IntegralExp, divUp, quot, rem)+import Futhark.Util.IntegralExp (divUp, rem) import Prelude hiding (quot, rem) callKernelOperations :: Operations GPUMem HostEnv Imp.HostOp callKernelOperations = Operations { opsExpCompiler = expCompiler,- opsCopyCompiler = callKernelCopy,+ opsCopyCompiler = lmadCopy, opsOpCompiler = opCompiler, opsStmsCompiler = defCompileStms, opsAllocCompilers = mempty@@ -76,7 +71,7 @@ ] compileProg ::- MonadFreshNames m =>+ (MonadFreshNames m) => HostEnv -> Prog GPUMem -> m (Warnings, Imp.Program)@@ -88,10 +83,12 @@ -- | Compile a 'GPUMem' program to low-level parallel code, with -- either CUDA or OpenCL characteristics. compileProgOpenCL,- compileProgCUDA ::- MonadFreshNames m => Prog GPUMem -> m (Warnings, Imp.Program)+ compileProgCUDA,+ compileProgHIP ::+ (MonadFreshNames m) => Prog GPUMem -> m (Warnings, Imp.Program) compileProgOpenCL = compileProg $ HostEnv openclAtomics OpenCL mempty compileProgCUDA = compileProg $ HostEnv cudaAtomics CUDA mempty+compileProgHIP = compileProg $ HostEnv cudaAtomics HIP mempty opCompiler :: Pat LetDecMem ->@@ -262,327 +259,3 @@ Just ok -> Imp.If (matches .&&. ok) tcode fcode expCompiler dest e = defCompileExp dest e--gpuCopyForType :: Rank -> PrimType -> CallKernelGen Name-gpuCopyForType r bt = do- let fname = nameFromString $ "builtin#" <> gpuCopyName r bt-- exists <- hasFunction fname- unless exists $ emitFunction fname $ gpuCopyFunction r bt-- pure fname--gpuCopyName :: Rank -> PrimType -> String-gpuCopyName (Rank r) bt = "gpu_copy_" <> show r <> "d_" <> prettyString bt--gpuCopyFunction :: Rank -> PrimType -> Imp.Function Imp.HostOp-gpuCopyFunction (Rank r) pt = do- let tdesc = mconcat (replicate r "[]") <> prettyString pt- Imp.Function Nothing [] params $- Imp.DebugPrint ("\n# Copy " <> tdesc) Nothing- <> copy_code- <> Imp.DebugPrint "" Nothing- where- space = Space "device"- memparam v = Imp.MemParam v space- intparam v = Imp.ScalarParam v $ IntType Int64-- mkIxFun desc = do- let new x = newVName $ desc <> "_" <> x- newDim i = LMAD.LMADDim <$> new "stride" <*> new "shape" <*> pure i- LMAD.LMAD <$> new "offset" <*> mapM newDim [0 .. r - 1]-- (params, copy_code) = do- flip evalState blankNameSource $ do- dest_mem <- newVName "destmem"- dest_lmad <- mkIxFun "dest"-- src_mem <- newVName "srcmem"- src_lmad <- mkIxFun "src"-- group_size <- newVName "group_size"- num_groups <- newVName "num_groups"-- let kernel =- copyKernel- pt- (le64 num_groups, Left $ untyped $ le64 group_size)- (dest_mem, le64 <$> dest_lmad)- (src_mem, le64 <$> src_lmad)-- dest_offset =- Imp.elements (le64 (LMAD.offset dest_lmad)) `Imp.withElemType` pt-- src_offset =- Imp.elements (le64 (LMAD.offset src_lmad)) `Imp.withElemType` pt-- num_bytes =- Imp.elements (product (le64 <$> LMAD.shape src_lmad)) `Imp.withElemType` pt-- do_copy =- Imp.Copy- pt- dest_mem- dest_offset- (Space "device")- src_mem- src_offset- (Space "device")- num_bytes-- pure- ( [memparam dest_mem]- ++ map intparam (toList dest_lmad)- ++ [memparam src_mem]- ++ map intparam (toList src_lmad),- Imp.DeclareScalar group_size Imp.Nonvolatile int64- <> Imp.DeclareScalar num_groups Imp.Nonvolatile int64- <> Imp.Op (Imp.GetSize group_size "copy_group_size" Imp.SizeGroup)- <> Imp.Op (Imp.GetSize num_groups "copy_num_groups" Imp.SizeNumGroups)- <> Imp.If- (LMAD.memcpyable (le64 <$> dest_lmad) (le64 <$> src_lmad))- ( Imp.DebugPrint "## Simple copy" Nothing- <> do_copy- )- ( Imp.DebugPrint "## Kernel copy" Nothing- <> Imp.Op (Imp.CallKernel kernel)- )- )--mapTransposeForType :: PrimType -> CallKernelGen Name-mapTransposeForType bt = do- let fname = nameFromString $ "builtin#" <> mapTransposeName bt-- exists <- hasFunction fname- unless exists $ emitFunction fname $ mapTransposeFunction bt-- pure fname--mapTransposeName :: PrimType -> String-mapTransposeName bt = "gpu_map_transpose_" ++ prettyString bt--mapTransposeFunction :: PrimType -> Imp.Function Imp.HostOp-mapTransposeFunction bt =- Imp.Function Nothing [] params $- Imp.DebugPrint ("\n# Transpose " <> prettyString bt) Nothing- <> Imp.DebugPrint "Number of arrays " (Just $ untyped $ Imp.le64 num_arrays)- <> Imp.DebugPrint "X elements " (Just $ untyped $ Imp.le64 x)- <> Imp.DebugPrint "Y elements " (Just $ untyped $ Imp.le64 y)- <> Imp.DebugPrint "Source offset" (Just $ untyped $ Imp.le64 srcoffset)- <> Imp.DebugPrint "Destination offset" (Just $ untyped $ Imp.le64 destoffset)- <> transpose_code- <> Imp.DebugPrint "" Nothing- where- params =- [ memparam destmem,- intparam destoffset,- memparam srcmem,- intparam srcoffset,- intparam num_arrays,- intparam x,- intparam y- ]-- space = Space "device"- memparam v = Imp.MemParam v space- intparam v = Imp.ScalarParam v $ IntType Int64-- [ destmem,- destoffset,- srcmem,- srcoffset,- num_arrays,- x,- y,- mulx,- muly,- block,- use_32b- ] =- zipWith- (VName . nameFromString)- [ "destmem",- "destoffset",- "srcmem",- "srcoffset",- "num_arrays",- "x_elems",- "y_elems",- -- The following is only used for low width/height- -- transpose kernels- "mulx",- "muly",- "block",- "use_32b"- ]- [0 ..]-- block_dim_int = 16-- block_dim :: IntegralExp a => a- block_dim = 16-- -- When an input array has either width==1 or height==1, performing a- -- transpose will be the same as performing a copy.- can_use_copy =- let onearr = Imp.le64 num_arrays .==. 1- height_is_one = Imp.le64 y .==. 1- width_is_one = Imp.le64 x .==. 1- in onearr .&&. (width_is_one .||. height_is_one)-- transpose_code =- Imp.If input_is_empty mempty $- mconcat- [ Imp.DeclareScalar muly Imp.Nonvolatile (IntType Int64),- Imp.SetScalar muly $ untyped $ block_dim `quot` Imp.le64 x,- Imp.DeclareScalar mulx Imp.Nonvolatile (IntType Int64),- Imp.SetScalar mulx $ untyped $ block_dim `quot` Imp.le64 y,- Imp.DeclareScalar use_32b Imp.Nonvolatile Bool,- Imp.SetScalar use_32b $- untyped $- (le64 destoffset + le64 num_arrays * le64 x * le64 y) .<=. 2 ^ (31 :: Int) - 1- .&&. (le64 srcoffset + le64 num_arrays * le64 x * le64 y) .<=. 2 ^ (31 :: Int) - 1,- Imp.If can_use_copy copy_code $- Imp.If should_use_lowwidth (callTransposeKernel TransposeLowWidth) $- Imp.If should_use_lowheight (callTransposeKernel TransposeLowHeight) $- Imp.If should_use_small (callTransposeKernel TransposeSmall) $- callTransposeKernel TransposeNormal- ]-- input_is_empty =- Imp.le64 num_arrays .==. 0 .||. Imp.le64 x .==. 0 .||. Imp.le64 y .==. 0-- should_use_small =- Imp.le64 x .<=. (block_dim `quot` 2)- .&&. Imp.le64 y .<=. (block_dim `quot` 2)-- should_use_lowwidth =- Imp.le64 x .<=. (block_dim `quot` 2)- .&&. block_dim .<. Imp.le64 y-- should_use_lowheight =- Imp.le64 y .<=. (block_dim `quot` 2)- .&&. block_dim .<. Imp.le64 x-- copy_code =- let num_bytes = sExt64 $ Imp.le64 x * Imp.le64 y * primByteSize bt- in Imp.Copy- bt- destmem- (Imp.Count $ Imp.le64 destoffset)- space- srcmem- (Imp.Count $ Imp.le64 srcoffset)- space- (Imp.Count num_bytes)-- callTransposeKernel which =- Imp.If- (isBool (LeafExp use_32b Bool))- ( Imp.DebugPrint "Using 32-bit indexing" Nothing- <> callTransposeKernel32 which- )- ( Imp.DebugPrint "Using 64-bit indexing" Nothing- <> callTransposeKernel64 which- )-- callTransposeKernel64 =- Imp.Op- . Imp.CallKernel- . mapTransposeKernel- (int64, le64)- (mapTransposeName bt)- block_dim_int- ( destmem,- le64 destoffset,- srcmem,- le64 srcoffset,- le64 x,- le64 y,- le64 mulx,- le64 muly,- le64 num_arrays,- block- )- bt-- callTransposeKernel32 =- Imp.Op- . Imp.CallKernel- . mapTransposeKernel- (int32, le32)- (mapTransposeName bt)- block_dim_int- ( destmem,- sExt32 (le64 destoffset),- srcmem,- sExt32 (le64 srcoffset),- sExt32 (le64 x),- sExt32 (le64 y),- sExt32 (le64 mulx),- sExt32 (le64 muly),- sExt32 (le64 num_arrays),- block- )- bt---- Note [32-bit transpositions]------ Transposition kernels are much slower when they have to use 64-bit--- arithmetic. I observed about 0.67x slowdown on an A100 GPU when--- transposing four-byte elements (much less when transposing 8-byte--- elements). Unfortunately, 64-bit arithmetic is a requirement for--- large arrays (see #1953 for what happens otherwise). We generate--- both 32- and 64-bit index arithmetic versions of transpositions,--- and dynamically pick between them at runtime. This is an--- unfortunate code bloat, and it would be preferable if we could--- simply optimise the 64-bit version to make this distinction--- unnecessary. Fortunately these kernels are quite small.--callKernelCopy :: CopyCompiler GPUMem HostEnv Imp.HostOp-callKernelCopy pt destloc@(MemLoc destmem _ dest_ixfun) srcloc@(MemLoc srcmem _ src_ixfun)- | Just (is_transpose, (destoffset, srcoffset, num_arrays, size_x, size_y)) <-- isMapTransposeCopy pt destloc srcloc = do- fname <- mapTransposeForType pt- sIf- is_transpose- ( emit . Imp.Call [] fname $- [ Imp.MemArg destmem,- Imp.ExpArg $ untyped destoffset,- Imp.MemArg srcmem,- Imp.ExpArg $ untyped srcoffset,- Imp.ExpArg $ untyped num_arrays,- Imp.ExpArg $ untyped size_x,- Imp.ExpArg $ untyped size_y- ]- )- nontranspose- | otherwise = nontranspose- where- nontranspose = do- fname <- gpuCopyForType (Rank (IxFun.rank dest_ixfun)) pt- dest_space <- entryMemSpace <$> lookupMemory destmem- src_space <- entryMemSpace <$> lookupMemory srcmem- let dest_lmad = LMAD.noPermutation $ IxFun.ixfunLMAD dest_ixfun- src_lmad = LMAD.noPermutation $ IxFun.ixfunLMAD src_ixfun- num_elems = Imp.elements $ product $ LMAD.shape dest_lmad- if dest_space == Space "device" && src_space == Space "device"- then- emit . Imp.Call [] fname $- [Imp.MemArg destmem]- ++ map (Imp.ExpArg . untyped) (toList dest_lmad)- ++ [Imp.MemArg srcmem]- ++ map (Imp.ExpArg . untyped) (toList src_lmad)- else -- FIXME: this assumes a linear representation!- -- Currently we never generate code where this is not the- -- case, but we might in the future.-- sCopy- destmem- (Imp.elements (LMAD.offset dest_lmad) `Imp.withElemType` pt)- dest_space- srcmem- (Imp.elements (LMAD.offset src_lmad) `Imp.withElemType` pt)- src_space- num_elems- pt
src/Futhark/CodeGen/ImpGen/GPU/Base.hs view
@@ -33,7 +33,6 @@ -- * Host-level bulk operations sReplicate, sIota,- sCopy, -- * Atomics AtomicBinOp,@@ -52,7 +51,7 @@ import Futhark.CodeGen.ImpGen import Futhark.Error import Futhark.IR.GPUMem-import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.MonadFreshNames import Futhark.Transform.Rename import Futhark.Util (dropLast, nubOrd, splitFromEnd)@@ -63,7 +62,7 @@ -- of the kernels code is the same, there are some cases where we -- generate special code based on the ultimate low-level API we are -- targeting.-data Target = CUDA | OpenCL+data Target = CUDA | OpenCL | HIP -- | Information about the locks available for accumulators. data Locks = Locks@@ -188,7 +187,7 @@ -- The body must contain thread-level code. For multidimensional -- loops, use 'groupCoverSpace'. kernelLoop ::- IntExp t =>+ (IntExp t) => Imp.TExp t -> Imp.TExp t -> Imp.TExp t ->@@ -208,7 +207,7 @@ -- passed-in function is invoked with the (symbolic) iteration. For -- multidimensional loops, use 'groupCoverSpace'. groupLoop ::- IntExp t =>+ (IntExp t) => Imp.TExp t -> (Imp.TExp t -> InKernelGen ()) -> InKernelGen ()@@ -224,7 +223,7 @@ -- all threads in the group participate. The passed-in function is -- invoked with a (symbolic) point in the index space. groupCoverSpace ::- IntExp t =>+ (IntExp t) => [Imp.TExp t] -> ([Imp.TExp t] -> InKernelGen ()) -> InKernelGen ()@@ -410,6 +409,12 @@ | otherwise = sOp $ Imp.Barrier fence + errorsync+ | array_scan =+ sOp $ Imp.ErrorSync Imp.FenceGlobal+ | otherwise =+ sOp $ Imp.ErrorSync Imp.FenceLocal+ group_offset = sExt64 (kernelGroupId constants) * kernelGroupSize constants writeBlockResult p arr@@ -453,7 +458,7 @@ "scan the first block, after which offset 'i' contains carry-in for block 'i+1'" $ doInBlockScan first_block_seg_flag (is_first_block .&&. ltid_in_bounds) renamed_lam - barrier+ errorsync when array_scan $ do sComment "move correct values for first block back a block" $@@ -528,38 +533,44 @@ constants <- kernelConstants <$> askEnv let local_tid = kernelLocalThreadId constants- global_tid = kernelGlobalThreadId constants barrier | all primType $ lambdaReturnType lam = sOp $ Imp.Barrier Imp.FenceLocal | otherwise = sOp $ Imp.Barrier Imp.FenceGlobal - readReduceArgument param arr- | Prim _ <- paramType param = do- let i = local_tid + tvExp offset- copyDWIMFix (paramName param) [] (Var arr) [sExt64 i]- | otherwise = do- let i = global_tid + tvExp offset- copyDWIMFix (paramName param) [] (Var arr) [sExt64 i]+ errorsync+ | all primType $ lambdaReturnType lam = sOp $ Imp.ErrorSync Imp.FenceLocal+ | otherwise = sOp $ Imp.ErrorSync Imp.FenceGlobal + readReduceArgument param arr = do+ let i = local_tid + tvExp offset+ copyDWIMFix (paramName param) [] (Var arr) [sExt64 i]+ writeReduceOpResult param arr | Prim _ <- paramType param = copyDWIMFix arr [sExt64 local_tid] (Var $ paramName param) [] | otherwise = pure () - let (reduce_acc_params, reduce_arr_params) = splitAt (length arrs) $ lambdaParams lam+ writeArrayOpResult param arr+ | Prim _ <- paramType param =+ pure ()+ | otherwise =+ copyDWIMFix arr [0] (Var $ paramName param) [] + let (reduce_acc_params, reduce_arr_params) =+ splitAt (length arrs) $ lambdaParams lam+ skip_waves <- dPrimV "skip_waves" (1 :: Imp.TExp Int32) dLParams $ lambdaParams lam offset <-- (0 :: Imp.TExp Int32) comment "participating threads read initial accumulator" $- sWhen (local_tid .<. w) $+ localOps threadOperations . sWhen (local_tid .<. w) $ zipWithM_ readReduceArgument reduce_acc_params arrs - let do_reduce = do+ let do_reduce = localOps threadOperations $ do comment "read array element" $ zipWithM_ readReduceArgument reduce_arr_params arrs comment "apply reduction operation" $@@ -600,14 +611,18 @@ sWhile doing_cross_wave_reductions $ do barrier offset <-- tvExp skip_waves * wave_size- sWhen- apply_in_cross_wave_iteration- do_reduce+ sWhen apply_in_cross_wave_iteration do_reduce skip_waves <-- tvExp skip_waves * 2 in_wave_reductions cross_wave_reductions+ errorsync + sComment "Copy array-typed operands to result array" $ do+ sWhen (local_tid .==. 0) $+ localOps threadOperations $+ zipWithM_ writeArrayOpResult reduce_acc_params arrs+ compileThreadOp :: OpCompiler GPUMem KernelEnv Imp.KernelOp compileThreadOp pat (Alloc size space) = kernelAlloc pat size space@@ -847,7 +862,7 @@ sWhen (isBool won) (run_loop <-- false) computeKernelUses ::- FreeIn a =>+ (FreeIn a) => a -> [VName] -> CallKernelGen [Imp.KernelUse]@@ -1195,7 +1210,7 @@ threadOperations :: Operations GPUMem KernelEnv Imp.KernelOp threadOperations = (defaultOperations compileThreadOp)- { opsCopyCompiler = copyElementWise,+ { opsCopyCompiler = lmadCopy, opsExpCompiler = compileThreadExp, opsStmsCompiler = \_ -> defCompileStms mempty, opsAllocCompilers =@@ -1246,7 +1261,7 @@ shape = Shape [Var num_elems] function fname [] params $ do arr <-- sArray "arr" bt shape mem $ IxFun.iota $ map pe64 $ shapeDims shape+ sArray "arr" bt shape mem $ LMAD.iota 0 $ map pe64 $ shapeDims shape sReplicateKernel arr $ Var val pure fname@@ -1257,7 +1272,7 @@ v_t <- subExpType v case v_t of Prim v_t'- | IxFun.isDirect arr_ixfun -> pure $+ | LMAD.isDirect arr_ixfun -> pure $ Just $ do fname <- replicateForType v_t' emit $@@ -1342,9 +1357,7 @@ function fname [] params $ do arr <- sArray "arr" (IntType bt) shape mem $- IxFun.iota $- map pe64 $- shapeDims shape+ LMAD.iota 0 (map pe64 (shapeDims shape)) sIotaKernel arr (sExt64 n') x' s' bt pure fname@@ -1359,7 +1372,7 @@ CallKernelGen () sIota arr n x s et = do ArrayEntry (MemLoc arr_mem _ arr_ixfun) _ <- lookupArray arr- if IxFun.isDirect arr_ixfun+ if LMAD.isDirect arr_ixfun then do fname <- iotaForType et emit $
− src/Futhark/CodeGen/ImpGen/GPU/Copy.hs
@@ -1,81 +0,0 @@--- | General implementation of GPU copying, using LMAD representation.--- That means the dynamic performance of this kernel depends crucially--- on the LMAD. In most cases we should use a more specialised kernel.--- Written in ImpCode so we can compile it to both CUDA and OpenCL.-module Futhark.CodeGen.ImpGen.GPU.Copy (copyKernel) where--import Control.Monad-import Control.Monad.State-import Data.Foldable (toList)-import Futhark.CodeGen.ImpCode.GPU-import Futhark.IR.Mem.LMAD qualified as LMAD-import Futhark.IR.Prop.Reshape-import Futhark.MonadFreshNames-import Futhark.Util (nubOrd)-import Futhark.Util.IntegralExp (divUp)-import Prelude hiding (quot, rem)--copyKernel ::- PrimType ->- (TExp Int64, GroupDim) ->- (VName, LMAD.LMAD (TExp Int64)) ->- (VName, LMAD.LMAD (TExp Int64)) ->- Kernel-copyKernel pt (num_groups, group_dim) (dest_mem, dest_lmad) (src_mem, src_lmad) =- Kernel- { kernelBody = body,- kernelUses =- let frees =- nubOrd- ( foldMap toList dest_lmad- <> foldMap toList src_lmad- <> toList num_groups- )- in map (`ScalarUse` IntType Int64) frees- ++ map MemoryUse [dest_mem, src_mem],- kernelNumGroups = [untyped num_groups],- kernelGroupSize = [group_dim],- kernelName = nameFromString ("copy_" <> show rank <> "d_" <> prettyString pt),- kernelFailureTolerant = True,- kernelCheckLocalMemory = False- }- where- shape = LMAD.shape dest_lmad- rank = length shape-- body = flip evalState (newNameSource 1000) $ do- group_id <- newVName "group_id"- local_id <- newVName "local_id"- local_size <- newVName "local_size"- global_id <- newVName "global_id"- group_iter <- newVName "group_iter"- let global_id_e =- ((le64 group_id + le64 group_iter * num_groups) * le64 local_size)- + le64 local_id-- is <- replicateM rank $ newVName "i"- let is_e = map untyped (unflattenIndex shape (le64 global_id))- in_bounds = foldl1 (.&&.) (zipWith (.<.) (map le64 is) shape)-- element <- newVName "element"-- let dec v = DeclareScalar v Nonvolatile $ IntType Int64- src_o = Count (LMAD.index src_lmad (map le64 is))- dest_o = Count (LMAD.index dest_lmad (map le64 is))- copy_elem =- DeclareScalar element Nonvolatile pt- <> Read element src_mem src_o pt (Space "device") Nonvolatile- <> Write dest_mem dest_o pt (Space "device") Nonvolatile (LeafExp element pt)- pure $- foldMap dec [group_id, local_id, local_size, global_id]- <> Op (GetLocalId local_id 0)- <> Op (GetLocalSize local_size 0)- <> Op (GetGroupId group_id 0)- <> For- group_iter- (untyped (product shape `divUp` (le64 local_size * num_groups)))- ( SetScalar global_id (untyped global_id_e)- <> foldMap dec is- <> mconcat (zipWith SetScalar is is_e)- <> If in_bounds copy_elem mempty- )
src/Futhark/CodeGen/ImpGen/GPU/Group.hs view
@@ -26,7 +26,7 @@ import Futhark.Construct (fullSliceNum) import Futhark.Error import Futhark.IR.GPUMem-import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.MonadFreshNames import Futhark.Transform.Rename import Futhark.Util (chunks, mapAccumLM, takeLast)@@ -42,9 +42,7 @@ let flat_shape = Shape $ Var (tvVar flat) : drop k (memLocShape arr_loc) sArray (baseString arr ++ "_flat") pt flat_shape (memLocName arr_loc) $ fromMaybe (error "flattenArray") $- IxFun.reshape (memLocIxFun arr_loc) $- map pe64 $- shapeDims flat_shape+ LMAD.reshape (memLocLMAD arr_loc) (map pe64 $ shapeDims flat_shape) sliceArray :: Imp.TExp Int64 -> TV Int64 -> VName -> ImpM rep r op VName sliceArray start size arr = do@@ -59,7 +57,7 @@ (elemType arr_t) (arrayShape arr_t `setOuterDim` Var (tvVar size)) mem- $ IxFun.slice ixfun slice+ $ LMAD.slice ixfun slice -- | @applyLambda lam dests args@ emits code that: --@@ -73,7 +71,7 @@ -- provided @dest@s, again interpreted as the destination for a -- 'copyDWIM'. applyLambda ::- Mem rep inner =>+ (Mem rep inner) => Lambda rep -> [(VName, [DimIndex (Imp.TExp Int64)])] -> [(SubExp, [DimIndex (Imp.TExp Int64)])] ->@@ -92,7 +90,7 @@ -- anyway, but you have to be more careful - use this if you are in -- doubt.) applyRenamedLambda ::- Mem rep inner =>+ (Mem rep inner) => Lambda rep -> [(VName, [DimIndex (Imp.TExp Int64)])] -> [(SubExp, [DimIndex (Imp.TExp Int64)])] ->@@ -138,9 +136,9 @@ carry_idx <- dPrimVE "carry_idx" $ sExt64 chunk_start - 1 applyRenamedLambda lam- (zip arrs $ repeat [DimFix $ sExt64 chunk_start])- ( zip (map Var arrs) (repeat [DimFix carry_idx])- ++ zip (map Var arrs) (repeat [DimFix $ sExt64 chunk_start])+ (map (,[DimFix $ sExt64 chunk_start]) arrs)+ ( map ((,[DimFix carry_idx]) . Var) arrs+ ++ map ((,[DimFix $ sExt64 chunk_start]) . Var) arrs ) arrs_chunks <- mapM (sliceArray (sExt64 chunk_start) chunk_size) arrs@@ -154,8 +152,8 @@ dest_space <- entryMemSpace <$> lookupMemory (memLocName destloc) src_space <- entryMemSpace <$> lookupMemory (memLocName srcloc) - let src_ixfun = memLocIxFun srcloc- dims = IxFun.shape src_ixfun+ let src_lmad = memLocLMAD srcloc+ dims = LMAD.shape src_lmad rank = length dims case (dest_space, src_space) of@@ -169,13 +167,13 @@ Slice $ replicate (rank - length srcds) (DimFix 0) ++ takeLast (length srcds) (map fullDim dims)- copyElementWise+ lmadCopy pt (sliceMemLoc destloc destslice') (sliceMemLoc srcloc srcslice') _ -> do groupCoverSpace (map sExt32 dims) $ \is ->- copyElementWise+ lmadCopy pt (sliceMemLoc destloc (Slice $ map (DimFix . sExt64) is)) (sliceMemLoc srcloc (Slice $ map (DimFix . sExt64) is))@@ -229,7 +227,7 @@ locks_mem <- sAlloc "locks_mem" (typeSize locks_t) $ Space "local" dArray locks int32 (arrayShape locks_t) locks_mem $- IxFun.iota . map pe64 . arrayDims $+ LMAD.iota 0 . map pe64 . arrayDims $ locks_t sComment "All locks start out unlocked" $@@ -326,8 +324,17 @@ slice' = fmap pe64 slice dims = map pe64 $ arrayDims $ patElemType pe write = copyDWIM (patElemName pe) (unSlice slice') se []-compileGroupExp dest e =+compileGroupExp dest e = do+ -- It is a messy to jump into control flow for error handling.+ -- Avoid that by always doing an error sync here. Potential+ -- improvement: only do this if any errors are pending (this could+ -- also be handled in later codegen).+ when (doSync e) $ sOp $ Imp.ErrorSync Imp.FenceLocal defCompileExp dest e+ where+ doSync Loop {} = True+ doSync Match {} = True+ doSync _ = False compileGroupOp :: OpCompiler GPUMem KernelEnv Imp.KernelOp compileGroupOp pat (Alloc size space) =@@ -421,9 +428,9 @@ forM_ (zip ops tmps_for_ops) $ \(op, tmps) -> applyRenamedLambda (segBinOpLambda op)- (zip tmps $ repeat [DimFix $ sExt64 chunk_start])- ( zip (map (Var . patElemName) red_pes) (repeat [])- ++ zip (map Var tmps) (repeat [DimFix $ sExt64 chunk_start])+ (map (,[DimFix $ sExt64 chunk_start]) tmps)+ ( map ((,[]) . Var . patElemName) red_pes+ ++ map ((,[DimFix $ sExt64 chunk_start]) . Var) tmps ) sOp $ Imp.ErrorSync Imp.FenceLocal@@ -434,8 +441,11 @@ sOp $ Imp.ErrorSync Imp.FenceLocal - forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->- copyDWIMFix (patElemName pe) [] (Var arr) [sExt64 chunk_start]+ sComment "Save result of reduction." $+ forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->+ copyDWIMFix (patElemName pe) [] (Var arr) [sExt64 chunk_start]++ -- virtCase dims' tmps_for_ops = do dims_flat <- dPrimV "dims_flat" $ product dims' let segment_size = last dims'@@ -452,29 +462,31 @@ sOp $ Imp.ErrorSync Imp.FenceLocal - forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->- copyDWIM- (patElemName pe)- []- (Var arr)- (map (unitSlice 0) (init dims') ++ [DimFix $ last dims' - 1])+ sComment "Save result of reduction." $+ forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->+ copyDWIM+ (patElemName pe)+ []+ (Var arr)+ (map (unitSlice 0) (init dims') ++ [DimFix $ last dims' - 1]) sOp $ Imp.Barrier Imp.FenceLocal + -- Nonsegmented case (or rather, a single segment) - this we can+ -- handle directly with a group-level reduction. nonvirtCase [dim'] tmps_for_ops = do- -- Nonsegmented case (or rather, a single segment) - this we can- -- handle directly with a group-level reduction. forM_ (zip ops tmps_for_ops) $ \(op, tmps) -> groupReduce (sExt32 dim') (segBinOpLambda op) tmps sOp $ Imp.ErrorSync Imp.FenceLocal- forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->- copyDWIMFix (patElemName pe) [] (Var arr) [0]- --- nonvirtCase dims' tmps_for_ops = do- -- Segmented intra-group reductions are turned into (regular)- -- segmented scans. It is possible that this can be done- -- better, but at least this approach is simple.+ sComment "Save result of reduction." $+ forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->+ copyDWIMFix (patElemName pe) [] (Var arr) [0]+ sOp $ Imp.ErrorSync Imp.FenceLocal + -- Segmented intra-group reductions are turned into (regular)+ -- segmented scans. It is possible that this can be done+ -- better, but at least this approach is simple.+ nonvirtCase dims' tmps_for_ops = do -- groupScan operates on flattened arrays. This does not -- involve copying anything; merely playing with the index -- function.@@ -494,12 +506,13 @@ sOp $ Imp.ErrorSync Imp.FenceLocal - forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->- copyDWIM- (patElemName pe)- []- (Var arr)- (map (unitSlice 0) (init dims') ++ [DimFix $ last dims' - 1])+ sComment "Save result of reduction." $+ forM_ (zip red_pes $ concat tmps_for_ops) $ \(pe, arr) ->+ copyDWIM+ (patElemName pe)+ []+ (Var arr)+ (map (unitSlice 0) (init dims') ++ [DimFix $ last dims' - 1]) sOp $ Imp.Barrier Imp.FenceLocal compileGroupOp pat (Inner (SegOp (SegHist lvl space ops _ kbody))) = do@@ -531,7 +544,7 @@ \(bin, op_vs, do_op, HistOp dest_shape _ _ _ shape lam) -> do let bin' = pe64 bin dest_shape' = map pe64 $ shapeDims dest_shape- bin_in_bounds = inBounds (Slice (map DimFix [bin'])) dest_shape'+ bin_in_bounds = inBounds (Slice [DimFix bin']) dest_shape' bin_is = map Imp.le64 (init ltids) ++ [bin'] vs_params = takeLast (length op_vs) $ lambdaParams lam @@ -693,7 +706,7 @@ S.singleton $ arrayDims $ patElemType pe onStm (Let _ _ (Match _ cases defbody _)) = foldMap (onStms . bodyStms . caseBody) cases <> onStms (bodyStms defbody)- onStm (Let _ _ (DoLoop _ _ body)) =+ onStm (Let _ _ (Loop _ _ body)) = onStms (bodyStms body) onStm _ = mempty
src/Futhark/CodeGen/ImpGen/GPU/SegHist.hs view
@@ -47,7 +47,7 @@ import Futhark.CodeGen.ImpGen.GPU.SegRed (compileSegRed') import Futhark.Construct (fullSliceNum) import Futhark.IR.GPUMem-import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.MonadFreshNames import Futhark.Pass.ExplicitAllocations () import Futhark.Util (chunks, mapAccumLM, maxinum, splitFromEnd, takeLast)@@ -114,7 +114,7 @@ (elemType dest_t) subhistos_shape subhistos_mem- $ IxFun.iota+ $ LMAD.iota 0 $ map pe64 $ shapeDims subhistos_shape
src/Futhark/CodeGen/ImpGen/GPU/SegRed.hs view
@@ -56,7 +56,7 @@ import Futhark.CodeGen.ImpGen.GPU.Base import Futhark.Error import Futhark.IR.GPUMem-import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.Transform.Rename import Futhark.Util (chunks) import Futhark.Util.IntegralExp (divUp, quot, rem)@@ -94,7 +94,7 @@ let map_arrs = drop (segBinOpResults reds) $ patElems pat zipWithM_ (compileThreadResult space) map_arrs map_res - red_cont $ zip (map kernelResultSubExp red_res) $ repeat []+ red_cont $ map ((,[]) . kernelResultSubExp) red_res emit $ Imp.DebugPrint "" Nothing -- | Like 'compileSegRed', but where the body is a monadic action.@@ -142,9 +142,7 @@ MemArray pt shape _ (ArrayIn mem _) -> do let shape' = Shape [num_threads] <> shape sArray "red_arr" pt shape' mem $- IxFun.iota $- map pe64 $- shapeDims shape'+ LMAD.iota 0 (map pe64 $ shapeDims shape') _ -> do let pt = elemType $ paramType p shape = Shape [group_size]@@ -311,7 +309,7 @@ in_bounds = body $ \red_res -> sComment "save results to be reduced" $ do- let red_dests = zip (concat reds_arrs) $ repeat [ltid]+ let red_dests = map (,[ltid]) (concat reds_arrs) forM_ (zip red_dests red_res) $ \((d, d_is), (res, res_is)) -> copyDWIMFix d d_is res res_is @@ -721,7 +719,7 @@ copyDWIMFix acc (acc_is ++ vec_is) ne [] sUnless (local_tid .==. 0) reset_to_neutral _ -> pure ()-+ sOp $ Imp.ErrorSync Imp.FenceLocal pure (slugs_op_renamed, doTheReduction) reductionStageOne ::@@ -872,7 +870,7 @@ when (primType $ paramType p) $ copyDWIMFix arr [sExt64 local_tid] (Var $ paramName p) [] - sOp $ Imp.Barrier Imp.FenceLocal+ sOp $ Imp.ErrorSync Imp.FenceLocal sComment "reduce the per-group results" $ do groupReduce (sExt32 group_size) red_op_renamed red_arrs
src/Futhark/CodeGen/ImpGen/GPU/SegScan.hs view
@@ -3,6 +3,8 @@ -- the scan and the chosen abckend. module Futhark.CodeGen.ImpGen.GPU.SegScan (compileSegScan) where +import Control.Monad+import Data.Maybe import Futhark.CodeGen.ImpCode.GPU qualified as Imp import Futhark.CodeGen.ImpGen hiding (compileProg) import Futhark.CodeGen.ImpGen.GPU.Base@@ -35,9 +37,21 @@ (concatMap (bodyResult . lambdaBody) lams) } -canBeSinglePass :: [SegBinOp GPUMem] -> Maybe (SegBinOp GPUMem)-canBeSinglePass ops- | all ok ops =+bodyHas :: (Exp GPUMem -> Bool) -> Body GPUMem -> Bool+bodyHas f = any (f' . stmExp) . bodyStms+ where+ f' e+ | f e = True+ | otherwise = isNothing $ walkExpM walker e+ walker =+ identityWalker+ { walkOnBody = const $ guard . not . bodyHas f+ }++canBeSinglePass :: [SegBinOp GPUMem] -> KernelBody GPUMem -> Maybe (SegBinOp GPUMem)+canBeSinglePass ops kbody+ | all ok ops,+ not $ bodyHas freshArray (Body () (kernelBodyStms kbody) []) = Just $ combineScans ops | otherwise = Nothing@@ -45,6 +59,19 @@ ok op = segBinOpShape op == mempty && all primType (lambdaReturnType (segBinOpLambda op))+ && not (bodyHas isAssert (lambdaBody (segBinOpLambda op)))+ isAssert (BasicOp Assert {}) = True+ isAssert _ = False+ -- XXX: Currently single pass scans cannot handle construction of+ -- arrays in the kernel body (#2013), because of insufficient+ -- memory expansion. This can in principle be fixed.+ freshArray (BasicOp Manifest {}) = True+ freshArray (BasicOp Iota {}) = True+ freshArray (BasicOp Replicate {}) = True+ freshArray (BasicOp Scratch {}) = True+ freshArray (BasicOp Concat {}) = True+ freshArray (BasicOp ArrayLit {}) = True+ freshArray _ = False -- | Compile 'SegScan' instance to host-level code with calls to -- various kernels.@@ -60,7 +87,10 @@ target <- hostTarget <$> askEnv case target of CUDA- | Just scan' <- canBeSinglePass scans ->+ | Just scan' <- canBeSinglePass scans kbody ->+ SinglePass.compileSegScan pat lvl space scan' kbody+ HIP+ | Just scan' <- canBeSinglePass scans kbody -> SinglePass.compileSegScan pat lvl space scan' kbody _ -> TwoPass.compileSegScan pat lvl space scans kbody emit $ Imp.DebugPrint "" Nothing
src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs view
@@ -12,9 +12,9 @@ import Futhark.CodeGen.ImpGen import Futhark.CodeGen.ImpGen.GPU.Base import Futhark.IR.GPUMem-import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.Transform.Rename-import Futhark.Util (takeLast)+import Futhark.Util (mapAccumLM, takeLast) import Futhark.Util.IntegralExp (IntegralExp (mod, rem), divUp, quot) import Prelude hiding (mod, quot, rem) @@ -24,7 +24,7 @@ yParams scan = drop (length (segBinOpNeutral scan)) (lambdaParams (segBinOpLambda scan)) -alignTo :: IntegralExp a => a -> a -> a+alignTo :: (IntegralExp a) => a -> a -> a alignTo x a = (x `divUp` a) * a createLocalArrays ::@@ -41,7 +41,7 @@ maxTransposedArraySize = foldl1 sMax64 $ map (\ty -> workSize * primByteSize ty) types - warpSize :: Num a => a+ warpSize :: (Num a) => a warpSize = 32 maxWarpExchangeSize = foldl (\acc tySize -> alignTo acc tySize + tySize * fromInteger warpSize) 0 $@@ -49,18 +49,23 @@ maxLookbackSize = maxWarpExchangeSize + warpSize size = Imp.bytes $ maxLookbackSize `sMax64` prefixArraysSize `sMax64` maxTransposedArraySize - varTE :: TV Int64 -> TPrimExp Int64 VName- varTE = le64 . tvVar-- byteOffsets <-- mapM (fmap varTE . dPrimV "byte_offsets") $- scanl (\off tySize -> alignTo off tySize + pe64 groupSize * tySize) 0 $- map primByteSize types+ (_, byteOffsets) <-+ mapAccumLM+ ( \off tySize -> do+ off' <- dPrimVE "byte_offsets" $ alignTo off tySize + pe64 groupSize * tySize+ pure (off', off)+ )+ 0+ $ map primByteSize types - warpByteOffsets <-- mapM (fmap varTE . dPrimV "warp_byte_offset") $- scanl (\off tySize -> alignTo off tySize + warpSize * tySize) warpSize $- map primByteSize types+ (_, warpByteOffsets) <-+ mapAccumLM+ ( \off tySize -> do+ off' <- dPrimVE "warp_byte_offset" $ alignTo off tySize + warpSize * tySize+ pure (off', off)+ )+ warpSize+ $ map primByteSize types sComment "Allocate reused shared memeory" $ pure () @@ -85,7 +90,7 @@ ty (Shape [groupSize]) localMem- $ IxFun.iotaOffset off' [pe64 groupSize]+ $ LMAD.iota off' [pe64 groupSize] warpscan <- sArrayInMem "warpscan" int8 (Shape [constant (warpSize :: Int64)]) localMem warpExchanges <-@@ -96,7 +101,7 @@ ty (Shape [constant (warpSize :: Int64)]) localMem- $ IxFun.iotaOffset off' [warpSize]+ $ LMAD.iota off' [warpSize] pure (sharedId, transposedArrays, prefixArrays, warpscan, warpExchanges) @@ -226,7 +231,7 @@ primByteSize' = max 4 . primByteSize sumT' = foldl (\bytes typ -> bytes + primByteSize' typ) 0 tys `div` 4 maxT = maximum (map primByteSize tys)- m :: Num a => a+ m :: (Num a) => a m = fromIntegral $ max 1 $ min mem_constraint reg_constraint -- TODO: Make these constants dynamic by querying device k_reg = 64@@ -250,13 +255,13 @@ not_segmented_e = if segmented then false else true segment_size = last dims' - statusX, statusA, statusP :: Num a => a+ statusX, statusA, statusP :: (Num a) => a statusX = 0 statusA = 1 statusP = 2 - emit $ Imp.DebugPrint "Sequential elements per thread (m):" $ Just $ untyped (m :: Imp.TExp Int32)- emit $ Imp.DebugPrint "Memory constraint " $ Just $ untyped (fromIntegral mem_constraint :: Imp.TExp Int32)+ emit $ Imp.DebugPrint "Sequential elements per thread (m) " $ Just $ untyped (m :: Imp.TExp Int32)+ emit $ Imp.DebugPrint "Memory constraint" $ Just $ untyped (fromIntegral mem_constraint :: Imp.TExp Int32) emit $ Imp.DebugPrint "Register constraint" $ Just $ untyped (fromIntegral reg_constraint :: Imp.TExp Int32) emit $ Imp.DebugPrint "sumT'" $ Just $ untyped (fromIntegral sumT' :: Imp.TExp Int32) @@ -359,7 +364,7 @@ sFor "i" m $ \i -> do sharedIdx <- dPrimV "sharedIdx" $ kernelLocalThreadId constants * m + i copyDWIMFix priv [sExt64 i] (Var trans) [sExt64 $ tvExp sharedIdx]- sOp localBarrier+ sOp $ Imp.ErrorSync Imp.FenceLocal sComment "Per thread scan" $ do -- We don't need to touch the first element, so only m-1@@ -410,7 +415,7 @@ scanOp' prefixArrays - sOp localBarrier+ sOp $ Imp.ErrorSync Imp.FenceLocal let firstThread acc prefixes = copyDWIMFix (tvVar acc) [] (Var prefixes) [sExt64 (kernelGroupSize constants) - 1]@@ -547,6 +552,7 @@ \(prefix, ty, res) -> prefix <-- TPrimExp (toExp' ty res) sOp localFence )+ -- end sWhile -- end sIf sWhen (kernelLocalThreadId constants .==. 0) $ do@@ -640,3 +646,4 @@ sComment "If this is the last block, reset the dynamicId" $ sWhen (tvExp dynamicId .==. num_groups' - 1) $ copyDWIMFix globalId [0] (constant (0 :: Int32)) []+{-# NOINLINE compileSegScan #-}
src/Futhark/CodeGen/ImpGen/GPU/SegScan/TwoPass.hs view
@@ -12,7 +12,7 @@ import Futhark.CodeGen.ImpGen import Futhark.CodeGen.ImpGen.GPU.Base import Futhark.IR.GPUMem-import Futhark.IR.Mem.IxFun qualified as IxFun+import Futhark.IR.Mem.LMAD qualified as LMAD import Futhark.Transform.Rename import Futhark.Util (takeLast) import Futhark.Util.IntegralExp (divUp, quot, rem)@@ -42,9 +42,7 @@ let shape' = Shape [num_threads] <> shape arr <- lift . sArray "scan_arr" pt shape' mem $- IxFun.iota $- map pe64 $- shapeDims shape'+ LMAD.iota 0 (map pe64 $ shapeDims shape') pure (arr, []) _ -> do let pt = elemType $ paramType p
src/Futhark/CodeGen/ImpGen/GPU/ToOpenCL.hs view
@@ -5,6 +5,7 @@ module Futhark.CodeGen.ImpGen.GPU.ToOpenCL ( kernelsToOpenCL, kernelsToCUDA,+ kernelsToHIP, ) where @@ -26,13 +27,21 @@ import Futhark.CodeGen.ImpCode.OpenCL hiding (Program) import Futhark.CodeGen.ImpCode.OpenCL qualified as ImpOpenCL import Futhark.CodeGen.RTS.C (atomicsH, halfH)+import Futhark.CodeGen.RTS.CUDA (preludeCU)+import Futhark.CodeGen.RTS.OpenCL (copyCL, preludeCL, transposeCL) import Futhark.Error (compilerLimitationS) import Futhark.MonadFreshNames-import Futhark.Util (zEncodeText)+import Futhark.Util (mapAccumLM, zEncodeText)+import Futhark.Util.IntegralExp (rem) import Language.C.Quote.OpenCL qualified as C import Language.C.Syntax qualified as C import NeatInterpolation (untrimming)+import Prelude hiding (rem) +-- | Generate HIP host and device code.+kernelsToHIP :: ImpGPU.Program -> ImpOpenCL.Program+kernelsToHIP = translateGPU TargetHIP+ -- | Generate CUDA host and device code. kernelsToCUDA :: ImpGPU.Program -> ImpOpenCL.Program kernelsToCUDA = translateGPU TargetCUDA@@ -87,6 +96,7 @@ where genPrelude TargetOpenCL = genOpenClPrelude genPrelude TargetCUDA = const genCUDAPrelude+ genPrelude TargetHIP = const genHIPPrelude -- | Due to simplifications after kernel extraction, some threshold -- parameters may contain KernelPaths that reference threshold@@ -139,7 +149,7 @@ pointerQuals s = error $ "'" ++ s ++ "' is not an OpenCL kernel address space." -- In-kernel name and per-workgroup size in bytes.-type LocalMemoryUse = (VName, Count Bytes Exp)+type LocalMemoryUse = (VName, Count Bytes (TExp Int64)) data KernelState = KernelState { kernelLocalMemory :: [LocalMemoryUse],@@ -259,12 +269,12 @@ [C.cparam|__global typename int64_t *global_failure_args|] ] (f, cstate) =- genGPUCode env FunMode (functionBody device_func) failures $+ genGPUCode env FunMode (declsFirst $ functionBody device_func) failures $ GC.compileFun mempty params (fname, device_func) in (f, GC.compUserState cstate) else let (f, cstate) =- genGPUCode env FunMode (functionBody device_func) failures $+ genGPUCode env FunMode (declsFirst $ functionBody device_func) failures $ GC.compileVoidFun mempty (fname, device_func) in (f, GC.compUserState cstate) @@ -338,46 +348,20 @@ let (kernel_body, cstate) = genGPUCode env KernelMode (kernelBody kernel) failures . GC.collect $ do- body <- GC.collect $ GC.compileCode $ kernelBody kernel+ body <- GC.collect $ GC.compileCode $ declsFirst $ kernelBody kernel -- No need to free, as we cannot allocate memory in kernels. mapM_ GC.item =<< GC.declAllocatedMem mapM_ GC.item body kstate = GC.compUserState cstate - (local_memory_args, local_memory_params, local_memory_init) =- unzip3 . flip evalState (blankNameSource :: VNameSource) $- mapM (prepareLocalMemory target) $- kernelLocalMemory kstate-- -- CUDA has very strict restrictions on the number of blocks- -- permitted along the 'y' and 'z' dimensions of the grid- -- (1<<16). To work around this, we are going to dynamically- -- permute the block dimensions to move the largest one to the- -- 'x' dimension, which has a higher limit (1<<31). This means- -- we need to extend the kernel with extra parameters that- -- contain information about this permutation, but we only do- -- this for multidimensional kernels (at the time of this- -- writing, only transposes). The corresponding arguments are- -- added automatically in CCUDA.hs.- (perm_params, block_dim_init) =- case (target, num_groups) of- (TargetCUDA, [_, _, _]) ->- ( [ [C.cparam|const int block_dim0|],- [C.cparam|const int block_dim1|],- [C.cparam|const int block_dim2|]- ],- mempty- )- _ ->- ( mempty,- [ [C.citem|const int block_dim0 = 0;|],- [C.citem|const int block_dim1 = 1;|],- [C.citem|const int block_dim2 = 2;|]- ]- )- (const_defs, const_undefs) = unzip $ mapMaybe constDef $ kernelUses kernel + let (local_memory_bytes, (local_memory_params, local_memory_args, local_memory_init)) =+ second unzip3 $+ evalState+ (mapAccumLM prepareLocalMemory 0 (kernelLocalMemory kstate))+ blankNameSource+ let (use_params, unpack_params) = unzip $ mapMaybe useAsParam $ kernelUses kernel @@ -430,29 +414,38 @@ [C.cparam|__global typename int64_t *global_failure_args|] ] + (local_memory_param, prepare_local_memory) =+ case target of+ TargetOpenCL ->+ ( [[C.cparam|__local typename uint64_t* local_mem_aligned|]],+ [C.citems|__local unsigned char* local_mem = local_mem_aligned;|]+ )+ TargetCUDA -> (mempty, mempty)+ TargetHIP -> (mempty, mempty)+ params =- perm_params+ local_memory_param ++ take (numFailureParams safety) failure_params- ++ catMaybes local_memory_params+ ++ local_memory_params ++ use_params attribute =- case (target, mapM isConst $ kernelGroupSize kernel) of- (TargetOpenCL, Just [x, y, z]) ->- "__attribute__((reqd_work_group_size" <> prettyText (x, y, z) <> "))\n"- (TargetOpenCL, Just [x, y]) ->- "__attribute__((reqd_work_group_size" <> prettyText (x, y, 1 :: Int) <> "))\n"- (TargetOpenCL, Just [x]) ->- "__attribute__((reqd_work_group_size" <> prettyText (x, 1 :: Int, 1 :: Int) <> "))\n"- _ -> ""+ case mapM isConst $ kernelGroupSize kernel of+ Just [x, y, z] ->+ "FUTHARK_KERNEL_SIZED" <> prettyText (x, y, z) <> "\n"+ Just [x, y] ->+ "FUTHARK_KERNEL_SIZED" <> prettyText (x, y, 1 :: Int) <> "\n"+ Just [x] ->+ "FUTHARK_KERNEL_SIZED" <> prettyText (x, 1 :: Int, 1 :: Int) <> "\n"+ _ -> "FUTHARK_KERNEL\n" kernel_fun = attribute <> funcText- [C.cfun|__kernel void $id:name ($params:params) {+ [C.cfun|void $id:name ($params:params) { $items:(mconcat unpack_params) $items:const_defs- $items:block_dim_init+ $items:prepare_local_memory $items:local_memory_init $items:error_init $items:kernel_body@@ -468,29 +461,25 @@ clFailures = kernelFailures kstate } - -- The argument corresponding to the global_failure parameters is- -- added automatically later.- let args = catMaybes local_memory_args ++ kernelArgs kernel+ -- The error handling stuff is automatically added later.+ let args = local_memory_args ++ kernelArgs kernel - pure $ LaunchKernel safety name args num_groups group_size+ pure $ LaunchKernel safety name local_memory_bytes args num_groups group_size where name = kernelName kernel num_groups = kernelNumGroups kernel group_size = kernelGroupSize kernel+ padTo8 e = e + ((8 - (e `rem` 8)) `rem` 8) - prepareLocalMemory TargetOpenCL (mem, size) = do- mem_aligned <- newVName $ baseString mem ++ "_aligned"- pure- ( Just $ SharedMemoryKArg size,- Just [C.cparam|__local volatile typename int64_t* $id:mem_aligned|],- [C.citem|__local volatile unsigned char* restrict $id:mem = (__local volatile unsigned char*) $id:mem_aligned;|]- )- prepareLocalMemory TargetCUDA (mem, size) = do+ prepareLocalMemory (Count offset) (mem, Count size) = do param <- newVName $ baseString mem ++ "_offset"+ let offset' = offset + padTo8 size pure- ( Just $ SharedMemoryKArg size,- Just [C.cparam|uint $id:param|],- [C.citem|volatile $ty:defaultMemBlockType $id:mem = &shared_mem[$id:param];|]+ ( bytes offset',+ ( [C.cparam|typename int64_t $id:param|],+ ValueKArg (untyped offset) $ IntType Int64,+ [C.citem|volatile __local $ty:defaultMemBlockType $id:mem = &local_mem[$id:param];|]+ ) ) useAsParam :: KernelUse -> Maybe (C.Param, [C.BlockItem])@@ -529,156 +518,37 @@ undef = "#undef " <> idText (C.toIdent v mempty) constDef _ = Nothing -genOpenClPrelude :: S.Set PrimType -> T.Text-genOpenClPrelude ts =- [untrimming|-// Clang-based OpenCL implementations need this for 'static' to work.-#ifdef cl_clang_storage_class_specifiers-#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable-#endif-#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable-$enable_f64-// Some OpenCL programs dislike empty progams, or programs with no kernels.-// Declare a dummy kernel to ensure they remain our friends.-__kernel void dummy_kernel(__global unsigned char *dummy, int n)-{- const int thread_gid = get_global_id(0);- if (thread_gid >= n) return;-}--#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable-#pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable--typedef char int8_t;-typedef short int16_t;-typedef int int32_t;-typedef long int64_t;--typedef uchar uint8_t;-typedef ushort uint16_t;-typedef uint uint32_t;-typedef ulong uint64_t;--// NVIDIAs OpenCL does not create device-wide memory fences (see #734), so we-// use inline assembly if we detect we are on an NVIDIA GPU.-#ifdef cl_nv_pragma_unroll-static inline void mem_fence_global() {- asm("membar.gl;");-}-#else-static inline void mem_fence_global() {- mem_fence(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);-}-#endif-static inline void mem_fence_local() {- mem_fence(CLK_LOCAL_MEM_FENCE);-}-|]- <> halfH+commonPrelude :: T.Text+commonPrelude =+ halfH <> cScalarDefs <> atomicsH+ <> transposeCL+ <> copyCL++genOpenClPrelude :: S.Set PrimType -> T.Text+genOpenClPrelude ts =+ "#define FUTHARK_OPENCL\n"+ <> enable_f64+ <> preludeCL+ <> commonPrelude where enable_f64 | FloatType Float64 `S.member` ts =- [untrimming|- #pragma OPENCL EXTENSION cl_khr_fp64 : enable- #define FUTHARK_F64_ENABLED- |]+ [untrimming|#define FUTHARK_F64_ENABLED|] | otherwise = mempty genCUDAPrelude :: T.Text genCUDAPrelude =- [untrimming|-#define FUTHARK_CUDA-#define FUTHARK_F64_ENABLED--typedef char int8_t;-typedef short int16_t;-typedef int int32_t;-typedef long long int64_t;-typedef unsigned char uint8_t;-typedef unsigned short uint16_t;-typedef unsigned int uint32_t;-typedef unsigned long long uint64_t;-typedef uint8_t uchar;-typedef uint16_t ushort;-typedef uint32_t uint;-typedef uint64_t ulong;-#define __kernel extern "C" __global__ __launch_bounds__(MAX_THREADS_PER_BLOCK)-#define __global-#define __local-#define __private-#define __constant-#define __write_only-#define __read_only--static inline int get_group_id_fn(int block_dim0, int block_dim1, int block_dim2, int d) {- switch (d) {- case 0: d = block_dim0; break;- case 1: d = block_dim1; break;- case 2: d = block_dim2; break;- }- switch (d) {- case 0: return blockIdx.x;- case 1: return blockIdx.y;- case 2: return blockIdx.z;- default: return 0;- }-}-#define get_group_id(d) get_group_id_fn(block_dim0, block_dim1, block_dim2, d)--static inline int get_num_groups_fn(int block_dim0, int block_dim1, int block_dim2, int d) {- switch (d) {- case 0: d = block_dim0; break;- case 1: d = block_dim1; break;- case 2: d = block_dim2; break;- }- switch(d) {- case 0: return gridDim.x;- case 1: return gridDim.y;- case 2: return gridDim.z;- default: return 0;- }-}-#define get_num_groups(d) get_num_groups_fn(block_dim0, block_dim1, block_dim2, d)--static inline int get_local_id(int d) {- switch (d) {- case 0: return threadIdx.x;- case 1: return threadIdx.y;- case 2: return threadIdx.z;- default: return 0;- }-}--static inline int get_local_size(int d) {- switch (d) {- case 0: return blockDim.x;- case 1: return blockDim.y;- case 2: return blockDim.z;- default: return 0;- }-}--#define CLK_LOCAL_MEM_FENCE 1-#define CLK_GLOBAL_MEM_FENCE 2-static inline void barrier(int x) {- __syncthreads();-}-static inline void mem_fence_local() {- __threadfence_block();-}-static inline void mem_fence_global() {- __threadfence();-}+ "#define FUTHARK_CUDA\n"+ <> preludeCU+ <> commonPrelude -#define NAN (0.0/0.0)-#define INFINITY (1.0/0.0)-extern volatile __shared__ unsigned char shared_mem[];-|]- <> halfH- <> cScalarDefs- <> atomicsH+genHIPPrelude :: T.Text+genHIPPrelude =+ "#define FUTHARK_HIP\n"+ <> preludeCU+ <> commonPrelude compilePrimExp :: PrimExp KernelConst -> C.Exp compilePrimExp e = runIdentity $ GC.compilePrimExp compileKernelConst e@@ -733,6 +603,7 @@ GC.opsAllocate = cannotAllocate, GC.opsDeallocate = cannotDeallocate, GC.opsCopy = copyInKernel,+ GC.opsCopies = mempty, GC.opsFatMemory = False, GC.opsError = errorInKernel, GC.opsCall = callInKernel,@@ -763,7 +634,7 @@ kernelOps (LocalAlloc name size) = do name' <- newVName $ prettyString name ++ "_backing" GC.modifyUserState $ \s ->- s {kernelLocalMemory = (name', fmap untyped size) : kernelLocalMemory s}+ s {kernelLocalMemory = (name', size) : kernelLocalMemory s} GC.stm [C.cstm|$id:name = (__local unsigned char*) $id:name';|] kernelOps (ErrorSync f) = do label <- nextErrorLabel@@ -941,8 +812,12 @@ 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))) =- typesInExp e1 <> typesInExp e2 <> typesInExp e3+typesInCode (LMADCopy _ shape _ (Count (TPrimExp dstoffset), dststrides) _ (Count (TPrimExp srcoffset), srcstrides)) =+ foldMap (typesInExp . untyped . unCount) shape+ <> typesInExp dstoffset+ <> foldMap (typesInExp . untyped . unCount) dststrides+ <> typesInExp srcoffset+ <> foldMap (typesInExp . untyped . unCount) srcstrides typesInCode (Write _ (Count (TPrimExp e1)) t _ _ e2) = typesInExp e1 <> S.singleton t <> typesInExp e2 typesInCode (Read _ _ (Count (TPrimExp e1)) t _ _) =
− src/Futhark/CodeGen/ImpGen/GPU/Transpose.hs
@@ -1,425 +0,0 @@--- | Carefully optimised implementations of GPU transpositions.--- Written in ImpCode so we can compile it to both CUDA and OpenCL.-module Futhark.CodeGen.ImpGen.GPU.Transpose- ( TransposeType (..),- TransposeArgs,- mapTransposeKernel,- )-where---- See also Note [32-bit transpositions].--import Futhark.CodeGen.ImpCode.GPU-import Futhark.Util.IntegralExp (divUp, quot, rem)-import Prelude hiding (quot, rem)---- | Which form of transposition to generate code for.-data TransposeType- = TransposeNormal- | TransposeLowWidth- | TransposeLowHeight- | -- | For small arrays that do not- -- benefit from coalescing.- TransposeSmall- deriving (Eq, Ord, Show)---- | The types of the arguments accepted by a transposition function.-type TransposeArgs int =- ( VName,- TExp int,- VName,- TExp int,- TExp int,- TExp int,- TExp int,- TExp int,- TExp int,- VName- )--elemsPerThread :: Num a => a-elemsPerThread = 8--mapTranspose :: forall int. IntExp int => (PrimType, VName -> TExp int) -> TExp int -> TransposeArgs int -> PrimType -> TransposeType -> KernelCode-mapTranspose (int, le) block_dim args t kind =- case kind of- TransposeSmall ->- mconcat- [ get_ids,- dec our_array_offset $ le get_global_id_0 `quot` (height * width) * (height * width),- dec x_index $ (le get_global_id_0 `rem` (height * width)) `quot` height,- dec y_index $ le get_global_id_0 `rem` height,- DeclareScalar val Nonvolatile t,- dec odata_offset $- (basic_odata_offset `quot` primByteSize t) + le our_array_offset,- dec idata_offset $- (basic_idata_offset `quot` primByteSize t) + le our_array_offset,- dec index_in $ le y_index * width + le x_index,- dec index_out $ le x_index * height + le y_index,- when- (le get_global_id_0 .<. width * height * num_arrays)- ( mconcat- [ Read val idata (elements $ toOffset $ le idata_offset + le index_in) t (Space "global") Nonvolatile,- Write odata (elements $ toOffset $ le odata_offset + le index_out) t (Space "global") Nonvolatile (var val t)- ]- )- ]- TransposeLowWidth ->- mkTranspose $- lowDimBody- (le get_group_id_0 * block_dim + (le get_local_id_0 `quot` muly))- ( le get_group_id_1 * block_dim * muly- + le get_local_id_1- + (le get_local_id_0 `rem` muly) * block_dim- )- ( le get_group_id_1 * block_dim * muly- + le get_local_id_0- + (le get_local_id_1 `rem` muly) * block_dim- )- (le get_group_id_0 * block_dim + (le get_local_id_1 `quot` muly))- TransposeLowHeight ->- mkTranspose $- lowDimBody- ( le get_group_id_0 * block_dim * mulx- + le get_local_id_0- + (le get_local_id_1 `rem` mulx) * block_dim- )- (le get_group_id_1 * block_dim + (le get_local_id_1 `quot` mulx))- (le get_group_id_1 * block_dim + (le get_local_id_0 `quot` mulx))- ( le get_group_id_0 * block_dim * mulx- + le get_local_id_1- + (le get_local_id_0 `rem` mulx) * block_dim- )- TransposeNormal ->- mkTranspose $- mconcat- [ dec x_index $ le get_global_id_0,- dec y_index $ le get_group_id_1 * tile_dim + le get_local_id_1,- DeclareScalar val Nonvolatile t,- when (le x_index .<. width) $- For j (untyped (elemsPerThread :: TExp int)) $- let i = le j * (tile_dim `quot` elemsPerThread)- in mconcat- [ dec index_in $ (le y_index + i) * width + le x_index,- when (le y_index + i .<. height) $- mconcat- [ Read- val- idata- (elements $ toOffset $ le idata_offset + le index_in)- t- (Space "global")- Nonvolatile,- Write- block- ( elements $- toOffset $- (le get_local_id_1 + i) * (tile_dim + 1)- + le get_local_id_0- )- t- (Space "local")- Nonvolatile- (var val t)- ]- ],- Op $ Barrier FenceLocal,- SetScalar x_index $ untyped $ le get_group_id_1 * tile_dim + le get_local_id_0,- SetScalar y_index $ untyped $ le get_group_id_0 * tile_dim + le get_local_id_1,- when (le x_index .<. height) $- For j (untyped (elemsPerThread :: TExp int)) $- let i = le j * (tile_dim `quot` elemsPerThread)- in mconcat- [ dec index_out $ (le y_index + i) * height + le x_index,- when (le y_index + i .<. width) $- mconcat- [ Read- val- block- ( elements . toOffset $- le get_local_id_0 * (tile_dim + 1) + le get_local_id_1 + i- )- t- (Space "local")- Nonvolatile,- Write- odata- (elements $ toOffset $ le odata_offset + le index_out)- t- (Space "global")- Nonvolatile- (var val t)- ]- ]- ]- where- toOffset :: TExp int -> TExp Int64- toOffset = sExt64-- dec v (TPrimExp e) =- DeclareScalar v Nonvolatile (primExpType e) <> SetScalar v e- tile_dim = 2 * block_dim-- when a b = If a b mempty-- ( odata,- basic_odata_offset,- idata,- basic_idata_offset,- width,- height,- mulx,- muly,- num_arrays,- block- ) = args-- -- Be extremely careful when editing this list to ensure that- -- the names match up. Also, be careful that the tags on- -- these names do not conflict with the tags of the- -- surrounding code. We accomplish the latter by using very- -- low tags (normal variables start at least in the low- -- hundreds).- [ our_array_offset,- x_index,- y_index,- odata_offset,- idata_offset,- index_in,- index_out,- get_global_id_0,- get_local_id_0,- get_local_id_1,- get_local_size_0,- get_group_id_0,- get_group_id_1,- get_group_id_2,- j,- val- ] =- zipWith (flip VName) [30 ..] $- map- nameFromString- [ "our_array_offset",- "x_index",- "y_index",- "odata_offset",- "idata_offset",- "index_in",- "index_out",- "get_global_id_0",- "get_local_id_0",- "get_local_id_1",- "get_local_size_0",- "get_group_id_0",- "get_group_id_1",- "get_group_id_2",- "j",- "val"- ]-- get_ids =- mconcat- [ DeclareScalar get_local_id_0 Nonvolatile int,- Op $ GetLocalId get_local_id_0 0,- DeclareScalar get_local_id_1 Nonvolatile int,- Op $ GetLocalId get_local_id_1 1,- DeclareScalar get_group_id_0 Nonvolatile int,- Op $ GetGroupId get_group_id_0 0,- DeclareScalar get_group_id_1 Nonvolatile int,- Op $ GetGroupId get_group_id_1 1,- DeclareScalar get_group_id_2 Nonvolatile int,- Op $ GetGroupId get_group_id_2 2,- DeclareScalar get_local_size_0 Nonvolatile int,- Op $ GetLocalSize get_local_size_0 0,- DeclareScalar get_global_id_0 Nonvolatile int,- SetScalar get_global_id_0 $ untyped $ le get_group_id_0 * le get_local_size_0 + le get_local_id_0- ]-- mkTranspose body =- mconcat- [ get_ids,- dec our_array_offset $ le get_group_id_2 * width * height,- dec odata_offset $- (basic_odata_offset `quot` primByteSize t) + le our_array_offset,- dec idata_offset $- (basic_idata_offset `quot` primByteSize t) + le our_array_offset,- body- ]-- lowDimBody x_in_index y_in_index x_out_index y_out_index =- mconcat- [ dec x_index x_in_index,- dec y_index y_in_index,- DeclareScalar val Nonvolatile t,- dec index_in $ le y_index * width + le x_index,- when (le x_index .<. width .&&. le y_index .<. height) $- mconcat- [ Read- val- idata- (elements $ sExt64 $ le idata_offset + le index_in)- t- (Space "global")- Nonvolatile,- Write- block- (elements $ sExt64 $ le get_local_id_1 * (block_dim + 1) + le get_local_id_0)- t- (Space "local")- Nonvolatile- (var val t)- ],- Op $ Barrier FenceLocal,- SetScalar x_index $ untyped x_out_index,- SetScalar y_index $ untyped y_out_index,- dec index_out $ le y_index * height + le x_index,- when (le x_index .<. height .&&. le y_index .<. width) $- mconcat- [ Read- val- block- (elements $ toOffset $ le get_local_id_0 * (block_dim + 1) + le get_local_id_1)- t- (Space "local")- Nonvolatile,- Write- odata- (elements $ toOffset (le odata_offset + le index_out))- t- (Space "global")- Nonvolatile- (var val t)- ]- ]--lowDimKernelAndGroupSize ::- IntExp int =>- TExp int ->- TExp int ->- TExp int ->- TExp int ->- ([TExp int], [TExp int])-lowDimKernelAndGroupSize block_dim num_arrays x_elems y_elems =- ( [ x_elems `divUp` block_dim,- y_elems `divUp` block_dim,- num_arrays- ],- [block_dim, block_dim, 1]- )---- | Generate a transpose kernel. There is special support to handle--- input arrays with low width, low height, or both.------ Normally when transposing a @[2][n]@ array we would use a @FUT_BLOCK_DIM x--- FUT_BLOCK_DIM@ group to process a @[2][FUT_BLOCK_DIM]@ slice of the input--- array. This would mean that many of the threads in a group would be inactive.--- We try to remedy this by using a special kernel that will process a larger--- part of the input, by using more complex indexing. In our example, we could--- use all threads in a group if we are processing @(2/FUT_BLOCK_DIM)@ as large--- a slice of each rows per group. The variable @mulx@ contains this factor for--- the kernel to handle input arrays with low height.------ See issue #308 on GitHub for more details.------ These kernels are optimized to ensure all global reads and writes--- are coalesced, and to avoid bank conflicts in shared memory. Each--- thread group transposes a 2D tile of block_dim*2 by block_dim*2--- elements. The size of a thread group is block_dim/2 by--- block_dim*2, meaning that each thread will process 4 elements in a--- 2D tile. The shared memory array containing the 2D tile consists--- of block_dim*2 by block_dim*2+1 elements. Padding each row with--- an additional element prevents bank conflicts from occuring when--- the tile is accessed column-wise.-mapTransposeKernel ::- forall int.- IntExp int =>- (PrimType, VName -> TExp int) ->- String ->- Integer ->- TransposeArgs int ->- PrimType ->- TransposeType ->- Kernel-mapTransposeKernel (int, le) desc block_dim_int args t kind =- Kernel- { kernelBody =- DeclareMem block (Space "local")- <> Op (LocalAlloc block block_size)- <> mapTranspose (int, le) block_dim args t kind,- kernelUses = uses,- kernelNumGroups = map untyped num_groups,- kernelGroupSize = map (Left . untyped) group_size,- kernelName = nameFromString (name <> "_" <> prettyString int),- kernelFailureTolerant = True,- kernelCheckLocalMemory = False- }- where- pad2DBytes k = k * (k + 1) * primByteSize t- block_size :: Count Bytes (TExp Int64)- block_size =- bytes $- case kind of- TransposeSmall -> 1- -- Not used, but AMD's OpenCL does not like zero-size local- -- memory.- TransposeNormal -> fromInteger $ pad2DBytes $ 2 * block_dim_int- TransposeLowWidth -> fromInteger $ pad2DBytes block_dim_int- TransposeLowHeight -> fromInteger $ pad2DBytes block_dim_int- block_dim = fromInteger block_dim_int :: TExp int-- ( odata,- basic_odata_offset,- idata,- basic_idata_offset,- width,- height,- mulx,- muly,- num_arrays,- block- ) = args-- (num_groups, group_size) =- case kind of- TransposeSmall ->- ( [(num_arrays * width * height) `divUp` (block_dim * block_dim)],- [block_dim * block_dim]- )- TransposeLowWidth ->- lowDimKernelAndGroupSize block_dim num_arrays width $ height `divUp` muly- TransposeLowHeight ->- lowDimKernelAndGroupSize block_dim num_arrays (width `divUp` mulx) height- TransposeNormal ->- let actual_dim = block_dim * 2- in ( [ width `divUp` actual_dim,- height `divUp` actual_dim,- num_arrays- ],- [actual_dim, actual_dim `quot` elemsPerThread, 1]- )-- uses =- map- (`ScalarUse` IntType Int64)- ( namesToList $- mconcat $- map- freeIn- [ basic_odata_offset,- basic_idata_offset,- num_arrays,- width,- height,- mulx,- muly- ]- )- ++ map MemoryUse [odata, idata]-- name =- case kind of- TransposeSmall -> desc ++ "_small"- TransposeLowHeight -> desc ++ "_low_height"- TransposeLowWidth -> desc ++ "_low_width"- TransposeNormal -> desc
+ src/Futhark/CodeGen/ImpGen/HIP.hs view
@@ -0,0 +1,17 @@+-- | Code generation for ImpCode with HIP kernels.+module Futhark.CodeGen.ImpGen.HIP+ ( compileProg,+ Warnings,+ )+where++import Data.Bifunctor (second)+import Futhark.CodeGen.ImpCode.OpenCL+import Futhark.CodeGen.ImpGen.GPU+import Futhark.CodeGen.ImpGen.GPU.ToOpenCL+import Futhark.IR.GPUMem+import Futhark.MonadFreshNames++-- | Compile the program to ImpCode with HIP kernels.+compileProg :: (MonadFreshNames m) => Prog GPUMem -> m (Warnings, Program)+compileProg prog = second kernelsToHIP <$> compileProgHIP prog
src/Futhark/CodeGen/ImpGen/Multicore.hs view
@@ -189,7 +189,7 @@ -- | Compile the program. compileProg ::- MonadFreshNames m =>+ (MonadFreshNames m) => Prog MCMem -> m (Warnings, Imp.Definitions Imp.Multicore) compileProg =
src/Futhark/CodeGen/ImpGen/Multicore/Base.hs view
@@ -142,7 +142,7 @@ compileThreadResult _ _ RegTileReturns {} = compilerBugS "compileThreadResult: RegTileReturns unhandled." -freeParams :: FreeIn a => a -> MulticoreGen [Imp.Param]+freeParams :: (FreeIn a) => a -> MulticoreGen [Imp.Param] freeParams code = do let free = namesToList $ freeIn code ts <- mapM lookupType free
src/Futhark/CodeGen/ImpGen/Multicore/SegRed.hs view
@@ -32,7 +32,7 @@ let map_arrs = drop (segBinOpResults reds) $ patElems pat zipWithM_ (compileThreadResult space) map_arrs map_res - red_cont $ segBinOpChunks reds $ zip (map kernelResultSubExp red_res) $ repeat []+ red_cont $ segBinOpChunks reds $ map ((,[]) . kernelResultSubExp) red_res -- | Like 'compileSegRed', but where the body is a monadic action. compileSegRed' ::
src/Futhark/CodeGen/ImpGen/OpenCL.hs view
@@ -13,5 +13,5 @@ import Futhark.MonadFreshNames -- | Compile the program to ImpCode with OpenCL kernels.-compileProg :: MonadFreshNames m => Prog GPUMem -> m (Warnings, OpenCL.Program)+compileProg :: (MonadFreshNames m) => Prog GPUMem -> m (Warnings, OpenCL.Program) compileProg prog = second kernelsToOpenCL <$> compileProgOpenCL prog
src/Futhark/CodeGen/ImpGen/Sequential.hs view
@@ -13,7 +13,7 @@ import Futhark.MonadFreshNames -- | Compile a 'SeqMem' program to sequential imperative code.-compileProg :: MonadFreshNames m => Prog SeqMem -> m (ImpGen.Warnings, Imp.Program)+compileProg :: (MonadFreshNames m) => Prog SeqMem -> m (ImpGen.Warnings, Imp.Program) compileProg = ImpGen.compileProg () ops Imp.DefaultSpace where ops = ImpGen.defaultOperations opCompiler
− src/Futhark/CodeGen/ImpGen/Transpose.hs
@@ -1,219 +0,0 @@--- | A cache-oblivious sequential transposition for CPU execution.--- Generates a recursive function.-module Futhark.CodeGen.ImpGen.Transpose- ( mapTransposeFunction,- transposeArgs,- )-where--import Futhark.CodeGen.ImpCode-import Futhark.IR.Prop.Types-import Futhark.Util.IntegralExp-import Prelude hiding (quot)---- | Take well-typed arguments to the transpose function and produce--- the actual argument list.-transposeArgs ::- PrimType ->- VName ->- Count Bytes (TExp Int64) ->- VName ->- Count Bytes (TExp Int64) ->- TExp Int64 ->- TExp Int64 ->- TExp Int64 ->- [Arg]-transposeArgs pt destmem destoffset srcmem srcoffset num_arrays m n =- [ MemArg destmem,- ExpArg $ untyped $ unCount destoffset `quot` primByteSize pt,- MemArg srcmem,- ExpArg $ untyped $ unCount srcoffset `quot` primByteSize pt,- ExpArg $ untyped num_arrays,- ExpArg $ untyped m,- ExpArg $ untyped n,- ExpArg $ untyped (0 :: TExp Int64),- ExpArg $ untyped m,- ExpArg $ untyped (0 :: TExp Int64),- ExpArg $ untyped n- ]---- | We need to know the name of the function we are generating, as--- this function is recursive.-mapTransposeFunction :: Name -> PrimType -> Function op-mapTransposeFunction fname pt =- Function- Nothing- []- params- ( mconcat- [ dec r $ le64 re - le64 rb,- dec c $ le64 ce - le64 cb,- If (le64 num_arrays .==. 1) doTranspose doMapTranspose- ]- )- where- params =- [ memparam destmem,- intparam destoffset,- memparam srcmem,- intparam srcoffset,- intparam num_arrays,- intparam m,- intparam n,- intparam cb,- intparam ce,- intparam rb,- intparam re- ]-- memparam v = MemParam v DefaultSpace- intparam v = ScalarParam v int64-- [ destmem,- destoffset,- srcmem,- srcoffset,- num_arrays,- n,- m,- rb,- re,- cb,- ce,- r,- c,- i,- j,- val- ] =- zipWith- (VName . nameFromString)- [ "destmem",- "destoffset",- "srcmem",- "srcoffset",- "num_arrays",- "n",- "m",- "rb",- "re",- "cb",- "ce",- "r",- "c",- "i",- "j", -- local- "val"- ]- [0 ..]-- dec v e = DeclareScalar v Nonvolatile int32 <> SetScalar v (untyped e)-- naiveTranspose =- For j (untyped $ le64 c) $- For i (untyped $ le64 r) $- let i' = le64 i + le64 rb- j' = le64 j + le64 cb- in mconcat- [ DeclareScalar val Nonvolatile pt,- Read- val- srcmem- (elements $ le64 srcoffset + i' * le64 m + j')- pt- DefaultSpace- Nonvolatile,- Write- destmem- (elements $ le64 destoffset + j' * le64 n + i')- pt- DefaultSpace- Nonvolatile- (var val pt)- ]-- recArgs (cb', ce', rb', re') =- [ MemArg destmem,- ExpArg $ untyped $ le64 destoffset,- MemArg srcmem,- ExpArg $ untyped $ le64 srcoffset,- ExpArg $ untyped $ le64 num_arrays,- ExpArg $ untyped $ le64 m,- ExpArg $ untyped $ le64 n,- ExpArg $ untyped cb',- ExpArg $ untyped ce',- ExpArg $ untyped rb',- ExpArg $ untyped re'- ]-- cutoff = 64 -- arbitrary- doTranspose =- mconcat- [ If- (le64 r .<=. cutoff .&&. le64 c .<=. cutoff)- naiveTranspose- $ If- (le64 r .>=. le64 c)- ( Call- []- fname- ( recArgs- ( le64 cb,- le64 ce,- le64 rb,- le64 rb + (le64 r `quot` 2)- )- )- <> Call- []- fname- ( recArgs- ( le64 cb,- le64 ce,- le64 rb + le64 r `quot` 2,- le64 re- )- )- )- ( Call- []- fname- ( recArgs- ( le64 cb,- le64 cb + (le64 c `quot` 2),- le64 rb,- le64 re- )- )- <> Call- []- fname- ( recArgs- ( le64 cb + le64 c `quot` 2,- le64 ce,- le64 rb,- le64 re- )- )- )- ]-- doMapTranspose =- -- In the map-transpose case, we assume that cb==rb==0, ce==m,- -- re==n.- For i (untyped $ le64 num_arrays) $- Call- []- fname- [ MemArg destmem,- ExpArg $ untyped $ le64 destoffset + le64 i * le64 m * le64 n,- MemArg srcmem,- ExpArg $ untyped $ le64 srcoffset + le64 i * le64 m * le64 n,- ExpArg $ untyped (1 :: TExp Int64),- ExpArg $ untyped $ le64 m,- ExpArg $ untyped $ le64 n,- ExpArg $ untyped $ le64 cb,- ExpArg $ untyped $ le64 ce,- ExpArg $ untyped $ le64 rb,- ExpArg $ untyped $ le64 re- ]
src/Futhark/CodeGen/RTS/C.hs view
@@ -5,7 +5,10 @@ ( atomicsH, contextH, contextPrototypesH,+ copyH, freeListH,+ gpuH,+ gpuPrototypesH, halfH, lockH, scalarF16H,@@ -22,6 +25,7 @@ ispcUtilH, backendsOpenclH, backendsCudaH,+ backendsHipH, backendsCH, backendsMulticoreH, )@@ -48,6 +52,16 @@ freeListH = $(embedStringFile "rts/c/free_list.h") {-# NOINLINE freeListH #-} +-- | @rts/c/gpu.h@+gpuH :: T.Text+gpuH = $(embedStringFile "rts/c/gpu.h")+{-# NOINLINE gpuH #-}++-- | @rts/c/gpu_prototypes.h@+gpuPrototypesH :: T.Text+gpuPrototypesH = $(embedStringFile "rts/c/gpu_prototypes.h")+{-# NOINLINE gpuPrototypesH #-}+ -- | @rts/c/half.h@ halfH :: T.Text halfH = $(embedStringFile "rts/c/half.h")@@ -133,6 +147,11 @@ backendsCudaH = $(embedStringFile "rts/c/backends/cuda.h") {-# NOINLINE backendsCudaH #-} +-- | @rts/c/backends/hip.h@+backendsHipH :: T.Text+backendsHipH = $(embedStringFile "rts/c/backends/hip.h")+{-# NOINLINE backendsHipH #-}+ -- | @rts/c/backends/c.h@ backendsCH :: T.Text backendsCH = $(embedStringFile "rts/c/backends/c.h")@@ -142,3 +161,8 @@ backendsMulticoreH :: T.Text backendsMulticoreH = $(embedStringFile "rts/c/backends/multicore.h") {-# NOINLINE backendsMulticoreH #-}++-- | @rts/c/copy.h@+copyH :: T.Text+copyH = $(embedStringFile "rts/c/copy.h")+{-# NOINLINE copyH #-}
+ src/Futhark/CodeGen/RTS/CUDA.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE TemplateHaskell #-}++-- | Code snippets used by the CUDA backend.+module Futhark.CodeGen.RTS.CUDA (preludeCU) where++import Data.FileEmbed+import Data.Text qualified as T++-- | @rts/cuda/prelude.cu@+preludeCU :: T.Text+preludeCU = $(embedStringFile "rts/cuda/prelude.cu")+{-# NOINLINE preludeCU #-}
+ src/Futhark/CodeGen/RTS/OpenCL.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE TemplateHaskell #-}++-- | Code snippets used by the OpenCL and CUDA backends.+module Futhark.CodeGen.RTS.OpenCL+ ( transposeCL,+ preludeCL,+ copyCL,+ )+where++import Data.FileEmbed+import Data.Text qualified as T++-- | @rts/opencl/transpose.cl@+transposeCL :: T.Text+transposeCL = $(embedStringFile "rts/opencl/transpose.cl")+{-# NOINLINE transposeCL #-}++-- | @rts/opencl/prelude.cl@+preludeCL :: T.Text+preludeCL = $(embedStringFile "rts/opencl/prelude.cl")+{-# NOINLINE preludeCL #-}++-- | @rts/opencl/copy.cl@+copyCL :: T.Text+copyCL = $(embedStringFile "rts/opencl/copy.cl")+{-# NOINLINE copyCL #-}
src/Futhark/Compiler.hs view
@@ -151,7 +151,7 @@ -- | Throw an exception formatted with 'pprProgErrors' if there's -- an error. throwOnProgError ::- MonadError CompilerError m =>+ (MonadError CompilerError m) => Either (NE.NonEmpty ProgError) a -> m a throwOnProgError =@@ -187,7 +187,7 @@ fmap (map (first includeToString)) . throwOnProgError <=< liftIO . readUntypedLibrary . pure -orDie :: MonadIO m => FutharkM a -> m a+orDie :: (MonadIO m) => FutharkM a -> m a orDie m = liftIO $ do res <- runFutharkM m NotVerbose case res of@@ -197,11 +197,11 @@ Right res' -> pure res' -- | Not verbose, and terminates process on error.-readProgramOrDie :: MonadIO m => FilePath -> m (Warnings, Imports, VNameSource)+readProgramOrDie :: (MonadIO m) => FilePath -> m (Warnings, Imports, VNameSource) readProgramOrDie file = orDie $ readProgramFile mempty file -- | Not verbose, and terminates process on error.-readUntypedProgramOrDie :: MonadIO m => FilePath -> m [(String, E.UncheckedProg)]+readUntypedProgramOrDie :: (MonadIO m) => FilePath -> m [(String, E.UncheckedProg)] readUntypedProgramOrDie file = orDie $ readUntypedProgram file -- | Run an operation that produces warnings, and handle them
src/Futhark/Compiler/Program.hs view
@@ -96,7 +96,7 @@ type ReaderState = MVar (M.Map ImportName (Maybe (MVar UncheckedImport))) newState :: [ImportName] -> IO ReaderState-newState known = newMVar $ M.fromList $ zip known $ repeat Nothing+newState known = newMVar $ M.fromList $ map (,Nothing) known orderedImports :: [((ImportName, Loc), MVar UncheckedImport)] ->@@ -364,7 +364,7 @@ lpFilePaths = map lfPath . lpFiles unchangedImports ::- MonadIO m =>+ (MonadIO m) => VNameSource -> VFS -> [LoadedFile CheckedFile] ->@@ -398,7 +398,7 @@ -- | Find out how many of the old imports can be used. Here we are -- forced to be overly conservative, because our type checker -- enforces a linear ordering.-usableLoadedProg :: MonadIO m => LoadedProg -> VFS -> [FilePath] -> m LoadedProg+usableLoadedProg :: (MonadIO m) => LoadedProg -> VFS -> [FilePath] -> m LoadedProg usableLoadedProg (LoadedProg roots imports src) vfs new_roots | sort roots == sort new_roots = do (imports', src') <- unchangedImports src vfs imports
src/Futhark/Construct.hs view
@@ -134,7 +134,7 @@ -- value. For expressions that produce multiple values, see -- 'letTupExp'. letSubExp ::- MonadBuilder m =>+ (MonadBuilder m) => String -> Exp (Rep m) -> m SubExp@@ -143,7 +143,7 @@ -- | Like 'letSubExp', but returns a name rather than a t'SubExp'. letExp ::- MonadBuilder m =>+ (MonadBuilder m) => String -> Exp (Rep m) -> m VName@@ -161,7 +161,7 @@ -- is 'Update'd with the result of the expression. The name of the -- updated array is returned. letInPlace ::- MonadBuilder m =>+ (MonadBuilder m) => String -> VName -> Slice SubExp ->@@ -198,14 +198,14 @@ -- lead to any code generation. This is supposed to be used alongside -- the other monadic expression functions, such as 'eIf'. eSubExp ::- MonadBuilder m =>+ (MonadBuilder m) => SubExp -> m (Exp (Rep m)) eSubExp = pure . BasicOp . SubExp -- | Treat a parameter as a monadic expression. eParam ::- MonadBuilder m =>+ (MonadBuilder m) => Param t -> m (Exp (Rep m)) eParam = eSubExp . Var . paramName@@ -292,7 +292,7 @@ -- | Construct a v'BinOp' expression with the given operator. eBinOp ::- MonadBuilder m =>+ (MonadBuilder m) => BinOp -> m (Exp (Rep m)) -> m (Exp (Rep m)) ->@@ -304,7 +304,7 @@ -- | Construct a v'UnOp' expression with the given operator. eUnOp ::- MonadBuilder m =>+ (MonadBuilder m) => UnOp -> m (Exp (Rep m)) -> m (Exp (Rep m))@@ -312,7 +312,7 @@ -- | Construct a v'CmpOp' expression with the given comparison. eCmpOp ::- MonadBuilder m =>+ (MonadBuilder m) => CmpOp -> m (Exp (Rep m)) -> m (Exp (Rep m)) ->@@ -324,7 +324,7 @@ -- | Construct a v'ConvOp' expression with the given conversion. eConvOp ::- MonadBuilder m =>+ (MonadBuilder m) => ConvOp -> m (Exp (Rep m)) -> m (Exp (Rep m))@@ -335,7 +335,7 @@ -- | Construct a 'SSignum' expression. Fails if the provided -- expression is not of integer type. eSignum ::- MonadBuilder m =>+ (MonadBuilder m) => m (Exp (Rep m)) -> m (Exp (Rep m)) eSignum em = do@@ -350,7 +350,7 @@ -- | Copy a value. eCopy ::- MonadBuilder m =>+ (MonadBuilder m) => m (Exp (Rep m)) -> m (Exp (Rep m)) eCopy e = BasicOp . Replicate mempty <$> (letSubExp "copy_arg" =<< e)@@ -375,7 +375,7 @@ -- bind the body of the lambda. The expressions must produce only a -- single value each. eLambda ::- MonadBuilder m =>+ (MonadBuilder m) => Lambda (Rep m) -> [m (Exp (Rep m))] -> m [SubExpRes]@@ -386,7 +386,7 @@ bindParam param arg = letBindNames [paramName param] =<< arg -- | @eInBoundsForDim w i@ produces @0 <= i < w@.-eDimInBounds :: MonadBuilder m => m (Exp (Rep m)) -> m (Exp (Rep m)) -> m (Exp (Rep m))+eDimInBounds :: (MonadBuilder m) => m (Exp (Rep m)) -> m (Exp (Rep m)) -> m (Exp (Rep m)) eDimInBounds w i = eBinOp LogAnd@@ -395,7 +395,7 @@ -- | Are these indexes out-of-bounds for the array? eOutOfBounds ::- MonadBuilder m =>+ (MonadBuilder m) => VName -> [m (Exp (Rep m))] -> m (Exp (Rep m))@@ -418,14 +418,14 @@ foldBinOp LogOr (constant False) =<< zipWithM checkDim ws is' -- | The array element at this index.-eIndex :: MonadBuilder m => VName -> m (Exp (Rep m)) -> m (Exp (Rep m))+eIndex :: (MonadBuilder m) => VName -> m (Exp (Rep m)) -> m (Exp (Rep m)) eIndex arr i = do i' <- letSubExp "i" =<< i arr_t <- lookupType arr pure $ BasicOp $ Index arr $ fullSlice arr_t [DimFix i'] -- | The last element of the given array.-eLast :: MonadBuilder m => VName -> m (Exp (Rep m))+eLast :: (MonadBuilder m) => VName -> m (Exp (Rep m)) eLast arr = do n <- arraySize 0 <$> lookupType arr nm1 <-@@ -434,22 +434,22 @@ eIndex arr (eSubExp nm1) -- | Construct an unspecified value of the given type.-eBlank :: MonadBuilder m => Type -> m (Exp (Rep m))+eBlank :: (MonadBuilder m) => Type -> m (Exp (Rep m)) eBlank (Prim t) = pure $ BasicOp $ SubExp $ Constant $ blankPrimValue t eBlank (Array t shape _) = pure $ BasicOp $ Scratch t $ shapeDims shape eBlank Acc {} = error "eBlank: cannot create blank accumulator" eBlank Mem {} = error "eBlank: cannot create blank memory" -- | Sign-extend to the given integer type.-asIntS :: MonadBuilder m => IntType -> SubExp -> m SubExp+asIntS :: (MonadBuilder m) => IntType -> SubExp -> m SubExp asIntS = asInt SExt -- | Zero-extend to the given integer type.-asIntZ :: MonadBuilder m => IntType -> SubExp -> m SubExp+asIntZ :: (MonadBuilder m) => IntType -> SubExp -> m SubExp asIntZ = asInt ZExt asInt ::- MonadBuilder m =>+ (MonadBuilder m) => (IntType -> IntType -> ConvOp) -> IntType -> SubExp ->@@ -468,7 +468,7 @@ -- | Apply a binary operator to several subexpressions. A left-fold. foldBinOp ::- MonadBuilder m =>+ (MonadBuilder m) => BinOp -> SubExp -> [SubExp] ->@@ -479,13 +479,13 @@ eBinOp bop (pure $ BasicOp $ SubExp e) (foldBinOp bop ne es) -- | True if all operands are true.-eAll :: MonadBuilder m => [SubExp] -> m (Exp (Rep m))+eAll :: (MonadBuilder m) => [SubExp] -> m (Exp (Rep m)) eAll [] = pure $ BasicOp $ SubExp $ constant True eAll [x] = eSubExp x eAll (x : xs) = foldBinOp LogAnd x xs -- | True if any operand is true.-eAny :: MonadBuilder m => [SubExp] -> m (Exp (Rep m))+eAny :: (MonadBuilder m) => [SubExp] -> m (Exp (Rep m)) eAny [] = pure $ BasicOp $ SubExp $ constant False eAny [x] = eSubExp x eAny (x : xs) = foldBinOp LogOr x xs@@ -535,7 +535,7 @@ -- | Easily construct a t'Lambda' within a 'MonadBuilder'. See also -- 'runLambdaBuilder'. mkLambda ::- MonadBuilder m =>+ (MonadBuilder m) => [LParam (Rep m)] -> m Result -> m (Lambda (Rep m))@@ -566,7 +566,7 @@ fullSlice t $ map sliceDim (take n $ arrayDims t) ++ slice -- | Like 'fullSlice', but the dimensions are simply numeric.-fullSliceNum :: Num d => [d] -> [DimIndex d] -> Slice d+fullSliceNum :: (Num d) => [d] -> [DimIndex d] -> Slice d fullSliceNum dims slice = Slice $ slice ++ map (\d -> DimSlice 0 d 1) (drop (length slice) dims) @@ -581,12 +581,12 @@ allOfIt _ _ = False -- | Conveniently construct a body that contains no bindings.-resultBody :: Buildable rep => [SubExp] -> Body rep+resultBody :: (Buildable rep) => [SubExp] -> Body rep resultBody = mkBody mempty . subExpsRes -- | Conveniently construct a body that contains no bindings - but -- this time, monadically!-resultBodyM :: MonadBuilder m => [SubExp] -> m (Body (Rep m))+resultBodyM :: (MonadBuilder m) => [SubExp] -> m (Body (Rep m)) resultBodyM = mkBodyM mempty . subExpsRes -- | Evaluate the action, producing a body, then wrap it in all the@@ -603,7 +603,7 @@ -- value, then return the body constructed from the 'Result' and any -- statements added during the action, along the auxiliary value. buildBody ::- MonadBuilder m =>+ (MonadBuilder m) => m (Result, a) -> m (Body (Rep m), a) buildBody m = do@@ -613,7 +613,7 @@ -- | As 'buildBody', but there is no auxiliary value. buildBody_ ::- MonadBuilder m =>+ (MonadBuilder m) => m Result -> m (Body (Rep m)) buildBody_ m = fst <$> buildBody ((,()) <$> m)@@ -621,7 +621,7 @@ -- | Change that result where evaluation of the body would stop. Also -- change type annotations at branches. mapResult ::- Buildable rep =>+ (Buildable rep) => (Result -> Body rep) -> Body rep -> Body rep@@ -634,7 +634,7 @@ -- You should call this function within some monad that allows you to -- collect the actions performed (say, 'State'). instantiateShapes ::- Monad m =>+ (Monad m) => (Int -> m SubExp) -> [TypeBase ExtShape u] -> m [TypeBase Shape u]@@ -700,7 +700,7 @@ -- | Instances of this class can be converted to Futhark expressions -- within a 'MonadBuilder'. class ToExp a where- toExp :: MonadBuilder m => a -> m (Exp (Rep m))+ toExp :: (MonadBuilder m) => a -> m (Exp (Rep m)) instance ToExp SubExp where toExp = pure . BasicOp . SubExp
src/Futhark/Error.hs view
@@ -43,15 +43,15 @@ prettyCompilerError (InternalError s _ _) = pretty s -- | Raise an 'ExternalError' based on a prettyprinting result.-externalError :: MonadError CompilerError m => Doc AnsiStyle -> m a+externalError :: (MonadError CompilerError m) => Doc AnsiStyle -> m a externalError = throwError . ExternalError -- | Raise an 'ExternalError' based on a string.-externalErrorS :: MonadError CompilerError m => String -> m a+externalErrorS :: (MonadError CompilerError m) => String -> m a externalErrorS = externalError . pretty -- | Raise an v'InternalError' based on a prettyprinting result.-internalErrorS :: MonadError CompilerError m => String -> Doc AnsiStyle -> m a+internalErrorS :: (MonadError CompilerError m) => String -> Doc AnsiStyle -> m a internalErrorS s d = throwError $ InternalError (T.pack s) (p d) CompilerBug where
src/Futhark/IR/Aliases.hs view
@@ -157,7 +157,7 @@ where merge_dec = case e of- DoLoop merge _ body ->+ Loop merge _ body -> let mergeParamAliases fparam als | primType (paramType fparam) = Nothing@@ -179,7 +179,7 @@ maybeComment [] = Nothing maybeComment cs = Just $ PP.stack cs -resultAliasComment :: PP.Pretty a => a -> Names -> Maybe (PP.Doc ann)+resultAliasComment :: (PP.Pretty a) => a -> Names -> Maybe (PP.Doc ann) resultAliasComment name als = case namesToList als of [] -> Nothing@@ -191,7 +191,7 @@ <> " aliases " <> PP.commasep (map PP.pretty als') -removeAliases :: RephraseOp (OpC rep) => Rephraser Identity (Aliases rep) rep+removeAliases :: (RephraseOp (OpC rep)) => Rephraser Identity (Aliases rep) rep removeAliases = Rephraser { rephraseExpDec = pure . snd,@@ -215,42 +215,42 @@ -- | Remove alias information from a program. removeProgAliases ::- RephraseOp (OpC rep) =>+ (RephraseOp (OpC rep)) => Prog (Aliases rep) -> Prog rep removeProgAliases = runIdentity . rephraseProg removeAliases -- | Remove alias information from a function. removeFunDefAliases ::- RephraseOp (OpC rep) =>+ (RephraseOp (OpC rep)) => FunDef (Aliases rep) -> FunDef rep removeFunDefAliases = runIdentity . rephraseFunDef removeAliases -- | Remove alias information from an expression. removeExpAliases ::- RephraseOp (OpC rep) =>+ (RephraseOp (OpC rep)) => Exp (Aliases rep) -> Exp rep removeExpAliases = runIdentity . rephraseExp removeAliases -- | Remove alias information from statements. removeStmAliases ::- RephraseOp (OpC rep) =>+ (RephraseOp (OpC rep)) => Stm (Aliases rep) -> Stm rep removeStmAliases = runIdentity . rephraseStm removeAliases -- | Remove alias information from body. removeBodyAliases ::- RephraseOp (OpC rep) =>+ (RephraseOp (OpC rep)) => Body (Aliases rep) -> Body rep removeBodyAliases = runIdentity . rephraseBody removeAliases -- | Remove alias information from lambda. removeLambdaAliases ::- RephraseOp (OpC rep) =>+ (RephraseOp (OpC rep)) => Lambda (Aliases rep) -> Lambda rep removeLambdaAliases = runIdentity . rephraseLambda removeAliases@@ -296,7 +296,7 @@ -- in scope outside of it. Note that this does *not* include aliases -- of results that are not bound in the statements! mkBodyAliasing ::- Aliased rep =>+ (Aliased rep) => Stms rep -> Result -> BodyAliasing@@ -313,7 +313,7 @@ -- | The aliases of the result and everything consumed in the given -- statements. mkStmsAliases ::- Aliased rep =>+ (Aliased rep) => Stms rep -> Result -> ([Names], Names)@@ -338,7 +338,7 @@ ) -- | The variables consumed in these statements.-consumedInStms :: Aliased rep => Stms rep -> Names+consumedInStms :: (Aliased rep) => Stms rep -> Names consumedInStms = snd . flip mkStmsAliases [] -- | A helper function for computing the aliases of a sequence of@@ -348,7 +348,7 @@ -- state. The main thing this function provides is proper handling of -- transitivity and "reverse" aliases. trackAliases ::- Aliased rep =>+ (Aliased rep) => AliasesAndConsumed -> Stm rep -> AliasesAndConsumed@@ -420,7 +420,7 @@ class CanBeAliased op where -- | Add aliases to this op. addOpAliases ::- AliasableRep rep => AliasTable -> op rep -> op (Aliases rep)+ (AliasableRep rep) => AliasTable -> op rep -> op (Aliases rep) instance CanBeAliased NoOp where addOpAliases _ NoOp = NoOp
src/Futhark/IR/GPU/Op.hs view
@@ -230,7 +230,7 @@ opMetrics CmpSizeLe {} = seen "CmpSizeLe" opMetrics CalcNumGroups {} = seen "CalcNumGroups" -typeCheckSizeOp :: TC.Checkable rep => SizeOp -> TC.TypeM rep ()+typeCheckSizeOp :: (TC.Checkable rep) => SizeOp -> TC.TypeM rep () typeCheckSizeOp GetSize {} = pure () typeCheckSizeOp GetSizeMax {} = pure () typeCheckSizeOp (CmpSizeLe _ _ x) = TC.require [Prim int64] x@@ -251,7 +251,7 @@ -- | A helper for defining 'TraverseOpStms'. traverseHostOpStms ::- Monad m =>+ (Monad m) => OpStmsTraverser m (op rep) rep -> OpStmsTraverser m (HostOp op rep) rep traverseHostOpStms _ f (SegOp segop) = SegOp <$> traverseSegOpStms f segop@@ -291,7 +291,7 @@ -- transfer scalars to device. SQ.null (bodyStms body) && all ((== 0) . arrayRank) types -instance TypedOp (op rep) => TypedOp (HostOp op rep) 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@@ -315,13 +315,13 @@ freeIn' (SizeOp op) = freeIn' op freeIn' (GPUBody ts body) = freeIn' ts <> freeIn' body -instance CanBeAliased op => CanBeAliased (HostOp op) where+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 -instance CanBeWise op => CanBeWise (HostOp op) where+instance (CanBeWise op) => CanBeWise (HostOp op) where addOpWisdom (SegOp op) = SegOp $ addOpWisdom op addOpWisdom (OtherOp op) = OtherOp $ addOpWisdom op addOpWisdom (SizeOp op) = SizeOp op@@ -345,19 +345,19 @@ opMetrics (SizeOp op) = opMetrics op opMetrics (GPUBody _ body) = inside "GPUBody" $ bodyMetrics body -instance RephraseOp op => RephraseOp (HostOp op) where+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 :: (TC.Checkable rep) => KernelGrid -> TC.TypeM rep () checkGrid grid = do TC.require [Prim int64] $ unCount $ gridNumGroups grid TC.require [Prim int64] $ unCount $ gridGroupSize grid checkSegLevel ::- TC.Checkable rep =>+ (TC.Checkable rep) => Maybe SegLevel -> SegLevel -> TC.TypeM rep ()@@ -381,7 +381,7 @@ mapM_ checkGrid grid typeCheckHostOp ::- TC.Checkable rep =>+ (TC.Checkable rep) => (SegLevel -> Op (Aliases rep) -> TC.TypeM rep ()) -> Maybe SegLevel -> (op (Aliases rep) -> TC.TypeM rep ()) ->
src/Futhark/IR/GPU/Simplify.hs view
@@ -71,7 +71,7 @@ keepOnGPU _ _ = keepExpOnGPU . stmExp keepExpOnGPU (BasicOp Index {}) = True keepExpOnGPU (BasicOp (ArrayLit _ t)) | primType t = True- keepExpOnGPU DoLoop {} = True+ keepExpOnGPU Loop {} = True keepExpOnGPU _ = False instance TraverseOpStms (Wise GPU) where@@ -130,7 +130,7 @@ -- Update with a slice of that array. This matters when the arrays -- are far away (on the GPU, say), because it avoids a copy of the -- scalar to and from the host.-removeScalarCopy :: BuilderOps rep => TopDownRuleBasicOp rep+removeScalarCopy :: (BuilderOps rep) => TopDownRuleBasicOp rep removeScalarCopy vtable pat aux (Update safety arr_x (Slice slice_x) (Var v)) | Just _ <- sliceIndices (Slice slice_x), Just (Index arr_y (Slice slice_y), cs_y) <- ST.lookupBasicOp v vtable,
src/Futhark/IR/GPUMem.hs view
@@ -90,11 +90,11 @@ traverseOpStms = traverseMemOpStms (traverseHostOpStms (const pure)) simplifyProg :: Prog GPUMem -> PassM (Prog GPUMem)-simplifyProg = simplifyProgGeneric simpleGPUMem+simplifyProg = simplifyProgGeneric memRuleBook simpleGPUMem simplifyStms :: (HasScope GPUMem m, MonadFreshNames m) => Stms GPUMem -> m (Stms GPUMem)-simplifyStms = simplifyStmsGeneric simpleGPUMem+simplifyStms = simplifyStmsGeneric memRuleBook simpleGPUMem simpleGPUMem :: Engine.SimpleOps GPUMem simpleGPUMem =
src/Futhark/IR/MC/Op.hs view
@@ -50,7 +50,7 @@ deriving (Eq, Ord, Show) traverseMCOpStms ::- Monad m =>+ (Monad m) => OpStmsTraverser m (op rep) rep -> OpStmsTraverser m (MCOp op rep) rep traverseMCOpStms _ f (ParOp par_op op) =@@ -78,7 +78,7 @@ cheapOp (ParOp _ op) = cheapOp op cheapOp (OtherOp op) = cheapOp op -instance TypedOp (op rep) => TypedOp (MCOp op rep) where+instance (TypedOp (op rep)) => TypedOp (MCOp op rep) where opType (ParOp _ op) = opType op opType (OtherOp op) = opType op @@ -89,13 +89,13 @@ consumedInOp (ParOp _ op) = consumedInOp op consumedInOp (OtherOp op) = consumedInOp op -instance CanBeAliased op => CanBeAliased (MCOp op) where+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 -instance CanBeWise op => CanBeWise (MCOp op) where+instance (CanBeWise op) => CanBeWise (MCOp op) where addOpWisdom (ParOp par_op op) = ParOp (addOpWisdom <$> par_op) (addOpWisdom op) addOpWisdom (OtherOp op) =@@ -118,13 +118,13 @@ opMetrics (ParOp par_op op) = opMetrics par_op >> opMetrics op opMetrics (OtherOp op) = opMetrics op -instance RephraseOp op => RephraseOp (MCOp op) where+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 =>+ (TC.Checkable rep) => (op (Aliases rep) -> TC.TypeM rep ()) -> MCOp op (Aliases rep) -> TC.TypeM rep ()
src/Futhark/IR/MCMem.hs view
@@ -82,7 +82,7 @@ traverseOpStms = traverseMemOpStms (traverseMCOpStms (const pure)) simplifyProg :: Prog MCMem -> PassM (Prog MCMem)-simplifyProg = simplifyProgGeneric simpleMCMem+simplifyProg = simplifyProgGeneric memRuleBook simpleMCMem simpleMCMem :: Engine.SimpleOps MCMem simpleMCMem =
src/Futhark/IR/Mem.hs view
@@ -64,6 +64,7 @@ MemReturn (..), IxFun, ExtIxFun,+ LMAD, isStaticIxFun, ExpReturns, BodyReturns,@@ -156,7 +157,7 @@ instance HasLetDecMem LetDecMem where letDecMem = id -instance HasLetDecMem b => HasLetDecMem (a, b) where+instance (HasLetDecMem b) => HasLetDecMem (a, b) where letDecMem = letDecMem . snd type Mem rep inner =@@ -186,70 +187,73 @@ -- | A helper for defining 'TraverseOpStms'. traverseMemOpStms ::- Monad m =>+ (Monad m) => 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 RephraseOp inner => RephraseOp (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+instance (FreeIn (inner rep)) => FreeIn (MemOp inner rep) where freeIn' (Alloc size _) = freeIn' size freeIn' (Inner k) = freeIn' k -instance TypedOp (inner rep) => TypedOp (MemOp inner rep) where+instance (TypedOp (inner rep)) => TypedOp (MemOp inner rep) where opType (Alloc _ space) = pure [Mem space] opType (Inner k) = opType k -instance AliasedOp (inner rep) => AliasedOp (MemOp inner rep) where+instance (AliasedOp (inner rep)) => AliasedOp (MemOp inner rep) where opAliases Alloc {} = [mempty] opAliases (Inner k) = opAliases k consumedInOp Alloc {} = mempty consumedInOp (Inner k) = consumedInOp k -instance CanBeAliased inner => CanBeAliased (MemOp inner) where+instance (CanBeAliased inner) => CanBeAliased (MemOp inner) where addOpAliases _ (Alloc se space) = Alloc se space addOpAliases aliases (Inner k) = Inner $ addOpAliases aliases k -instance Rename (inner rep) => Rename (MemOp inner rep) 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 rep) => Substitute (MemOp inner rep) 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 rep) => PP.Pretty (MemOp inner rep) 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 rep) => OpMetrics (MemOp inner rep) where+instance (OpMetrics (inner rep)) => OpMetrics (MemOp inner rep) where opMetrics Alloc {} = seen "Alloc" opMetrics (Inner k) = opMetrics k -instance IsOp (inner rep) => IsOp (MemOp inner rep) 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 cheapOp (Inner k) = cheapOp k cheapOp Alloc {} = True -instance CanBeWise inner => CanBeWise (MemOp inner) where+instance (CanBeWise inner) => CanBeWise (MemOp inner) where addOpWisdom (Alloc size space) = Alloc size space addOpWisdom (Inner k) = Inner $ addOpWisdom k -instance ST.IndexOp (inner rep) => ST.IndexOp (MemOp inner rep) 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 -- | The index function representation used for memory annotations. type IxFun = IxFun.IxFun (TPrimExp Int64 VName) +-- | The LMAD representation used for memory annotations.+type LMAD = IxFun.LMAD (TPrimExp Int64 VName)+ -- | An index function that may contain existential variables. type ExtIxFun = IxFun.IxFun (TPrimExp Int64 (Ext VName)) @@ -273,22 +277,22 @@ type MemBound u = MemInfo SubExp u MemBind -instance FixExt ret => DeclExtTyped (MemInfo ExtSize Uniqueness ret) where+instance (FixExt ret) => DeclExtTyped (MemInfo ExtSize Uniqueness ret) where declExtTypeOf (MemPrim pt) = Prim pt declExtTypeOf (MemMem space) = Mem space declExtTypeOf (MemArray pt shape u _) = Array pt shape u declExtTypeOf (MemAcc acc ispace ts u) = Acc acc ispace ts u -instance FixExt ret => ExtTyped (MemInfo ExtSize Uniqueness ret) where+instance (FixExt ret) => ExtTyped (MemInfo ExtSize Uniqueness ret) where extTypeOf = fromDecl . declExtTypeOf -instance FixExt ret => ExtTyped (MemInfo ExtSize NoUniqueness ret) where+instance (FixExt ret) => ExtTyped (MemInfo ExtSize NoUniqueness ret) where extTypeOf (MemPrim pt) = Prim pt extTypeOf (MemMem space) = Mem space extTypeOf (MemArray pt shape u _) = Array pt shape u extTypeOf (MemAcc acc ispace ts u) = Acc acc ispace ts u -instance FixExt ret => FixExt (MemInfo ExtSize u ret) where+instance (FixExt ret) => FixExt (MemInfo ExtSize u ret) where fixExt _ _ (MemPrim pt) = MemPrim pt fixExt _ _ (MemMem space) = MemMem space fixExt i se (MemArray pt shape u ret) =@@ -338,13 +342,13 @@ rename = substituteRename simplifyIxFun ::- Engine.SimplifiableRep rep =>+ (Engine.SimplifiableRep rep) => IxFun -> Engine.SimpleM rep IxFun simplifyIxFun = traverse $ fmap isInt64 . simplifyPrimExp . untyped simplifyExtIxFun ::- Engine.SimplifiableRep rep =>+ (Engine.SimplifiableRep rep) => ExtIxFun -> Engine.SimpleM rep ExtIxFun simplifyExtIxFun = traverse $ fmap isInt64 . simplifyExtPrimExp . untyped@@ -668,7 +672,7 @@ ) matchReturnType ::- PP.Pretty u =>+ (PP.Pretty u) => [MemInfo ExtSize u MemReturn] -> [SubExp] -> [MemInfo SubExp NoUniqueness MemBind] ->@@ -817,7 +821,7 @@ matches _ _ _ _ = False varMemInfo ::- Mem rep inner =>+ (Mem rep inner) => VName -> TC.TypeM rep (MemInfo SubExp NoUniqueness MemBind) varMemInfo name = do@@ -829,7 +833,7 @@ LParamName summary -> pure summary IndexName it -> pure $ MemPrim $ IntType it -nameInfoToMemInfo :: Mem rep inner => NameInfo rep -> MemBound NoUniqueness+nameInfoToMemInfo :: (Mem rep inner) => NameInfo rep -> MemBound NoUniqueness nameInfoToMemInfo info = case info of FParamName summary -> noUniquenessReturns summary@@ -883,7 +887,7 @@ <> prettyText summary checkMemInfo ::- TC.Checkable rep =>+ (TC.Checkable rep) => VName -> MemInfo SubExp u MemBind -> TC.TypeM rep ()@@ -1053,13 +1057,13 @@ Just . pure . varInfoToExpReturns <$> sliceInfo v slice expReturns (BasicOp (Update _ v _ _)) = Just . pure <$> varReturns v-expReturns (BasicOp (FlatIndex v slice)) = do- fmap (pure . varInfoToExpReturns) <$> flatSliceInfo v slice+expReturns (BasicOp (FlatIndex v slice)) =+ Just . pure . varInfoToExpReturns <$> flatSliceInfo v slice expReturns (BasicOp (FlatUpdate v _ _)) = Just . pure <$> varReturns v expReturns (BasicOp op) = Just . extReturns . staticShapes <$> basicOpType op-expReturns e@(DoLoop merge _ _) = do+expReturns e@(Loop merge _ _) = do t <- expExtType e Just <$> zipWithM typeWithDec t (map fst merge) where@@ -1122,20 +1126,20 @@ (Monad m, HasScope rep m, Mem rep inner) => VName -> FlatSlice SubExp ->- m (Maybe (MemInfo SubExp NoUniqueness MemBind))+ m (MemInfo SubExp NoUniqueness MemBind) flatSliceInfo v slice@(FlatSlice offset idxs) = do (et, _, mem, ixfun) <- arrayVarReturns v map (fmap pe64) idxs & FlatSlice (pe64 offset) & IxFun.flatSlice ixfun- & fmap (MemArray et (Shape (flatSliceDims slice)) NoUniqueness . ArrayIn mem)+ & MemArray et (Shape (flatSliceDims slice)) NoUniqueness . ArrayIn mem & pure -class IsOp op => OpReturns op where+class (IsOp op) => OpReturns op where opReturns :: (Mem rep inner, Monad m, HasScope rep m) => op -> m [ExpReturns] opReturns op = extReturns <$> opType op -instance OpReturns (inner rep) => OpReturns (MemOp inner rep) where+instance (OpReturns (inner rep)) => OpReturns (MemOp inner rep) where opReturns (Alloc _ space) = pure [MemMem space] opReturns (Inner op) = opReturns op @@ -1143,7 +1147,7 @@ opReturns NoOp = pure [] applyFunReturns ::- Typed dec =>+ (Typed dec) => [FunReturns] -> [Param dec] -> [(SubExp, Type)] ->
src/Futhark/IR/Mem/Interval.hs view
@@ -30,7 +30,7 @@ instance FreeIn Interval where freeIn' (Interval lb ne st) = freeIn' lb <> freeIn' ne <> freeIn' st -distributeOffset :: MonadFail m => AlgSimplify.SofP -> [Interval] -> m [Interval]+distributeOffset :: (MonadFail m) => AlgSimplify.SofP -> [Interval] -> m [Interval] distributeOffset [] interval = pure interval distributeOffset offset [] = fail $ "Cannot distribute offset " <> show offset <> " across empty interval" distributeOffset offset [Interval lb ne 1] = pure [Interval (lb + TPrimExp (AlgSimplify.sumToExp offset)) ne 1]
src/Futhark/IR/Mem/IxFun.hs view
@@ -10,45 +10,41 @@ index, mkExistential, iota,- iotaOffset, permute, reshape, coerce, slice, flatSlice,- rebase,+ expand, shape,- permutation, rank, isDirect, substituteInIxFun, substituteInLMAD, existentialize, closeEnough,- equivalent,- permuteInv, disjoint, disjoint2, disjoint3,- dynamicEqualsLMAD, ) where import Control.Category import Control.Monad import Control.Monad.State-import Data.List (sort, zip4) import Data.Map.Strict qualified as M import Data.Traversable import Futhark.Analysis.PrimExp import Futhark.Analysis.PrimExp.Convert import Futhark.IR.Mem.LMAD hiding- ( flatSlice,+ ( equivalent,+ flatSlice, index, iota,+ isDirect, mkExistential,- permutation, permute,+ rank, reshape, shape, slice,@@ -83,20 +79,20 @@ } deriving (Show, Eq) -instance Pretty num => Pretty (IxFun num) where+instance (Pretty num) => Pretty (IxFun num) where pretty (IxFun lmad oshp) = braces . semistack $ [ "base:" <+> brackets (commasep $ map pretty oshp), "LMAD:" <+> pretty lmad ] -instance Substitute num => Substitute (IxFun num) where+instance (Substitute num) => Substitute (IxFun num) where substituteNames substs = fmap $ substituteNames substs -instance Substitute num => Rename (IxFun num) where+instance (Substitute num) => Rename (IxFun num) where rename = substituteRename -instance FreeIn num => FreeIn (IxFun num) where+instance (FreeIn num) => FreeIn (IxFun num) where freeIn' = foldMap freeIn' instance Functor IxFun where@@ -113,7 +109,7 @@ -- | Substitute a name with a PrimExp in an index function. substituteInIxFun ::- Ord a =>+ (Ord a) => M.Map a (TPrimExp t a) -> IxFun (TPrimExp t a) -> IxFun (TPrimExp t a)@@ -131,24 +127,13 @@ in length oshp == length dims && offset == 0 && all- (\(LMADDim s n p, m, d, se) -> s == se && n == d && p == m)- (zip4 dims [0 .. length dims - 1] oshp strides_expected)---- | Does the index function have an ascending permutation?-hasContiguousPerm :: IxFun num -> Bool-hasContiguousPerm (IxFun lmad _) =- let perm = LMAD.permutation lmad- in perm == sort perm+ (\(LMADDim s n, d, se) -> s == se && n == d)+ (zip3 dims oshp strides_expected) -- | The index space of the index function. This is the same as the -- shape of arrays that the index function supports. shape :: (Eq num, IntegralExp num) => IxFun num -> Shape num-shape (IxFun lmad _) =- permuteFwd (LMAD.permutation lmad) $ LMAD.shapeBase lmad---- | The permutation of the first LMAD of the index function.-permutation :: IxFun num -> Permutation-permutation = map LMAD.ldPerm . LMAD.dims . ixfunLMAD+shape = LMAD.shape . ixfunLMAD -- | Compute the flat memory index for a complete set @inds@ of array indices -- and a certain element size @elem_size@.@@ -160,25 +145,24 @@ index = LMAD.index . ixfunLMAD -- | iota with offset.-iotaOffset :: IntegralExp num => num -> Shape num -> IxFun num+iotaOffset :: (IntegralExp num) => num -> Shape num -> IxFun num iotaOffset o ns = IxFun (LMAD.iota o ns) ns -- | iota.-iota :: IntegralExp num => Shape num -> IxFun num+iota :: (IntegralExp num) => Shape num -> IxFun num iota = iotaOffset 0 -- | Create a single-LMAD index function that is -- existential in everything, with the provided permutation.-mkExistential :: Int -> [Int] -> Int -> IxFun (Ext a)-mkExistential basis_rank perm start =- IxFun (LMAD.mkExistential perm start) basis+mkExistential :: Int -> Int -> Int -> IxFun (Ext a)+mkExistential basis_rank lmad_rank start =+ IxFun (LMAD.mkExistential lmad_rank start) basis where- basis = take basis_rank $ map Ext [start + 1 + dims_rank * 2 ..]- dims_rank = length perm+ basis = take basis_rank $ map Ext [start + 1 + lmad_rank * 2 ..] -- | Permute dimensions. permute ::- IntegralExp num =>+ (IntegralExp num) => IxFun num -> Permutation -> IxFun num@@ -202,10 +186,8 @@ (Eq num, IntegralExp num) => IxFun num -> FlatSlice num ->- Maybe (IxFun num)-flatSlice (IxFun lmad oshp) s = do- lmad' <- LMAD.flatSlice lmad s- Just $ IxFun lmad' oshp+ IxFun num+flatSlice (IxFun lmad oshp) s = IxFun (LMAD.flatSlice lmad s) oshp -- | Reshape an index function. --@@ -243,89 +225,21 @@ onDim ld d = ld {ldShape = d} -- | The number of dimensions in the domain of the input function.-rank :: IntegralExp num => IxFun num -> Int+rank :: (IntegralExp num) => IxFun num -> Int rank (IxFun (LMAD _ sss) _) = length sss --- | Essentially @rebase new_base ixfun = ixfun o new_base@--- Core soundness condition: @base ixfun == shape new_base@--- Handles the case where a rebase operation can stay within m + n - 1 LMADs,--- where m is the number of LMADs in the index function, and n is the number of--- LMADs in the new base. If both index function have only on LMAD, this means--- that we stay within the single-LMAD domain.------ We can often stay in that domain if the original ixfun is essentially a--- slice, e.g. `x[i, (k1,m,s1), (k2,n,s2)] = orig`.------ However, I strongly suspect that for in-place update what we need is actually--- the INVERSE of the rebase function, i.e., given an index function new-base--- and another one orig, compute the index function ixfun0 such that:------ new-base == rebase ixfun0 ixfun, or equivalently:--- new-base == ixfun o ixfun0------ because then I can go bottom up and compose with ixfun0 all the index--- functions corresponding to the memory block associated with ixfun.-rebase ::- (Eq num, IntegralExp num) =>- IxFun num ->- IxFun num ->- Maybe (IxFun num)-rebase new_base@(IxFun lmad_base _) ixfun@(IxFun lmad shp) = do- let dims = LMAD.dims lmad- perm = LMAD.permutation lmad- perm_base = LMAD.permutation lmad_base-- guard $- -- Core rebase condition.- base ixfun == shape new_base- -- XXX: We should be able to handle some basic cases where both index- -- functions have non-trivial permutations.- && (hasContiguousPerm ixfun || hasContiguousPerm new_base)- -- We need the permutations to be of the same size if we want to compose- -- them. They don't have to be of the same size if the ixfun has a trivial- -- permutation. Supporting this latter case allows us to rebase when ixfun- -- has been created by slicing with fixed dimensions.- && (length perm == length perm_base || hasContiguousPerm ixfun)- -- To not have to worry about ixfun having non-1 strides, we also check that- -- it is a row-major array (modulo permutation, which is handled- -- separately). Accept a non-full outermost dimension. XXX: Maybe this can- -- be less conservative?- && and- ( zipWith3- (\sn ld inner -> inner || sn == ldShape ld)- shp- dims- (True : replicate (length dims - 1) False)- )-- -- Compose permutations, reverse strides and adjust offset if necessary.- let perm_base' =- if hasContiguousPerm ixfun- then perm_base- else map (perm !!) perm_base- lmad_base' = LMAD.setPermutation perm_base' lmad_base- dims_base = LMAD.dims lmad_base'- n_fewer_dims = length dims_base - length dims- (dims_base', offs_contrib) =- unzip $- zipWith- ( \(LMADDim s1 n1 p1) (LMADDim {}) ->- let (s', off') = (s1, 0)- in (LMADDim s' n1 (p1 - n_fewer_dims), off')- )- -- If @dims@ is morally a slice, it might have fewer dimensions than- -- @dims_base@. Drop extraneous outer dimensions.- (drop n_fewer_dims dims_base)- dims- off_base = LMAD.offset lmad_base' + sum offs_contrib- lmad_base'' =- LMAD.setShape- (LMAD.shape lmad)- ( LMAD- (off_base + ldStride (last dims_base) * LMAD.offset lmad)- dims_base'- )- pure $ IxFun lmad_base'' shp+-- | Conceptually expand index function to be a particular slice of+-- another by adjusting the offset and strides. Used for memory+-- expansion.+expand ::+ (Eq num, IntegralExp num) => num -> num -> IxFun num -> Maybe (IxFun num)+expand o p (IxFun lmad base) =+ let onDim ld = ld {LMAD.ldStride = LMAD.ldStride ld * p}+ lmad' =+ LMAD+ (o + p * LMAD.offset lmad)+ (map onDim (LMAD.dims lmad))+ in Just $ IxFun lmad' base -- | Turn all the leaves of the index function into 'Ext's. We -- require that there's only one LMAD, that the index function is@@ -357,18 +271,3 @@ where closeEnoughLMADs lmad1 lmad2 = length (LMAD.dims lmad1) == length (LMAD.dims lmad2)- && map ldPerm (LMAD.dims lmad1) == map ldPerm (LMAD.dims lmad2)---- | Returns true if two 'IxFun's are equivalent.------ Equivalence in this case is defined as having the same number of LMADs, with--- each pair of LMADs matching in permutation, offsets, and strides.-equivalent :: Eq num => IxFun num -> IxFun num -> Bool-equivalent ixf1 ixf2 =- equivalentLMADs (ixfunLMAD ixf1) (ixfunLMAD ixf2)- where- equivalentLMADs lmad1 lmad2 =- length (LMAD.dims lmad1) == length (LMAD.dims lmad2)- && map ldPerm (LMAD.dims lmad1) == map ldPerm (LMAD.dims lmad2)- && LMAD.offset lmad1 == LMAD.offset lmad2- && map ldStride (LMAD.dims lmad1) == map ldStride (LMAD.dims lmad2)
src/Futhark/IR/Mem/LMAD.hs view
@@ -15,32 +15,25 @@ reshape, permute, shape,- permutation,- shapeBase,- setPermutation,- setShape,+ rank, substituteInLMAD,- permuteInv,- permuteFwd, disjoint, disjoint2, disjoint3, dynamicEqualsLMAD,- contiguous,- memcpyable,- noPermutation, iota, mkExistential,+ equivalent,+ isDirect, ) where import Control.Category import Control.Monad-import Data.Foldable (toList) import Data.Function (on, (&))-import Data.List (elemIndex, partition, sort, sortBy)+import Data.List (elemIndex, partition, sortBy) import Data.Map.Strict qualified as M-import Data.Maybe (fromJust, isJust, isNothing)+import Data.Maybe (fromJust, isNothing) import Data.Traversable import Futhark.Analysis.AlgSimplify qualified as AlgSimplify import Futhark.Analysis.PrimExp@@ -54,7 +47,6 @@ FlatSlice (..), Slice (..), Type,- dimFix, unitSlice, ) import Futhark.IR.Syntax.Core (VName (..))@@ -77,8 +69,7 @@ -- | A single dimension in an 'LMAD'. data LMADDim num = LMADDim { ldStride :: num,- ldShape :: num,- ldPerm :: Int+ ldShape :: num } deriving (Show, Eq, Ord) @@ -118,28 +109,27 @@ } deriving (Show, Eq, Ord) -instance Pretty num => Pretty (LMAD num) where+instance (Pretty num) => Pretty (LMAD num) where pretty (LMAD offset dims) = braces . semistack $ [ "offset:" <+> group (pretty offset), "strides:" <+> p ldStride,- "shape:" <+> p ldShape,- "permutation:" <+> p ldPerm+ "shape:" <+> p ldShape ] where p f = group $ brackets $ align $ commasep $ map (pretty . f) dims -instance Substitute num => Substitute (LMAD num) where+instance (Substitute num) => Substitute (LMAD num) where substituteNames substs = fmap $ substituteNames substs -instance Substitute num => Rename (LMAD num) where+instance (Substitute num) => Rename (LMAD num) where rename = substituteRename -instance FreeIn num => FreeIn (LMAD num) where+instance (FreeIn num) => FreeIn (LMAD num) where freeIn' = foldMap freeIn' -instance FreeIn num => FreeIn (LMADDim num) where- freeIn' (LMADDim s n _) = freeIn' s <> freeIn' n+instance (FreeIn num) => FreeIn (LMADDim num) where+ freeIn' (LMADDim s n) = freeIn' s <> freeIn' n instance Functor LMAD where fmap = fmapDefault@@ -151,7 +141,7 @@ traverse f (LMAD offset dims) = LMAD <$> f offset <*> traverse f' dims where- f' (LMADDim s n p) = LMADDim <$> f s <*> f n <*> pure p+ f' (LMADDim s n) = LMADDim <$> f s <*> f n flatOneDim :: (Eq num, IntegralExp num) =>@@ -163,18 +153,10 @@ | otherwise = i * s index :: (IntegralExp num, Eq num) => LMAD num -> Indices num -> num-index lmad@(LMAD off dims) inds =+index (LMAD off dims) inds = off + sum prods where- prods =- zipWith- flatOneDim- (map ldStride dims)- (permuteInv (permutation lmad) inds)--setLMADPermutation :: Permutation -> LMAD num -> LMAD num-setLMADPermutation perm lmad =- lmad {dims = zipWith (\dim p -> dim {ldPerm = p}) (dims lmad) perm}+ prods = zipWith flatOneDim (map ldStride dims) inds -- | Handle the case where a slice can stay within a single LMAD. slice ::@@ -183,69 +165,41 @@ Slice num -> LMAD num slice lmad@(LMAD _ ldims) (Slice is) =- let perm = permutation lmad- is' = permuteInv perm is- lmad' = foldl sliceOne (LMAD (offset lmad) []) $ zip is' ldims- -- need to remove the fixed dims from the permutation- perm' =- updatePerm perm $- map fst $- filter (isJust . dimFix . snd) $- zip [0 .. length is' - 1] is'- in setLMADPermutation perm' lmad'+ foldl sliceOne (LMAD (offset lmad) []) $ zip is ldims where- updatePerm ps inds = concatMap decrease ps- where- decrease p =- let f n i- | i == p = -1- | i > p = n- | n /= -1 = n + 1- | otherwise = n- d = foldl f 0 inds- in [p - d | d /= -1]- sliceOne :: (Eq num, IntegralExp num) => LMAD num -> (DimIndex num, LMADDim num) -> LMAD num- sliceOne (LMAD off dims) (DimFix i, LMADDim s _x _) =+ sliceOne (LMAD off dims) (DimFix i, LMADDim s _x) = LMAD (off + flatOneDim s i) dims- sliceOne (LMAD off dims) (DimSlice _ ne _, LMADDim 0 _ p) =- LMAD off (dims ++ [LMADDim 0 ne p])- sliceOne (LMAD off dims) (dmind, dim@(LMADDim _ n _))+ sliceOne (LMAD off dims) (DimSlice _ ne _, LMADDim 0 _) =+ LMAD off (dims ++ [LMADDim 0 ne])+ sliceOne (LMAD off dims) (dmind, dim@(LMADDim _ n)) | dmind == unitSlice 0 n = LMAD off (dims ++ [dim])- sliceOne (LMAD off dims) (dmind, LMADDim s n p)+ sliceOne (LMAD off dims) (dmind, LMADDim s n) | dmind == DimSlice (n - 1) n (-1) = let off' = off + flatOneDim s (n - 1)- in LMAD off' (dims ++ [LMADDim (s * (-1)) n p])- sliceOne (LMAD off dims) (DimSlice b ne 0, LMADDim s _ p) =- LMAD (off + flatOneDim s b) (dims ++ [LMADDim 0 ne p])- sliceOne (LMAD off dims) (DimSlice bs ns ss, LMADDim s _ p) =- LMAD (off + s * bs) (dims ++ [LMADDim (ss * s) ns p])--hasContiguousPerm :: LMAD num -> Bool-hasContiguousPerm lmad = perm == sort perm- where- perm = permutation lmad+ in LMAD off' (dims ++ [LMADDim (s * (-1)) n])+ sliceOne (LMAD off dims) (DimSlice b ne 0, LMADDim s _) =+ LMAD (off + flatOneDim s b) (dims ++ [LMADDim 0 ne])+ sliceOne (LMAD off dims) (DimSlice bs ns ss, LMADDim s _) =+ LMAD (off + s * bs) (dims ++ [LMADDim (ss * s) ns]) -- | Flat-slice an LMAD. flatSlice :: (IntegralExp num) => LMAD num -> FlatSlice num ->- Maybe (LMAD num)-flatSlice lmad@(LMAD offset (dim : dims)) (FlatSlice new_offset is)- | hasContiguousPerm lmad =- Just $- LMAD- (offset + new_offset * ldStride dim)- (map (helper $ ldStride dim) is <> dims)- & setLMADPermutation [0 ..]+ LMAD num+flatSlice (LMAD offset (dim : dims)) (FlatSlice new_offset is) =+ LMAD+ (offset + new_offset * ldStride dim)+ (map (helper $ ldStride dim) is <> dims) where- helper s0 (FlatDimIndex n s) = LMADDim (s0 * s) n 0-flatSlice _ _ = Nothing+ helper s0 (FlatDimIndex n s) = LMADDim (s0 * s) n+flatSlice (LMAD offset []) _ = LMAD offset [] -- | Handle the case where a reshape operation can stay inside a -- single LMAD. See "Futhark.IR.Mem.IxFun.reshape" for@@ -254,115 +208,56 @@ (Eq num, IntegralExp num) => LMAD num -> Shape num -> Maybe (LMAD num) -- -- First a special case for when we are merely injecting unit--- dimensions into a non-permuted LMAD.-reshape lmad@(LMAD off dims) newshape- | sort (permutation lmad) == permutation lmad,- Just dims' <- addingVacuous 0 newshape dims =+-- dimensions into an LMAD.+reshape (LMAD off dims) newshape+ | Just dims' <- addingVacuous newshape dims = Just $ LMAD off dims' where- addingVacuous i (dnew : dnews) (dold : dolds)+ addingVacuous (dnew : dnews) (dold : dolds) | dnew == ldShape dold =- (dold {ldPerm = i} :) <$> addingVacuous (i + 1) dnews dolds- addingVacuous i (1 : dnews) dolds =- (LMADDim 0 1 i :) <$> addingVacuous (i + 1) dnews dolds- addingVacuous _ [] [] = Just []- addingVacuous _ _ _ = Nothing+ (dold :) <$> addingVacuous dnews dolds+ addingVacuous (1 : dnews) dolds =+ (LMADDim 0 1 :) <$> addingVacuous dnews dolds+ addingVacuous [] [] = Just []+ addingVacuous _ _ = Nothing -- Then the general case. reshape lmad@(LMAD off dims) newshape = do- let perm = permutation lmad- dims_perm = permuteFwd perm dims- mid_dims = take (length dims) dims_perm+ let mid_dims = take (length dims) dims guard $ -- checking conditions (2)- all (\(LMADDim s _ _) -> s /= 0) mid_dims- &&- -- checking condition (1)- consecutive 0 (map ldPerm mid_dims)- &&- -- checking condition (3)- hasContiguousPerm lmad+ all (\(LMADDim s _) -> s /= 0) mid_dims && all (\(ld, se) -> ldStride ld == se) (zip dims (reverse $ scanl (*) 1 (reverse (tail (shape lmad))))) - -- make new permutation- let rsh_len = length newshape- diff = length newshape - length dims- iota_shape = [0 .. length newshape - 1]- perm' =- map- ( \i ->- let ind = i - diff- in if (i >= 0) && (i < rsh_len)- then i -- already checked mid_dims not affected- else ldPerm (dims !! ind) + diff- )- iota_shape- -- split the dimensions- (support_inds, repeat_inds) =- foldl- (\(sup, rpt) (shpdim, ip) -> ((ip, shpdim) : sup, rpt))- ([], [])- $ reverse- $ zip newshape perm'-- (sup_inds, support) = unzip $ sortBy (compare `on` fst) support_inds- (rpt_inds, repeats) = unzip repeat_inds- LMAD off' dims_sup = iota off support- repeats' = map (\n -> LMADDim 0 n 0) repeats- dims' =- map snd $- sortBy (compare `on` fst) $- zip sup_inds dims_sup ++ zip rpt_inds repeats'- lmad' = LMAD off' dims'- Just $ setLMADPermutation perm' lmad'- where- consecutive _ [] = True- consecutive i [p] = i == p- consecutive i ps = and $ zipWith (==) ps [i, i + 1 ..]--permutation :: LMAD num -> Permutation-permutation = map ldPerm . dims--setPermutation :: Permutation -> LMAD num -> LMAD num-setPermutation perm lmad =- lmad {dims = zipWith (\dim p -> dim {ldPerm = p}) (dims lmad) perm}--setShape :: Shape num -> LMAD num -> LMAD num-setShape shp lmad = lmad {dims = zipWith (\dim s -> dim {ldShape = s}) (dims lmad) shp}+ let LMAD off' dims_sup = iota off newshape+ Just $ LMAD off' dims_sup -- | Substitute a name with a PrimExp in an LMAD. substituteInLMAD ::- Ord a =>+ (Ord a) => M.Map a (TPrimExp t a) -> LMAD (TPrimExp t a) -> LMAD (TPrimExp t a) substituteInLMAD tab (LMAD offset dims) =- LMAD (sub offset) $- map (\(LMADDim s n p) -> LMADDim (sub s) (sub n) p) dims+ LMAD (sub offset) $ map (\(LMADDim s n) -> LMADDim (sub s) (sub n)) dims where tab' = fmap untyped tab sub = TPrimExp . substituteInPrimExp tab' . untyped -- | Shape of an LMAD. shape :: LMAD num -> Shape num-shape lmad = permuteInv (permutation lmad) $ shapeBase lmad---- | Shape of an LMAD, ignoring permutations.-shapeBase :: LMAD num -> Shape num-shapeBase = map ldShape . dims--permuteFwd :: Permutation -> [a] -> [a]-permuteFwd ps elems = map (elems !!) ps+shape = map ldShape . dims -permuteInv :: Permutation -> [a] -> [a]-permuteInv ps elems = map snd $ sortBy (compare `on` fst) $ zip ps elems+-- | Rank of an LMAD.+rank :: LMAD num -> Int+rank = length . shape -- | Generalised iota with user-specified offset. iota ::- IntegralExp num =>+ (IntegralExp num) => -- | Offset num -> -- | Shape@@ -371,25 +266,18 @@ iota off ns = let rk = length ns ss = reverse $ take rk $ scanl (*) 1 $ reverse ns- ps = map fromIntegral [0 .. rk - 1]- in LMAD off $ zipWith3 LMADDim ss ns ps+ in LMAD off $ zipWith LMADDim ss ns --- | Create an LMAD that is existential in everything, with the--- provided permutation.-mkExistential :: [Int] -> Int -> LMAD (Ext a)-mkExistential perm start =- lmad+-- | Create an LMAD that is existential in everything.+mkExistential :: Int -> Int -> LMAD (Ext a)+mkExistential r start = LMAD (Ext start) $ map onDim [0 .. r - 1] where- lmad = LMAD (Ext start) $ zipWith onDim perm [0 ..]- onDim p i =- LMADDim (Ext (start + 1 + i * 2)) (Ext (start + 2 + i * 2)) p+ onDim i = LMADDim (Ext (start + 1 + i * 2)) (Ext (start + 2 + i * 2)) -- | Permute dimensions. permute :: LMAD num -> Permutation -> LMAD num-permute lmad perm_new =- let perm_cur = permutation lmad- perm = map (perm_cur !!) perm_new- in setPermutation perm lmad+permute lmad perm =+ lmad {dims = rearrangeShape perm $ dims lmad} -- | Computes the maximum span of an 'LMAD'. The result is the lowest and -- highest flat values representable by that 'LMAD'.@@ -412,7 +300,7 @@ -- conservativeFlatten :: (IntegralExp e, Ord e, Pretty e) => LMAD e -> LMAD e conservativeFlatten :: LMAD (TPrimExp Int64 VName) -> Maybe (LMAD (TPrimExp Int64 VName)) conservativeFlatten (LMAD offset []) =- pure $ LMAD offset [LMADDim 1 1 0]+ pure $ LMAD offset [LMADDim 1 1] conservativeFlatten l@(LMAD _ [_]) = pure l conservativeFlatten l@(LMAD offset dims) = do@@ -421,7 +309,7 @@ gcd (ldStride $ head dims) $ map ldStride dims- pure $ LMAD offset [LMADDim strd (shp + 1) 0]+ pure $ LMAD offset [LMADDim strd (shp + 1)] where shp = flatSpan l @@ -603,28 +491,26 @@ lmadToIntervals :: LMAD (TPrimExp Int64 VName) -> (AlgSimplify.SofP, [Interval]) lmadToIntervals (LMAD offset []) = (AlgSimplify.simplify0 $ untyped offset, [Interval 0 1 1])-lmadToIntervals lmad@(LMAD offset dims0) =- (offset', map helper $ permuteInv (permutation lmad) dims0)+lmadToIntervals (LMAD offset dims0) =+ (offset', map helper dims0) where offset' = AlgSimplify.simplify0 $ untyped offset helper :: LMADDim (TPrimExp Int64 VName) -> Interval- helper (LMADDim strd shp _) = do+ helper (LMADDim strd shp) = do Interval 0 (AlgSimplify.simplify' shp) (AlgSimplify.simplify' strd) -- | Dynamically determine if two 'LMADDim' are equal. -- -- True if the dynamic values of their constituents are equal.-dynamicEqualsLMADDim :: Eq num => LMADDim (TPrimExp t num) -> LMADDim (TPrimExp t num) -> TPrimExp Bool num+dynamicEqualsLMADDim :: (Eq num) => LMADDim (TPrimExp t num) -> LMADDim (TPrimExp t num) -> TPrimExp Bool num dynamicEqualsLMADDim dim1 dim2 =- ldStride dim1 .==. ldStride dim2- .&&. ldShape dim1 .==. ldShape dim2- .&&. fromBool (ldPerm dim1 == ldPerm dim2)+ ldStride dim1 .==. ldStride dim2 .&&. ldShape dim1 .==. ldShape dim2 -- | Dynamically determine if two 'LMAD' are equal. -- -- True if offset and constituent 'LMADDim' are equal.-dynamicEqualsLMAD :: Eq num => LMAD (TPrimExp t num) -> LMAD (TPrimExp t num) -> TPrimExp Bool num+dynamicEqualsLMAD :: (Eq num) => LMAD (TPrimExp t num) -> LMAD (TPrimExp t num) -> TPrimExp Bool num dynamicEqualsLMAD lmad1 lmad2 = offset lmad1 .==. offset lmad2 .&&. foldr@@ -632,40 +518,18 @@ true (zip (dims lmad1) (dims lmad2)) --- | True if these LMADs represent the same function (ignoring--- offset).-compatible ::- Eq num =>- LMAD (TPrimExp Int64 num) ->- LMAD (TPrimExp Int64 num) ->- TPrimExp Bool num-compatible x y =- foldl1 (.&&.) $ zipWith dynamicEqualsLMADDim (dims x) (dims y)---- | True if this LMAD corresponds to an array without "holes". This--- implies it can be copied with a memcpy()-like operation.-contiguous ::- (Pretty num, Eq num) =>- LMAD (TPrimExp Int64 num) ->- TPrimExp Bool num-contiguous lmad =- foldl1 (.&&.) $ zipWith (.==.) (toList lmad) lmad'- where- lmad' = toList (iota (offset lmad) $ map ldShape $ dims lmad)---- | True if these LMADs have the same contiguous representation, such--- that one can be copied to the other with a @memcpy()@-like--- operation.-memcpyable ::- (Pretty num, Eq num) =>- LMAD (TPrimExp Int64 num) ->- LMAD (TPrimExp Int64 num) ->- TPrimExp Bool num-memcpyable dest_lmad src_lmad =- contiguous dest_lmad .&&. compatible dest_lmad src_lmad+-- | Returns true if two 'LMAD's are equivalent.+--+-- Equivalence in this case is matching in offsets and strides.+equivalent :: (Eq num) => LMAD num -> LMAD num -> Bool+equivalent lmad1 lmad2 =+ length (dims lmad1) == length (dims lmad2)+ && offset lmad1 == offset lmad2+ && map ldStride (dims lmad1) == map ldStride (dims lmad2) --- | Remove the permutation of an LMAD by actually applying it to the--- dimensions.-noPermutation :: LMAD t -> LMAD t-noPermutation lmad =- lmad {dims = rearrangeShape (permutation lmad) $ dims lmad}+-- | Is this is a row-major array?+isDirect :: (Eq num, IntegralExp num) => LMAD num -> Bool+isDirect (LMAD offset dims) =+ let strides_expected = reverse $ scanl (*) 1 $ reverse $ tail $ map ldShape dims+ in offset == 0+ && and (zipWith (==) (map ldStride dims) strides_expected)
src/Futhark/IR/Mem/Simplify.hs view
@@ -5,6 +5,7 @@ simplifyStmsGeneric, simpleGeneric, SimplifyMemory,+ memRuleBook, ) where @@ -50,13 +51,14 @@ simplifyProgGeneric :: (SimplifyMemory rep inner) =>+ RuleBook (Wise rep) -> Simplify.SimpleOps rep -> Prog rep -> PassM (Prog rep)-simplifyProgGeneric ops =+simplifyProgGeneric rules ops = Simplify.simplifyProg ops- callKernelRules+ rules blockers {Engine.blockHoistBranch = blockAllocs} where blockAllocs vtable _ (Let _ _ (Op Alloc {})) =@@ -75,24 +77,25 @@ MonadFreshNames m, SimplifyMemory rep inner ) =>+ RuleBook (Wise rep) -> Simplify.SimpleOps rep -> Stms rep -> m (Stms rep)-simplifyStmsGeneric ops stms = do+simplifyStmsGeneric rules ops stms = do scope <- askScope Simplify.simplifyStms ops- callKernelRules+ rules blockers scope stms -isResultAlloc :: OpC 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 :: OpC rep ~ MemOp op => Engine.BlockPred rep+isAlloc :: (OpC rep ~ MemOp op) => Engine.BlockPred rep isAlloc _ _ (Let _ _ (Op Alloc {})) = True isAlloc _ _ _ = False @@ -106,8 +109,10 @@ Engine.isAllocation = isAlloc mempty mempty } -callKernelRules :: SimplifyMemory rep inner => RuleBook (Wise rep)-callKernelRules =+-- | Standard collection of simplification rules for representations+-- with memory.+memRuleBook :: (SimplifyMemory rep inner) => RuleBook (Wise rep)+memRuleBook = standardRules <> ruleBook [ RuleMatch unExistentialiseMemory,@@ -119,7 +124,7 @@ -- the array is not existential, and the index function of the array -- does not refer to any names in the pattern, then we can create a -- block of the proper size and always return there.-unExistentialiseMemory :: SimplifyMemory rep inner => TopDownRuleMatch (Wise rep)+unExistentialiseMemory :: (SimplifyMemory rep inner) => TopDownRuleMatch (Wise rep) unExistentialiseMemory vtable pat _ (cond, cases, defbody, ifdec) | ST.simplifyMemory vtable, fixable <- foldl hasConcretisableMemory mempty $ patElems pat,@@ -185,7 +190,7 @@ -- If an allocation is statically known to be safe, then we can remove -- the certificates on it. This can help hoist things that would -- otherwise be stuck inside loops or branches.-decertifySafeAlloc :: SimplifyMemory rep inner => TopDownRuleOp (Wise rep)+decertifySafeAlloc :: (SimplifyMemory rep inner) => TopDownRuleOp (Wise rep) decertifySafeAlloc _ pat (StmAux cs attrs _) op | cs /= mempty, [Mem _] <- patTypes pat,
src/Futhark/IR/Parse.hs view
@@ -104,7 +104,7 @@ ] pTypeBase ::- ArrayShape shape =>+ (ArrayShape shape) => Parser shape -> Parser u -> Parser (TypeBase shape u)@@ -479,7 +479,7 @@ pLoop :: PR rep -> Parser (Exp rep) pLoop pr = keyword "loop"- $> DoLoop+ $> Loop <*> pLoopParams <*> pLoopForm <* keyword "do"@@ -978,9 +978,8 @@ pLMAD = braces $ do offset <- pLab "offset" pNum <* pSemi strides <- pLab "strides" $ brackets (pNum `sepBy` pComma) <* pSemi- shape <- pLab "shape" $ brackets (pNum `sepBy` pComma) <* pSemi- perm <- pLab "permutation" $ brackets (pInt `sepBy` pComma)- pure $ IxFun.LMAD offset $ zipWith3 IxFun.LMADDim strides shape perm+ shape <- pLab "shape" $ brackets (pNum `sepBy` pComma)+ pure $ IxFun.LMAD offset $ zipWith IxFun.LMADDim strides shape pPrimExpLeaf :: Parser VName pPrimExpLeaf = pVName
src/Futhark/IR/Pretty.hs view
@@ -49,7 +49,7 @@ instance Pretty Rank where pretty (Rank r) = mconcat $ replicate r "[]" -instance Pretty a => Pretty (Ext a) where+instance (Pretty a) => Pretty (Ext a) where pretty (Free e) = pretty e pretty (Ext x) = "?" <> pretty (show x) @@ -61,7 +61,7 @@ pretty (Space s) = "@" <> pretty s pretty (ScalarSpace d t) = "@" <> mconcat (map (brackets . pretty) d) <> pretty t -instance Pretty u => Pretty (TypeBase Shape u) where+instance (Pretty u) => Pretty (TypeBase Shape u) where pretty (Prim t) = pretty t pretty (Acc acc ispace ts u) = pretty u@@ -75,7 +75,7 @@ pretty u <> mconcat (map (brackets . pretty) ds) <> pretty et pretty (Mem s) = "mem" <> pretty s -instance Pretty u => Pretty (TypeBase ExtShape u) where+instance (Pretty u) => Pretty (TypeBase ExtShape u) where pretty (Prim t) = pretty t pretty (Acc acc ispace ts u) = pretty u@@ -89,7 +89,7 @@ pretty u <> mconcat (map (brackets . pretty) ds) <> pretty et pretty (Mem s) = "mem" <> pretty s -instance Pretty u => Pretty (TypeBase Rank u) where+instance (Pretty u) => Pretty (TypeBase Rank u) where pretty (Prim t) = pretty t pretty (Acc acc ispace ts u) = pretty u@@ -114,13 +114,13 @@ pretty (Certs []) = mempty pretty (Certs cs) = "#" <> braces (commasep (map pretty cs)) -instance PrettyRep rep => Pretty (Stms rep) where+instance (PrettyRep rep) => Pretty (Stms rep) where pretty = stack . map pretty . stmsToList instance Pretty SubExpRes where pretty (SubExpRes cs se) = hsep $ certAnnots cs ++ [pretty se] -instance PrettyRep rep => Pretty (Body rep) where+instance (PrettyRep rep) => Pretty (Body rep) where pretty (Body _ stms res) | null stms = braces (commasep $ map pretty res) | otherwise =@@ -152,17 +152,17 @@ instance Pretty Attrs where pretty = hsep . attrAnnots -instance Pretty t => Pretty (Pat t) where+instance (Pretty t) => Pretty (Pat t) where pretty (Pat xs) = braces $ commastack $ map pretty xs -instance Pretty t => Pretty (PatElem t) where+instance (Pretty t) => Pretty (PatElem t) where pretty (PatElem name t) = pretty name <+> colon <+> align (pretty t) -instance Pretty t => Pretty (Param t) where+instance (Pretty t) => Pretty (Param t) where pretty (Param attrs name t) = annot (attrAnnots attrs) $ pretty name <+> colon <+> align (pretty t) -instance PrettyRep rep => Pretty (Stm rep) where+instance (PrettyRep rep) => Pretty (Stm rep) where pretty stm@(Let pat aux e) = align . hang 2 $ "let"@@ -178,13 +178,13 @@ stmCertAnnots stm ] -instance Pretty a => Pretty (Slice a) where+instance (Pretty a) => Pretty (Slice a) where pretty (Slice xs) = brackets (commasep (map pretty xs)) -instance Pretty d => Pretty (FlatDimIndex d) where+instance (Pretty d) => Pretty (FlatDimIndex d) where pretty (FlatDimIndex n s) = pretty n <+> ":" <+> pretty s -instance Pretty a => Pretty (FlatSlice a) where+instance (Pretty a) => Pretty (FlatSlice a) where pretty (FlatSlice offset xs) = brackets (pretty offset <> ";" <+> commasep (map pretty xs)) instance Pretty BasicOp where@@ -241,22 +241,22 @@ ppTuple' $ map pretty v ] -instance Pretty a => Pretty (ErrorMsg a) where+instance (Pretty a) => Pretty (ErrorMsg a) where pretty (ErrorMsg parts) = braces $ align $ commasep $ map p parts where p (ErrorString s) = pretty $ show s p (ErrorVal t x) = pretty x <+> colon <+> pretty t -maybeNest :: PrettyRep rep => Body rep -> Doc a+maybeNest :: (PrettyRep rep) => Body rep -> Doc a maybeNest b | null $ bodyStms b = pretty b | otherwise = nestedBlock "{" "}" $ pretty b -instance PrettyRep rep => Pretty (Case (Body rep)) where+instance (PrettyRep rep) => Pretty (Case (Body rep)) where pretty (Case vs b) = "case" <+> ppTuple' (map (maybe "_" pretty) vs) <+> "->" <+> maybeNest b -prettyRet :: Pretty t => (t, RetAls) -> Doc a+prettyRet :: (Pretty t) => (t, RetAls) -> Doc a prettyRet (t, RetAls pals rals) | pals == mempty, rals == mempty =@@ -266,7 +266,7 @@ where pl = brackets . commasep . map pretty -instance PrettyRep rep => Pretty (Exp rep) where+instance (PrettyRep rep) => Pretty (Exp rep) where pretty (Match [c] [Case [Just (BoolValue True)] t] f (MatchDec ret ifsort)) = "if" <> info'@@ -299,7 +299,7 @@ pretty (Apply fname args ret (safety, _, _)) = applykw <+> pretty (nameToString fname)- <> apply (map (align . prettyArg) args)+ <> apply (map (align . prettyArg) args) </> colon <+> braces (commasep $ map prettyRet ret) where@@ -309,7 +309,7 @@ Unsafe -> "apply <unsafe>" Safe -> "apply" pretty (Op op) = pretty op- pretty (DoLoop merge form loopbody) =+ pretty (Loop merge form loopbody) = "loop" <+> braces (commastack $ map pretty params) <+> equals@@ -325,7 +325,9 @@ ForLoop i it bound loop_vars -> "for" <+> align- ( pretty i <> ":" <> pretty it+ ( pretty i+ <> ":"+ <> pretty it <+> "<" <+> align (pretty bound) </> stack (map prettyLoopVar loop_vars)@@ -352,7 +354,7 @@ comma </> parens (pretty op' <> comma </> ppTuple' (map pretty nes)) ) -instance PrettyRep rep => Pretty (Lambda rep) where+instance (PrettyRep rep) => Pretty (Lambda rep) where pretty (Lambda [] (Body _ stms []) []) | stms == mempty = "nilFn" pretty (Lambda params body rettype) = "\\"@@ -378,7 +380,7 @@ instance Pretty EntryResult where pretty (EntryResult u t) = pretty u <> pretty t -instance PrettyRep rep => Pretty (FunDef rep) where+instance (PrettyRep rep) => Pretty (FunDef rep) where pretty (FunDef entry attrs name rettype fparams body) = annot (attrAnnots attrs) $ fun@@ -393,8 +395,12 @@ Just (p_name, p_entry, ret_entry) -> "entry" <> (parens . align)- ( "\"" <> pretty p_name <> "\"" <> comma- </> ppTupleLines' (map pretty p_entry) <> comma+ ( "\""+ <> pretty p_name+ <> "\""+ <> comma+ </> ppTupleLines' (map pretty p_entry)+ <> comma </> ppTupleLines' (map pretty ret_entry) ) @@ -411,10 +417,10 @@ where p (name, t) = "type" <+> dquotes (pretty name) <+> equals <+> pretty t -instance PrettyRep rep => Pretty (Prog rep) where+instance (PrettyRep rep) => Pretty (Prog rep) where pretty (Prog types consts funs) = stack $ punctuate line $ pretty types : pretty consts : map pretty funs -instance Pretty d => Pretty (DimIndex d) where+instance (Pretty d) => Pretty (DimIndex d) where pretty (DimFix i) = pretty i pretty (DimSlice i n s) = pretty i <+> ":+" <+> pretty n <+> "*" <+> pretty s
src/Futhark/IR/Prop.hs view
@@ -76,7 +76,7 @@ -- any required certificates have been checked) in any context. For -- example, array indexing is not safe, as the index may be out of -- bounds. On the other hand, adding two numbers cannot fail.-safeExp :: IsOp (Op rep) => Exp rep -> Bool+safeExp :: (IsOp (Op rep)) => Exp rep -> Bool safeExp (BasicOp op) = safeBasicOp op where safeBasicOp (BinOp (SDiv _ Safe) _ _) = True@@ -119,7 +119,7 @@ safeBasicOp Iota {} = True safeBasicOp Replicate {} = True safeBasicOp _ = False-safeExp (DoLoop _ _ body) = safeBody body+safeExp (Loop _ _ body) = safeBody body safeExp (Apply fname _ _ _) = isBuiltInFunction fname safeExp (Match _ cases def_case _) =@@ -128,7 +128,7 @@ safeExp WithAcc {} = True -- Although unlikely to matter. safeExp (Op op) = safeOp op -safeBody :: IsOp (Op rep) => Body rep -> Bool+safeBody :: (IsOp (Op rep)) => Body rep -> Bool safeBody = all (safeExp . stmExp) . bodyStms -- | Return the variable names used in 'Var' subexpressions. May contain@@ -223,7 +223,7 @@ m [BranchType rep] -- | Construct the type of an expression that would match the pattern.-expExtTypesFromPat :: Typed dec => Pat dec -> [ExtType]+expExtTypesFromPat :: (Typed dec) => Pat dec -> [ExtType] expExtTypesFromPat pat = existentialiseExtTypes (patNames pat) $ staticShapes $@@ -239,7 +239,7 @@ attrForAssert = (== AttrComp "warn" ["safety_checks"]) -- | Horizontally fission a lambda that models a binary operator.-lamIsBinOp :: ASTRep rep => Lambda rep -> Maybe [(BinOp, PrimType, VName, VName)]+lamIsBinOp :: (ASTRep rep) => Lambda rep -> Maybe [(BinOp, PrimType, VName, VName)] lamIsBinOp lam = mapM splitStm $ bodyResult $ lambdaBody lam where n = length $ lambdaReturnType lam
src/Futhark/IR/Prop/Aliases.hs view
@@ -122,7 +122,7 @@ onBody body = (bodyAliases body, consumedInBody body) bound = foldMap boundInBody $ defbody : map caseBody cases expAliases _ (BasicOp op) = basicOpAliases op-expAliases pes (DoLoop merge _ loopbody) =+expAliases pes (Loop merge _ loopbody) = mutualAliases (bound <> param_names) pes $ do (p, als) <- transitive . zip params $ zipWith (<>) arg_aliases (bodyAliases loopbody)@@ -154,7 +154,7 @@ expAliases _ (Op op) = opAliases op -- | The variables consumed in this statement.-consumedInStm :: Aliased rep => Stm rep -> Names+consumedInStm :: (Aliased rep) => Stm rep -> Names consumedInStm = consumedInExp . stmExp -- | The variables consumed in this expression.@@ -166,7 +166,7 @@ consumeArg _ = mempty consumedInExp (Match _ cases defbody _) = foldMap (consumedInBody . caseBody) cases <> consumedInBody defbody-consumedInExp (DoLoop merge form body) =+consumedInExp (Loop merge form body) = mconcat ( map (subExpAliases . snd) $ filter (unique . paramDeclType . fst) merge@@ -193,11 +193,11 @@ consumedInExp (Op op) = consumedInOp op -- | The variables consumed by this lambda.-consumedByLambda :: Aliased rep => Lambda rep -> Names+consumedByLambda :: (Aliased rep) => Lambda rep -> Names consumedByLambda = consumedInBody . lambdaBody -- | The aliases of each pattern element.-patAliases :: AliasesOf dec => Pat dec -> [Names]+patAliases :: (AliasesOf dec) => Pat dec -> [Names] patAliases = map aliasesOf . patElems -- | Something that contains alias information.@@ -208,11 +208,11 @@ instance AliasesOf Names where aliasesOf = id -instance AliasesOf dec => AliasesOf (PatElem dec) where+instance (AliasesOf dec) => AliasesOf (PatElem dec) where aliasesOf = aliasesOf . patElemDec -- | Also includes the name itself.-lookupAliases :: AliasesOf (LetDec rep) => VName -> Scope rep -> Names+lookupAliases :: (AliasesOf (LetDec rep)) => VName -> Scope rep -> Names lookupAliases root scope = -- We must be careful to handle circular aliasing properly (this -- can happen due to Match and Loop).@@ -229,7 +229,7 @@ -- | The class of operations that can produce aliasing and consumption -- information.-class IsOp op => AliasedOp op where+class (IsOp op) => AliasedOp op where opAliases :: op -> [Names] consumedInOp :: op -> Names
src/Futhark/IR/Prop/Constants.hs view
@@ -61,7 +61,7 @@ value = FloatValue -- | Create a 'Constant' 'SubExp' containing the given value.-constant :: IsValue v => v -> SubExp+constant :: (IsValue v) => v -> SubExp constant = Constant . value -- | Utility definition for reasons of type ambiguity.
src/Futhark/IR/Prop/Names.hs view
@@ -192,7 +192,7 @@ freeIn' = fvNames . freeIn -- | The free variables of some syntactic construct.-freeIn :: FreeIn a => a -> Names+freeIn :: (FreeIn a) => a -> Names freeIn = unFV . freeIn' instance FreeIn FV where@@ -216,10 +216,10 @@ instance (FreeIn a, FreeIn b) => FreeIn (Either a b) where freeIn' = either freeIn' freeIn' -instance FreeIn a => FreeIn [a] where+instance (FreeIn a) => FreeIn [a] where freeIn' = foldMap freeIn' -instance FreeIn a => FreeIn (S.Set a) where+instance (FreeIn a) => FreeIn (S.Set a) where freeIn' = foldMap freeIn' instance FreeIn (NoOp rep) where@@ -284,7 +284,7 @@ ) => FreeIn (Exp rep) where- freeIn' (DoLoop merge form loopbody) =+ freeIn' (Loop merge form loopbody) = let (params, args) = unzip merge bound_here = namesFromList $ M.keys $ scopeOf form <> scopeOfFParams params@@ -311,10 +311,10 @@ <> freeIn' attrs <> precomputed dec (freeIn' dec <> freeIn' e <> freeIn' pat) -instance FreeIn (Stm rep) => FreeIn (Stms rep) where+instance (FreeIn (Stm rep)) => FreeIn (Stms rep) where freeIn' = foldMap freeIn' -instance FreeIn body => FreeIn (Case body) where+instance (FreeIn body) => FreeIn (Case body) where freeIn' = freeIn' . caseBody instance FreeIn Names where@@ -323,7 +323,7 @@ instance FreeIn Bool where freeIn' _ = mempty -instance FreeIn a => FreeIn (Maybe a) where+instance (FreeIn a) => FreeIn (Maybe a) where freeIn' = maybe mempty freeIn' instance FreeIn VName where@@ -341,48 +341,48 @@ freeIn' DefaultSpace = mempty freeIn' (Space _) = mempty -instance FreeIn d => FreeIn (ShapeBase d) where+instance (FreeIn d) => FreeIn (ShapeBase d) where freeIn' = freeIn' . shapeDims -instance FreeIn d => FreeIn (Ext d) where+instance (FreeIn d) => FreeIn (Ext d) where freeIn' (Free x) = freeIn' x freeIn' (Ext _) = mempty instance FreeIn PrimType where freeIn' _ = mempty -instance FreeIn shape => FreeIn (TypeBase shape u) where+instance (FreeIn shape) => FreeIn (TypeBase shape u) where freeIn' (Array t shape _) = freeIn' t <> freeIn' shape freeIn' (Mem s) = freeIn' s freeIn' Prim {} = mempty freeIn' (Acc acc ispace ts _) = freeIn' (acc, ispace, ts) -instance FreeIn dec => FreeIn (Param dec) where+instance (FreeIn dec) => FreeIn (Param dec) where freeIn' (Param attrs _ dec) = freeIn' attrs <> freeIn' dec -instance FreeIn dec => FreeIn (PatElem dec) where+instance (FreeIn dec) => FreeIn (PatElem dec) where freeIn' (PatElem _ dec) = freeIn' dec -instance FreeIn (LParamInfo rep) => FreeIn (LoopForm rep) where+instance (FreeIn (LParamInfo rep)) => FreeIn (LoopForm rep) where freeIn' (ForLoop _ _ bound loop_vars) = freeIn' bound <> freeIn' loop_vars freeIn' (WhileLoop cond) = freeIn' cond -instance FreeIn d => FreeIn (DimIndex d) where+instance (FreeIn d) => FreeIn (DimIndex d) where freeIn' = Data.Foldable.foldMap freeIn' -instance FreeIn d => FreeIn (Slice d) where+instance (FreeIn d) => FreeIn (Slice d) where freeIn' = Data.Foldable.foldMap freeIn' -instance FreeIn d => FreeIn (FlatDimIndex d) where+instance (FreeIn d) => FreeIn (FlatDimIndex d) where freeIn' = Data.Foldable.foldMap freeIn' -instance FreeIn d => FreeIn (FlatSlice d) where+instance (FreeIn d) => FreeIn (FlatSlice d) where freeIn' = Data.Foldable.foldMap freeIn' instance FreeIn SubExpRes where freeIn' (SubExpRes cs se) = freeIn' cs <> freeIn' se -instance FreeIn dec => FreeIn (Pat dec) where+instance (FreeIn dec) => FreeIn (Pat dec) where freeIn' (Pat xs) = fvBind bound_here $ freeIn' xs where@@ -394,16 +394,16 @@ instance FreeIn Attrs where freeIn' (Attrs _) = mempty -instance FreeIn dec => FreeIn (StmAux dec) where+instance (FreeIn dec) => FreeIn (StmAux dec) where freeIn' (StmAux cs attrs dec) = freeIn' cs <> freeIn' attrs <> freeIn' dec -instance FreeIn a => FreeIn (MatchDec a) where+instance (FreeIn a) => FreeIn (MatchDec a) where freeIn' (MatchDec r _) = freeIn' r -- | Either return precomputed free names stored in the attribute, or -- the freshly computed names. Relies on lazy evaluation to avoid the -- work.-class FreeIn dec => FreeDec dec where+class (FreeIn dec) => FreeDec dec where precomputed :: dec -> FV -> FV precomputed _ = id @@ -412,11 +412,11 @@ instance (FreeDec a, FreeIn b) => FreeDec (a, b) where precomputed (a, _) = precomputed a -instance FreeDec a => FreeDec [a] where+instance (FreeDec a) => FreeDec [a] where precomputed [] = id precomputed (a : _) = precomputed a -instance FreeDec a => FreeDec (Maybe a) where+instance (FreeDec a) => FreeDec (Maybe a) where precomputed Nothing = id precomputed (Just a) = precomputed a
src/Futhark/IR/Prop/Patterns.hs view
@@ -26,23 +26,23 @@ import Futhark.IR.Syntax -- | The 'Type' of a parameter.-paramType :: Typed dec => Param dec -> Type+paramType :: (Typed dec) => Param dec -> Type paramType = typeOf -- | The 'DeclType' of a parameter.-paramDeclType :: DeclTyped dec => Param dec -> DeclType+paramDeclType :: (DeclTyped dec) => Param dec -> DeclType paramDeclType = declTypeOf -- | An 'Ident' corresponding to a parameter.-paramIdent :: Typed dec => Param dec -> Ident+paramIdent :: (Typed dec) => Param dec -> Ident paramIdent param = Ident (paramName param) (typeOf param) -- | An 'Ident' corresponding to a pattern element.-patElemIdent :: Typed dec => PatElem dec -> Ident+patElemIdent :: (Typed dec) => PatElem dec -> Ident patElemIdent pelem = Ident (patElemName pelem) (typeOf pelem) -- | The type of a name bound by a t'PatElem'.-patElemType :: Typed dec => PatElem dec -> Type+patElemType :: (Typed dec) => PatElem dec -> Type patElemType = typeOf -- | Set the rep of a t'PatElem'.@@ -50,7 +50,7 @@ setPatElemDec pe x = fmap (const x) pe -- | Return a list of the 'Ident's bound by the t'Pat'.-patIdents :: Typed dec => Pat dec -> [Ident]+patIdents :: (Typed dec) => Pat dec -> [Ident] patIdents = map patElemIdent . patElems -- | Return a list of the 'Name's bound by the t'Pat'.@@ -58,7 +58,7 @@ patNames = map patElemName . patElems -- | Return a list of the typess bound by the pattern.-patTypes :: Typed dec => Pat dec -> [Type]+patTypes :: (Typed dec) => Pat dec -> [Type] patTypes = map identType . patIdents -- | Return the number of names bound by the pattern.
src/Futhark/IR/Prop/Rearrange.hs view
@@ -47,14 +47,14 @@ -- if so, return the permutation. This will also find identity -- permutations (i.e. the lists are the same) The implementation is -- naive and slow.-isPermutationOf :: Eq a => [a] -> [a] -> Maybe [Int]+isPermutationOf :: (Eq a) => [a] -> [a] -> Maybe [Int] isPermutationOf l1 l2 = case mapAccumLM (pick 0) (map Just l2) l1 of Just (l2', perm) | all (== Nothing) l2' -> Just perm _ -> Nothing where- pick :: Eq a => Int -> [Maybe a] -> a -> Maybe ([Maybe a], Int)+ pick :: (Eq a) => Int -> [Maybe a] -> a -> Maybe ([Maybe a], Int) pick _ [] _ = Nothing pick i (x : xs) y | Just y == x = Just (Nothing : xs, i)
src/Futhark/IR/Prop/Reshape.hs view
@@ -47,7 +47,7 @@ -- have the same length as @from_dims@, and @is'@ will have the same -- length as @to_dims@. reshapeIndex ::- IntegralExp num =>+ (IntegralExp num) => [num] -> [num] -> [num] ->@@ -59,14 +59,14 @@ -- with dimension @dims@ given the flat index @i@. The resulting list -- will have the same size as @dims@. unflattenIndex ::- IntegralExp num =>+ (IntegralExp num) => [num] -> num -> [num] unflattenIndex = unflattenIndexFromSlices . drop 1 . sliceSizes unflattenIndexFromSlices ::- IntegralExp num =>+ (IntegralExp num) => [num] -> num -> [num]@@ -78,7 +78,7 @@ -- array with dimensions @dims@. The length of @dims@ and @is@ must -- be the same. flattenIndex ::- IntegralExp num =>+ (IntegralExp num) => [num] -> [num] -> num@@ -92,7 +92,7 @@ -- slice. The first element of this list will be the product of -- @dims@, and the last element will be 1. sliceSizes ::- IntegralExp num =>+ (IntegralExp num) => [num] -> [num] sliceSizes [] = [1]
src/Futhark/IR/Prop/Scope.hs view
@@ -51,9 +51,9 @@ | LParamName (LParamInfo rep) | IndexName IntType -deriving instance RepTypes rep => Show (NameInfo rep)+deriving instance (RepTypes rep) => Show (NameInfo rep) -instance RepTypes rep => Typed (NameInfo rep) where+instance (RepTypes rep) => Typed (NameInfo rep) where typeOf (LetName dec) = typeOf dec typeOf (FParamName dec) = typeOf dec typeOf (LParamName dec) = typeOf dec@@ -156,7 +156,7 @@ inScopeOf :: (Scoped rep a, LocalScope rep m) => a -> m b -> m b inScopeOf = localScope . scopeOf -instance Scoped rep a => Scoped rep [a] where+instance (Scoped rep a) => Scoped rep [a] where scopeOf = mconcat . map scopeOf instance Scoped rep (Stms rep) where@@ -177,17 +177,17 @@ M.insert i (IndexName it) $ scopeOfLParams (map fst xs) -- | The scope of a pattern.-scopeOfPat :: LetDec rep ~ dec => Pat dec -> Scope rep+scopeOfPat :: (LetDec rep ~ dec) => Pat dec -> Scope rep scopeOfPat = mconcat . map scopeOfPatElem . patElems -- | The scope of a pattern element.-scopeOfPatElem :: LetDec rep ~ dec => PatElem dec -> Scope rep+scopeOfPatElem :: (LetDec rep ~ dec) => PatElem dec -> Scope rep scopeOfPatElem (PatElem name dec) = M.singleton name $ LetName dec -- | The scope of some lambda parameters. scopeOfLParams ::- LParamInfo rep ~ dec =>+ (LParamInfo rep ~ dec) => [Param dec] -> Scope rep scopeOfLParams = M.fromList . map f@@ -196,7 +196,7 @@ -- | The scope of some function or loop parameters. scopeOfFParams ::- FParamInfo rep ~ dec =>+ (FParamInfo rep ~ dec) => [Param dec] -> Scope rep scopeOfFParams = M.fromList . map f@@ -217,13 +217,13 @@ -- | If two scopes are really the same, then you can convert one to -- the other. castScope ::- SameScope fromrep torep =>+ (SameScope fromrep torep) => Scope fromrep -> Scope torep castScope = M.map castNameInfo castNameInfo ::- SameScope fromrep torep =>+ (SameScope fromrep torep) => NameInfo fromrep -> NameInfo torep castNameInfo (LetName dec) = LetName dec
src/Futhark/IR/Prop/TypeOf.hs view
@@ -39,13 +39,13 @@ import Futhark.IR.Syntax -- | The type of a subexpression.-subExpType :: HasScope t m => SubExp -> m Type+subExpType :: (HasScope t m) => SubExp -> m Type subExpType (Constant val) = pure $ Prim $ primValueType val subExpType (Var name) = lookupType name -- | Type type of a 'SubExpRes' - not that this might refer to names -- bound in the body containing the result.-subExpResType :: HasScope t m => SubExpRes -> m Type+subExpResType :: (HasScope t m) => SubExpRes -> m Type subExpResType = subExpType . resSubExp -- | @mapType f arrts@ wraps each element in the return type of @f@ in@@ -58,7 +58,7 @@ ] -- | The type of a primitive operation.-basicOpType :: HasScope rep m => BasicOp -> m [Type]+basicOpType :: (HasScope rep m) => BasicOp -> m [Type] basicOpType (SubExp se) = pure <$> subExpType se basicOpType (Opaque _ se) =@@ -127,7 +127,7 @@ m [ExtType] expExtType (Apply _ _ rt _) = pure $ map (fromDecl . declExtTypeOf . fst) rt expExtType (Match _ _ _ rt) = pure $ map extTypeOf $ matchReturns rt-expExtType (DoLoop merge _ _) =+expExtType (Loop merge _ _) = pure $ loopExtType $ map fst merge expExtType (BasicOp op) = staticShapes <$> basicOpType op expExtType (WithAcc inputs lam) =@@ -141,7 +141,7 @@ expExtType (Op op) = opType op -- | Given the parameters of a loop, produce the return type.-loopExtType :: Typed dec => [Param dec] -> [ExtType]+loopExtType :: (Typed dec) => [Param dec] -> [ExtType] loopExtType params = existentialiseExtTypes inaccessible $ staticShapes $ map typeOf params where@@ -150,7 +150,7 @@ -- | Any operation must define an instance of this class, which -- describes the type of the operation (at the value level). class TypedOp op where- opType :: HasScope t m => op -> m [ExtType]+ opType :: (HasScope t m) => op -> m [ExtType] instance TypedOp (NoOp rep) where opType NoOp = pure []
src/Futhark/IR/Prop/Types.hs view
@@ -77,7 +77,7 @@ import Futhark.IR.Syntax.Core -- | Remove shape information from a type.-rankShaped :: ArrayShape shape => TypeBase shape u -> TypeBase Rank u+rankShaped :: (ArrayShape shape) => TypeBase shape u -> TypeBase Rank u rankShaped (Array et sz u) = Array et (Rank $ shapeRank sz) u rankShaped (Prim pt) = Prim pt rankShaped (Acc acc ispace ts u) = Acc acc ispace ts u@@ -86,18 +86,18 @@ -- | Return the dimensionality of a type. For non-arrays, this is -- zero. For a one-dimensional array it is one, for a two-dimensional -- it is two, and so forth.-arrayRank :: ArrayShape shape => TypeBase shape u -> Int+arrayRank :: (ArrayShape shape) => TypeBase shape u -> Int arrayRank = shapeRank . arrayShape -- | Return the shape of a type - for non-arrays, this is the -- 'mempty'.-arrayShape :: ArrayShape shape => TypeBase shape u -> shape+arrayShape :: (ArrayShape shape) => TypeBase shape u -> shape arrayShape (Array _ ds _) = ds arrayShape _ = mempty -- | Modify the shape of an array - for non-arrays, this does nothing. modifyArrayShape ::- ArrayShape newshape =>+ (ArrayShape newshape) => (oldshape -> newshape) -> TypeBase oldshape u -> TypeBase newshape u@@ -113,7 +113,7 @@ -- | Set the shape of an array. If the given type is not an -- array, return the type unchanged. setArrayShape ::- ArrayShape newshape =>+ (ArrayShape newshape) => TypeBase oldshape u -> newshape -> TypeBase newshape u@@ -169,7 +169,7 @@ -- be returned, although if it is an array, with the uniqueness -- changed to @u@. arrayOf ::- ArrayShape shape =>+ (ArrayShape shape) => TypeBase shape u_unused -> shape -> u ->@@ -188,7 +188,7 @@ -- size is the given dimension. This is just a convenient wrapper -- around 'arrayOf'. arrayOfRow ::- ArrayShape (ShapeBase d) =>+ (ArrayShape (ShapeBase d)) => TypeBase (ShapeBase d) NoUniqueness -> d -> TypeBase (ShapeBase d) NoUniqueness@@ -208,7 +208,7 @@ -- | Replace the size of the outermost dimension of an array. If the -- given type is not an array, it is returned unchanged. setOuterSize ::- ArrayShape (ShapeBase d) =>+ (ArrayShape (ShapeBase d)) => TypeBase (ShapeBase d) u -> d -> TypeBase (ShapeBase d) u@@ -217,7 +217,7 @@ -- | Replace the size of the given dimension of an array. If the -- given type is not an array, it is returned unchanged. setDimSize ::- ArrayShape (ShapeBase d) =>+ (ArrayShape (ShapeBase d)) => Int -> TypeBase (ShapeBase d) u -> d ->@@ -322,7 +322,7 @@ -- | Transform any t'SubExp's in the type. mapOnExtType ::- Monad m =>+ (Monad m) => (SubExp -> m SubExp) -> TypeBase ExtShape u -> m (TypeBase ExtShape u)@@ -345,7 +345,7 @@ -- | Transform any t'SubExp's in the type. mapOnType ::- Monad m =>+ (Monad m) => (SubExp -> m SubExp) -> TypeBase Shape u -> m (TypeBase Shape u)@@ -385,9 +385,9 @@ u2 <= u1 && t1- == t2+ == t2 && shape1- `subShapeOf` shape2+ `subShapeOf` shape2 subtypeOf t1 t2 = t1 == t2 -- | @xs \`subtypesOf\` ys@ is true if @xs@ is the same size as @ys@,@@ -515,7 +515,7 @@ match (Ext i) dim = M.singleton i dim dimMapping ::- Monoid res =>+ (Monoid res) => (t1 -> [dim1]) -> (t2 -> [dim2]) -> (dim1 -> dim2 -> res) ->@@ -563,13 +563,13 @@ instance Typed Ident where typeOf = identType -instance Typed dec => Typed (Param dec) where+instance (Typed dec) => Typed (Param dec) where typeOf = typeOf . paramDec -instance Typed dec => Typed (PatElem dec) where+instance (Typed dec) => Typed (PatElem dec) where typeOf = typeOf . patElemDec -instance Typed b => Typed (a, b) where+instance (Typed b) => Typed (a, b) where typeOf = typeOf . snd -- | Typeclass for things that contain 'DeclType's.@@ -579,11 +579,11 @@ instance DeclTyped DeclType where declTypeOf = id -instance DeclTyped dec => DeclTyped (Param dec) where+instance (DeclTyped dec) => DeclTyped (Param dec) where declTypeOf = declTypeOf . paramDec -- | Typeclass for things that contain 'ExtType's.-class FixExt t => ExtTyped t where+class (FixExt t) => ExtTyped t where extTypeOf :: t -> ExtType instance ExtTyped ExtType where@@ -593,23 +593,23 @@ extTypeOf = fromDecl . declExtTypeOf -- | Typeclass for things that contain 'DeclExtType's.-class FixExt t => DeclExtTyped t where+class (FixExt t) => DeclExtTyped t where declExtTypeOf :: t -> DeclExtType instance DeclExtTyped DeclExtType where declExtTypeOf = id -- | Typeclass for things whose type can be changed.-class Typed a => SetType a where+class (Typed a) => SetType a where setType :: a -> Type -> a instance SetType Type where setType _ t = t -instance SetType b => SetType (a, b) where+instance (SetType b) => SetType (a, b) where setType (a, b) t = (a, setType b t) -instance SetType dec => SetType (PatElem dec) where+instance (SetType dec) => SetType (PatElem dec) where setType (PatElem name dec) t = PatElem name $ setType dec t @@ -623,10 +623,10 @@ instance (FixExt shape, ArrayShape shape) => FixExt (TypeBase shape u) where fixExt i se = modifyArrayShape $ fixExt i se -instance FixExt d => FixExt (ShapeBase d) where+instance (FixExt d) => FixExt (ShapeBase d) where fixExt i se = fmap $ fixExt i se -instance FixExt a => FixExt [a] where+instance (FixExt a) => FixExt [a] where fixExt i se = fmap $ fixExt i se instance FixExt ExtSize where
src/Futhark/IR/Rephrase.hs view
@@ -36,14 +36,14 @@ } -- | Rephrase an entire program.-rephraseProg :: Monad m => Rephraser m from to -> Prog from -> m (Prog to)+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 :: (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@@ -51,11 +51,11 @@ pure fundec {funDefBody = body', funDefParams = params', funDefRetType = rettype'} -- | Rephrase an expression.-rephraseExp :: Monad m => Rephraser m from to -> Exp from -> m (Exp to)+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 :: (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@@ -64,24 +64,24 @@ -- | Rephrase a pattern. rephrasePat ::- Monad m =>+ (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 :: (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 :: (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 :: (Monad m) => Rephraser m from to -> Body from -> m (Body to) rephraseBody rephraser (Body rep stms res) = Body <$> rephraseBodyDec rephraser rep@@ -89,13 +89,13 @@ <*> pure res -- | Rephrase a lambda.-rephraseLambda :: Monad m => Rephraser m from to -> Lambda from -> m (Lambda to)+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 :: (Monad m) => Rephraser m from to -> Mapper from to m mapper rephraser = identityMapper { mapOnBody = const $ rephraseBody rephraser,@@ -109,7 +109,7 @@ -- | 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)+ rephraseInOp :: (Monad m) => Rephraser m from to -> op from -> m (op to) instance RephraseOp NoOp where rephraseInOp _ NoOp = pure NoOp
src/Futhark/IR/RetType.hs view
@@ -36,7 +36,7 @@ -- and the arguments for a concrete call, return the instantiated -- return type for the concrete call, if valid. applyRetType ::- Typed dec =>+ (Typed dec) => [rt] -> [Param dec] -> [(SubExp, Type)] ->@@ -44,7 +44,7 @@ -- | Given shape parameter names and types, produce the types of -- arguments accepted.-expectedTypes :: Typed t => [VName] -> [t] -> [SubExp] -> [Type]+expectedTypes :: (Typed t) => [VName] -> [t] -> [SubExp] -> [Type] expectedTypes shapes value_ts args = map (correctDims . typeOf) value_ts where parammap :: M.Map VName SubExp
src/Futhark/IR/SOACS.hs view
@@ -65,7 +65,7 @@ lamUsesAD lam expUsesAD (Match _ cases def_case _) = any (bodyUsesAD . caseBody) cases || bodyUsesAD def_case- expUsesAD (DoLoop _ _ body) = bodyUsesAD body+ expUsesAD (Loop _ _ body) = bodyUsesAD body expUsesAD (WithAcc _ lam) = lamUsesAD lam expUsesAD BasicOp {} = False expUsesAD Apply {} = False
src/Futhark/IR/SOACS/SOAC.hs view
@@ -149,7 +149,7 @@ (Lambda rep) deriving (Eq, Ord, Show) -singleBinOp :: Buildable rep => [Lambda rep] -> Lambda rep+singleBinOp :: (Buildable rep) => [Lambda rep] -> Lambda rep singleBinOp lams = Lambda { lambdaParams = concatMap xParams lams ++ concatMap yParams lams,@@ -175,7 +175,7 @@ scanResults = sum . map (length . scanNeutral) -- | Combine multiple scan operators to a single operator.-singleScan :: Buildable rep => [Scan rep] -> Scan rep+singleScan :: (Buildable rep) => [Scan rep] -> Scan rep singleScan scans = let scan_nes = concatMap scanNeutral scans scan_lam = singleBinOp $ map scanLambda scans@@ -194,7 +194,7 @@ redResults = sum . map (length . redNeutral) -- | Combine multiple reduction operators to a single operator.-singleReduce :: Buildable rep => [Reduce rep] -> Reduce rep+singleReduce :: (Buildable rep) => [Reduce rep] -> Reduce rep singleReduce reds = let red_nes = concatMap redNeutral reds red_lam = singleBinOp $ map redLambda reds@@ -234,7 +234,7 @@ == map (Var . paramName) (lambdaParams lam) -- | A lambda with no parameters that returns no values.-nilFn :: Buildable rep => Lambda rep+nilFn :: (Buildable rep) => Lambda rep nilFn = Lambda mempty (mkBody mempty mempty) mempty -- | Construct a Screma with possibly multiple scans, and@@ -372,7 +372,7 @@ } -- | A mapper that simply returns the SOAC verbatim.-identitySOACMapper :: forall rep m. Monad m => SOACMapper rep rep m+identitySOACMapper :: forall rep m. (Monad m) => SOACMapper rep rep m identitySOACMapper = SOACMapper { mapOnSOACSubExp = pure,@@ -384,7 +384,7 @@ -- SOAC. The mapping does not descend recursively into subexpressions -- and is done left-to-right. mapSOACM ::- Monad m =>+ (Monad m) => SOACMapper frep trep m -> SOAC frep -> m (SOAC trep)@@ -455,26 +455,26 @@ ) -- | A helper for defining 'TraverseOpStms'.-traverseSOACStms :: Monad m => OpStmsTraverser m (SOAC rep) rep+traverseSOACStms :: (Monad m) => OpStmsTraverser m (SOAC rep) rep traverseSOACStms f = mapSOACM mapper where mapper = identitySOACMapper {mapOnSOACLambda = traverseLambdaStms f} -instance ASTRep rep => FreeIn (Scan rep) where+instance (ASTRep rep) => FreeIn (Scan rep) where freeIn' (Scan lam ne) = freeIn' lam <> freeIn' ne -instance ASTRep rep => FreeIn (Reduce rep) where+instance (ASTRep rep) => FreeIn (Reduce rep) where freeIn' (Reduce _ lam ne) = freeIn' lam <> freeIn' ne -instance ASTRep rep => FreeIn (ScremaForm rep) where+instance (ASTRep rep) => FreeIn (ScremaForm rep) where freeIn' (ScremaForm scans reds lam) = freeIn' scans <> freeIn' reds <> freeIn' lam -instance ASTRep rep => FreeIn (HistOp rep) where+instance (ASTRep rep) => FreeIn (HistOp rep) where freeIn' (HistOp w rf dests nes lam) = freeIn' w <> freeIn' rf <> freeIn' dests <> freeIn' nes <> freeIn' lam -instance ASTRep rep => FreeIn (SOAC rep) where+instance (ASTRep rep) => FreeIn (SOAC rep) where freeIn' = flip execState mempty . mapSOACM free where walk f x = modify (<> f x) >> pure x@@ -485,7 +485,7 @@ mapOnSOACVName = walk freeIn' } -instance ASTRep rep => Substitute (SOAC rep) where+instance (ASTRep rep) => Substitute (SOAC rep) where substituteNames subst = runIdentity . mapSOACM substitute where@@ -496,13 +496,13 @@ mapOnSOACVName = pure . substituteNames subst } -instance ASTRep rep => Rename (SOAC rep) where+instance (ASTRep rep) => Rename (SOAC rep) where rename = mapSOACM renamer where renamer = SOACMapper rename rename rename -- | The type of a SOAC.-soacType :: Typed (LParamInfo rep) => SOAC rep -> [Type]+soacType :: (Typed (LParamInfo rep)) => SOAC rep -> [Type] soacType (JVP lam _ _) = lambdaReturnType lam ++ lambdaReturnType lam@@ -516,21 +516,20 @@ substs = M.fromList $ zip nms (outersize : accs) Lambda params _ rtp = lam soacType (Scatter _w _ivs lam dests) =- zipWith arrayOfShape val_ts ws+ zipWith arrayOfShape (map (snd . head) rets) shapes where- indexes = sum $ zipWith (*) ns $ map length ws- val_ts = drop indexes $ lambdaReturnType lam- (ws, ns, _) = unzip3 dests+ (shapes, _, rets) =+ unzip3 $ groupScatterResults dests $ lambdaReturnType lam soacType (Hist _ _ ops _bucket_fun) = do op <- ops map (`arrayOfShape` histShape op) (lambdaReturnType $ histOp op) soacType (Screma w _arrs form) = scremaType w form -instance ASTRep rep => TypedOp (SOAC rep) where+instance (ASTRep rep) => TypedOp (SOAC rep) where opType = pure . staticShapes . soacType -instance Aliased rep => AliasedOp (SOAC rep) where+instance (Aliased rep) => AliasedOp (SOAC rep) where opAliases = map (const mempty) . soacType consumedInOp JVP {} = mempty@@ -586,7 +585,7 @@ onRed red = red {redLambda = Alias.analyseLambda aliases $ redLambda red} onScan scan = scan {scanLambda = Alias.analyseLambda aliases $ scanLambda scan} -instance ASTRep rep => IsOp (SOAC rep) where+instance (ASTRep rep) => IsOp (SOAC rep) where safeOp _ = False cheapOp _ = False @@ -606,7 +605,7 @@ instance CanBeWise SOAC where addOpWisdom = runIdentity . mapSOACM (SOACMapper pure (pure . informLambda) pure) -instance RepTypes rep => ST.IndexOp (SOAC rep) where+instance (RepTypes rep) => ST.IndexOp (SOAC rep) where indexOp vtable k soac [i] = do (lam, se, arr_params, arrs) <- lambdaAndSubExp soac let arr_indexes = M.fromList $ catMaybes $ zipWith arrIndex arr_params arrs@@ -645,7 +644,7 @@ indexOp _ _ _ _ = Nothing -- | Type-check a SOAC.-typeCheckSOAC :: TC.Checkable rep => SOAC (Aliases rep) -> TC.TypeM rep ()+typeCheckSOAC :: (TC.Checkable rep) => SOAC (Aliases rep) -> TC.TypeM rep () typeCheckSOAC (VJP lam args vec) = do args' <- mapM TC.checkArg args TC.checkLambda lam $ map TC.noArgAliases args'@@ -850,7 +849,7 @@ 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+instance (OpMetrics (Op rep)) => OpMetrics (SOAC rep) where opMetrics (VJP lam _ _) = inside "VJP" $ lambdaMetrics lam opMetrics (JVP lam _ _) =@@ -867,21 +866,25 @@ mapM_ (lambdaMetrics . redLambda) reds lambdaMetrics map_lam -instance PrettyRep rep => PP.Pretty (SOAC rep) where+instance (PrettyRep rep) => PP.Pretty (SOAC rep) where pretty (VJP lam args vec) = "vjp" <> parens ( PP.align $- pretty lam <> comma- </> PP.braces (commasep $ map pretty args) <> comma+ pretty lam+ <> comma+ </> PP.braces (commasep $ map pretty args)+ <> comma </> PP.braces (commasep $ map pretty vec) ) pretty (JVP lam args vec) = "jvp" <> parens ( PP.align $- pretty lam <> comma- </> PP.braces (commasep $ map pretty args) <> comma+ pretty lam+ <> comma+ </> PP.braces (commasep $ map pretty args)+ <> comma </> PP.braces (commasep $ map pretty vec) ) pretty (Stream size arrs acc lam) =@@ -895,24 +898,32 @@ null reds = "map" <> (parens . align)- ( pretty w <> comma- </> ppTuple' (map pretty arrs) <> comma+ ( pretty w+ <> comma+ </> ppTuple' (map pretty arrs)+ <> comma </> pretty map_lam ) | null scans = "redomap" <> (parens . align)- ( pretty w <> comma- </> ppTuple' (map pretty arrs) <> comma- </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map pretty reds) <> comma+ ( pretty w+ <> comma+ </> ppTuple' (map pretty arrs)+ <> comma+ </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map pretty reds)+ <> comma </> pretty map_lam ) | null reds = "scanomap" <> (parens . align)- ( pretty w <> comma- </> ppTuple' (map pretty arrs) <> comma- </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map pretty scans) <> comma+ ( pretty w+ <> comma+ </> ppTuple' (map pretty arrs)+ <> comma+ </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map pretty scans)+ <> comma </> pretty map_lam ) pretty (Screma w arrs form) = ppScrema w arrs form@@ -923,10 +934,14 @@ ppScrema w arrs (ScremaForm scans reds map_lam) = "screma" <> (parens . align)- ( pretty w <> comma- </> ppTuple' (map pretty arrs) <> comma- </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map pretty scans) <> comma- </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map pretty reds) <> comma+ ( pretty w+ <> comma+ </> ppTuple' (map pretty arrs)+ <> comma+ </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map pretty scans)+ <> comma+ </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map pretty reds)+ <> comma </> pretty map_lam ) @@ -936,9 +951,12 @@ ppStream size arrs acc lam = "streamSeq" <> (parens . align)- ( pretty size <> comma- </> ppTuple' (map pretty arrs) <> comma- </> ppTuple' (map pretty acc) <> comma+ ( pretty size+ <> comma+ </> ppTuple' (map pretty arrs)+ <> comma+ </> ppTuple' (map pretty acc)+ <> comma </> pretty lam ) @@ -948,13 +966,16 @@ ppScatter w arrs lam dests = "scatter" <> (parens . align)- ( pretty w <> comma- </> ppTuple' (map pretty arrs) <> comma- </> pretty lam <> comma+ ( pretty w+ <> comma+ </> ppTuple' (map pretty arrs)+ <> comma+ </> pretty lam+ <> comma </> commasep (map pretty dests) ) -instance PrettyRep rep => Pretty (Scan rep) where+instance (PrettyRep rep) => Pretty (Scan rep) where pretty (Scan scan_lam scan_nes) = pretty scan_lam <> comma </> PP.braces (commasep $ map pretty scan_nes) @@ -962,9 +983,11 @@ ppComm Noncommutative = mempty ppComm Commutative = "commutative " -instance PrettyRep rep => Pretty (Reduce rep) where+instance (PrettyRep rep) => Pretty (Reduce rep) where pretty (Reduce comm red_lam red_nes) =- ppComm comm <> pretty red_lam <> comma+ ppComm comm+ <> pretty red_lam+ <> comma </> PP.braces (commasep $ map pretty red_nes) -- | Prettyprint the given histogram operation.@@ -978,15 +1001,22 @@ ppHist w arrs ops bucket_fun = "hist" <> parens- ( pretty w <> comma- </> ppTuple' (map pretty arrs) <> comma- </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map ppOp ops) <> comma+ ( pretty w+ <> comma+ </> ppTuple' (map pretty arrs)+ <> comma+ </> PP.braces (mconcat $ intersperse (comma <> PP.line) $ map ppOp ops)+ <> comma </> pretty bucket_fun ) where ppOp (HistOp dest_w rf dests nes op) =- pretty dest_w <> comma- <+> pretty rf <> comma- <+> PP.braces (commasep $ map pretty dests) <> comma- </> ppTuple' (map pretty nes) <> comma+ pretty dest_w+ <> comma+ <+> pretty rf+ <> comma+ <+> PP.braces (commasep $ map pretty dests)+ <> comma+ </> ppTuple' (map pretty nes)+ <> comma </> pretty op
src/Futhark/IR/SOACS/Simplify.hs view
@@ -56,7 +56,7 @@ Simplify.simplifyProg simpleSOACS soacRules Engine.noExtraHoistBlockers simplifyFun ::- MonadFreshNames m =>+ (MonadFreshNames m) => ST.SymbolTable (Wise SOACS) -> FunDef SOACS -> m (FunDef SOACS)@@ -75,12 +75,12 @@ Simplify.simplifyStms simpleSOACS soacRules Engine.noExtraHoistBlockers scope stms simplifyConsts ::- MonadFreshNames m => Stms SOACS -> m (Stms SOACS)+ (MonadFreshNames m) => Stms SOACS -> m (Stms SOACS) simplifyConsts = Simplify.simplifyStms simpleSOACS soacRules Engine.noExtraHoistBlockers mempty simplifySOAC ::- Simplify.SimplifiableRep rep =>+ (Simplify.SimplifiableRep rep) => Simplify.SimplifyOp rep (SOAC (Wise rep)) simplifySOAC (VJP lam arr vec) = do (lam', hoisted) <- Engine.simplifyLambda mempty lam@@ -356,7 +356,7 @@ removeReplicateWrite _ _ _ _ = Skip removeReplicateInput ::- Aliased rep =>+ (Aliased rep) => ST.SymbolTable rep -> Lambda rep -> [VName] ->@@ -537,7 +537,7 @@ (zip redlam_params $ map resSubExp $ redlam_res <> redlam_res) redlam_deps, let alive_mask = map ((`nameIn` necessary) . paramName) redlam_params,- not $ all (== True) (take (length nes) alive_mask) = Simplify $ do+ not $ and (take (length nes) alive_mask) = Simplify $ do let fixDeadToNeutral lives ne = if lives then Nothing else Just ne dead_fix = zipWith fixDeadToNeutral alive_mask nes (used_red_pes, _, used_nes) =
src/Futhark/IR/SegOp.hs view
@@ -163,11 +163,11 @@ kernelBodyResult :: [KernelResult] } -deriving instance RepTypes rep => Ord (KernelBody rep)+deriving instance (RepTypes rep) => Ord (KernelBody rep) -deriving instance RepTypes rep => Show (KernelBody rep)+deriving instance (RepTypes rep) => Show (KernelBody rep) -deriving instance RepTypes rep => Eq (KernelBody rep)+deriving instance (RepTypes rep) => Eq (KernelBody rep) -- | Metadata about whether there is a subtle point to this -- 'KernelResult'. This is used to protect things like tiling, which@@ -236,13 +236,13 @@ freeIn' (RegTileReturns cs dims_n_tiles v) = freeIn' cs <> freeIn' dims_n_tiles <> freeIn' v -instance ASTRep rep => FreeIn (KernelBody rep) where+instance (ASTRep rep) => FreeIn (KernelBody rep) where freeIn' (KernelBody dec stms res) = fvBind bound_in_stms $ freeIn' dec <> freeIn' stms <> freeIn' res where bound_in_stms = foldMap boundByStm stms -instance ASTRep rep => Substitute (KernelBody rep) where+instance (ASTRep rep) => Substitute (KernelBody rep) where substituteNames subst (KernelBody dec stms res) = KernelBody (substituteNames subst dec)@@ -269,7 +269,7 @@ (substituteNames subst dims_n_tiles) (substituteNames subst v) -instance ASTRep rep => Rename (KernelBody rep) where+instance (ASTRep rep) => Rename (KernelBody rep) where rename (KernelBody dec stms res) = do dec' <- rename dec renamingStms stms $ \stms' ->@@ -280,7 +280,7 @@ -- | Perform alias analysis on a 'KernelBody'. aliasAnalyseKernelBody ::- Alias.AliasableRep rep =>+ (Alias.AliasableRep rep) => AliasTable -> KernelBody rep -> KernelBody (Aliases rep)@@ -290,7 +290,7 @@ -- | The variables consumed in the kernel body. consumedInKernelBody ::- Aliased rep =>+ (Aliased rep) => KernelBody rep -> Names consumedInKernelBody (KernelBody dec stms res) =@@ -300,7 +300,7 @@ consumedByReturn _ = mempty checkKernelBody ::- TC.Checkable rep =>+ (TC.Checkable rep) => [Type] -> KernelBody (Aliases rep) -> TC.TypeM rep ()@@ -374,10 +374,10 @@ (dims, blk_tiles, reg_tiles) = unzip3 dims_n_tiles expected = t `arrayOfShape` Shape (blk_tiles <> reg_tiles) -kernelBodyMetrics :: OpMetrics (Op rep) => KernelBody rep -> MetricsM ()+kernelBodyMetrics :: (OpMetrics (Op rep)) => KernelBody rep -> MetricsM () kernelBodyMetrics = mapM_ stmMetrics . kernelBodyStms -instance PrettyRep rep => Pretty (KernelBody rep) where+instance (PrettyRep rep) => Pretty (KernelBody rep) where pretty (KernelBody _ stms res) = PP.stack (map pretty (stmsToList stms)) </> "return"@@ -434,9 +434,9 @@ -- this 'SegSpace'. scopeOfSegSpace :: SegSpace -> Scope rep scopeOfSegSpace (SegSpace phys space) =- M.fromList $ zip (phys : map fst space) $ repeat $ IndexName Int64+ M.fromList $ map (,IndexName Int64) (phys : map fst space) -checkSegSpace :: TC.Checkable rep => SegSpace -> TC.TypeM rep ()+checkSegSpace :: (TC.Checkable rep) => SegSpace -> TC.TypeM rep () checkSegSpace (SegSpace _ dims) = mapM_ (TC.require [Prim int64] . snd) dims @@ -546,7 +546,7 @@ -- | Type check a 'SegOp', given a checker for its level. typeCheckSegOp ::- TC.Checkable rep =>+ (TC.Checkable rep) => (lvl -> TC.TypeM rep ()) -> SegOp lvl (Aliases rep) -> TC.TypeM rep ()@@ -621,7 +621,7 @@ segment_dims = init $ segSpaceDims space checkScanRed ::- TC.Checkable rep =>+ (TC.Checkable rep) => SegSpace -> [(Lambda (Aliases rep), [SubExp], Shape)] -> [Type] ->@@ -669,7 +669,7 @@ } -- | A mapper that simply returns the 'SegOp' verbatim.-identitySegOpMapper :: Monad m => SegOpMapper lvl rep rep m+identitySegOpMapper :: (Monad m) => SegOpMapper lvl rep rep m identitySegOpMapper = SegOpMapper { mapOnSegOpSubExp = pure,@@ -680,14 +680,14 @@ } mapOnSegSpace ::- Monad f => SegOpMapper lvl frep trep f -> SegSpace -> f SegSpace+ (Monad f) => SegOpMapper lvl frep trep f -> SegSpace -> f SegSpace mapOnSegSpace tv (SegSpace phys dims) = SegSpace <$> mapOnSegOpVName tv phys <*> traverse (bitraverse (mapOnSegOpVName tv) (mapOnSegOpSubExp tv)) dims mapSegBinOp ::- Monad m =>+ (Monad m) => SegOpMapper lvl frep trep m -> SegBinOp frep -> m (SegBinOp trep)@@ -699,7 +699,7 @@ -- | Apply a 'SegOpMapper' to the given 'SegOp'. mapSegOpM ::- Monad m =>+ (Monad m) => SegOpMapper lvl frep trep m -> SegOp lvl frep -> m (SegOp lvl trep)@@ -741,7 +741,7 @@ <*> mapOnSegOpLambda tv op mapOnSegOpType ::- Monad m =>+ (Monad m) => SegOpMapper lvl frep trep m -> Type -> m Type@@ -757,7 +757,7 @@ mapOnSegOpType _tv (Mem s) = pure $ Mem s rephraseBinOp ::- Monad f =>+ (Monad f) => Rephraser f from rep -> SegBinOp from -> f (SegBinOp rep)@@ -765,7 +765,7 @@ SegBinOp comm <$> rephraseLambda r lam <*> pure nes <*> pure shape rephraseKernelBody ::- Monad f =>+ (Monad f) => Rephraser f from rep -> KernelBody from -> f (KernelBody rep)@@ -795,7 +795,7 @@ HistOp w rf arrs nes shape <$> rephraseLambda r op -- | A helper for defining 'TraverseOpStms'.-traverseSegOpStms :: Monad m => OpStmsTraverser m (SegOp lvl rep) rep+traverseSegOpStms :: (Monad m) => OpStmsTraverser m (SegOp lvl rep) rep traverseSegOpStms f segop = mapSegOpM mapper segop where seg_scope = scopeOfSegSpace (segSpace segop)@@ -845,7 +845,7 @@ mapOnSegOpLevel = walk freeIn' } -instance OpMetrics (Op rep) => OpMetrics (SegOp lvl rep) where+instance (OpMetrics (Op rep)) => OpMetrics (SegOp lvl rep) where opMetrics (SegMap _ _ _ body) = inside "SegMap" $ kernelBodyMetrics body opMetrics (SegRed _ _ reds _ body) =@@ -870,11 +870,14 @@ ) <+> parens ("~" <> pretty phys) -instance PrettyRep rep => Pretty (SegBinOp rep) where+instance (PrettyRep rep) => Pretty (SegBinOp rep) where pretty (SegBinOp comm lam nes shape) =- PP.braces (PP.commasep $ map pretty nes) <> PP.comma- </> pretty shape <> PP.comma- </> comm' <> pretty lam+ PP.braces (PP.commasep $ map pretty nes)+ <> PP.comma+ </> pretty shape+ <> PP.comma+ </> comm'+ <> pretty lam where comm' = case comm of Commutative -> "commutative "@@ -882,27 +885,31 @@ instance (PrettyRep rep, PP.Pretty lvl) => PP.Pretty (SegOp lvl rep) where pretty (SegMap lvl space ts body) =- "segmap" <> pretty lvl+ "segmap"+ <> pretty lvl </> PP.align (pretty space) <+> PP.colon <+> ppTuple' (map pretty ts) <+> PP.nestedBlock "{" "}" (pretty body) pretty (SegRed lvl space reds ts body) =- "segred" <> pretty lvl+ "segred"+ <> pretty lvl </> PP.align (pretty space) </> PP.parens (mconcat $ intersperse (PP.comma <> PP.line) $ map pretty reds) </> PP.colon <+> ppTuple' (map pretty ts) <+> PP.nestedBlock "{" "}" (pretty body) pretty (SegScan lvl space scans ts body) =- "segscan" <> pretty lvl+ "segscan"+ <> pretty lvl </> PP.align (pretty space) </> PP.parens (mconcat $ intersperse (PP.comma <> PP.line) $ map pretty scans) </> PP.colon <+> ppTuple' (map pretty ts) <+> PP.nestedBlock "{" "}" (pretty body) pretty (SegHist lvl space ops ts body) =- "seghist" <> pretty lvl+ "seghist"+ <> pretty lvl </> PP.align (pretty space) </> PP.parens (mconcat $ intersperse (PP.comma <> PP.line) $ map ppOp ops) </> PP.colon@@ -910,11 +917,16 @@ <+> PP.nestedBlock "{" "}" (pretty body) where ppOp (HistOp w rf dests nes shape op) =- pretty w <> PP.comma- <+> pretty rf <> PP.comma- </> PP.braces (PP.commasep $ map pretty dests) <> PP.comma- </> PP.braces (PP.commasep $ map pretty nes) <> PP.comma- </> pretty shape <> PP.comma+ pretty w+ <> PP.comma+ <+> pretty rf+ <> PP.comma+ </> PP.braces (PP.commasep $ map pretty dests)+ <> PP.comma+ </> PP.braces (PP.commasep $ map pretty nes)+ <> PP.comma+ </> pretty shape+ <> PP.comma </> pretty op instance CanBeAliased (SegOp lvl) where@@ -928,7 +940,7 @@ pure pure -informKernelBody :: Informing rep => KernelBody rep -> KernelBody (Wise rep)+informKernelBody :: (Informing rep) => KernelBody rep -> KernelBody (Wise rep) informKernelBody (KernelBody dec stms res) = mkWiseKernelBody dec (informStms stms) res @@ -943,7 +955,7 @@ pure pure -instance ASTRep rep => ST.IndexOp (SegOp lvl rep) where+instance (ASTRep rep) => ST.IndexOp (SegOp lvl rep) where indexOp vtable k (SegMap _ space _ kbody) is = do Returns ResultMaySimplify _ se <- maybeNth k $ kernelBodyResult kbody guard $ length gtids <= length is@@ -1018,7 +1030,7 @@ <*> Engine.simplify what mkWiseKernelBody ::- Informing rep =>+ (Informing rep) => BodyDec rep -> Stms (Wise rep) -> [KernelResult] ->@@ -1030,7 +1042,7 @@ res_vs = map kernelResultSubExp res mkKernelBodyM ::- MonadBuilder m =>+ (MonadBuilder m) => Stms (Rep m) -> [KernelResult] -> m (KernelBody (Rep m))@@ -1080,20 +1092,20 @@ [] simplifyLambda ::- Engine.SimplifiableRep rep =>+ (Engine.SimplifiableRep rep) => Names -> Lambda (Wise rep) -> Engine.SimpleM rep (Lambda (Wise rep), Stms (Wise rep)) simplifyLambda bound = Engine.blockMigrated . Engine.simplifyLambda bound -segSpaceSymbolTable :: ASTRep rep => SegSpace -> ST.SymbolTable rep+segSpaceSymbolTable :: (ASTRep rep) => SegSpace -> ST.SymbolTable rep segSpaceSymbolTable (SegSpace flat gtids_and_dims) = foldl' f (ST.fromScope $ M.singleton flat $ IndexName Int64) gtids_and_dims where f vtable (gtid, dim) = ST.insertLoopVar gtid Int64 dim vtable simplifySegBinOp ::- Engine.SimplifiableRep rep =>+ (Engine.SimplifiableRep rep) => VName -> SegBinOp (Wise rep) -> Engine.SimpleM rep (SegBinOp (Wise rep), Stms (Wise rep))@@ -1358,13 +1370,13 @@ space = segSpace segop sliceWithGtidsFixed stm- | Let _ _ (BasicOp (Index arr slice)) <- stm,+ | Let _ aux (BasicOp (Index arr slice)) <- stm, space_slice <- map (DimFix . Var . fst) $ unSegSpace space, space_slice `isPrefixOf` unSlice slice, remaining_slice <- Slice $ drop (length space_slice) (unSlice slice), all (isJust . flip ST.lookup vtable) $ namesToList $- freeIn arr <> freeIn remaining_slice =+ freeIn arr <> freeIn remaining_slice <> freeIn (stmAuxCerts aux) = Just (remaining_slice, arr) | otherwise = Nothing@@ -1376,20 +1388,15 @@ let outer_slice = map ( \d ->- DimSlice- (constant (0 :: Int64))- d- (constant (1 :: Int64))+ DimSlice (constant (0 :: Int64)) d (constant (1 :: Int64)) ) $ segSpaceDims space index kpe' = letBindNames [patElemName kpe'] . BasicOp . Index arr $ Slice $ outer_slice <> remaining_slice- if patElemName kpe- `UT.isConsumed` used- || arr- `nameIn` consumed_in_segop+ if (patElemName kpe `UT.isConsumed` used)+ || (arr `nameIn` consumed_in_segop) then do precopy <- newVName $ baseString (patElemName kpe) <> "_precopy" index kpe {patElemName = precopy}
src/Futhark/IR/SeqMem.hs view
@@ -65,7 +65,7 @@ traverseOpStms _ = pure simplifyProg :: Prog SeqMem -> PassM (Prog SeqMem)-simplifyProg = simplifyProgGeneric simpleSeqMem+simplifyProg = simplifyProgGeneric memRuleBook simpleSeqMem simpleSeqMem :: Engine.SimpleOps SeqMem simpleSeqMem =
src/Futhark/IR/Syntax.hs view
@@ -205,7 +205,7 @@ } deriving (Ord, Show, Eq) -instance Semigroup dec => Semigroup (StmAux dec) where+instance (Semigroup dec) => Semigroup (StmAux dec) where StmAux cs1 attrs1 dec1 <> StmAux cs2 attrs2 dec2 = StmAux (cs1 <> cs2) (attrs1 <> attrs2) (dec1 <> dec2) @@ -219,11 +219,11 @@ stmExp :: Exp rep } -deriving instance RepTypes rep => Ord (Stm rep)+deriving instance (RepTypes rep) => Ord (Stm rep) -deriving instance RepTypes rep => Show (Stm rep)+deriving instance (RepTypes rep) => Show (Stm rep) -deriving instance RepTypes rep => Eq (Stm rep)+deriving instance (RepTypes rep) => Eq (Stm rep) -- | A sequence of statements. type Stms rep = Seq.Seq (Stm rep)@@ -291,11 +291,11 @@ bodyResult :: Result } -deriving instance RepTypes rep => Ord (Body rep)+deriving instance (RepTypes rep) => Ord (Body rep) -deriving instance RepTypes rep => Show (Body rep)+deriving instance (RepTypes rep) => Show (Body rep) -deriving instance RepTypes rep => Eq (Body rep)+deriving instance (RepTypes rep) => Eq (Body rep) -- | Apart from being Opaque, what else is going on here? data OpaqueOp@@ -435,7 +435,7 @@ -- body/ is picked. Match [SubExp] [Case (Body rep)] (Body rep) (MatchDec (BranchType rep)) | -- | @loop {a} = {v} (for i < n|while b) do b@.- DoLoop [(FParam rep, SubExp)] (LoopForm rep) (Body rep)+ Loop [(FParam rep, SubExp)] (LoopForm rep) (Body rep) | -- | Create accumulators backed by the given arrays (which are -- consumed) and pass them to the lambda, which must return the -- updated accumulators and possibly some extra values. The@@ -446,11 +446,11 @@ WithAcc [WithAccInput rep] (Lambda rep) | Op (Op rep) -deriving instance RepTypes rep => Eq (Exp rep)+deriving instance (RepTypes rep) => Eq (Exp rep) -deriving instance RepTypes rep => Show (Exp rep)+deriving instance (RepTypes rep) => Show (Exp rep) -deriving instance RepTypes rep => Ord (Exp rep)+deriving instance (RepTypes rep) => Ord (Exp rep) -- | For-loop or while-loop? data LoopForm rep@@ -464,11 +464,11 @@ [(LParam rep, VName)] | WhileLoop VName -deriving instance RepTypes rep => Eq (LoopForm rep)+deriving instance (RepTypes rep) => Eq (LoopForm rep) -deriving instance RepTypes rep => Show (LoopForm rep)+deriving instance (RepTypes rep) => Show (LoopForm rep) -deriving instance RepTypes rep => Ord (LoopForm rep)+deriving instance (RepTypes rep) => Ord (LoopForm rep) -- | Data associated with a branch. data MatchDec rt = MatchDec@@ -503,11 +503,11 @@ lambdaReturnType :: [Type] } -deriving instance RepTypes rep => Eq (Lambda rep)+deriving instance (RepTypes rep) => Eq (Lambda rep) -deriving instance RepTypes rep => Show (Lambda rep)+deriving instance (RepTypes rep) => Show (Lambda rep) -deriving instance RepTypes rep => Ord (Lambda rep)+deriving instance (RepTypes rep) => Ord (Lambda rep) -- | A function and loop parameter. type FParam rep = Param (FParamInfo rep)@@ -527,11 +527,11 @@ funDefBody :: Body rep } -deriving instance RepTypes rep => Eq (FunDef rep)+deriving instance (RepTypes rep) => Eq (FunDef rep) -deriving instance RepTypes rep => Show (FunDef rep)+deriving instance (RepTypes rep) => Show (FunDef rep) -deriving instance RepTypes rep => Ord (FunDef rep)+deriving instance (RepTypes rep) => Ord (FunDef rep) -- | An entry point parameter, comprising its name and original type. data EntryParam = EntryParam
src/Futhark/IR/Syntax/Core.hs view
@@ -390,12 +390,12 @@ dimSlice DimFix {} = Nothing -- | A slice with a stride of one.-unitSlice :: Num d => d -> d -> DimIndex d+unitSlice :: (Num d) => d -> d -> DimIndex d unitSlice offset n = DimSlice offset n 1 -- | Fix the 'DimSlice's of a slice. The number of indexes must equal -- the length of 'sliceDims' for the slice.-fixSlice :: Num d => Slice d -> [d] -> [d]+fixSlice :: (Num d) => Slice d -> [d] -> [d] fixSlice = fixSlice' . unSlice where fixSlice' (DimFix j : mis') is' =@@ -406,7 +406,7 @@ -- | Further slice the 'DimSlice's of a slice. The number of slices -- must equal the length of 'sliceDims' for the slice.-sliceSlice :: Num d => Slice d -> Slice d -> Slice d+sliceSlice :: (Num d) => Slice d -> Slice d -> Slice d sliceSlice (Slice jslice) (Slice islice) = Slice $ sliceSlice' jslice islice where sliceSlice' (DimFix j : js') is' =
src/Futhark/IR/Traversals.hs view
@@ -66,7 +66,7 @@ } -- | A mapper that simply returns the tree verbatim.-identityMapper :: forall rep m. Monad m => Mapper rep rep m+identityMapper :: forall rep m. (Monad m) => Mapper rep rep m identityMapper = Mapper { mapOnSubExp = pure,@@ -83,7 +83,7 @@ -- expression. Importantly, the mapping does not descend recursively -- into subexpressions. The mapping is done left-to-right. mapExpM ::- Monad m =>+ (Monad m) => Mapper frep trep m -> Exp frep -> m (Exp trep)@@ -181,11 +181,11 @@ <$> mapOnShape tv shape <*> mapM (mapOnVName tv) vs <*> traverse (bitraverse (mapOnLambda tv) (mapM (mapOnSubExp tv))) op-mapExpM tv (DoLoop merge form loopbody) = do+mapExpM tv (Loop merge form loopbody) = do params' <- mapM (mapOnFParam tv) params form' <- mapOnLoopForm tv form let scope = scopeOf form' <> scopeOfFParams params'- DoLoop+ Loop <$> (zip params' <$> mapM (mapOnSubExp tv) args) <*> pure form' <*> mapOnBody tv scope loopbody@@ -194,11 +194,11 @@ mapExpM tv (Op op) = Op <$> mapOnOp tv op -mapOnShape :: Monad m => Mapper frep trep m -> Shape -> m Shape+mapOnShape :: (Monad m) => Mapper frep trep m -> Shape -> m Shape mapOnShape tv (Shape ds) = Shape <$> mapM (mapOnSubExp tv) ds mapOnLoopForm ::- Monad m =>+ (Monad m) => Mapper frep trep m -> LoopForm frep -> m (LoopForm trep)@@ -214,7 +214,7 @@ WhileLoop <$> mapOnVName tv cond mapOnLambda ::- Monad m =>+ (Monad m) => Mapper frep trep m -> Lambda frep -> m (Lambda trep)@@ -243,7 +243,7 @@ } -- | A no-op traversal.-identityWalker :: forall rep m. Monad m => Walker rep m+identityWalker :: forall rep m. (Monad m) => Walker rep m identityWalker = Walker { walkOnSubExp = const $ pure (),@@ -256,10 +256,10 @@ walkOnOp = const $ pure () } -walkOnShape :: Monad m => Walker rep m -> Shape -> m ()+walkOnShape :: (Monad m) => Walker rep m -> Shape -> m () walkOnShape tv (Shape ds) = mapM_ (walkOnSubExp tv) ds -walkOnType :: Monad m => Walker rep m -> Type -> m ()+walkOnType :: (Monad m) => Walker rep m -> Type -> m () walkOnType _ Prim {} = pure () walkOnType tv (Acc acc ispace ts _) = do walkOnVName tv acc@@ -268,7 +268,7 @@ walkOnType _ Mem {} = pure () walkOnType tv (Array _ shape _) = walkOnShape tv shape -walkOnLoopForm :: Monad m => Walker rep m -> LoopForm rep -> m ()+walkOnLoopForm :: (Monad m) => Walker rep m -> LoopForm rep -> m () walkOnLoopForm tv (ForLoop i _ bound loop_vars) = walkOnVName tv i >> walkOnSubExp tv bound@@ -279,14 +279,14 @@ walkOnLoopForm tv (WhileLoop cond) = walkOnVName tv cond -walkOnLambda :: Monad m => Walker rep m -> Lambda rep -> m ()+walkOnLambda :: (Monad m) => Walker rep m -> Lambda rep -> m () walkOnLambda tv (Lambda params body ret) = do mapM_ (walkOnLParam tv) params walkOnBody tv (scopeOfLParams params) body mapM_ (walkOnType tv) ret -- | As 'mapExpM', but do not construct a result AST.-walkExpM :: Monad m => Walker rep m -> Exp rep -> m ()+walkExpM :: (Monad m) => Walker rep m -> Exp rep -> m () walkExpM tv (BasicOp (SubExp se)) = walkOnSubExp tv se walkExpM tv (BasicOp (ArrayLit els rowt)) =@@ -347,7 +347,7 @@ mapM_ (walkOnVName tv) vs traverse_ (bitraverse (walkOnLambda tv) (mapM (walkOnSubExp tv))) op walkOnLambda tv lam-walkExpM tv (DoLoop merge form loopbody) = do+walkExpM tv (Loop merge form loopbody) = do mapM_ (walkOnFParam tv) params walkOnLoopForm tv form mapM_ (walkOnSubExp tv) args@@ -366,9 +366,9 @@ -- This is used for some simplification rules. class TraverseOpStms rep where -- | Transform every sub-'Stms' of this op.- traverseOpStms :: Monad m => OpStmsTraverser m (Op rep) rep+ traverseOpStms :: (Monad m) => OpStmsTraverser m (Op rep) rep -- | A helper for defining 'traverseOpStms'.-traverseLambdaStms :: Monad m => OpStmsTraverser m (Lambda rep) rep+traverseLambdaStms :: (Monad m) => OpStmsTraverser m (Lambda rep) rep traverseLambdaStms f (Lambda ps (Body dec stms res) ret) = Lambda ps <$> (Body dec <$> f (scopeOfLParams ps) stms <*> pure res) <*> pure ret
src/Futhark/IR/TypeCheck.hs view
@@ -79,7 +79,7 @@ | NotAnArray VName Type | PermutationError [Int] Int (Maybe VName) -instance Checkable rep => Show (ErrorCase rep) where+instance (Checkable rep) => Show (ErrorCase rep) where show (TypeError msg) = "Type error:\n" ++ T.unpack msg show (UnexpectedType e _ []) =@@ -102,7 +102,7 @@ ++ "\nBut body has type\n " ++ T.unpack (prettyTuple bodytype) show (DupDefinitionError name) =- "Duplicate definition of function " ++ nameToString name ++ ""+ "Duplicate definition of function " ++ nameToString name show (DupParamError funname paramname) = "Parameter " ++ prettyString paramname@@ -181,7 +181,7 @@ -- | A type error. data TypeError rep = Error [T.Text] (ErrorCase rep) -instance Checkable rep => Show (TypeError rep) where+instance (Checkable rep) => Show (TypeError rep) where show (Error [] err) = show err show (Error msgs err) =@@ -297,7 +297,7 @@ ) instance- Checkable rep =>+ (Checkable rep) => HasScope (Aliases rep) (TypeM rep) where lookupType = fmap typeOf . lookupVar@@ -331,7 +331,7 @@ TypeM rep a context s = local $ \env -> env {envContext = s : envContext env} -message :: Pretty a => T.Text -> a -> T.Text+message :: (Pretty a) => T.Text -> a -> T.Text message s x = docText $ pretty s <+> align (pretty x) -- | Mark a name as bound. If the name has been bound previously in@@ -349,7 +349,7 @@ -- | Proclaim that we have made read-only use of the given variable. -- No-op unless the variable is array-typed. observe ::- Checkable rep =>+ (Checkable rep) => VName -> TypeM rep () observe name = do@@ -358,7 +358,7 @@ occur [observation $ oneName name <> aliases dec] -- | Proclaim that we have written to the given variables.-consume :: Checkable rep => Names -> TypeM rep ()+consume :: (Checkable rep) => Names -> TypeM rep () consume als = do scope <- askScope let isArray = maybe False (not . primType . typeOf) . (`M.lookup` scope)@@ -433,7 +433,7 @@ _ -> mempty binding ::- Checkable rep =>+ (Checkable rep) => Scope (Aliases rep) -> TypeM rep a -> TypeM rep a@@ -468,7 +468,7 @@ Nothing -> bad $ UnknownVariableError name Just dec -> pure dec -lookupAliases :: Checkable rep => VName -> TypeM rep Names+lookupAliases :: (Checkable rep) => VName -> TypeM rep Names lookupAliases name = do info <- lookupVar name pure $@@ -480,12 +480,12 @@ aliases (LetName (als, _)) = unAliases als aliases _ = mempty -subExpAliasesM :: Checkable rep => SubExp -> TypeM rep Names+subExpAliasesM :: (Checkable rep) => SubExp -> TypeM rep Names subExpAliasesM Constant {} = pure mempty subExpAliasesM (Var v) = lookupAliases v lookupFun ::- Checkable rep =>+ (Checkable rep) => Name -> [SubExp] -> TypeM rep ([(RetType rep, RetAls)], [DeclType])@@ -514,7 +514,7 @@ -- | @require ts se@ causes a '(TypeError vn)' if the type of @se@ is -- not a subtype of one of the types in @ts@.-require :: Checkable rep => [Type] -> SubExp -> TypeM rep ()+require :: (Checkable rep) => [Type] -> SubExp -> TypeM rep () require ts se = do t <- checkSubExp se unless (t `elem` ts) $@@ -522,11 +522,11 @@ UnexpectedType (BasicOp $ SubExp se) t ts -- | Variant of 'require' working on variable names.-requireI :: Checkable rep => [Type] -> VName -> TypeM rep ()+requireI :: (Checkable rep) => [Type] -> VName -> TypeM rep () requireI ts ident = require ts $ Var ident checkArrIdent ::- Checkable rep =>+ (Checkable rep) => VName -> TypeM rep (Shape, PrimType) checkArrIdent v = do@@ -536,7 +536,7 @@ _ -> bad $ NotAnArray v t checkAccIdent ::- Checkable rep =>+ (Checkable rep) => VName -> TypeM rep (Shape, [Type]) checkAccIdent v = do@@ -571,7 +571,7 @@ -- yielding either a type error or a program with complete type -- information. checkProg ::- Checkable rep =>+ (Checkable rep) => Prog (Aliases rep) -> Either (TypeError rep) () checkProg (Prog opaques consts funs) = do@@ -604,7 +604,7 @@ pure $ M.insert name (ret, params) ftable initialFtable ::- Checkable rep =>+ (Checkable rep) => TypeM rep (M.Map Name (FunBinding rep)) initialFtable = fmap M.fromList $ mapM addBuiltin $ M.toList builtInFunctions where@@ -614,7 +614,7 @@ name = VName (nameFromString "x") 0 checkFun ::- Checkable rep =>+ (Checkable rep) => FunDef (Aliases rep) -> TypeM rep () checkFun (FunDef _ _ fname rettype params body) =@@ -647,7 +647,7 @@ ) checkFunParams ::- Checkable rep =>+ (Checkable rep) => [FParam rep] -> TypeM rep () checkFunParams = mapM_ $ \param ->@@ -655,7 +655,7 @@ checkFParamDec (paramName param) (paramDec param) checkLambdaParams ::- Checkable rep =>+ (Checkable rep) => [LParam rep] -> TypeM rep () checkLambdaParams = mapM_ $ \param ->@@ -672,7 +672,7 @@ pure $ pname : seen checkFun' ::- Checkable rep =>+ (Checkable rep) => ( Name, [(DeclExtType, RetAls)], [(VName, NameInfo (Aliases rep))]@@ -728,23 +728,23 @@ isProblem i als rals (j, jals, j_rals) = i /= j && j `notElem` rals && i `notElem` j_rals && namesIntersect als jals -checkSubExp :: Checkable rep => SubExp -> TypeM rep Type+checkSubExp :: (Checkable rep) => SubExp -> TypeM rep Type checkSubExp (Constant val) = pure $ Prim $ primValueType val checkSubExp (Var ident) = context ("In subexp " <> prettyText ident) $ do observe ident lookupType ident -checkCerts :: Checkable rep => Certs -> TypeM rep ()+checkCerts :: (Checkable rep) => Certs -> TypeM rep () checkCerts (Certs cs) = mapM_ (requireI [Prim Unit]) cs -checkSubExpRes :: Checkable rep => SubExpRes -> TypeM rep Type+checkSubExpRes :: (Checkable rep) => SubExpRes -> TypeM rep Type checkSubExpRes (SubExpRes cs se) = do checkCerts cs checkSubExp se checkStms ::- Checkable rep =>+ (Checkable rep) => Stms (Aliases rep) -> TypeM rep a -> TypeM rep a@@ -759,13 +759,13 @@ m checkResult ::- Checkable rep =>+ (Checkable rep) => Result -> TypeM rep () checkResult = mapM_ checkSubExpRes checkFunBody ::- Checkable rep =>+ (Checkable rep) => [(RetType rep, RetAls)] -> Body (Aliases rep) -> TypeM rep [Names]@@ -778,7 +778,7 @@ mapM (subExpAliasesM . resSubExp) res checkLambdaBody ::- Checkable rep =>+ (Checkable rep) => [Type] -> Body (Aliases rep) -> TypeM rep ()@@ -787,7 +787,7 @@ checkStms stms $ checkLambdaResult ret res checkLambdaResult ::- Checkable rep =>+ (Checkable rep) => [Type] -> Result -> TypeM rep ()@@ -813,7 +813,7 @@ <> prettyText t checkBody ::- Checkable rep =>+ (Checkable rep) => Body (Aliases rep) -> TypeM rep [Names] checkBody (Body (_, rep) stms res) = do@@ -824,7 +824,7 @@ where bound_here = namesFromList $ M.keys $ scopeOf stms -checkBasicOp :: Checkable rep => BasicOp -> TypeM rep ()+checkBasicOp :: (Checkable rep) => BasicOp -> TypeM rep () checkBasicOp (SubExp es) = void $ checkSubExp es checkBasicOp (Opaque _ es) =@@ -953,7 +953,7 @@ consume =<< lookupAliases acc matchLoopResultExt ::- Checkable rep =>+ (Checkable rep) => [Param DeclType] -> Result -> TypeM rep ()@@ -984,7 +984,7 @@ RetAls [0 .. n - 1] [0 .. m - 1] checkExp ::- Checkable rep =>+ (Checkable rep) => Exp (Aliases rep) -> TypeM rep () checkExp (BasicOp op) = checkBasicOp op@@ -1017,7 +1017,7 @@ </> "But annotation is:" </> indent 2 (pretty $ map fst rettype_annot) consumeArgs paramtypes argflows-checkExp (DoLoop merge form loopbody) = do+checkExp (Loop merge form loopbody) = do let (mergepat, mergeexps) = unzip merge mergeargs <- mapM checkArg mergeexps @@ -1102,9 +1102,8 @@ <> prettyText (paramType condparam) <> "." Nothing ->- bad $- TypeError $- "Conditional '" <> prettyText cond <> "' of while-loop is not a merge variable."+ -- Implies infinite loop, but that's OK.+ pure () let mergepat = map fst merge funparams = mergepat paramts = map paramDeclType funparams@@ -1167,7 +1166,7 @@ checker op checkSOACArrayArgs ::- Checkable rep =>+ (Checkable rep) => SubExp -> [VName] -> TypeM rep [Arg]@@ -1192,7 +1191,7 @@ "SOAC argument " <> prettyText v <> " is not an array" checkType ::- Checkable rep =>+ (Checkable rep) => TypeBase Shape u -> TypeM rep () checkType (Mem (ScalarSpace d _)) = mapM_ (require [Prim int64]) d@@ -1203,7 +1202,7 @@ checkType t = mapM_ checkSubExp $ arrayDims t checkExtType ::- Checkable rep =>+ (Checkable rep) => TypeBase ExtShape u -> TypeM rep () checkExtType = mapM_ checkExtDim . shapeDims . arrayShape@@ -1212,7 +1211,7 @@ checkExtDim (Ext _) = pure () checkCmpOp ::- Checkable rep =>+ (Checkable rep) => CmpOp -> SubExp -> SubExp ->@@ -1230,7 +1229,7 @@ checkCmpOp CmpLle x y = checkBinOpArgs Bool x y checkBinOpArgs ::- Checkable rep =>+ (Checkable rep) => PrimType -> SubExp -> SubExp ->@@ -1240,7 +1239,7 @@ require [Prim t] e2 checkPatElem ::- Checkable rep =>+ (Checkable rep) => PatElem (LetDec rep) -> TypeM rep () checkPatElem (PatElem name dec) =@@ -1248,13 +1247,13 @@ checkLetBoundDec name dec checkFlatDimIndex ::- Checkable rep =>+ (Checkable rep) => FlatDimIndex SubExp -> TypeM rep () checkFlatDimIndex (FlatDimIndex n s) = mapM_ (require [Prim int64]) [n, s] checkFlatSlice ::- Checkable rep =>+ (Checkable rep) => FlatSlice SubExp -> TypeM rep () checkFlatSlice (FlatSlice offset idxs) = do@@ -1262,14 +1261,14 @@ mapM_ checkFlatDimIndex idxs checkDimIndex ::- Checkable rep =>+ (Checkable rep) => DimIndex SubExp -> TypeM rep () checkDimIndex (DimFix i) = require [Prim int64] i checkDimIndex (DimSlice i n s) = mapM_ (require [Prim int64]) [i, n, s] checkStm ::- Checkable rep =>+ (Checkable rep) => Stm (Aliases rep) -> TypeM rep a -> TypeM rep a@@ -1283,7 +1282,7 @@ m matchExtPat ::- Checkable rep =>+ (Checkable rep) => Pat (LetDec (Aliases rep)) -> [ExtType] -> TypeM rep ()@@ -1293,7 +1292,7 @@ InvalidPatError pat ts Nothing matchExtReturnType ::- Checkable rep =>+ (Checkable rep) => [ExtType] -> Result -> TypeM rep ()@@ -1302,7 +1301,7 @@ matchExtReturns rettype res ts matchExtBranchType ::- Checkable rep =>+ (Checkable rep) => [ExtType] -> Body (Aliases rep) -> TypeM rep ()@@ -1335,7 +1334,7 @@ unless (rettype' == ts) problem validApply ::- ArrayShape shape =>+ (ArrayShape shape) => [TypeBase shape Uniqueness] -> [TypeBase shape NoUniqueness] -> Bool@@ -1361,7 +1360,7 @@ noArgAliases (t, _) = (t, mempty) checkArg ::- Checkable rep =>+ (Checkable rep) => SubExp -> TypeM rep Arg checkArg arg = do@@ -1396,7 +1395,7 @@ -- The boolean indicates whether we only allow consumption of -- parameters. checkAnyLambda ::- Checkable rep => Bool -> Lambda (Aliases rep) -> [Arg] -> TypeM rep ()+ (Checkable rep) => Bool -> Lambda (Aliases rep) -> [Arg] -> TypeM rep () checkAnyLambda soac (Lambda params body rettype) args = do let fname = nameFromString "<anonymous>" if length params == length args@@ -1428,10 +1427,10 @@ <> prettyText (length args) <> " arguments." -checkLambda :: Checkable rep => Lambda (Aliases rep) -> [Arg] -> TypeM rep ()+checkLambda :: (Checkable rep) => Lambda (Aliases rep) -> [Arg] -> TypeM rep () checkLambda = checkAnyLambda True -checkPrimExp :: Checkable rep => PrimExp VName -> TypeM rep ()+checkPrimExp :: (Checkable rep) => PrimExp VName -> TypeM rep () checkPrimExp ValueExp {} = pure () checkPrimExp (LeafExp v pt) = requireI [Prim pt] v checkPrimExp (BinOpExp op x y) = do@@ -1461,7 +1460,7 @@ <> prettyText h_ret zipWithM_ requirePrimExp h_ts args -requirePrimExp :: Checkable rep => PrimType -> PrimExp VName -> TypeM rep ()+requirePrimExp :: (Checkable rep) => PrimType -> PrimExp VName -> TypeM rep () requirePrimExp t e = context ("in PrimExp " <> prettyText e) $ do checkPrimExp e unless (primExpType e == t) . bad . TypeError $@@ -1484,38 +1483,38 @@ -- | Used at top level; can be locally changed with 'checkOpWith'. checkOp :: Op (Aliases rep) -> TypeM rep () - default checkExpDec :: ExpDec rep ~ () => ExpDec rep -> TypeM rep ()+ default checkExpDec :: (ExpDec rep ~ ()) => ExpDec rep -> TypeM rep () checkExpDec = pure - default checkBodyDec :: BodyDec rep ~ () => BodyDec rep -> TypeM rep ()+ default checkBodyDec :: (BodyDec rep ~ ()) => BodyDec rep -> TypeM rep () checkBodyDec = pure - default checkFParamDec :: FParamInfo rep ~ DeclType => VName -> FParamInfo rep -> TypeM rep ()+ default checkFParamDec :: (FParamInfo rep ~ DeclType) => VName -> FParamInfo rep -> TypeM rep () checkFParamDec _ = checkType - default checkLParamDec :: LParamInfo rep ~ Type => VName -> LParamInfo rep -> TypeM rep ()+ default checkLParamDec :: (LParamInfo rep ~ Type) => VName -> LParamInfo rep -> TypeM rep () checkLParamDec _ = checkType - default checkLetBoundDec :: LetDec rep ~ Type => VName -> LetDec rep -> TypeM rep ()+ default checkLetBoundDec :: (LetDec rep ~ Type) => VName -> LetDec rep -> TypeM rep () checkLetBoundDec _ = checkType - default checkRetType :: RetType rep ~ DeclExtType => [RetType rep] -> TypeM rep ()+ default checkRetType :: (RetType rep ~ DeclExtType) => [RetType rep] -> TypeM rep () checkRetType = mapM_ $ checkExtType . declExtTypeOf default matchPat :: Pat (LetDec (Aliases rep)) -> Exp (Aliases rep) -> TypeM rep () matchPat pat = matchExtPat pat <=< expExtType - default primFParam :: FParamInfo rep ~ DeclType => VName -> PrimType -> TypeM rep (FParam (Aliases rep))+ default primFParam :: (FParamInfo rep ~ DeclType) => VName -> PrimType -> TypeM rep (FParam (Aliases rep)) primFParam name t = pure $ Param mempty name (Prim t) - default matchReturnType :: RetType rep ~ DeclExtType => [RetType rep] -> Result -> TypeM rep ()+ default matchReturnType :: (RetType rep ~ DeclExtType) => [RetType rep] -> Result -> TypeM rep () matchReturnType = matchExtReturnType . map fromDecl - default matchBranchType :: BranchType rep ~ ExtType => [BranchType rep] -> Body (Aliases rep) -> TypeM rep ()+ default matchBranchType :: (BranchType rep ~ ExtType) => [BranchType rep] -> Body (Aliases rep) -> TypeM rep () matchBranchType = matchExtBranchType default matchLoopResult ::- FParamInfo rep ~ DeclType =>+ (FParamInfo rep ~ DeclType) => [FParam (Aliases rep)] -> Result -> TypeM rep ()
src/Futhark/Internalise/Bindings.hs view
@@ -117,7 +117,7 @@ type Params t = [I.Param t] processFlatPat ::- Show t =>+ (Show t) => [(E.Ident ParamType, [E.AttrInfo VName])] -> [t] -> InternaliseM ([Params t], VarSubsts)@@ -150,7 +150,7 @@ n -> replicateM n $ newVName $ baseString name bindingFlatPat ::- Show t =>+ (Show t) => [(E.Ident E.ParamType, [E.AttrInfo VName])] -> [t] -> ([Params t] -> InternaliseM a) ->@@ -161,7 +161,7 @@ m ps -- | Flatten a pattern. Returns a list of identifiers.-flattenPat :: MonadFreshNames m => E.Pat (TypeBase Size u) -> m [(E.Ident (TypeBase Size u), [E.AttrInfo VName])]+flattenPat :: (MonadFreshNames m) => E.Pat (TypeBase Size u) -> m [(E.Ident (TypeBase Size u), [E.AttrInfo VName])] flattenPat = flattenPat' where flattenPat' (E.PatParens p _) =
src/Futhark/Internalise/Defunctionalise.hs view
@@ -117,7 +117,7 @@ mapOnParamType = pure . replaceTypeSizes substs, mapOnResRetType = pure, mapOnExp = pure . onExp substs,- mapOnName = pure . onName substs+ mapOnName = pure . fmap (onName substs) } onName substs v =@@ -282,7 +282,7 @@ deriving (Eq, Ord, Show) dimMapping ::- Monoid a =>+ (Monoid a) => TypeBase Size a -> TypeBase Size a -> M.Map VName SizeSubst@@ -299,7 +299,7 @@ f _ d _ = pure d dimMapping' ::- Monoid a =>+ (Monoid a) => TypeBase Size a -> TypeBase Size a -> M.Map VName VName@@ -372,7 +372,7 @@ -- When we instantiate a polymorphic StaticVal, we rename all the -- sizes to avoid name conflicts later on. This is a bit of a hack... instStaticVal ::- MonadFreshNames m =>+ (MonadFreshNames m) => S.Set VName -> [VName] -> StructType ->@@ -582,7 +582,7 @@ defuncExp OpSectionRight {} = error "defuncExp: unexpected operator section." defuncExp ProjectSection {} = error "defuncExp: unexpected projection section." defuncExp IndexSection {} = error "defuncExp: unexpected projection section."-defuncExp (AppExp (DoLoop sparams pat e1 form e3 loc) res) = do+defuncExp (AppExp (Loop sparams pat e1 form e3 loc) res) = do (e1', sv1) <- defuncExp e1 let env1 = alwaysMatchPatSV pat sv1 (form', env2) <- case form of@@ -596,7 +596,7 @@ e2' <- localEnv env1 $ defuncExp' e2 pure (While e2', mempty) (e3', sv) <- localEnv (env1 <> env2) $ defuncExp e3- pure (AppExp (DoLoop sparams pat e1' form' e3' loc) res, sv)+ pure (AppExp (Loop sparams pat e1' form' e3' loc) res, sv) where envFromIdent (Ident vn (Info tp) _) = M.singleton vn $ Binding Nothing $ Dynamic $ toParam Observe tp@@ -668,14 +668,14 @@ pure (Constr name es' (Info sum_t') loc, sv) where defuncType ::- Monoid als =>+ (Monoid als) => TypeBase Size als -> TypeBase Size als defuncType (Array u shape t) = Array u shape (defuncScalar t) defuncType (Scalar t) = Scalar $ defuncScalar t defuncScalar ::- Monoid als =>+ (Monoid als) => ScalarTypeBase Size als -> ScalarTypeBase Size als defuncScalar (Record fs) = Record $ M.map defuncType fs@@ -826,7 +826,7 @@ RecordSV $ M.toList $ M.intersectionWith imposeType (M.fromList fs1) fs2 imposeType sv _ = sv -instAnySizes :: MonadFreshNames m => [Pat ParamType] -> m [Pat ParamType]+instAnySizes :: (MonadFreshNames m) => [Pat ParamType] -> m [Pat ParamType] instAnySizes = traverse $ traverse $ bitraverse onDim pure where onDim d@@ -1298,7 +1298,7 @@ -- | Transform a list of top-level value bindings. May produce new -- lifted function definitions, which are placed in front of the -- resulting list of declarations.-transformProg :: MonadFreshNames m => [ValBind] -> m [ValBind]+transformProg :: (MonadFreshNames m) => [ValBind] -> m [ValBind] transformProg decs = modifyNameSource $ \namesrc -> let ((), namesrc', decs') = runDefM namesrc $ defuncVals decs in (decs', namesrc')
src/Futhark/Internalise/Defunctorise.hs view
@@ -239,7 +239,7 @@ transformName v = lookupSubst v . scopeSubsts <$> askScope -- | A general-purpose substitution of names.-transformNames :: ASTMappable x => x -> TransformM x+transformNames :: (ASTMappable x) => x -> TransformM x transformNames x = do scope <- askScope pure $ runIdentity $ astMap (substituter scope) x@@ -247,8 +247,7 @@ substituter scope = ASTMapper { mapOnExp = onExp scope,- mapOnName = \v ->- pure $ qualLeaf $ fst $ lookupSubstInScope (qualName v) scope,+ mapOnName = \v -> pure $ fst $ lookupSubstInScope v {qualQuals = []} scope, mapOnStructType = astMap (substituter scope), mapOnParamType = astMap (substituter scope), mapOnResRetType = astMap (substituter scope)@@ -291,17 +290,15 @@ tdecl' <- traverse transformTypeExp tdecl t' <- transformResType t e' <- transformExp e- tparams' <- traverse transformNames tparams params' <- traverse transformNames params- emit $ ValDec $ ValBind entry' name' tdecl' (Info (RetType dims t')) tparams' params' e' doc attrs loc+ emit $ ValDec $ ValBind entry' name' tdecl' (Info (RetType dims t')) tparams params' e' doc attrs loc transformTypeBind :: TypeBind -> TransformM () transformTypeBind (TypeBind name l tparams te (Info (RetType dims t)) doc loc) = do name' <- transformName name emit . TypeDec- =<< ( TypeBind name' l- <$> traverse transformNames tparams- <*> transformTypeExp te+ =<< ( TypeBind name' l tparams+ <$> transformTypeExp te <*> (Info . RetType dims <$> transformStructType t) <*> pure doc <*> pure loc@@ -373,7 +370,7 @@ maybeHideEntryPoint d = d -- | Perform defunctorisation.-transformProg :: MonadFreshNames m => Imports -> m [Dec]+transformProg :: (MonadFreshNames m) => Imports -> m [Dec] transformProg prog = modifyNameSource $ \namesrc -> let ((), namesrc', prog') = runTransformM namesrc $ transformImports prog in (DL.toList prog', namesrc')
src/Futhark/Internalise/Exps.hs view
@@ -30,7 +30,7 @@ -- | Convert a program in source Futhark to a program in the Futhark -- core language.-transformProg :: MonadFreshNames m => Bool -> VisibleTypes -> [E.ValBind] -> m (I.Prog SOACS)+transformProg :: (MonadFreshNames m) => Bool -> VisibleTypes -> [E.ValBind] -> m (I.Prog SOACS) transformProg always_safe types vbinds = do (opaques, consts, funs) <- runInternaliseM always_safe (internaliseValBinds types vbinds)@@ -340,7 +340,7 @@ -- application. One caveat is that we need to replace any -- existential sizes, too (with zeroes, because they don't -- matter).- let subst = zip ext $ repeat $ E.ExpSubst $ E.sizeFromInteger 0 mempty+ let subst = map (,E.ExpSubst (E.sizeFromInteger 0 mempty)) ext et' = E.applySubst (`lookup` subst) et internaliseExp desc (E.Hole (Info et') loc) (FunctionName qfname, args) -> do@@ -391,7 +391,7 @@ internalisePat desc sizes pat e $ internaliseExp desc body internaliseAppExp _ _ (E.LetFun ofname _ _ _) = error $ "Unexpected LetFun " ++ prettyString ofname-internaliseAppExp desc _ (E.DoLoop sparams mergepat mergeexp form loopbody loc) = do+internaliseAppExp desc _ (E.Loop sparams mergepat mergeexp form loopbody loc) = do ses <- internaliseExp "loop_init" mergeexp ((loopbody', (form', shapepat, mergepat', mergeinit')), initstms) <- collectStms $ handleForm ses form@@ -438,7 +438,7 @@ map I.Var . dropCond <$> attributing attrs- (letValExp desc (I.DoLoop merge form' loopbody''))+ (letValExp desc (I.Loop merge form' loopbody'')) where sparams' = map (`TypeParamDim` mempty) sparams @@ -474,7 +474,7 @@ num_iterations_t <- I.subExpType num_iterations' it <- case num_iterations_t of I.Prim (IntType it) -> pure it- _ -> error "internaliseExp DoLoop: invalid type"+ _ -> error "internaliseExp Loop: invalid type" ts <- mapM subExpType mergeinit bindingLoopParams sparams' mergepat ts $
src/Futhark/Internalise/FullNormalise.hs view
@@ -82,7 +82,7 @@ addBind b@FunBind {} = OrderingM $ modify $ first $ first (b :) -runOrdering :: MonadFreshNames m => OrderingM a -> m (a, [Binding])+runOrdering :: (MonadFreshNames m) => OrderingM a -> m (a, [Binding]) runOrdering (OrderingM m) = modifyNameSource $ mod_tup . flip runReader "tmp" . runStateT m . (([], []),) where@@ -283,14 +283,14 @@ et' <- transformBody et ef' <- transformBody ef nameExp final $ AppExp (If cond' et' ef' loc) resT-getOrdering final (AppExp (DoLoop sizes pat einit form body loc) resT) = do+getOrdering final (AppExp (Loop sizes pat einit form body loc) resT) = do einit' <- getOrdering False einit form' <- case form of For ident e -> For ident <$> getOrdering True e ForIn fpat e -> ForIn fpat <$> getOrdering True e While e -> While <$> transformBody e body' <- transformBody body- nameExp final $ AppExp (DoLoop sizes pat einit' form' body' loc) resT+ nameExp final $ AppExp (Loop sizes pat einit' form' body' loc) resT getOrdering final (AppExp (BinOp (op, oloc) opT (el, Info elp) (er, Info erp) loc) (Info resT)) = do expr' <- case (isOr, isAnd) of (True, _) -> do@@ -335,7 +335,7 @@ -- branches of an if/match... -- Note that this is not producing an OrderingM, produce -- a complete separtion of states.-transformBody :: MonadFreshNames m => Exp -> m Exp+transformBody :: (MonadFreshNames m) => Exp -> m Exp transformBody e = do (e', pre_eval) <- runOrdering (getOrdering True e) pure $ foldl f e' pre_eval@@ -357,11 +357,11 @@ f body (FunBind vn infos) = AppExp (LetFun vn infos body mempty) appRes -transformDec :: MonadFreshNames m => Dec -> m Dec+transformDec :: (MonadFreshNames m) => Dec -> m Dec transformDec (ValDec valbind) = do body' <- transformBody $ valBindBody valbind pure $ ValDec (valbind {valBindBody = body'}) transformDec d = pure d -transformProg :: MonadFreshNames m => [Dec] -> m [Dec]+transformProg :: (MonadFreshNames m) => [Dec] -> m [Dec] transformProg = mapM transformDec
src/Futhark/Internalise/LiftLambdas.hs view
@@ -158,11 +158,20 @@ e' <- transformExp e body' <- bindingLetPat (map sizeName sizes) pat $ transformExp body pure $ AppExp (LetPat sizes pat e' body' loc) appres-transformExp (AppExp (DoLoop sizes pat args form body loc) appres) = do+transformExp (AppExp (Match e cases loc) appres) = do+ e' <- transformExp e+ cases' <- mapM transformCase cases+ pure $ AppExp (Match e' cases' loc) appres+ where+ transformCase (CasePat case_pat case_e case_loc) =+ CasePat case_pat+ <$> bindingLetPat [] case_pat (transformExp case_e)+ <*> pure case_loc+transformExp (AppExp (Loop sizes pat args form body loc) appres) = do args' <- transformExp args form' <- astMap transformSubExps form body' <- bindingParams sizes [pat] $ bindingForm form' $ transformExp body- pure $ AppExp (DoLoop sizes pat args' form' body' loc) appres+ pure $ AppExp (Loop sizes pat args' form' body' loc) appres transformExp e@(Var v _ _) = -- Note that function-typed variables can only occur in expressions, -- not in other places where VNames/QualNames can occur.@@ -179,7 +188,7 @@ {-# NOINLINE transformProg #-} -- | Perform the transformation.-transformProg :: MonadFreshNames m => [ValBind] -> m [ValBind]+transformProg :: (MonadFreshNames m) => [ValBind] -> m [ValBind] transformProg vbinds = modifyNameSource $ \namesrc -> runLiftM namesrc $ mapM_ transformValBind vbinds
src/Futhark/Internalise/Monad.hs view
@@ -97,7 +97,7 @@ collectStms (InternaliseM m) = InternaliseM $ collectStms m runInternaliseM ::- MonadFreshNames m =>+ (MonadFreshNames m) => Bool -> InternaliseM () -> m (OpaqueTypes, Stms SOACS, [FunDef SOACS])
src/Futhark/Internalise/Monomorphise.hs view
@@ -460,7 +460,7 @@ let dims' = dims <> map snd rl pure $ RetType dims' ty' -sizesForPat :: MonadFreshNames m => Pat ParamType -> m ([VName], Pat ParamType)+sizesForPat :: (MonadFreshNames m) => Pat ParamType -> m ([VName], Pat ParamType) sizesForPat pat = do (params', sizes) <- runStateT (traverse (bitraverse onDim pure) pat) [] pure (sizes, params')@@ -528,7 +528,7 @@ <*> transformAppRes res where onArg (Info (d, ext), e) = (d,ext,) <$> transformExp e-transformAppExp (DoLoop sparams pat e1 form body loc) res = do+transformAppExp (Loop sparams pat e1 form body loc) res = do e1' <- transformExp e1 let dimArgs = S.fromList sparams@@ -555,7 +555,7 @@ -- sizes for them. (pat_sizes, pat'') <- sizesForPat pat' res' <- transformAppRes res- pure $ AppExp (DoLoop (sparams' ++ pat_sizes) pat'' e1' form' body' loc) (Info res')+ pure $ AppExp (Loop (sparams' ++ pat_sizes) pat'' e1' form' body' loc) (Info res') transformAppExp (BinOp (fname, _) (Info t) (e1, d1) (e2, d2) loc) res = do (AppRes ret ext) <- transformAppRes res fname' <- transformFName loc fname (toStruct t)@@ -866,7 +866,7 @@ type DimInst = M.Map VName Size dimMapping ::- Monoid a =>+ (Monoid a) => TypeBase Size a -> TypeBase Size a -> ExpReplacements ->@@ -899,7 +899,7 @@ inferSizeArgs :: [TypeParam] -> StructType -> ExpReplacements -> StructType -> MonoM [Exp] inferSizeArgs tparams bind_t bind_r t = do- r <- get+ r <- gets (<>) <*> asks envParametrized let dinst = dimMapping bind_t t bind_r r mapM (tparamArg dinst) tparams where@@ -1142,7 +1142,7 @@ } typeSubstsM ::- MonadFreshNames m =>+ (MonadFreshNames m) => SrcLoc -> TypeBase () NoUniqueness -> MonoType ->@@ -1309,7 +1309,7 @@ -- | Monomorphise a list of top-level declarations. A module-free input program -- is expected, so only value declarations and type declaration are accepted.-transformProg :: MonadFreshNames m => [Dec] -> m [ValBind]+transformProg :: (MonadFreshNames m) => [Dec] -> m [ValBind] transformProg decs = fmap (toList . fmap snd . snd) $ modifyNameSource $ \namesrc ->
src/Futhark/Internalise/ReplaceRecords.hs view
@@ -141,7 +141,7 @@ -- | Monomorphise a list of top-level declarations. A module-free input program -- is expected, so only value declarations and type declaration are accepted.-transformProg :: MonadFreshNames m => [ValBind] -> m [ValBind]+transformProg :: (MonadFreshNames m) => [ValBind] -> m [ValBind] transformProg vbs = modifyNameSource $ \namesrc -> runRecordM namesrc $ mapM onValBind vbs
src/Futhark/Internalise/TypesValues.hs view
@@ -97,7 +97,7 @@ <$> internaliseParamTypes [et] -- Tag every sublist with its offset in corresponding flattened list.-withOffsets :: Foldable a => [a b] -> [(a b, Int)]+withOffsets :: (Foldable a) => [a b] -> [(a b, Int)] withOffsets xs = zip xs (scanl (+) 0 $ map length xs) numberFrom :: Int -> Tree a -> Tree (a, Int)
src/Futhark/MonadFreshNames.hs view
@@ -40,15 +40,15 @@ -- getNameSource = get -- putNameSource = put -- @-class Monad m => MonadFreshNames m where+class (Monad m) => MonadFreshNames m where getNameSource :: m VNameSource putNameSource :: VNameSource -> m () -instance Monad im => MonadFreshNames (Control.Monad.State.Lazy.StateT VNameSource im) where+instance (Monad im) => MonadFreshNames (Control.Monad.State.Lazy.StateT VNameSource im) where getNameSource = Control.Monad.State.Lazy.get putNameSource = Control.Monad.State.Lazy.put -instance Monad im => MonadFreshNames (Control.Monad.State.Strict.StateT VNameSource im) where+instance (Monad im) => MonadFreshNames (Control.Monad.State.Strict.StateT VNameSource im) where getNameSource = Control.Monad.State.Strict.get putNameSource = Control.Monad.State.Strict.put @@ -69,7 +69,7 @@ -- | Run a computation needing a fresh name source and returning a new -- one, using 'getNameSource' and 'putNameSource' before and after the -- computation.-modifyNameSource :: MonadFreshNames m => (VNameSource -> (a, VNameSource)) -> m a+modifyNameSource :: (MonadFreshNames m) => (VNameSource -> (a, VNameSource)) -> m a modifyNameSource m = do src <- getNameSource let (x, src') = m src@@ -77,24 +77,24 @@ pure x -- | Produce a fresh name, using the given name as a template.-newName :: MonadFreshNames m => VName -> m VName+newName :: (MonadFreshNames m) => VName -> m VName newName = modifyNameSource . flip FreshNames.newName -- | As @newName@, but takes a 'String' for the name template.-newNameFromString :: MonadFreshNames m => String -> m VName+newNameFromString :: (MonadFreshNames m) => String -> m VName newNameFromString s = newName $ VName (nameFromString s) 0 -- | Produce a fresh 'VName', using the given base name as a template.-newID :: MonadFreshNames m => Name -> m VName+newID :: (MonadFreshNames m) => Name -> m VName newID s = newName $ VName s 0 -- | Produce a fresh 'VName', using the given base name as a template.-newVName :: MonadFreshNames m => String -> m VName+newVName :: (MonadFreshNames m) => String -> m VName newVName = newID . nameFromString -- | Produce a fresh 'Ident', using the given name as a template. newIdent ::- MonadFreshNames m =>+ (MonadFreshNames m) => String -> Type -> m Ident@@ -105,7 +105,7 @@ -- | Produce a fresh 'Ident', using the given 'Ident' as a template, -- but possibly modifying the name. newIdent' ::- MonadFreshNames m =>+ (MonadFreshNames m) => (String -> String) -> Ident -> m Ident@@ -116,7 +116,7 @@ -- | Produce a fresh 'Param', using the given name as a template. newParam ::- MonadFreshNames m =>+ (MonadFreshNames m) => String -> dec -> m (Param dec)@@ -127,7 +127,7 @@ -- Utility instance defintions for MTL classes. This requires -- UndecidableInstances, but saves on typing elsewhere. -instance MonadFreshNames m => MonadFreshNames (ReaderT s m) where+instance (MonadFreshNames m) => MonadFreshNames (ReaderT s m) where getNameSource = lift getNameSource putNameSource = lift . putNameSource @@ -146,14 +146,14 @@ putNameSource = lift . putNameSource instance- MonadFreshNames m =>+ (MonadFreshNames m) => MonadFreshNames (Control.Monad.Trans.Maybe.MaybeT m) where getNameSource = lift getNameSource putNameSource = lift . putNameSource instance- MonadFreshNames m =>+ (MonadFreshNames m) => MonadFreshNames (ExceptT e m) where getNameSource = lift getNameSource
src/Futhark/Optimise/ArrayShortCircuiting.hs view
@@ -144,12 +144,12 @@ case_rets <- zipWithM (generalizeIxfun pat_elems) pat_elems $ matchReturns dec let dec' = dec {matchReturns = case_rets} pure $ Match cond_ses cases' defbody' dec'-replaceInExp _ (DoLoop loop_inits loop_form (Body dec stms res)) = do+replaceInExp _ (Loop loop_inits loop_form (Body dec stms res)) = do loop_inits' <- mapM (replaceInFParam . fst) loop_inits stms' <- updateStms stms coalstab <- asks envCoalesceTab let res' = map (replaceResMem coalstab) res- pure $ DoLoop (zip loop_inits' $ map snd loop_inits) loop_form $ Body dec stms' res'+ pure $ Loop (zip loop_inits' $ map snd loop_inits) loop_form $ Body dec stms' res' replaceInExp _ (Op op) = case op of Inner i -> do
src/Futhark/Optimise/ArrayShortCircuiting/ArrayCoalescing.hs view
@@ -121,7 +121,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)@@ -184,7 +184,7 @@ -- | Short-circuit handler for SegOp. shortCircuitSegOp ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => (lvl -> Bool) -> LUTabFun -> Pat (VarAliases, LetDecMem) ->@@ -347,7 +347,7 @@ -- 4. Mark active coalescings as finished, since a 'SegOp' is an array creation -- point. shortCircuitSegOpHelper ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => -- | The number of returns for which we should drop the last seg space Int -> -- | Whether we should look at a segop with this lvl.@@ -485,21 +485,17 @@ Just (Coalesced knd mbd@(MemBlock _ _ _ ixfn) _) -> pure $ case freeVarSubstitutions (scope td_env) (scalarTable td_env) ixfn of Just fv_subst ->- if IxFun.permutation ixfn- == IxFun.permutation (ixfun $ fromJust $ getScopeMemInfo (patElemName p) $ scope td_env)- then- let entry =- coal_entry- { vartab =- M.insert- (patElemName p)- (Coalesced knd mbd fv_subst)- (vartab coal_entry)- }- (ac, suc) =- markSuccessCoal (activeCoals bu_env_f, successCoals bu_env_f) m_b entry- in bu_env_f {activeCoals = ac, successCoals = suc}- else fail_res+ let entry =+ coal_entry+ { vartab =+ M.insert+ (patElemName p)+ (Coalesced knd mbd fv_subst)+ (vartab coal_entry)+ }+ (ac, suc) =+ markSuccessCoal (activeCoals bu_env_f, successCoals bu_env_f) m_b entry+ in bu_env_f {activeCoals = ac, successCoals = suc} Nothing -> fail_res else pure fail_res@@ -600,7 +596,7 @@ Slice $ slc ++ map (\d -> DimSlice 0 d 1) (drop (length slc) shp) fixPointCoalesce ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => LUTabFun -> [Param FParamMem] -> Body (Aliases rep) ->@@ -616,7 +612,9 @@ handleFunctionParams (a, i, s) (_, u, MemBlock _ _ m ixf) = case (u, M.lookup m a) of (Unique, Just entry)- | dstind entry == ixf ->+ | dstind entry == ixf,+ Set dst_uses <- dstrefs (memrefs entry),+ dst_uses == mempty -> let (a', s') = markSuccessCoal (a, s) m entry in (a', i, s') _ ->@@ -663,7 +661,7 @@ -- | Perform short-circuiting on 'Stms'. mkCoalsTabStms ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => LUTabFun -> Stms (Aliases rep) -> TopdownEnv rep ->@@ -706,7 +704,7 @@ -- then the checks should be extended to the actual -- array-creation points. mkCoalsTabStm ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => LUTabFun -> Stm (Aliases rep) -> TopdownEnv rep ->@@ -841,7 +839,7 @@ -- hence remove the coalescing of the result. (markFailedCoal (act, inhb) (patMem mbr), succc)-mkCoalsTabStm lutab (Let pat _ (DoLoop arginis lform body)) td_env bu_env = do+mkCoalsTabStm lutab (Let pat _ (Loop arginis lform body)) td_env bu_env = do let pat_val_elms = patElems pat -- i) Filter @activeCoals@ by the 2nd, 3rd AND 5th safety conditions. In@@ -1004,6 +1002,9 @@ | b <- patElemName patel, (_, MemArray _ _ _ (ArrayIn m_b _)) <- patElemDec patel, a <- paramName arg,+ -- Not safe to short-circuit if the index function of this+ -- parameter is variant to the loop.+ not $ any ((`nameIn` freeIn (paramDec arg)) . paramName . fst) arginis, Var a0 <- ini, Var r <- bdyres, Just coal_etry <- M.lookup m_b actv0,@@ -1179,9 +1180,9 @@ mkCoalsTabStm lutab stm@(Let pat aux (Op op)) td_env bu_env = do -- Process body on_op <- asks onOp- activeCoals' <- mkCoalsHelper3PatternMatch stm lutab td_env bu_env- let bu_env' = bu_env {activeCoals = activeCoals'}- on_op lutab pat (stmAuxCerts aux) op td_env bu_env'+ bu_env' <- on_op lutab pat (stmAuxCerts aux) op td_env bu_env+ activeCoals' <- mkCoalsHelper3PatternMatch stm lutab td_env bu_env'+ pure $ bu_env' {activeCoals = activeCoals'} mkCoalsTabStm lutab stm@(Let pat _ e) td_env bu_env = do -- i) Filter @activeCoals@ by the 3rd safety condition: -- this is now relaxed by use of LMAD eqs:@@ -1267,7 +1268,7 @@ -- any variables used in the index function of the target array are available at -- the definition site of b. filterSafetyCond2and5 ::- HasMemBlock (Aliases rep) =>+ (HasMemBlock (Aliases rep)) => CoalsTab -> InhibitTab -> ScalarTab ->@@ -1323,7 +1324,7 @@ -- | Pattern matches a potentially coalesced statement and -- records a new association in @activeCoals@ mkCoalsHelper3PatternMatch ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => Stm (Aliases rep) -> LUTabFun -> TopdownEnv rep ->@@ -1435,7 +1436,7 @@ -- | For 'SegOp', we currently only handle 'SegMap', and only under the following -- circumstances: ----- 1. The 'SegMap' has only one return/pattern value.+-- 1. The 'SegMap' has only one return/pattern value, which is a 'Returns'. -- -- 2. The 'KernelBody' contains an 'Index' statement that is indexing an array using -- only the values from the 'SegSpace'.@@ -1456,19 +1457,19 @@ -- The result of the 'SegMap' is treated as the destination, while the candidate -- array from inside the body is treated as the source. genSSPointInfoSegOp ::- Coalesceable rep inner => GenSSPoint rep (SegOp lvl (Aliases rep))+ (Coalesceable rep inner) => GenSSPoint rep (SegOp lvl (Aliases rep)) genSSPointInfoSegOp lutab td_env scopetab (Pat [PatElem dst (_, MemArray dst_pt _ _ (ArrayIn dst_mem dst_ixf))]) certs- (SegMap _ space _ kernel_body)- | (src, MemBlock _ shp src_mem src_ixf) : _ <-+ (SegMap _ space _ kernel_body@KernelBody {kernelBodyResult = [Returns {}]})+ | (src, MemBlock src_pt shp src_mem src_ixf) : _ <- mapMaybe getPotentialMapShortCircuit $ stmsToList $ kernelBodyStms kernel_body =- Just [(MapCoal, id, dst, dst_mem, dst_ixf, src, src_mem, src_ixf, dst_pt, shp, certs)]+ Just [(MapCoal, id, dst, dst_mem, dst_ixf, src, src_mem, src_ixf, src_pt, shp, certs)] where iterators = map fst $ unSegSpace space frees = freeIn kernel_body@@ -1517,7 +1518,7 @@ f _ _ _ _ _ _ = Nothing genCoalStmtInfo ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => LUTabFun -> TopdownEnv rep -> ScopeTab rep ->@@ -1557,10 +1558,7 @@ where updateIndFunSlice :: IxFun -> FlatSlice SubExp -> IxFun updateIndFunSlice ind_fun (FlatSlice offset dims) =- fromMaybe (error "updateIndFunSlice") $- IxFun.flatSlice ind_fun $- FlatSlice (pe64 offset) $- map (fmap pe64) dims+ IxFun.flatSlice ind_fun $ FlatSlice (pe64 offset) $ map (fmap pe64) dims -- CASE b) @let x = concat(a, b^{lu})@ genCoalStmtInfo lutab _ scopetab (Let pat aux (BasicOp (Concat concat_dim (b0 :| bs) _)))@@ -1694,14 +1692,14 @@ mki64subst _ = Nothing computeScalarTable ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => ScopeTab rep -> Stm (Aliases rep) -> ScalarTableM rep (M.Map VName (PrimExp VName)) computeScalarTable scope_table (Let (Pat [pe]) _ e) | Just primexp <- primExpFromExp (vnameToPrimExp scope_table mempty) e = pure $ M.singleton (patElemName pe) primexp-computeScalarTable scope_table (Let _ _ (DoLoop loop_inits loop_form body)) =+computeScalarTable scope_table (Let _ _ (Loop loop_inits loop_form body)) = concatMapM ( computeScalarTable $ scope_table@@ -1734,7 +1732,7 @@ computeScalarTableMemOp onInner scope_table (Inner op) = onInner scope_table op computeScalarTableSegOp ::- Coalesceable rep inner =>+ (Coalesceable rep inner) => ComputeScalarTable rep (GPU.SegOp lvl (Aliases rep)) computeScalarTableSegOp scope_table segop = do concatMapM
src/Futhark/Optimise/ArrayShortCircuiting/MemRefAggreg.hs view
@@ -40,7 +40,7 @@ -- table) until all vars appearing in the index function are defined in the -- current scope?" freeVarSubstitutions ::- FreeIn a =>+ (FreeIn a) => ScopeTab rep -> ScalarTab -> a ->@@ -135,7 +135,8 @@ Var x -> Just (ws, ws ++ mapMaybe (getDirAliasedIxfn td_env coal_tab) [x]) getUseSumFromStm td_env coal_tab (Let (Pat [x]) _ (BasicOp (FlatUpdate _ (FlatSlice offset slc) v))) | Just (m_b, m_x, x_ixfn) <- getDirAliasedIxfn td_env coal_tab (patElemName x) = do- x_ixfn_slc <- IxFun.flatSlice x_ixfn $ FlatSlice (pe64 offset) $ map (fmap pe64) slc+ let x_ixfn_slc =+ IxFun.flatSlice x_ixfn $ FlatSlice (pe64 offset) $ map (fmap pe64) slc let r1 = (m_b, m_x, x_ixfn_slc) case getDirAliasedIxfn td_env coal_tab v of Nothing -> Just ([r1], [r1])@@ -298,7 +299,7 @@ -- \bigcup_{j=0}^{j<n} Access_j -- \] aggSummaryLoopTotal ::- MonadFreshNames m =>+ (MonadFreshNames m) => ScopeTab rep -> ScopeTab rep -> ScalarTab ->@@ -335,7 +336,7 @@ -- \bigcup_{j=i+1}^{j<n} Access_j -- \] aggSummaryLoopPartial ::- MonadFreshNames m =>+ (MonadFreshNames m) => ScalarTab -> Maybe (VName, (TPrimExp Int64 VName, TPrimExp Int64 VName)) -> AccessSummary ->@@ -372,7 +373,7 @@ -- total aggregation of the inner dimensions. For outer dimensions, the equation -- is the same, the point accesses in $Access_j$ are replaced with the total -- aggregation of the inner dimensions.-aggSummaryMapPartial :: MonadFreshNames m => ScalarTab -> [(VName, SubExp)] -> LmadRef -> m AccessSummary+aggSummaryMapPartial :: (MonadFreshNames m) => ScalarTab -> [(VName, SubExp)] -> LmadRef -> m AccessSummary aggSummaryMapPartial _ [] = const $ pure mempty aggSummaryMapPartial scalars dims = helper mempty (reverse dims) . Set . S.singleton -- Reverse dims so we work from the inside out@@ -396,7 +397,7 @@ -- \[ -- \bigcup_{j=0}^{j<i} a_j \cup \bigcup_{j=i+1}^{j<n} a_j -- \]-aggSummaryMapPartialOne :: MonadFreshNames m => ScalarTab -> (VName, SubExp) -> AccessSummary -> m AccessSummary+aggSummaryMapPartialOne :: (MonadFreshNames m) => ScalarTab -> (VName, SubExp) -> AccessSummary -> m AccessSummary aggSummaryMapPartialOne _ _ Undeterminable = pure Undeterminable aggSummaryMapPartialOne _ (_, Constant n) (Set _) | oneIsh n = pure mempty aggSummaryMapPartialOne scalars (gtid, size) (Set lmads0) =@@ -412,7 +413,7 @@ helper (x, y) = concatMapM (aggSummaryOne gtid x y) lmads -- | Computes to total access summary over a multi-dimensional map.-aggSummaryMapTotal :: MonadFreshNames m => ScalarTab -> [(VName, SubExp)] -> AccessSummary -> m AccessSummary+aggSummaryMapTotal :: (MonadFreshNames m) => ScalarTab -> [(VName, SubExp)] -> AccessSummary -> m AccessSummary aggSummaryMapTotal _ [] _ = pure mempty aggSummaryMapTotal _ _ (Set lmads) | lmads == mempty = pure mempty@@ -446,7 +447,7 @@ -- -- The function returns 'Underterminable' if the iterator is free in the output -- LMAD or the dimensions of the input LMAD .-aggSummaryOne :: MonadFreshNames m => VName -> TPrimExp Int64 VName -> TPrimExp Int64 VName -> LmadRef -> m AccessSummary+aggSummaryOne :: (MonadFreshNames m) => VName -> TPrimExp Int64 VName -> TPrimExp Int64 VName -> LmadRef -> m AccessSummary aggSummaryOne iterator_var lower_bound spn lmad@(IxFun.LMAD offset0 dims0) | iterator_var `nameIn` freeIn dims0 = pure Undeterminable | iterator_var `notNameIn` freeIn offset0 = pure $ Set $ S.singleton lmad@@ -457,13 +458,11 @@ new_stride = TPrimExp $ constFoldPrimExp $ simplify $ untyped $ offsetp1 - offset new_offset = replaceIteratorWith lower_bound offset0 new_lmad =- IxFun.LMAD new_offset $- IxFun.LMADDim new_stride spn 0 : map incPerm dims0+ IxFun.LMAD new_offset $ IxFun.LMADDim new_stride spn : dims0 if new_var `nameIn` freeIn new_lmad then pure Undeterminable else pure $ Set $ S.singleton new_lmad where- incPerm dim = dim {IxFun.ldPerm = IxFun.ldPerm dim + 1} replaceIteratorWith se = TPrimExp . substituteInPrimExp (M.singleton iterator_var $ untyped se) . untyped -- | Takes a 'VName' and converts it into a 'TPrimExp' with type 'Int64'.
src/Futhark/Optimise/ArrayShortCircuiting/TopdownAnalysis.hs view
@@ -83,7 +83,7 @@ getDirAliasFromExp (BasicOp (FlatIndex x (FlatSlice offset idxs))) = Just ( x,- (`IxFun.flatSlice` FlatSlice (pe64 offset) (map (fmap pe64) idxs))+ Just . (`IxFun.flatSlice` FlatSlice (pe64 offset) (map (fmap pe64) idxs)) ) getDirAliasFromExp (BasicOp (FlatUpdate x _ _)) = Just (x, Just) getDirAliasFromExp _ = Nothing@@ -110,8 +110,7 @@ getInvAliasFromExp (BasicOp (Opaque _ (Var _))) = Just id getInvAliasFromExp (BasicOp Update {}) = Just id getInvAliasFromExp (BasicOp (Rearrange perm _)) =- let perm' = IxFun.permuteInv perm [0 .. length perm - 1]- in Just (`IxFun.permute` perm')+ Just (`IxFun.permute` rearrangeInverse perm) getInvAliasFromExp _ = Nothing class TopDownHelper inner where@@ -142,7 +141,7 @@ scopeHelper (SegOp op) = scopeHelper op scopeHelper _ = mempty -instance TopDownHelper (inner (Aliases MCMem)) => TopDownHelper (MC.MCOp inner (Aliases MCMem)) 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@@ -198,7 +197,7 @@ nonNegatives = nonNegatives env <> nonNegativesInPat (stmPat stm) } -nonNegativesInPat :: Typed rep => Pat rep -> Names+nonNegativesInPat :: (Typed rep) => Pat rep -> Names nonNegativesInPat (Pat elems) = foldMap (namesFromList . mapMaybe subExpVar . arrayDims . typeOf) elems @@ -226,7 +225,7 @@ -- | Get direct aliased index function. Returns a triple of current memory -- block to be coalesced, the destination memory block and the index function of -- the access in the space of the destination block.-getDirAliasedIxfn :: HasMemBlock (Aliases rep) => TopdownEnv rep -> CoalsTab -> VName -> Maybe (VName, VName, IxFun)+getDirAliasedIxfn :: (HasMemBlock (Aliases rep)) => TopdownEnv rep -> CoalsTab -> VName -> Maybe (VName, VName, IxFun) getDirAliasedIxfn td_env coals_tab x = case getScopeMemInfo x (scope td_env) of Just (MemBlock _ _ m_x orig_ixfun) ->@@ -242,7 +241,7 @@ -- | Like 'getDirAliasedIxfn', but this version returns 'Nothing' if the value -- is not currently subject to coalescing.-getDirAliasedIxfn' :: HasMemBlock (Aliases rep) => TopdownEnv rep -> CoalsTab -> VName -> Maybe (VName, VName, IxFun)+getDirAliasedIxfn' :: (HasMemBlock (Aliases rep)) => TopdownEnv rep -> CoalsTab -> VName -> Maybe (VName, VName, IxFun) getDirAliasedIxfn' td_env coals_tab x = case getScopeMemInfo x (scope td_env) of Just (MemBlock _ _ m_x _) ->@@ -284,7 +283,7 @@ -- @vartab@, of course if their aliasing operations are invertible. -- We assume inverting aliases has been performed by the top-down pass. addInvAliasesVarTab ::- HasMemBlock (Aliases rep) =>+ (HasMemBlock (Aliases rep)) => TopdownEnv rep -> M.Map VName Coalesced -> VName ->
src/Futhark/Optimise/BlkRegTiling.hs view
@@ -47,7 +47,7 @@ se8 :: SubExp se8 = intConst Int64 8 -scratch :: MonadBuilder m => String -> PrimType -> [SubExp] -> m VName+scratch :: (MonadBuilder m) => String -> PrimType -> [SubExp] -> m VName scratch se_name t shape = letExp se_name $ BasicOp $ Scratch t shape -- | Main helper function for Register-and-Block Tiling@@ -149,10 +149,8 @@ error "kkLoopBody.isInnerCoal: not an error, but I would like to know why!" innerHasStride1 lmad = let lmad_dims = LMAD.dims lmad- q = length lmad_dims- last_perm = IxFun.ldPerm $ last lmad_dims stride = IxFun.ldStride $ last lmad_dims- in (last_perm == q - 1) && (stride == pe64 (intConst Int64 1))+ in stride == pe64 (intConst Int64 1) -- mkRedomapOneTileBody acc_merge asss bsss fits_ij = do -- the actual redomap.@@ -713,7 +711,7 @@ matchesBlkRegTile _ _ = Nothing -- ceiled division expression-ceilDiv :: MonadBuilder m => SubExp -> SubExp -> m (Exp (Rep m))+ceilDiv :: (MonadBuilder m) => SubExp -> SubExp -> m (Exp (Rep m)) ceilDiv x y = pure $ BasicOp $ BinOp (SDivUp Int64 Unsafe) x y mkTileMemSizes ::
src/Futhark/Optimise/CSE.hs view
@@ -188,7 +188,7 @@ nestedCSE stm' = do let ds = case stmExp stm' of- DoLoop merge _ _ -> map (diet . declTypeOf . fst) merge+ Loop merge _ _ -> map (diet . declTypeOf . fst) merge _ -> map patElemDiet $ patElems $ stmPat stm' e <- mapExpM (cse ds) $ stmExp stm' pure stm' {stmExp = e}@@ -211,7 +211,7 @@ normExp e = e cseInStm ::- ASTRep rep =>+ (ASTRep rep) => Names -> Stm rep -> ([Stm rep] -> CSEM rep a) ->@@ -271,7 +271,7 @@ CSEState (esubsts, mkSubsts pat subpat `M.union` nsubsts) cse_arrays addExpSubst ::- ASTRep rep =>+ (ASTRep rep) => Pat (LetDec rep) -> ExpDec rep -> Certs ->@@ -336,7 +336,7 @@ Body _ stms' _ <- cseInBody (map (const Observe) res) $ Body bodydec stms [] pure $ GPU.KernelBody bodydec stms' res -instance CSEInOp (op rep) => CSEInOp (Memory.MemOp op rep) 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)
src/Futhark/Optimise/DoubleBuffer.hs view
@@ -98,7 +98,7 @@ doubleBufferMC = doubleBuffer optimiseMCOp -- | The double buffering pass definition.-doubleBuffer :: Mem rep inner => OptimiseOp rep -> Pass rep rep+doubleBuffer :: (Mem rep inner) => OptimiseOp rep -> Pass rep rep doubleBuffer onOp = Pass { passName = "Double buffer",@@ -140,32 +140,32 @@ } deriving (Functor, Applicative, Monad, MonadReader (Env rep), MonadFreshNames) -instance ASTRep rep => HasScope rep (DoubleBufferM rep) where+instance (ASTRep rep) => HasScope rep (DoubleBufferM rep) where askScope = asks envScope -instance ASTRep rep => LocalScope rep (DoubleBufferM rep) where+instance (ASTRep rep) => LocalScope rep (DoubleBufferM rep) where localScope scope = local $ \env -> env {envScope = envScope env <> scope} -optimiseBody :: ASTRep rep => Body rep -> DoubleBufferM rep (Body rep)+optimiseBody :: (ASTRep rep) => Body rep -> DoubleBufferM rep (Body rep) optimiseBody body = do stms' <- optimiseStms $ stmsToList $ bodyStms body pure $ body {bodyStms = stms'} -optimiseStms :: ASTRep rep => [Stm rep] -> DoubleBufferM rep (Stms rep)+optimiseStms :: (ASTRep rep) => [Stm rep] -> DoubleBufferM rep (Stms rep) optimiseStms [] = pure mempty optimiseStms (e : es) = do e_es <- optimiseStm e es' <- localScope (castScope $ scopeOf e_es) $ optimiseStms es pure $ e_es <> es' -optimiseStm :: forall rep. ASTRep rep => Stm rep -> DoubleBufferM rep (Stms rep)-optimiseStm (Let pat aux (DoLoop merge form body)) = do+optimiseStm :: forall rep. (ASTRep rep) => Stm rep -> DoubleBufferM rep (Stms rep)+optimiseStm (Let pat aux (Loop merge form body)) = do body' <- localScope (scopeOf form <> scopeOfFParams (map fst merge)) $ optimiseBody body opt_loop <- asks envOptimiseLoop (stms, pat', merge', body'') <- opt_loop pat merge body'- pure $ stms <> oneStm (Let pat' aux $ DoLoop merge' form body'')+ pure $ stms <> oneStm (Let pat' aux $ Loop merge' form body'') optimiseStm (Let pat aux e) = do onOp <- asks envOptimiseOp oneStm . Let pat aux <$> mapExpM (optimise onOp) e@@ -204,7 +204,7 @@ optimiseMCOp op = pure op optimiseKernelBody ::- ASTRep rep =>+ (ASTRep rep) => KernelBody rep -> DoubleBufferM rep (KernelBody rep) optimiseKernelBody kbody = do@@ -212,7 +212,7 @@ pure $ kbody {kernelBodyStms = stms'} optimiseLambda ::- ASTRep rep =>+ (ASTRep rep) => Lambda rep -> DoubleBufferM rep (Lambda rep) optimiseLambda lam = do@@ -227,7 +227,7 @@ LetDec rep ~ LetDecMem ) -extractAllocOf :: Constraints rep inner => Names -> VName -> Stms rep -> Maybe (Stm rep, Stms rep)+extractAllocOf :: (Constraints rep inner) => Names -> VName -> Stms rep -> Maybe (Stm rep, Stms rep) extractAllocOf bound needle stms = do (stm, stms') <- stmsHead stms case stm of@@ -242,7 +242,7 @@ invariant Constant {} = True invariant (Var v) = v `notNameIn` bound -optimiseLoop :: Constraints rep inner => OptimiseLoop rep+optimiseLoop :: (Constraints rep inner) => OptimiseLoop rep optimiseLoop pat merge body = do (outer_stms_1, pat', merge', body') <- optimiseLoopBySwitching pat merge body@@ -254,7 +254,7 @@ isArrayIn x (Param _ _ (MemArray _ _ _ (ArrayIn y _))) = x == y isArrayIn _ _ = False -optimiseLoopBySwitching :: Constraints rep inner => OptimiseLoop rep+optimiseLoopBySwitching :: (Constraints rep inner) => OptimiseLoop rep optimiseLoopBySwitching (Pat pes) merge (Body _ body_stms body_res) = do ((pat', merge', body'), outer_stms) <- runBuilder $ do ((buffered, body_stms'), (pes', merge', body_res')) <-@@ -321,7 +321,7 @@ mkUnique (MemArray bt shape _ ret) = MemArray bt shape Unique ret mkUnique x = x -optimiseLoopByCopying :: Constraints rep inner => OptimiseLoop rep+optimiseLoopByCopying :: (Constraints rep inner) => OptimiseLoop rep optimiseLoopByCopying pat merge body = do -- We start out by figuring out which of the merge variables should -- be double-buffered.@@ -347,7 +347,7 @@ deriving (Show) doubleBufferMergeParams ::- MonadFreshNames m =>+ (MonadFreshNames m) => [(Param FParamMem, SubExpRes)] -> Names -> m [DoubleBuffer]@@ -359,7 +359,7 @@ v `nameIn` bound_in_loop || v- `elem` map (paramName . fst) ctx_and_res+ `elem` map (paramName . fst) ctx_and_res loopInvariantSize (Constant v) = Just (Constant v, True)@@ -410,7 +410,7 @@ _ -> pure NoBuffer allocStms ::- Constraints rep inner =>+ (Constraints rep inner) => [(FParam rep, SubExp)] -> [DoubleBuffer] -> DoubleBufferM rep ([(FParam rep, SubExp)], [Stm rep])@@ -447,7 +447,7 @@ pure (f, se) doubleBufferResult ::- Constraints rep inner =>+ (Constraints rep inner) => [FParam rep] -> [DoubleBuffer] -> Body rep ->
src/Futhark/Optimise/EntryPointMem.hs view
@@ -28,15 +28,15 @@ mkTable :: Stms rep -> Table rep mkTable = foldMap f where- f stm = M.fromList $ zip (patNames (stmPat stm)) $ repeat stm+ f stm = M.fromList $ map (,stm) (patNames (stmPat stm)) -varInfo :: Mem rep inner => VName -> Table rep -> Maybe (LetDecMem, Exp rep)+varInfo :: (Mem rep inner) => VName -> Table rep -> Maybe (LetDecMem, Exp rep) varInfo v table = do Let pat _ e <- M.lookup v table PatElem _ info <- find ((== v) . patElemName) (patElems pat) Just (letDecMem info, e) -optimiseFun :: Mem rep inner => Table rep -> FunDef rep -> FunDef rep+optimiseFun :: (Mem rep inner) => Table rep -> FunDef rep -> FunDef rep optimiseFun consts_table fd = fd {funDefBody = onBody $ funDefBody fd} where@@ -53,7 +53,7 @@ let substs = mconcat $ map (mkSubst . resSubExp) res in Body dec stms $ substituteNames substs res -entryPointMem :: Mem rep inner => Pass rep rep+entryPointMem :: (Mem rep inner) => Pass rep rep entryPointMem = Pass { passName = "Entry point memory optimisation",
src/Futhark/Optimise/Fusion.hs view
@@ -56,7 +56,7 @@ putNameSource source = modify (\env -> env {vNameSource = source}) -runFusionM :: MonadFreshNames m => Scope SOACS -> FusionEnv -> FusionM a -> m a+runFusionM :: (MonadFreshNames m) => Scope SOACS -> FusionEnv -> FusionM a -> m a runFusionM scope fenv (FusionM a) = modifyNameSource $ \src -> let x = runReaderT a scope (y, z) = runState x (fenv {vNameSource = src})@@ -401,10 +401,10 @@ runInnerFusionOnContext :: DepContext -> FusionM DepContext runInnerFusionOnContext c@(incoming, node, nodeT, outgoing) = case nodeT of- DoNode (Let pat aux (DoLoop params form body)) to_fuse ->+ DoNode (Let pat aux (Loop params form body)) to_fuse -> doFuseScans . localScope (scopeOfFParams (map fst params) <> scopeOf form) $ do b <- doFusionWithDelayed body to_fuse- pure (incoming, node, DoNode (Let pat aux (DoLoop params form b)) [], outgoing)+ pure (incoming, node, DoNode (Let pat aux (Loop params form b)) [], outgoing) MatchNode (Let pat aux (Match cond cases defbody dec)) to_fuse -> doFuseScans $ do cases' <- mapM (traverse $ renameBody <=< (`doFusionWithDelayed` to_fuse)) cases defbody' <- doFusionWithDelayed defbody to_fuse
src/Futhark/Optimise/Fusion/Composing.hs view
@@ -43,7 +43,7 @@ -- The result is the fused function, and a list of the array inputs -- expected by the SOAC containing the fused function. fuseMaps ::- Buildable rep =>+ (Buildable rep) => -- | The producer var names that still need to be returned Names -> -- | Function of SOAC to be fused.@@ -91,7 +91,7 @@ -- (unfus_accpat, unfus_arrpat) = splitAt (length unfus_accs) unfus_pat fuseInputs ::- Buildable rep =>+ (Buildable rep) => Names -> Lambda rep -> [SOAC.Input] ->@@ -168,7 +168,7 @@ _ -> (m, ra) removeDuplicateInputs ::- Buildable rep =>+ (Buildable rep) => M.Map Ident SOAC.Input -> (M.Map Ident SOAC.Input, Body rep -> Body rep) removeDuplicateInputs = fst . M.foldlWithKey' comb ((M.empty, id), M.empty)@@ -187,7 +187,7 @@ mkLet [to] (BasicOp $ SubExp $ Var from) `insertStm` b fuseRedomap ::- Buildable rep =>+ (Buildable rep) => Names -> [VName] -> Lambda rep ->
src/Futhark/Optimise/Fusion/GraphRep.hs view
@@ -162,7 +162,7 @@ -- it. type ProducerMapping = M.Map VName G.Node -makeMapping :: Monad m => DepGraphAug m+makeMapping :: (Monad m) => DepGraphAug m makeMapping dg@(DepGraph {dgGraph = g}) = pure dg {dgProducerMapping = M.fromList $ concatMap gen_dep_list (G.labNodes g)} where@@ -170,11 +170,11 @@ gen_dep_list (i, node) = [(name, i) | name <- getOutputs node] -- | Apply several graph augmentations in sequence.-applyAugs :: Monad m => [DepGraphAug m] -> DepGraphAug m+applyAugs :: (Monad m) => [DepGraphAug m] -> DepGraphAug m applyAugs augs g = foldlM (flip ($)) g augs -- | Creates deps for the given nodes on the graph using the 'EdgeGenerator'.-genEdges :: Monad m => [DepNode] -> EdgeGenerator -> DepGraphAug m+genEdges :: (Monad m) => [DepNode] -> EdgeGenerator -> DepGraphAug m genEdges l_stms edge_fun dg = depGraphInsertEdges (concatMap (genEdge (dgProducerMapping dg)) l_stms) dg where@@ -185,11 +185,11 @@ Just to <- [M.lookup dep name_map] pure $ G.toLEdge (from, to) edgeT -depGraphInsertEdges :: Monad m => [DepEdge] -> DepGraphAug m+depGraphInsertEdges :: (Monad m) => [DepEdge] -> DepGraphAug m depGraphInsertEdges edgs dg = pure $ dg {dgGraph = G.insEdges edgs $ dgGraph dg} -- | Monadically modify every node of the graph.-mapAcross :: Monad m => (DepContext -> m DepContext) -> DepGraphAug m+mapAcross :: (Monad m) => (DepContext -> m DepContext) -> DepGraphAug m mapAcross f dg = do g' <- foldlM (flip helper) (dgGraph dg) (G.nodes (dgGraph dg)) pure $ dg {dgGraph = g'}@@ -221,10 +221,10 @@ reachable dg source target = target `elem` Q.reachable source (dgGraph dg) -- Utility func for augs-augWithFun :: Monad m => EdgeGenerator -> DepGraphAug m+augWithFun :: (Monad m) => EdgeGenerator -> DepGraphAug m augWithFun f dg = genEdges (G.labNodes (dgGraph dg)) f dg -addDeps :: Monad m => DepGraphAug m+addDeps :: (Monad m) => DepGraphAug m addDeps = augWithFun toDep where toDep stmt =@@ -237,7 +237,7 @@ mkInfDep vname = (vname, InfDep vname) in map mkDep fusible <> map mkInfDep infusible -addConsAndAliases :: Monad m => DepGraphAug m+addConsAndAliases :: (Monad m) => DepGraphAug m addConsAndAliases = augWithFun edges where edges (StmNode s) = consEdges s' <> aliasEdges s'@@ -257,7 +257,7 @@ -- 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 -- fixes asymptotic complexity guarantees)-addExtraCons :: Monad m => DepGraphAug m+addExtraCons :: (Monad m) => DepGraphAug m addExtraCons dg = depGraphInsertEdges (concatMap makeEdge (G.labEdges g)) dg where@@ -273,7 +273,7 @@ pure $ G.toLEdge (from, to2) (Fake cname) makeEdge _ = [] -mapAcrossNodeTs :: Monad m => (NodeT -> m NodeT) -> DepGraphAug m+mapAcrossNodeTs :: (Monad m) => (NodeT -> m NodeT) -> DepGraphAug m mapAcrossNodeTs f = mapAcross f' where f' (ins, n, nodeT, outs) = do@@ -287,7 +287,7 @@ case maybeSoac of Right hsoac -> pure $ SoacNode mempty pat hsoac aux Left H.NotSOAC -> pure n- DoLoop {} ->+ Loop {} -> pure $ DoNode s [] Match {} -> pure $ MatchNode s []@@ -317,7 +317,7 @@ getStmRes (ResNode name) = [(name, Res name)] getStmRes _ = [] -addResEdges :: Monad m => DepGraphAug m+addResEdges :: (Monad m) => DepGraphAug m addResEdges = augWithFun getStmRes -- | Make a dependency graph corresponding to a 'Body'.@@ -340,7 +340,7 @@ scope = scopeOfFParams (funDefParams f) <> scopeOf (bodyStms (funDefBody f)) -- | Merges two contexts.-mergedContext :: Ord b => a -> G.Context a b -> G.Context a b -> G.Context a b+mergedContext :: (Ord b) => a -> G.Context a b -> G.Context a b -> G.Context a b mergedContext mergedlabel (inp1, n1, _, out1) (inp2, n2, _, out2) = let new_inp = filter (\n -> snd n /= n1 && snd n /= n2) (nubOrd (inp1 <> inp2)) new_out = filter (\n -> snd n /= n1 && snd n /= n2) (nubOrd (out1 <> out2))@@ -349,7 +349,7 @@ -- | Remove the given node, and insert the 'DepContext' into the -- graph, replacing any existing information about the node contained -- in the 'DepContext'.-contractEdge :: Monad m => G.Node -> DepContext -> DepGraphAug m+contractEdge :: (Monad m) => G.Node -> DepContext -> DepGraphAug m contractEdge n2 ctx dg = do let n1 = G.node' ctx -- n1 remains pure $ dg {dgGraph = ctx G.& G.delNodes [n1, n2] (dgGraph dg)}@@ -367,7 +367,7 @@ type Classifications = S.Set (VName, Classification) -freeClassifications :: FreeIn a => a -> Classifications+freeClassifications :: (FreeIn a) => a -> Classifications freeClassifications = S.fromList . (`zip` repeat Other) . namesToList . freeIn @@ -383,7 +383,7 @@ foldMap (bodyInputs . caseBody) cases <> bodyInputs defbody <> freeClassifications (cond, attr)-expInputs (DoLoop params form b1) =+expInputs (Loop params form b1) = freeClassifications (params, form) <> bodyInputs b1 expInputs (Op soac) = case soac of Futhark.Screma w is form -> inputs is <> freeClassifications (w, form)
src/Futhark/Optimise/Fusion/TryFusion.hs view
@@ -51,7 +51,7 @@ ) tryFusion ::- MonadFreshNames m =>+ (MonadFreshNames m) => TryFusion a -> Scope SOACS -> m (Maybe a)
src/Futhark/Optimise/GenRedOpt.hs view
@@ -403,7 +403,7 @@ costRedundantStmt :: Stm GPU -> Cost costRedundantStmt (Let _ _ (Op _)) = Big-costRedundantStmt (Let _ _ DoLoop {}) = Big+costRedundantStmt (Let _ _ Loop {}) = Big costRedundantStmt (Let _ _ Apply {}) = Big costRedundantStmt (Let _ _ WithAcc {}) = Big costRedundantStmt (Let _ _ (Match _ cases defbody _)) =
src/Futhark/Optimise/HistAccs.hs view
@@ -56,7 +56,7 @@ ) mkHistBody _ _ = Nothing -withAccLamToHistLam :: MonadFreshNames m => Shape -> Lambda GPU -> m (Lambda GPU)+withAccLamToHistLam :: (MonadFreshNames m) => Shape -> Lambda GPU -> m (Lambda GPU) withAccLamToHistLam shape lam = renameLambda $ lam {lambdaParams = drop (shapeRank shape) (lambdaParams lam)} @@ -89,7 +89,7 @@ KernelBody () stms [Returns ResultMaySimplify mempty (Var acc')] flatKernelBody ::- MonadBuilder m =>+ (MonadBuilder m) => SegSpace -> KernelBody (Rep m) -> m (SegSpace, KernelBody (Rep m))
src/Futhark/Optimise/InPlaceLowering.hs view
@@ -93,7 +93,7 @@ -- | Apply the in-place lowering optimisation to the given program. inPlaceLowering ::- Constraints rep =>+ (Constraints rep) => OnOp rep -> LowerUpdate rep (ForwardingM rep) -> Pass rep rep@@ -122,7 +122,7 @@ type Constraints rep = (Buildable rep, AliasableRep rep) optimiseBody ::- Constraints rep =>+ (Constraints rep) => Body (Aliases rep) -> ForwardingM rep (Body (Aliases rep)) optimiseBody (Body als stms res) = do@@ -133,7 +133,7 @@ seen (Var v) = seenVar v optimiseStms ::- Constraints rep =>+ (Constraints rep) => [Stm (Aliases rep)] -> ForwardingM rep () -> ForwardingM rep [Stm (Aliases rep)]@@ -180,14 +180,14 @@ checkIfForwardableUpdate stm' = mapM_ seenVar $ namesToList $ freeIn $ stmExp stm' -optimiseInStm :: Constraints rep => Stm (Aliases rep) -> ForwardingM rep (Stm (Aliases rep))+optimiseInStm :: (Constraints rep) => Stm (Aliases rep) -> ForwardingM rep (Stm (Aliases rep)) optimiseInStm (Let pat dec e) = Let pat dec <$> optimiseExp e -optimiseExp :: Constraints rep => Exp (Aliases rep) -> ForwardingM rep (Exp (Aliases rep))-optimiseExp (DoLoop merge form body) =+optimiseExp :: (Constraints rep) => Exp (Aliases rep) -> ForwardingM rep (Exp (Aliases rep))+optimiseExp (Loop merge form body) = bindingScope (scopeOf form) . bindingFParams (map fst merge) $- DoLoop merge form <$> optimiseBody body+ Loop merge form <$> optimiseBody body optimiseExp (Op op) = do f <- asks topOnOp Op <$> f op@@ -199,7 +199,7 @@ } onSegOp ::- Constraints rep =>+ (Constraints rep) => SegOp lvl (Aliases rep) -> ForwardingM rep (SegOp lvl (Aliases rep)) onSegOp op =@@ -270,7 +270,7 @@ getNameSource = get putNameSource = put -instance Constraints rep => HasScope (Aliases rep) (ForwardingM rep) where+instance (Constraints rep) => HasScope (Aliases rep) (ForwardingM rep) where askScope = M.map entryType <$> asks topDownTable runForwardingM ::@@ -393,7 +393,7 @@ pure (x, bup) maybeForward ::- Constraints rep =>+ (Constraints rep) => VName -> VName -> LetDec (Aliases rep) ->
src/Futhark/Optimise/InPlaceLowering/LowerIntoStm.hs view
@@ -50,7 +50,7 @@ AliasableRep rep ) => LowerUpdate rep m-lowerUpdate scope (Let pat aux (DoLoop merge form body)) updates = do+lowerUpdate scope (Let pat aux (Loop merge form body)) updates = do canDo <- lowerUpdateIntoLoop scope updates pat merge form body Just $ do (prestms, poststms, pat', merge', body') <- canDo@@ -58,7 +58,7 @@ prestms ++ [ certify (stmAuxCerts aux) $ mkLet pat' $- DoLoop merge' form body'+ Loop merge' form body' ] ++ poststms lowerUpdate@@ -77,7 +77,7 @@ lowerUpdate _ _ _ = Nothing -lowerUpdateGPU :: MonadFreshNames m => LowerUpdate GPU m+lowerUpdateGPU :: (MonadFreshNames m) => LowerUpdate GPU m lowerUpdateGPU scope (Let pat aux (Op (SegOp (SegMap lvl space ts kbody))))@@ -103,7 +103,7 @@ lowerUpdateGPU scope stm updates = lowerUpdate scope stm updates lowerUpdatesIntoSegMap ::- MonadFreshNames m =>+ (MonadFreshNames m) => Scope (Aliases GPU) -> Pat (LetDec (Aliases GPU)) -> [DesiredUpdate (LetDec (Aliases GPU))] ->@@ -339,7 +339,7 @@ } deriving (Show) -indexSubstitutions :: Typed dec => [LoopResultSummary dec] -> IndexSubstitutions+indexSubstitutions :: (Typed dec) => [LoopResultSummary dec] -> IndexSubstitutions indexSubstitutions = mapMaybe getSubstitution where getSubstitution res = do
src/Futhark/Optimise/InPlaceLowering/SubstituteIndices.hs view
@@ -25,7 +25,7 @@ -- should be replaced with. type IndexSubstitutions = [(VName, IndexSubstitution)] -typeEnvFromSubstitutions :: LParamInfo rep ~ Type => IndexSubstitutions -> Scope rep+typeEnvFromSubstitutions :: (LParamInfo rep ~ Type) => IndexSubstitutions -> Scope rep typeEnvFromSubstitutions = M.fromList . map (fromSubstitution . snd) where fromSubstitution (_, name, t, _) =@@ -130,7 +130,7 @@ in foldM consumingSubst substs . namesToList . consumedInExp substituteIndicesInSubExp ::- MonadBuilder m =>+ (MonadBuilder m) => IndexSubstitutions -> SubExp -> m SubExp@@ -140,7 +140,7 @@ pure se substituteIndicesInVar ::- MonadBuilder m =>+ (MonadBuilder m) => IndexSubstitutions -> VName -> m VName
src/Futhark/Optimise/InliningDeadFun.hs view
@@ -32,7 +32,7 @@ ) import Futhark.Transform.Rename -parMapM :: MonadFreshNames m => (a -> State VNameSource b) -> [a] -> m [b]+parMapM :: (MonadFreshNames m) => (a -> State VNameSource b) -> [a] -> m [b] -- The special-casing of [] is quite important here! If 'as' is -- empty, then we might otherwise create an empty name source below, -- which can wreak all kinds of havoc.@@ -50,7 +50,7 @@ -- simplification rates used have been determined heuristically and -- are probably not optimal for any given program. inlineFunctions ::- MonadFreshNames m =>+ (MonadFreshNames m) => Int -> CallGraph -> S.Set Name ->@@ -119,14 +119,14 @@ -- Conservative inlining of functions that are called just once, or -- have #[inline] on them.-consInlineFunctions :: MonadFreshNames m => Prog SOACS -> m (Prog SOACS)+consInlineFunctions :: (MonadFreshNames m) => Prog SOACS -> m (Prog SOACS) consInlineFunctions prog = inlineFunctions 4 cg (calledOnce cg <> inlineBecauseTiny prog) prog where cg = buildCallGraph prog -- Inline everything that is not #[noinline].-aggInlineFunctions :: MonadFreshNames m => Prog SOACS -> m (Prog SOACS)+aggInlineFunctions :: (MonadFreshNames m) => Prog SOACS -> m (Prog SOACS) aggInlineFunctions prog = inlineFunctions 3 cg (S.fromList $ map funDefName $ progFuns prog) prog where@@ -138,7 +138,7 @@ -- importantly, the functions in @fdmap@ do not call any other -- functions. inlineInFunDef ::- MonadFreshNames m =>+ (MonadFreshNames m) => M.Map Name (FunDef SOACS) -> FunDef SOACS -> m (FunDef SOACS)@@ -146,7 +146,7 @@ FunDef entry attrs name rtp args <$> inlineInBody fdmap body inlineFunction ::- MonadFreshNames m =>+ (MonadFreshNames m) => Pat Type -> StmAux dec -> [(SubExp, Diet)] ->@@ -180,7 +180,7 @@ notmempty = (/= mempty) . locOf inlineInStms ::- MonadFreshNames m =>+ (MonadFreshNames m) => M.Map Name (FunDef SOACS) -> Stms SOACS -> m (Stms SOACS)@@ -188,7 +188,7 @@ bodyStms <$> inlineInBody fdmap (mkBody stms []) inlineInBody ::- MonadFreshNames m =>+ (MonadFreshNames m) => M.Map Name (FunDef SOACS) -> Body SOACS -> m (Body SOACS)
src/Futhark/Optimise/MemoryBlockMerging.hs view
@@ -30,7 +30,7 @@ getAllocsStm (Let _ _ (Op (Alloc _ _))) = error "impossible" getAllocsStm (Let _ _ (Match _ cases defbody _)) = foldMap (foldMap getAllocsStm . bodyStms) $ defbody : map caseBody cases-getAllocsStm (Let _ _ (DoLoop _ _ body)) =+getAllocsStm (Let _ _ (Loop _ _ body)) = foldMap getAllocsStm (bodyStms body) getAllocsStm _ = mempty @@ -55,10 +55,10 @@ stm {stmExp = Match cond (map (fmap onBody) cases) (onBody defbody) dec} where onBody (Body () stms res) = Body () (setAllocsStm m <$> stms) res-setAllocsStm m stm@(Let _ _ (DoLoop merge form body)) =+setAllocsStm m stm@(Let _ _ (Loop merge form body)) = stm { stmExp =- DoLoop merge form (body {bodyStms = setAllocsStm m <$> bodyStms body})+ Loop merge form (body {bodyStms = setAllocsStm m <$> bodyStms body}) } setAllocsStm _ stm = stm @@ -79,7 +79,7 @@ SegHist lvl sp segbinops tps $ body {kernelBodyStms = setAllocsStm m <$> kernelBodyStms body} -maxSubExp :: MonadBuilder m => Set SubExp -> m SubExp+maxSubExp :: (MonadBuilder m) => Set SubExp -> m SubExp maxSubExp = helper . S.toList where helper (s1 : s2 : sexps) = do@@ -98,7 +98,7 @@ isScalarSpace _ = False onKernelBodyStms ::- MonadBuilder m =>+ (MonadBuilder m) => SegOp lvl GPUMem -> (Stms GPUMem -> m (Stms GPUMem)) -> m (SegOp lvl GPUMem)@@ -160,7 +160,7 @@ -- | Helper function that modifies kernels found inside some statements. onKernels ::- LocalScope GPUMem m =>+ (LocalScope GPUMem m) => (SegOp SegLevel GPUMem -> m (SegOp SegLevel GPUMem)) -> Stms GPUMem -> m (Stms GPUMem)@@ -176,9 +176,9 @@ where onBody (Body () stms res) = Body () <$> f `onKernels` stms <*> pure res- helper stm@Let {stmExp = DoLoop merge form body} = do+ helper stm@Let {stmExp = Loop merge form body} = do body_stms <- f `onKernels` bodyStms body- pure $ stm {stmExp = DoLoop merge form (body {bodyStms = body_stms})}+ pure $ stm {stmExp = Loop merge form (body {bodyStms = body_stms})} helper stm = pure stm -- | Perform the reuse-allocations optimization.
src/Futhark/Optimise/MemoryBlockMerging/GreedyColoring.hs view
@@ -14,7 +14,7 @@ type Neighbors a = M.Map a (S.Set a) -- | Computes the neighbor map of a graph.-neighbors :: Ord a => Interference.Graph a -> Neighbors a+neighbors :: (Ord a) => Interference.Graph a -> Neighbors a neighbors = S.foldr ( \(x, y) acc ->@@ -24,7 +24,7 @@ ) M.empty -firstAvailable :: Eq space => M.Map Int space -> S.Set Int -> Int -> space -> (M.Map Int space, Int)+firstAvailable :: (Eq space) => M.Map Int space -> S.Set Int -> Int -> space -> (M.Map Int space, Int) firstAvailable spaces xs i sp = case (i `S.member` xs, spaces M.!? i) of (False, Just sp') | sp' == sp -> (spaces, i)
src/Futhark/Optimise/MergeGPUBodies.hs view
@@ -64,7 +64,7 @@ -------------------------------------------------------------------------------- -- | All free variables of a construct as 'Dependencies'.-depsOf :: FreeIn a => a -> Dependencies+depsOf :: (FreeIn a) => a -> Dependencies depsOf = namesToSet . freeIn -- | Convert 'Names' to an integer set of name tags.@@ -181,7 +181,7 @@ (defbody', defbody_deps) <- transformBody aliases defbody let deps = depsOf ses <> mconcat cases_deps <> defbody_deps <> depsOf dec pure (Match ses cases' defbody' dec, deps)- DoLoop merge lform body -> do+ Loop merge lform body -> do -- What merge and lform aliases outside the loop is irrelevant as those -- cannot be consumed within the loop. (body', body_deps) <- transformBody aliases body@@ -192,10 +192,10 @@ let bound = IS.fromList $ map baseTag (M.keys scope) let deps' = deps \\ bound - let dummy = DoLoop merge lform (Body (bodyDec body) SQ.empty [])- let DoLoop merge' lform' _ = removeExpAliases dummy+ let dummy = Loop merge lform (Body (bodyDec body) SQ.empty [])+ let Loop merge' lform' _ = removeExpAliases dummy - pure (DoLoop merge' lform' body', deps')+ pure (Loop merge' lform' body', deps') WithAcc inputs lambda -> do accs <- mapM (transformWithAccInput aliases) inputs let (inputs', input_deps) = unzip accs
src/Futhark/Optimise/ReduceDeviceSyncs.hs view
@@ -195,7 +195,7 @@ -- Read migrated scalars that are used on host. foldM addRead (out |> stm') (zip pes pes')- DoLoop ps lf b -> do+ Loop ps lf b -> do -- Enable the migration of for-in loop variables. (params, lform, body) <- rewriteForIn (ps, lf, b) @@ -249,7 +249,7 @@ let body3 = body2 {bodyStms = bstms, bodyResult = reverse res} -- Rewrite statement.- let e' = DoLoop params' lform body3+ let e' = Loop params' lform body3 let stm' = Let (Pat pes') (stmAux stm) e' -- Read migrated scalars that are used on host.@@ -393,7 +393,7 @@ MonadReader MigrationTable ) -runReduceM :: MonadFreshNames m => MigrationTable -> ReduceM a -> m a+runReduceM :: (MonadFreshNames m) => MigrationTable -> ReduceM a -> m a runReduceM mt (ReduceM m) = modifyNameSource $ \src -> second stateNameSource (runReader (runStateT m (initialState src)) mt)
src/Futhark/Optimise/ReduceDeviceSyncs/MigrationTable.hs view
@@ -64,7 +64,7 @@ import Data.IntSet qualified as IS import Data.List qualified as L import Data.Map.Strict qualified as M-import Data.Maybe (fromJust, fromMaybe, isJust, isNothing)+import Data.Maybe (fromMaybe, isJust, isNothing) import Data.Sequence qualified as SQ import Data.Set (Set, (\\)) import Data.Set qualified as S@@ -127,9 +127,9 @@ statusOf n mt /= StayOnHost shouldMoveStm (Let _ _ (Match cond _ _ _)) mt = all ((== MoveToDevice) . (`statusOf` mt)) $ subExpVars cond-shouldMoveStm (Let _ _ (DoLoop _ (ForLoop _ _ (Var n) _) _)) mt =+shouldMoveStm (Let _ _ (Loop _ (ForLoop _ _ (Var n) _) _)) mt = statusOf n mt == MoveToDevice-shouldMoveStm (Let _ _ (DoLoop _ (WhileLoop n) _)) mt =+shouldMoveStm (Let _ _ (Loop _ (WhileLoop n) _)) mt = statusOf n mt == MoveToDevice -- BasicOp and Apply statements might not bind any variables (shouldn't happen). -- If statements might use a constant branch condition.@@ -216,7 +216,7 @@ checkExp (Apply fn _ _ _) = Just (S.singleton fn) checkExp (Match _ cases defbody _) = mconcat <$> mapM checkBody (defbody : map caseBody cases)- checkExp (DoLoop params lform body) = do+ checkExp (Loop params lform body) = do checkLParams params checkLoopForm lform checkBody body@@ -296,7 +296,7 @@ -- TYPE HELPERS -- -------------------------------------------------------------------------------- -isScalar :: Typed t => t -> Bool+isScalar :: (Typed t) => t -> Bool isScalar = isScalarType . typeOf isScalarType :: TypeBase shape u -> Bool@@ -304,10 +304,10 @@ isScalarType (Prim _) = True isScalarType _ = False -isArray :: Typed t => t -> Bool+isArray :: (Typed t) => t -> Bool isArray = isArrayType . typeOf -isArrayType :: ArrayShape shape => TypeBase shape u -> Bool+isArrayType :: (ArrayShape shape) => TypeBase shape u -> Bool isArrayType = (0 <) . arrayRank --------------------------------------------------------------------------------@@ -507,7 +507,7 @@ graphApply fn bs e Match ses cases defbody _ -> graphMatch bs ses cases defbody- DoLoop params lform body ->+ Loop params lform body -> graphLoop bs params lform body WithAcc inputs f -> graphWithAcc bs inputs f@@ -700,7 +700,7 @@ unless may_migrate $ case lform of ForLoop _ _ (Var n) _ -> connectToSink (nameToId n) WhileLoop n- | (_, p, _, res) <- loopValueFor n -> do+ | Just (_, p, _, res) <- loopValueFor n -> do connectToSink p case res of Var v -> connectToSink (nameToId v)@@ -741,8 +741,9 @@ ForLoop _ _ n _ -> onlyGraphedScalarSubExp n >>= addEdges (ToNodes bindings Nothing) WhileLoop n- | (_, _, arg, _) <- loopValueFor n ->+ | Just (_, _, arg, _) <- loopValueFor n -> onlyGraphedScalarSubExp arg >>= addEdges (ToNodes bindings Nothing)+ _ -> pure () where subgraphId :: Id subgraphId = fst b@@ -759,9 +760,8 @@ bindings :: IdSet bindings = IS.fromList $ map (\((i, _), _, _, _) -> i) loopValues - loopValueFor :: VName -> LoopValue loopValueFor n =- fromJust $ find (\(_, p, _, _) -> p == nameToId n) loopValues+ find (\(_, p, _, _) -> p == nameToId n) loopValues graphTheLoop :: Grapher () graphTheLoop = do@@ -1012,7 +1012,7 @@ mapM_ collectSubExp ses mapM_ (collectBody . caseBody) cases collectBody defbody- collect (DoLoop params lform body) = do+ collect (Loop params lform body) = do mapM_ (collectSubExp . snd) params collectLForm lform collectBody body@@ -1504,7 +1504,7 @@ -- | Reduces the variables to just the 'Id's of those that are scalars and which -- have a vertex representation in the graph, excluding those that have been -- connected to sinks.-onlyGraphedScalars :: Foldable t => t VName -> Grapher IdSet+onlyGraphedScalars :: (Foldable t) => t VName -> Grapher IdSet onlyGraphedScalars vs = do let is = foldl' (\s n -> IS.insert (nameToId n) s) IS.empty vs IS.intersection is <$> getGraphedScalars
src/Futhark/Optimise/ReduceDeviceSyncs/MigrationTable/Graph.hs view
@@ -185,7 +185,7 @@ FoundSink deriving (Eq) -instance Semigroup a => Semigroup (Result a) where+instance (Semigroup a) => Semigroup (Result a) where FoundSink <> _ = FoundSink _ <> FoundSink = FoundSink Produced x <> Produced y = Produced (x <> y)@@ -344,7 +344,7 @@ -- -- The reduction of a cyclic reference resolves to 'mempty'. reduce ::- Monoid a =>+ (Monoid a) => Graph m -> (a -> EdgeType -> Vertex m -> a) -> Visited (Result a) ->
src/Futhark/Optimise/Simplify.hs view
@@ -31,7 +31,7 @@ -- output, meaningful simplification may not have taken place - the -- order of bindings may simply have been rearranged. simplifyProg ::- Engine.SimplifiableRep rep =>+ (Engine.SimplifiableRep rep) => Engine.SimpleOps rep -> RuleBook (Engine.Wise rep) -> Engine.HoistBlockers rep ->
src/Futhark/Optimise/Simplify/Engine.hs view
@@ -136,10 +136,6 @@ -- actually be used. protectHoistedOpS :: Protect (Builder (Wise rep)), opUsageS :: Op (Wise rep) -> UT.UsageTable,- simplifyPatFromExpS ::- Pat (LetDec rep) ->- Exp (Wise rep) ->- SimpleM rep (Pat (LetDec rep)), simplifyOpS :: SimplifyOp rep (Op (Wise rep)) } @@ -148,12 +144,11 @@ SimplifyOp rep (Op (Wise rep)) -> SimpleOps rep bindableSimpleOps =- SimpleOps mkExpDecS' mkBodyS' protectHoistedOpS' (const mempty) simplifyPatFromExp+ SimpleOps mkExpDecS' mkBodyS' protectHoistedOpS' (const mempty) where mkExpDecS' _ pat e = pure $ mkExpDec pat e mkBodyS' _ stms res = pure $ mkBody stms res protectHoistedOpS' _ _ _ = Nothing- simplifyPatFromExp pat _ = traverse simplify pat newtype SimpleM rep a = SimpleM@@ -174,7 +169,7 @@ putNameSource src = modify $ \(_, b, c) -> (src, b, c) getNameSource = gets $ \(a, _, _) -> a -instance SimplifiableRep rep => HasScope (Wise rep) (SimpleM rep) where+instance (SimplifiableRep rep) => HasScope (Wise rep) (SimpleM rep) where askScope = ST.toScope <$> askVtable lookupType name = do vtable <- askVtable@@ -187,7 +182,7 @@ ++ " in symbol table." instance- SimplifiableRep rep =>+ (SimplifiableRep rep) => LocalScope (Wise rep) (SimpleM rep) where localScope types = localVtable (<> ST.fromScope types)@@ -236,16 +231,16 @@ enterLoop :: SimpleM rep a -> SimpleM rep a enterLoop = localVtable ST.deepen -bindFParams :: SimplifiableRep rep => [FParam (Wise rep)] -> SimpleM rep a -> SimpleM rep a+bindFParams :: (SimplifiableRep rep) => [FParam (Wise rep)] -> SimpleM rep a -> SimpleM rep a bindFParams params = localVtable $ ST.insertFParams params -bindLParams :: SimplifiableRep rep => [LParam (Wise rep)] -> SimpleM rep a -> SimpleM rep a+bindLParams :: (SimplifiableRep rep) => [LParam (Wise rep)] -> SimpleM rep a -> SimpleM rep a bindLParams params = localVtable $ \vtable -> foldr ST.insertLParam vtable params bindArrayLParams ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => [LParam (Wise rep)] -> SimpleM rep a -> SimpleM rep a@@ -253,13 +248,13 @@ localVtable $ \vtable -> foldl' (flip ST.insertLParam) vtable params bindMerge ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => [(FParam (Wise rep), SubExp, SubExpRes)] -> SimpleM rep a -> SimpleM rep a bindMerge = localVtable . ST.insertLoopMerge -bindLoopVar :: SimplifiableRep rep => VName -> IntType -> SubExp -> SimpleM rep a -> SimpleM rep a+bindLoopVar :: (SimplifiableRep rep) => VName -> IntType -> SubExp -> SimpleM rep a -> SimpleM rep a bindLoopVar var it bound = localVtable $ ST.insertLoopVar var it bound @@ -283,7 +278,7 @@ makeSafe _ = Nothing -emptyOfType :: MonadBuilder m => [VName] -> Type -> m (Exp (Rep m))+emptyOfType :: (MonadBuilder m) => [VName] -> Type -> m (Exp (Rep m)) emptyOfType _ Mem {} = error "emptyOfType: Cannot hoist non-existential memory." emptyOfType _ Acc {} =@@ -298,7 +293,7 @@ zeroIfContext se = se protectIf ::- MonadBuilder m =>+ (MonadBuilder m) => Protect m -> (Exp (Rep m) -> Bool) -> SubExp ->@@ -339,7 +334,7 @@ -- loops, but they must be protected by adding a branch on top of -- them. protectLoopHoisted ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => [(FParam (Wise rep), SubExp)] -> LoopForm (Wise rep) -> SimpleM rep (a, b, Stms (Wise rep)) ->@@ -370,7 +365,7 @@ -- Produces a true subexpression if the pattern (as in a 'Case') -- matches the subexpression. matching ::- BuilderOps rep =>+ (BuilderOps rep) => [(SubExp, Maybe PrimValue)] -> Builder rep SubExp matching = letSubExp "match" <=< eAll <=< sequence . mapMaybe cmp@@ -383,7 +378,7 @@ cmp (_, Nothing) = Nothing matchingExactlyThis ::- BuilderOps rep =>+ (BuilderOps rep) => [SubExp] -> [[Maybe PrimValue]] -> [Maybe PrimValue] ->@@ -401,7 +396,7 @@ -- them. (This means such hoisting is not worth it unless they are in -- turn hoisted out of a loop somewhere.) protectCaseHoisted ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => -- | Scrutinee. [SubExp] -> -- | Pattern of previosu cases.@@ -426,21 +421,20 @@ -- | Statements that are not worth hoisting out of loops, because they -- are unsafe, and added safety (by 'protectLoopHoisted') may inhibit -- further optimisation.-notWorthHoisting :: ASTRep rep => BlockPred rep+notWorthHoisting :: (ASTRep rep) => BlockPred rep notWorthHoisting _ _ (Let pat _ e) = not (safeExp e) && any ((> 0) . arrayRank) (patTypes pat) -- Top-down simplify a statement (including copy propagation into the -- pattern and such). Does not recurse into any sub-Bodies or Ops. nonrecSimplifyStm ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => Stm (Wise rep) -> SimpleM rep (Stm (Wise rep)) nonrecSimplifyStm (Let pat (StmAux cs attrs (_, dec)) e) = do cs' <- simplify cs e' <- simplifyExpBase e- simplifyPat <- asks $ simplifyPatFromExpS . fst- (pat', pat_cs) <- collectCerts $ simplifyPat (removePatWisdom pat) e'+ (pat', pat_cs) <- collectCerts $ traverse simplify $ removePatWisdom pat let aux' = StmAux (cs' <> pat_cs) attrs dec pure $ mkWiseStm pat' aux' e' @@ -449,7 +443,7 @@ -- assumed 'nonrecSimplifyStm' has already touched it (and worst case, -- it'll get it on the next round of the overall fixpoint iteration.) recSimplifyStm ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => Stm (Wise rep) -> UT.UsageTable -> SimpleM rep (Stms (Wise rep), Stm (Wise rep))@@ -459,7 +453,7 @@ pure (e_hoisted, mkWiseStm (removePatWisdom pat) aux' e') hoistStms ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => RuleBook (Wise rep) -> BlockPred (Wise rep) -> Stms (Wise rep) ->@@ -542,7 +536,7 @@ process usageInStm stms_h'' stms_t' usage x blockUnhoistedDeps ::- ASTRep rep =>+ (ASTRep rep) => [Either (Stm rep) (Stm rep)] -> [Either (Stm rep) (Stm rep)] blockUnhoistedDeps = snd . mapAccumL block mempty@@ -559,7 +553,7 @@ provides = patNames . stmPat expandUsage ::- Aliased rep =>+ (Aliased rep) => (Stm rep -> UT.UsageTable) -> ST.SymbolTable rep -> UT.UsageTable ->@@ -608,7 +602,7 @@ isOp _ _ _ = False constructBody ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => Stms (Wise rep) -> Result -> SimpleM rep (Body (Wise rep))@@ -618,7 +612,7 @@ pure res blockIf ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => BlockPred (Wise rep) -> Stms (Wise rep) -> SimpleM rep (a, UT.UsageTable) ->@@ -627,24 +621,24 @@ rules <- asksEngineEnv envRules hoistStms rules block stms m -hasFree :: ASTRep rep => Names -> BlockPred rep+hasFree :: (ASTRep rep) => Names -> BlockPred rep hasFree ks _ _ need = ks `namesIntersect` freeIn need -isNotSafe :: ASTRep rep => BlockPred rep+isNotSafe :: (ASTRep rep) => BlockPred rep isNotSafe _ _ = not . safeExp . stmExp -isConsuming :: Aliased rep => BlockPred rep+isConsuming :: (Aliased rep) => BlockPred rep isConsuming _ _ = isUpdate . stmExp where isUpdate e = consumedInExp e /= mempty -isNotCheap :: ASTRep rep => BlockPred rep+isNotCheap :: (ASTRep rep) => BlockPred rep isNotCheap _ _ = not . cheapStm -cheapStm :: ASTRep rep => Stm rep -> Bool+cheapStm :: (ASTRep rep) => Stm rep -> Bool cheapStm = cheapExp . stmExp -cheapExp :: ASTRep rep => Exp rep -> Bool+cheapExp :: (ASTRep rep) => Exp rep -> Bool cheapExp (BasicOp BinOp {}) = True cheapExp (BasicOp SubExp {}) = True cheapExp (BasicOp UnOp {}) = True@@ -654,7 +648,7 @@ cheapExp (BasicOp Replicate {}) = False cheapExp (BasicOp Concat {}) = False cheapExp (BasicOp Manifest {}) = False-cheapExp DoLoop {} = False+cheapExp Loop {} = False cheapExp (Match _ cases defbranch _) = all (all cheapStm . bodyStms . caseBody) cases && all cheapStm (bodyStms defbranch)@@ -662,12 +656,12 @@ cheapExp _ = True -- Used to be False, but -- let's try it out. -loopInvariantStm :: ASTRep rep => ST.SymbolTable rep -> Stm rep -> Bool+loopInvariantStm :: (ASTRep rep) => ST.SymbolTable rep -> Stm rep -> Bool loopInvariantStm vtable = all (`nameIn` ST.availableAtClosestLoop vtable) . namesToList . freeIn matchBlocker ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => [SubExp] -> MatchDec rt -> SimpleM rep (BlockPred (Wise rep))@@ -728,7 +722,7 @@ -- | Simplify a single body. simplifyBody ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => BlockPred (Wise rep) -> UT.UsageTable -> [UT.Usages] ->@@ -744,7 +738,7 @@ -- | Simplify a single body. simplifyBodyNoHoisting ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => UT.UsageTable -> [UT.Usages] -> Body (Wise rep) ->@@ -758,7 +752,7 @@ -- | Simplify a single 'Result'. simplifyResult ::- SimplifiableRep rep => [UT.Usages] -> Result -> SimpleM rep (Result, UT.UsageTable)+ (SimplifiableRep rep) => [UT.Usages] -> Result -> SimpleM rep (Result, UT.UsageTable) simplifyResult usages res = do res' <- mapM simplify res vtable <- askVtable@@ -776,14 +770,14 @@ <> more_usages ) -isDoLoopResult :: Result -> UT.UsageTable-isDoLoopResult = mconcat . map checkForVar+isLoopResult :: Result -> UT.UsageTable+isLoopResult = mconcat . map checkForVar where checkForVar (SubExpRes _ (Var ident)) = UT.inResultUsage ident checkForVar _ = mempty simplifyStms ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => Stms (Wise rep) -> SimpleM rep (Stms (Wise rep)) simplifyStms stms = do@@ -793,7 +787,7 @@ UT.usages (namesFromList (M.keys (scopeOf stms))) simplifyStmsWithUsage ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => UT.UsageTable -> Stms (Wise rep) -> SimpleM rep (Stms (Wise rep))@@ -807,7 +801,7 @@ f op simplifyExp ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => UT.UsageTable -> Pat (LetDec (Wise rep)) -> Exp (Wise rep) ->@@ -833,7 +827,7 @@ protectCaseHoisted ses' prior vs $ simplifyBody block usage pes_usages body pure (hoisted, Case vs body')-simplifyExp _ _ (DoLoop merge form loopbody) = do+simplifyExp _ _ (Loop merge form loopbody) = do let (params, args) = unzip merge params' <- mapM (traverse simplify) params args' <- mapM simplify args@@ -876,9 +870,9 @@ (\p -> if unique (paramDeclType p) then UT.consumedU else mempty) params' (res, uses) <- simplifyResult params_usages $ bodyResult loopbody- pure (res, uses <> isDoLoopResult res)+ pure (res, uses <> isLoopResult res) loopbody' <- constructBody loopstms loopres- pure (DoLoop merge' form' loopbody', hoisted)+ pure (Loop merge' form' loopbody', hoisted) where fparamnames = namesFromList (map (paramName . fst) merge)@@ -909,7 +903,7 @@ -- | Block hoisting of 'Index' statements introduced by migration. blockMigrated ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => SimpleM rep (Lambda (Wise rep), Stms (Wise rep)) -> SimpleM rep (Lambda (Wise rep), Stms (Wise rep)) blockMigrated = local withMigrationBlocker@@ -925,7 +919,7 @@ in (ops, env') -- | Statement is a scalar read from a single element array of rank one.-isDeviceMigrated :: SimplifiableRep rep => BlockPred (Wise rep)+isDeviceMigrated :: (SimplifiableRep rep) => BlockPred (Wise rep) isDeviceMigrated vtable _ stm | BasicOp (Index arr slice) <- stmExp stm, [DimFix idx] <- unSlice slice,@@ -939,7 +933,7 @@ -- The simple nonrecursive case that we can perform without bottom-up -- information.-simplifyExpBase :: SimplifiableRep rep => Exp (Wise rep) -> SimpleM rep (Exp (Wise rep))+simplifyExpBase :: (SimplifiableRep rep) => Exp (Wise rep) -> SimpleM rep (Exp (Wise rep)) -- Special case for simplification of commutative BinOps where we -- arrange the operands in sorted order. This can make expressions -- more identical, which helps CSE.@@ -975,7 +969,7 @@ ) class Simplifiable e where- simplify :: SimplifiableRep rep => e -> SimpleM rep e+ simplify :: (SimplifiableRep rep) => e -> SimpleM rep e instance (Simplifiable a, Simplifiable b) => Simplifiable (a, b) where simplify (x, y) = (,) <$> simplify x <*> simplify y@@ -990,11 +984,11 @@ instance Simplifiable Int where simplify = pure -instance Simplifiable a => Simplifiable (Maybe a) where+instance (Simplifiable a) => Simplifiable (Maybe a) where simplify Nothing = pure Nothing simplify (Just x) = Just <$> simplify x -instance Simplifiable a => Simplifiable [a] where+instance (Simplifiable a) => Simplifiable [a] where simplify = mapM simplify instance Simplifiable SubExp where@@ -1032,7 +1026,7 @@ pure v' _ -> pure v -instance Simplifiable d => Simplifiable (ShapeBase d) where+instance (Simplifiable d) => Simplifiable (ShapeBase d) where simplify = fmap Shape . simplify . shapeDims instance Simplifiable ExtSize where@@ -1046,7 +1040,7 @@ instance Simplifiable PrimType where simplify = pure -instance Simplifiable shape => Simplifiable (TypeBase shape u) where+instance (Simplifiable shape) => Simplifiable (TypeBase shape u) where simplify (Array et shape u) = Array <$> simplify et <*> simplify shape <*> pure u simplify (Acc acc ispace ts u) =@@ -1056,15 +1050,15 @@ simplify (Prim bt) = pure $ Prim bt -instance Simplifiable d => Simplifiable (DimIndex d) where+instance (Simplifiable d) => Simplifiable (DimIndex d) where simplify (DimFix i) = DimFix <$> simplify i simplify (DimSlice i n s) = DimSlice <$> simplify i <*> simplify n <*> simplify s -instance Simplifiable d => Simplifiable (Slice d) where+instance (Simplifiable d) => Simplifiable (Slice d) where simplify = traverse simplify simplifyLambda ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => Names -> Lambda (Wise rep) -> SimpleM rep (Lambda (Wise rep), Stms (Wise rep))@@ -1073,14 +1067,14 @@ simplifyLambdaMaybeHoist (par_blocker `orIf` hasFree extra_bound) mempty lam simplifyLambdaNoHoisting ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => Lambda (Wise rep) -> SimpleM rep (Lambda (Wise rep)) simplifyLambdaNoHoisting lam = fst <$> simplifyLambdaMaybeHoist (isFalse False) mempty lam simplifyLambdaMaybeHoist ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => BlockPred (Wise rep) -> UT.UsageTable -> Lambda (Wise rep) ->@@ -1088,7 +1082,7 @@ simplifyLambdaMaybeHoist = simplifyLambdaWith id simplifyLambdaWith ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => (ST.SymbolTable (Wise rep) -> ST.SymbolTable (Wise rep)) -> BlockPred (Wise rep) -> UT.UsageTable ->@@ -1118,7 +1112,7 @@ _ -> pure [idd] simplifyFun ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => FunDef (Wise rep) -> SimpleM rep (FunDef (Wise rep)) simplifyFun (FunDef entry attrs fname rettype params body) = do
src/Futhark/Optimise/Simplify/Rep.hs view
@@ -157,11 +157,11 @@ instance AliasesOf (VarWisdom, dec) where aliasesOf = unAliases . varWisdomAliases . fst -instance Informing rep => Aliased (Wise rep) where+instance (Informing rep) => Aliased (Wise rep) where bodyAliases = map unAliases . bodyWisdomAliases . fst . bodyDec consumedInBody = unAliases . bodyWisdomConsumed . fst . bodyDec -removeWisdom :: RephraseOp (OpC rep) => Rephraser Identity (Wise rep) rep+removeWisdom :: (RephraseOp (OpC rep)) => Rephraser Identity (Wise rep) rep removeWisdom = Rephraser { rephraseExpDec = pure . snd,@@ -194,23 +194,23 @@ alias (IndexName it) = IndexName it -- | Remove simplifier information from function.-removeFunDefWisdom :: RephraseOp (OpC 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 :: RephraseOp (OpC 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 :: RephraseOp (OpC 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 :: RephraseOp (OpC 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 :: RephraseOp (OpC rep) => Exp (Wise rep) -> Exp rep+removeExpWisdom :: (RephraseOp (OpC rep)) => Exp (Wise rep) -> Exp rep removeExpWisdom = runIdentity . rephraseExp removeWisdom -- | Remove simplifier information from pattern.@@ -219,7 +219,7 @@ -- | Add simplifier information to pattern. addWisdomToPat ::- Informing rep =>+ (Informing rep) => Pat (LetDec rep) -> Exp (Wise rep) -> Pat (LetDec (Wise rep))@@ -230,7 +230,7 @@ -- | Produce a body with simplifier information. mkWiseBody ::- Informing rep =>+ (Informing rep) => BodyDec rep -> Stms (Wise rep) -> Result ->@@ -247,7 +247,7 @@ -- | Produce a statement with simplifier information. mkWiseStm ::- Informing rep =>+ (Informing rep) => Pat (LetDec rep) -> StmAux (ExpDec rep) -> Exp (Wise rep) ->@@ -258,7 +258,7 @@ -- | Produce simplifier information for an expression. mkWiseExpDec ::- Informing rep =>+ (Informing rep) => Pat (LetDec (Wise rep)) -> ExpDec rep -> Exp (Wise rep) ->@@ -299,36 +299,36 @@ -- | A type class for indicating that this operation can be lifted into the simplifier representation. class CanBeWise op where- addOpWisdom :: Informing rep => op rep -> op (Wise rep)+ addOpWisdom :: (Informing rep) => op rep -> op (Wise rep) instance CanBeWise NoOp where addOpWisdom NoOp = NoOp -- | Construct a 'Wise' statement.-informStm :: Informing rep => Stm rep -> Stm (Wise rep)+informStm :: (Informing rep) => Stm rep -> Stm (Wise rep) informStm (Let pat aux e) = mkWiseStm pat aux $ informExp e -- | Construct 'Wise' statements.-informStms :: Informing rep => Stms rep -> Stms (Wise rep)+informStms :: (Informing rep) => Stms rep -> Stms (Wise rep) informStms = fmap informStm -- | Construct a 'Wise' body.-informBody :: Informing rep => Body rep -> Body (Wise rep)+informBody :: (Informing rep) => Body rep -> Body (Wise rep) informBody (Body dec stms res) = mkWiseBody dec (informStms stms) res -- | Construct a 'Wise' lambda.-informLambda :: Informing rep => Lambda rep -> Lambda (Wise rep)+informLambda :: (Informing rep) => Lambda rep -> Lambda (Wise rep) informLambda (Lambda ps body ret) = Lambda ps (informBody body) ret -- | Construct a 'Wise' expression.-informExp :: Informing rep => Exp rep -> Exp (Wise rep)+informExp :: (Informing rep) => Exp rep -> Exp (Wise rep) informExp (Match cond cases defbody (MatchDec ts ifsort)) = Match cond (map (fmap informBody) cases) (informBody defbody) (MatchDec ts ifsort)-informExp (DoLoop merge form loopbody) =+informExp (Loop merge form loopbody) = let form' = case form of ForLoop i it bound params -> ForLoop i it bound params WhileLoop cond -> WhileLoop cond- in DoLoop merge form' $ informBody loopbody+ in Loop merge form' $ informBody loopbody informExp e = runIdentity $ mapExpM mapper e where mapper =@@ -344,6 +344,6 @@ } -- | Construct a 'Wise' function definition.-informFunDef :: Informing rep => FunDef rep -> FunDef (Wise rep)+informFunDef :: (Informing rep) => FunDef rep -> FunDef (Wise rep) informFunDef (FunDef entry attrs fname rettype params body) = FunDef entry attrs fname rettype params $ informBody body
src/Futhark/Optimise/Simplify/Rule.hs view
@@ -23,7 +23,7 @@ RuleGeneric, RuleBasicOp, RuleMatch,- RuleDoLoop,+ RuleLoop, -- * Top-down rules TopDown,@@ -31,7 +31,7 @@ TopDownRuleGeneric, TopDownRuleBasicOp, TopDownRuleMatch,- TopDownRuleDoLoop,+ TopDownRuleLoop, TopDownRuleOp, -- * Bottom-up rules@@ -40,7 +40,7 @@ BottomUpRuleGeneric, BottomUpRuleBasicOp, BottomUpRuleMatch,- BottomUpRuleDoLoop,+ BottomUpRuleLoop, BottomUpRuleOp, -- * Assembling rules@@ -125,7 +125,7 @@ ) -> Rule rep -type RuleDoLoop rep a =+type RuleLoop rep a = a -> Pat (LetDec rep) -> StmAux (ExpDec rep) ->@@ -148,7 +148,7 @@ = RuleGeneric (RuleGeneric rep a) | RuleBasicOp (RuleBasicOp rep a) | RuleMatch (RuleMatch rep a)- | RuleDoLoop (RuleDoLoop rep a)+ | RuleLoop (RuleLoop rep a) | RuleOp (RuleOp rep a) -- | A collection of rules grouped by which forms of statements they@@ -157,7 +157,7 @@ { rulesAny :: [SimplificationRule rep a], rulesBasicOp :: [SimplificationRule rep a], rulesMatch :: [SimplificationRule rep a],- rulesDoLoop :: [SimplificationRule rep a],+ rulesLoop :: [SimplificationRule rep a], rulesOp :: [SimplificationRule rep a] } @@ -178,7 +178,7 @@ type TopDownRuleMatch rep = RuleMatch rep (TopDown rep) -type TopDownRuleDoLoop rep = RuleDoLoop rep (TopDown rep)+type TopDownRuleLoop rep = RuleLoop rep (TopDown rep) type TopDownRuleOp rep = RuleOp rep (TopDown rep) @@ -194,7 +194,7 @@ type BottomUpRuleMatch rep = RuleMatch rep (BottomUp rep) -type BottomUpRuleDoLoop rep = RuleDoLoop rep (BottomUp rep)+type BottomUpRuleLoop rep = RuleLoop rep (BottomUp rep) type BottomUpRuleOp rep = RuleOp rep (BottomUp rep) @@ -232,7 +232,7 @@ { rulesAny = rs, rulesBasicOp = filter forBasicOp rs, rulesMatch = filter forMatch rs,- rulesDoLoop = filter forDoLoop rs,+ rulesLoop = filter forLoop rs, rulesOp = filter forOp rs } @@ -244,9 +244,9 @@ forMatch RuleGeneric {} = True forMatch _ = False - forDoLoop RuleDoLoop {} = True- forDoLoop RuleGeneric {} = True- forDoLoop _ = False+ forLoop RuleLoop {} = True+ forLoop RuleGeneric {} = True+ forLoop _ = False forOp RuleOp {} = True forOp RuleGeneric {} = True@@ -280,7 +280,7 @@ rulesForStm :: Stm rep -> Rules rep a -> [SimplificationRule rep a] rulesForStm stm = case stmExp stm of BasicOp {} -> rulesBasicOp- DoLoop {} -> rulesDoLoop+ Loop {} -> rulesLoop Op {} -> rulesOp Match {} -> rulesMatch _ -> rulesAny@@ -288,7 +288,7 @@ applyRule :: SimplificationRule rep a -> a -> Stm rep -> Rule rep applyRule (RuleGeneric f) a stm = f a stm applyRule (RuleBasicOp f) a (Let pat aux (BasicOp e)) = f a pat aux e-applyRule (RuleDoLoop f) a (Let pat aux (DoLoop merge form body)) =+applyRule (RuleLoop f) a (Let pat aux (Loop merge form body)) = f a pat aux (merge, form, body) applyRule (RuleMatch f) a (Let pat aux (Match cond cases defbody ifsort)) = f a pat aux (cond, cases, defbody, ifsort)
src/Futhark/Optimise/Simplify/Rules.hs view
@@ -35,7 +35,7 @@ import Futhark.Optimise.Simplify.Rules.Match import Futhark.Util -topDownRules :: BuilderOps rep => [TopDownRule rep]+topDownRules :: (BuilderOps rep) => [TopDownRule rep] topDownRules = [ RuleGeneric constantFoldPrimFun, RuleGeneric withAccTopDown,@@ -62,7 +62,7 @@ -- statement and it can be consumed. -- -- This simplistic rule is only valid before we introduce memory.-removeUnnecessaryCopy :: BuilderOps rep => BottomUpRuleBasicOp rep+removeUnnecessaryCopy :: (BuilderOps rep) => BottomUpRuleBasicOp rep removeUnnecessaryCopy (vtable, used) (Pat [d]) aux (Replicate (Shape []) (Var v)) | not (v `UT.isConsumed` used), -- This two first clauses below are too conservative, but the@@ -95,7 +95,7 @@ pure True removeUnnecessaryCopy _ _ _ _ = Skip -constantFoldPrimFun :: BuilderOps rep => TopDownRuleGeneric rep+constantFoldPrimFun :: (BuilderOps rep) => TopDownRuleGeneric rep constantFoldPrimFun _ (Let pat (StmAux cs attrs _) (Apply fname args _ _)) | Just args' <- mapM (isConst . fst) args, Just (_, _, fun) <- M.lookup (nameToString fname) primFuns,@@ -114,7 +114,7 @@ -- | If an expression produces an array with a constant zero anywhere -- in its shape, just turn that into a Scratch.-emptyArrayToScratch :: BuilderOps rep => TopDownRuleGeneric rep+emptyArrayToScratch :: (BuilderOps rep) => TopDownRuleGeneric rep emptyArrayToScratch _ (Let pat@(Pat [pe]) aux e) | Just (pt, shape) <- isEmptyArray $ patElemType pe, not $ isScratch e =@@ -124,7 +124,7 @@ isScratch _ = False emptyArrayToScratch _ _ = Skip -simplifyIndex :: BuilderOps rep => BottomUpRuleBasicOp rep+simplifyIndex :: (BuilderOps rep) => BottomUpRuleBasicOp rep simplifyIndex (vtable, used) pat@(Pat [pe]) (StmAux cs attrs _) (Index idd inds) | Just m <- simplifyIndexing vtable seType idd inds consumed = Simplify $ certifying cs $ do@@ -140,7 +140,7 @@ seType (Constant v) = Just $ Prim $ primValueType v simplifyIndex _ _ _ _ = Skip -withAccTopDown :: BuilderOps rep => TopDownRuleGeneric rep+withAccTopDown :: (BuilderOps rep) => TopDownRuleGeneric rep -- A WithAcc with no accumulators is sent to Valhalla. withAccTopDown _ (Let pat aux (WithAcc [] lam)) = Simplify . auxing aux $ do lam_res <- bodyBind $ lambdaBody lam@@ -219,7 +219,7 @@ onExp = mapExpM mapper where mapper =- (identityMapper :: forall m. Monad m => Mapper rep rep m)+ (identityMapper :: forall m. (Monad m) => Mapper rep rep m) { mapOnOp = traverseOpStms (\_ stms -> onStms stms), mapOnBody = \_ body -> onBody body }
src/Futhark/Optimise/Simplify/Rules/BasicOp.hs view
@@ -44,7 +44,7 @@ (ArgVar v, mempty) fromConcatArg ::- MonadBuilder m =>+ (MonadBuilder m) => Type -> (ConcatArg, Certs) -> m VName@@ -75,7 +75,7 @@ fuseConcatArg xs y = y : xs -simplifyConcat :: BuilderOps rep => BottomUpRuleBasicOp rep+simplifyConcat :: (BuilderOps rep) => BottomUpRuleBasicOp rep -- concat@1(transpose(x),transpose(y)) == transpose(concat@0(x,y)) simplifyConcat (vtable, _) pat _ (Concat i (x :| xs) new_d) | Just r <- arrayRank <$> ST.lookupType x vtable,@@ -144,7 +144,7 @@ forSingleArray ys = ys simplifyConcat _ _ _ _ = Skip -ruleBasicOp :: BuilderOps rep => TopDownRuleBasicOp rep+ruleBasicOp :: (BuilderOps rep) => TopDownRuleBasicOp rep ruleBasicOp vtable pat aux op | Just (op', cs) <- applySimpleRules defOf seType op = Simplify $ certifying (cs <> stmAuxCerts aux) $ letBind pat $ BasicOp op'@@ -330,6 +330,11 @@ | isCt0 y, maybe False ST.entryIsSize $ ST.lookup x vtable = Simplify $ auxing aux $ letBind pat $ BasicOp $ SubExp $ constant False+-- Simplify away 0<=y when 'y' has been used as array size.+ruleBasicOp vtable pat aux (CmpOp CmpSle {} x (Var y))+ | isCt0 x,+ maybe False ST.entryIsSize $ ST.lookup y vtable =+ Simplify $ auxing aux $ letBind pat $ BasicOp $ SubExp $ constant True -- Remove certificates for variables whose definition already contain -- that certificate. ruleBasicOp vtable pat aux (SubExp (Var v))@@ -351,24 +356,26 @@ Just (_, _, Just (_, ne)) <- ST.entryAccInput =<< ST.lookup token vtable, vs == ne = Simplify . auxing aux $ letBind pat $ BasicOp $ SubExp $ Var acc--- Manifest of a a copy can be simplified to manifesting the original--- array, if it is still available.+-- Manifest of a a copy (or another Manifest) can be simplified to+-- manifesting the original array, if it is still available. ruleBasicOp vtable pat aux (Manifest perm v1) | Just (Replicate (Shape []) (Var v2), cs) <- ST.lookupBasicOp v1 vtable, ST.available v2 vtable =- Simplify . auxing aux . certifying cs $- letBind pat $- BasicOp $- Manifest perm v2+ Simplify . auxing aux . certifying cs . letBind pat . BasicOp $+ Manifest perm v2+ | Just (Manifest _ v2, cs) <- ST.lookupBasicOp v1 vtable,+ ST.available v2 vtable =+ Simplify . auxing aux . certifying cs . letBind pat . BasicOp $+ Manifest perm v2 ruleBasicOp _ _ _ _ = Skip -topDownRules :: BuilderOps rep => [TopDownRule rep]+topDownRules :: (BuilderOps rep) => [TopDownRule rep] topDownRules = [ RuleBasicOp ruleBasicOp ] -bottomUpRules :: BuilderOps rep => [BottomUpRule rep]+bottomUpRules :: (BuilderOps rep) => [BottomUpRule rep] bottomUpRules = [ RuleBasicOp simplifyConcat ]
src/Futhark/Optimise/Simplify/Rules/ClosedForm.hs view
@@ -118,7 +118,7 @@ knownBnds = M.fromList $ zip mergenames mergeexp checkResults ::- BuilderOps rep =>+ (BuilderOps rep) => [VName] -> SubExp -> Names ->
src/Futhark/Optimise/Simplify/Rules/Index.hs view
@@ -33,7 +33,7 @@ -- | Try to simplify an index operation. simplifyIndexing ::- MonadBuilder m =>+ (MonadBuilder m) => ST.SymbolTable (Rep m) -> TypeLookup -> VName ->
src/Futhark/Optimise/Simplify/Rules/Loop.hs view
@@ -24,7 +24,7 @@ -- I do not claim that the current implementation of this rule is -- perfect, but it should suffice for many cases, and should never -- generate wrong code.-removeRedundantMergeVariables :: BuilderOps rep => BottomUpRuleDoLoop rep+removeRedundantMergeVariables :: (BuilderOps rep) => BottomUpRuleLoop rep removeRedundantMergeVariables (_, used) pat aux (merge, form, body) | not $ all (usedAfterLoop . fst) merge = let necessaryForReturned =@@ -63,7 +63,7 @@ body'' <- insertStmsM $ do mapM_ (uncurry letBindNames) $ dummyStms discard_val pure body'- auxing aux $ letBind pat' $ DoLoop merge' form body''+ auxing aux $ letBind pat' $ Loop merge' form body'' where pat_used = map (`UT.isUsedDirectly` used) $ patNames pat used_vals = map fst $ filter snd $ zip (map (paramName . fst) merge) pat_used@@ -85,7 +85,7 @@ -- We may change the type of the loop if we hoist out a shape -- annotation, in which case we also need to tweak the bound pattern.-hoistLoopInvariantMergeVariables :: BuilderOps rep => TopDownRuleDoLoop rep+hoistLoopInvariantMergeVariables :: (BuilderOps rep) => TopDownRuleLoop rep hoistLoopInvariantMergeVariables vtable pat aux (merge, form, loopbody) = do -- Figure out which of the elements of loopresult are -- loop-invariant, and hoist them out.@@ -101,7 +101,7 @@ explpat'' = map fst explpat' forM_ invariant $ \(v1, (v2, cs)) -> certifying cs $ letBindNames [identName v1] $ BasicOp $ SubExp v2- letBind (Pat explpat'') $ DoLoop merge' form loopbody'+ letBind (Pat explpat'') $ Loop merge' form loopbody' where res = bodyResult loopbody @@ -118,8 +118,6 @@ (pat_name, (mergeParam, mergeInit), resExp) (invariant, explpat', merge', resExps) | isInvariant,- -- Also do not remove the condition in a while-loop.- paramName mergeParam `notNameIn` freeIn form, -- Certificates must be available. all (`ST.elem` vtable) $ unCerts $ resCerts resExp = let (stm, explpat'') =@@ -174,12 +172,12 @@ (name `notNameIn` namesOfMergeParams) || (name `nameIn` namesOfInvariant) -simplifyClosedFormLoop :: BuilderOps rep => TopDownRuleDoLoop rep+simplifyClosedFormLoop :: (BuilderOps rep) => TopDownRuleLoop rep simplifyClosedFormLoop _ pat _ (val, ForLoop i it bound [], body) = Simplify $ loopClosedForm pat val (oneName i) it bound body simplifyClosedFormLoop _ _ _ _ = Skip -simplifyLoopVariables :: (BuilderOps rep, Aliased rep) => TopDownRuleDoLoop rep+simplifyLoopVariables :: (BuilderOps rep, Aliased rep) => TopDownRuleLoop rep simplifyLoopVariables vtable pat aux (merge, form@(ForLoop i it num_iters loop_vars), body) | simplifiable <- map checkIfSimplifiable loop_vars, not $ all isNothing simplifiable = Simplify $ do@@ -195,7 +193,7 @@ addStms $ mconcat body_prefix_stms bodyBind body let form' = ForLoop i it num_iters $ catMaybes maybe_loop_vars- auxing aux $ letBind pat $ DoLoop merge form' body'+ auxing aux $ letBind pat $ Loop merge form' body' where seType (Var v) | v == i = Just $ Prim $ IntType it@@ -246,7 +244,7 @@ simplifyLoopVariables _ _ _ _ = Skip unroll ::- BuilderOps rep =>+ (BuilderOps rep) => Integer -> [(FParam rep, SubExpRes)] -> (VName, IntType, Integer) ->@@ -277,7 +275,7 @@ let merge' = zip (map fst merge) $ bodyResult iter_body' unroll n merge' (iv, it, i + 1) loop_vars body -simplifyKnownIterationLoop :: BuilderOps rep => TopDownRuleDoLoop rep+simplifyKnownIterationLoop :: (BuilderOps rep) => TopDownRuleLoop rep simplifyKnownIterationLoop _ pat aux (merge, ForLoop i it (Constant iters) loop_vars, body) | IntValue n <- iters, zeroIshInt n || oneIshInt n || "unroll" `inAttrs` stmAuxAttrs aux = Simplify $ do@@ -289,15 +287,15 @@ topDownRules :: (BuilderOps rep, Aliased rep) => [TopDownRule rep] topDownRules =- [ RuleDoLoop hoistLoopInvariantMergeVariables,- RuleDoLoop simplifyClosedFormLoop,- RuleDoLoop simplifyKnownIterationLoop,- RuleDoLoop simplifyLoopVariables+ [ RuleLoop hoistLoopInvariantMergeVariables,+ RuleLoop simplifyClosedFormLoop,+ RuleLoop simplifyKnownIterationLoop,+ RuleLoop simplifyLoopVariables ] -bottomUpRules :: BuilderOps rep => [BottomUpRule rep]+bottomUpRules :: (BuilderOps rep) => [BottomUpRule rep] bottomUpRules =- [ RuleDoLoop removeRedundantMergeVariables+ [ RuleLoop removeRedundantMergeVariables ] -- | Standard loop simplification rules.
src/Futhark/Optimise/Simplify/Rules/Match.hs view
@@ -28,7 +28,7 @@ impossible (Constant v1) (Just v2) = v1 /= v2 impossible _ _ = False -ruleMatch :: BuilderOps rep => TopDownRuleMatch rep+ruleMatch :: (BuilderOps rep) => TopDownRuleMatch rep -- Remove impossible cases. ruleMatch _ pat _ (cond, cases, defbody, ifdec) | (impossible, cases') <- partition (caseNeverMatches cond) cases,@@ -135,7 +135,7 @@ -- | Move out results of a conditional expression whose computation is -- either invariant to the branches (only done for results used for -- existentials), or the same in both branches.-hoistBranchInvariant :: BuilderOps rep => TopDownRuleMatch rep+hoistBranchInvariant :: (BuilderOps rep) => TopDownRuleMatch rep hoistBranchInvariant _ pat _ (cond, cases, defbody, MatchDec ret ifsort) = let case_reses = map (bodyResult . caseBody) cases defbody_res = bodyResult defbody@@ -211,7 +211,7 @@ -- after a branch. Standard dead code removal can remove the branch -- if *none* of the return values are used, but this rule is more -- precise.-removeDeadBranchResult :: BuilderOps rep => BottomUpRuleMatch rep+removeDeadBranchResult :: (BuilderOps rep) => BottomUpRuleMatch rep removeDeadBranchResult (_, used) pat _ (cond, cases, defbody, MatchDec rettype ifsort) | -- Only if there is no existential binding... all (`notNameIn` foldMap freeIn (patElems pat)) (patNames pat),@@ -234,7 +234,7 @@ where onBody pick (Body _ stms res) = mkBodyM stms $ pick res -topDownRules :: BuilderOps rep => [TopDownRule rep]+topDownRules :: (BuilderOps rep) => [TopDownRule rep] topDownRules = [ RuleMatch ruleMatch, RuleMatch hoistBranchInvariant
src/Futhark/Optimise/Sink.hs view
@@ -76,7 +76,7 @@ -- | Given a statement, compute how often each of its free variables -- are used. Not accurate: what we care about are only 1, and greater -- than 1.-multiplicity :: Constraints rep => Stm rep -> M.Map VName Int+multiplicity :: (Constraints rep) => Stm rep -> M.Map VName Int multiplicity stm = case stmExp stm of Match cond cases defbody _ ->@@ -85,14 +85,14 @@ : free 1 defbody : map (free 1 . caseBody) cases Op {} -> free 2 stm- DoLoop {} -> free 2 stm+ Loop {} -> free 2 stm _ -> free 1 stm where- free k x = M.fromList $ zip (namesToList $ freeIn x) $ repeat k+ free k x = M.fromList $ map (,k) $ namesToList $ freeIn x comb = M.unionWith (+) optimiseBranch ::- Constraints rep =>+ (Constraints rep) => Sinker rep (Op rep) -> Sinker rep (Body rep) optimiseBranch onOp vtable sinking (Body dec stms res) =@@ -111,7 +111,7 @@ sunk = namesFromList $ foldMap (patNames . stmPat) sunk_stms optimiseLoop ::- Constraints rep =>+ (Constraints rep) => Sinker rep (Op rep) -> Sinker rep ([(FParam rep, SubExp)], LoopForm rep, Body rep) optimiseLoop onOp vtable sinking (merge, form, body0)@@ -144,7 +144,7 @@ in stm <| stms optimiseStms ::- Constraints rep =>+ (Constraints rep) => Sinker rep (Op rep) -> SymbolTable rep -> Sinking rep ->@@ -159,7 +159,7 @@ multiplicities = foldl' (M.unionWith (+))- (M.fromList (zip (namesToList free_in_res) (repeat 1)))+ (M.fromList (map (,1) (namesToList free_in_res))) (map multiplicity $ stmsToList all_stms) optimiseStms' _ _ [] = ([], mempty)@@ -183,13 +183,13 @@ in ( stm {stmExp = Match cond cases' defbody' ret} : stms', mconcat cases_sunk <> defbody_sunk <> sunk )- | DoLoop merge lform body <- stmExp stm =+ | Loop merge lform body <- stmExp stm = let comps = (merge, lform, body) (comps', loop_sunk) = optimiseLoop onOp vtable sinking comps (merge', lform', body') = comps' (stms', stms_sunk) = optimiseStms' vtable' sinking stms- in ( stm {stmExp = DoLoop merge' lform' body'} : stms',+ in ( stm {stmExp = Loop merge' lform' body'} : stms', stms_sunk <> loop_sunk ) | Op op <- stmExp stm =@@ -220,7 +220,7 @@ } optimiseBody ::- Constraints rep =>+ (Constraints rep) => Sinker rep (Op rep) -> Sinker rep (Body rep) optimiseBody onOp vtable sinking (Body attr stms res) =@@ -228,7 +228,7 @@ in (Body attr stms' res, sunk) optimiseKernelBody ::- Constraints rep =>+ (Constraints rep) => Sinker rep (Op rep) -> Sinker rep (KernelBody rep) optimiseKernelBody onOp vtable sinking (KernelBody attr stms res) =@@ -236,7 +236,7 @@ in (KernelBody attr stms' res, sunk) optimiseSegOp ::- Constraints rep =>+ (Constraints rep) => Sinker rep (Op rep) -> Sinker rep (SegOp lvl rep) optimiseSegOp onOp vtable sinking op =
src/Futhark/Optimise/TileLoops.hs view
@@ -164,7 +164,7 @@ poststms' stms_res -- Tiling inside for-loop.- | DoLoop merge (ForLoop i it bound []) loopbody <- stmExp stm_to_tile,+ | Loop merge (ForLoop i it bound []) loopbody <- stmExp stm_to_tile, not $ any ((`nameIn` freeIn merge) . paramName . fst) merge, Just (prestms', poststms') <- preludeToPostlude variance prestms stm_to_tile (stmsFromList poststms) = do@@ -191,7 +191,7 @@ Nothing -> next Just tiled -> Just- <$> tileDoLoop+ <$> tileLoop initial_space variance prestms'@@ -350,7 +350,7 @@ tiledBody private' (prelude_privstms <> privstms) -tileDoLoop ::+tileLoop :: SegSpace -> VarianceTable -> Stms GPU ->@@ -366,7 +366,7 @@ Stms GPU -> Result -> TileM (Stms GPU, Tiling, TiledBody)-tileDoLoop initial_space variance prestms used_in_body (host_stms, tiling, tiledBody) res_ts pat aux merge i it bound poststms poststms_res = do+tileLoop initial_space variance prestms used_in_body (host_stms, tiling, tiledBody) res_ts pat aux merge i it bound poststms poststms_res = do let prestms_used = used_in_body <> freeIn poststms <> freeIn poststms_res ( invariant_prestms, precomputed_variant_prestms,@@ -432,7 +432,7 @@ resultBody . map Var <$> tiledBody private' privstms' accs' <- letTupExp "tiled_inside_loop" $- DoLoop merge' (ForLoop i it bound []) loopbody'+ Loop merge' (ForLoop i it bound []) loopbody' postludeGeneric tiling (privstms <> inloop_privstms) pat accs' poststms poststms_res res_ts @@ -454,7 +454,7 @@ addStms prestms pure $ varsRes prestms_live -liveSet :: FreeIn a => Stms GPU -> a -> Names+liveSet :: (FreeIn a) => Stms GPU -> a -> Names liveSet stms after = namesFromList (concatMap (patNames . stmPat) stms) `namesIntersection` freeIn after@@ -508,7 +508,7 @@ -- The atual tile size may be smaller for the last tile, so we have to -- be careful now. sliceUntiled ::- MonadBuilder m =>+ (MonadBuilder m) => VName -> SubExp -> SubExp ->@@ -713,7 +713,7 @@ ProcessTileArgs privstms red_comm red_lam map_lam tile accs (Var tile_id) resultBody . map Var <$> tilingProcessTile tiling tile_args - accs <- letTupExp "accs" $ DoLoop merge loopform loopbody+ accs <- letTupExp "accs" $ Loop merge loopform loopbody -- We possibly have to traverse a residual tile. red_lam' <- renameLambda red_lam@@ -1049,7 +1049,7 @@ TileFull -> mapM readTileElem arrs_and_perms -findTileSize :: HasScope rep m => [InputTile] -> m SubExp+findTileSize :: (HasScope rep m) => [InputTile] -> m SubExp findTileSize tiles = case mapMaybe isTiled tiles of v : _ -> arraySize 0 <$> lookupType v
@@ -36,13 +36,13 @@ -- index an array with indices given in outer_indices; any inner -- dims of arr not indexed by outer_indices are sliced entirely-index :: MonadBuilder m => String -> VName -> [VName] -> m VName+index :: (MonadBuilder m) => String -> VName -> [VName] -> m VName index se_desc arr outer_indices = do arr_t <- lookupType arr let slice = fullSlice arr_t $ map (DimFix . Var) outer_indices letExp se_desc $ BasicOp $ Index arr slice -update :: MonadBuilder m => String -> VName -> [VName] -> SubExp -> m VName+update :: (MonadBuilder m) => String -> VName -> [VName] -> SubExp -> m VName update se_desc arr indices new_elem = letExp se_desc $ BasicOp $ Update Unsafe arr (Slice $ map (DimFix . Var) indices) new_elem @@ -67,7 +67,7 @@ map paramName loop_inits letTupExp "loop" $- DoLoop (zip loop_inits $ map Var merge) loop_form loop_body+ Loop (zip loop_inits $ map Var merge) loop_form loop_body forLoop :: SubExp ->
src/Futhark/Optimise/Unstream.hs view
@@ -43,7 +43,7 @@ data Stage = SeqStreams | SeqAll unstream ::- ASTRep rep =>+ (ASTRep rep) => (Stage -> OnOp rep) -> (Prog rep -> PassM (Prog rep)) -> Pass rep rep@@ -64,7 +64,7 @@ Pat (LetDec rep) -> StmAux (ExpDec rep) -> Op rep -> UnstreamM rep [Stm rep] optimiseStms ::- ASTRep rep =>+ (ASTRep rep) => OnOp rep -> Stms rep -> UnstreamM rep (Stms rep)@@ -73,7 +73,7 @@ stmsFromList . concat <$> mapM (optimiseStm onOp) (stmsToList stms) optimiseBody ::- ASTRep rep =>+ (ASTRep rep) => OnOp rep -> Body rep -> UnstreamM rep (Body rep)@@ -81,7 +81,7 @@ Body aux <$> optimiseStms onOp stms <*> pure res optimiseKernelBody ::- ASTRep rep =>+ (ASTRep rep) => OnOp rep -> KernelBody rep -> UnstreamM rep (KernelBody rep)@@ -92,7 +92,7 @@ <*> pure res optimiseLambda ::- ASTRep rep =>+ (ASTRep rep) => OnOp rep -> Lambda rep -> UnstreamM rep (Lambda rep)@@ -101,7 +101,7 @@ pure lam {lambdaBody = body} optimiseStm ::- ASTRep rep =>+ (ASTRep rep) => OnOp rep -> Stm rep -> UnstreamM rep [Stm rep]@@ -117,7 +117,7 @@ } optimiseSegOp ::- ASTRep rep =>+ (ASTRep rep) => OnOp rep -> SegOp lvl rep -> UnstreamM rep (SegOp lvl rep)
src/Futhark/Pass.hs view
@@ -36,7 +36,7 @@ -- | Execute a 'PassM' action, yielding logging information and either -- an error pretty or a result. runPassM ::- MonadFreshNames m =>+ (MonadFreshNames m) => PassM a -> m (a, Log) runPassM (PassM m) = modifyNameSource $ runState (runWriterT m)
src/Futhark/Pass/ExpandAllocations.hs view
@@ -219,7 +219,8 @@ let user = (lvl, [le64 $ segFlat space]) (kbody', kbody_allocs) = extractKernelBodyAllocations user bound_outside bound_in_kernel kbody- (ops', ops_allocs) = unzip $ map (extractLambdaAllocations user bound_outside mempty) ops+ (ops', ops_allocs) =+ unzip $ map (extractLambdaAllocations user bound_outside mempty) ops variantAlloc (_, Var v, _) = v `notNameIn` bound_outside variantAlloc _ = False (variant_allocs, invariant_allocs) =@@ -247,10 +248,11 @@ then pure (mempty, (lvl, ops, kbody)) else do (lvl_stms, lvl', grid) <- ensureGridKnown lvl- 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''))+ 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'')) where bound_in_kernel = namesFromList (M.keys $ scopeOfSegSpace space)@@ -320,9 +322,11 @@ num_threads_stms <> invariant_alloc_stms <> variant_alloc_stms ) +type Exp64 = TPrimExp Int64 VName+ -- | Identifying the spot where an allocation occurs in terms of its -- level and unique thread ID.-type User = (SegLevel, [TPrimExp Int64 VName])+type User = (SegLevel, [Exp64]) -- | A description of allocations that have been extracted, and how -- much memory (and which space) is needed.@@ -356,9 +360,12 @@ Names -> Lambda GPUMem -> (Lambda GPUMem, Extraction)-extractLambdaAllocations user bound_outside bound_kernel lam = (lam {lambdaBody = body'}, allocs)+extractLambdaAllocations user bound_outside bound_kernel lam =+ (lam {lambdaBody = body'}, allocs) where- (body', allocs) = extractBodyAllocations user bound_outside bound_kernel $ lambdaBody lam+ (body', allocs) =+ extractBodyAllocations user bound_outside bound_kernel $+ lambdaBody lam extractGenericBodyAllocations :: User ->@@ -373,11 +380,9 @@ extractGenericBodyAllocations user bound_outside bound_kernel get_stms set_stms body = let bound_kernel' = bound_kernel <> boundByStms (get_stms body) (stms, allocs) =- runWriter $- fmap catMaybes $- mapM (extractStmAllocations user bound_outside bound_kernel') $- stmsToList $- get_stms body+ runWriter . fmap catMaybes $+ mapM (extractStmAllocations user bound_outside bound_kernel') $+ stmsToList (get_stms body) in (set_stms (stmsFromList stms) body, allocs) expandable, notScalar :: Space -> Bool@@ -436,7 +441,8 @@ } onKernelBody user' body = do- let (body', allocs) = extractKernelBodyAllocations user' bound_outside bound_kernel body+ let (body', allocs) =+ extractKernelBodyAllocations user' bound_outside bound_kernel body tell allocs pure body' @@ -445,7 +451,7 @@ pure lam {lambdaBody = body} genericExpandedInvariantAllocations ::- (User -> (Shape, [TPrimExp Int64 VName])) -> Extraction -> ExpandM (Stms GPUMem, RebaseMap)+ (User -> (Shape, [Exp64])) -> Extraction -> ExpandM (Stms GPUMem, RebaseMap) genericExpandedInvariantAllocations getNumUsers invariant_allocs = do -- We expand the invariant allocations by adding an inner dimension -- equal to the number of kernel threads.@@ -462,29 +468,21 @@ letBind allocpat $ Op $ Alloc (Var total_size) space pure $ M.singleton mem $ newBase user - untouched d = DimSlice 0 d 1-- newBaseThread user (old_shape, _) =+ newBaseThread user _old_shape = let (users_shape, user_ids) = getNumUsers user- num_dims = length old_shape- perm = [num_dims .. num_dims + shapeRank users_shape - 1] ++ [0 .. num_dims - 1]- root_ixfun = IxFun.iota (old_shape ++ map pe64 (shapeDims users_shape))- permuted_ixfun = IxFun.permute root_ixfun perm- offset_ixfun =- IxFun.slice permuted_ixfun $- Slice $- map DimFix user_ids ++ map untouched old_shape- in offset_ixfun+ dims = map pe64 (shapeDims users_shape)+ in ( flattenIndex dims user_ids,+ product dims+ ) newBase user@(SegThreadInGroup {}, _) = newBaseThread user newBase user@(SegThread {}, _) = newBaseThread user- newBase user@(SegGroup {}, _) = \(old_shape, _) ->+ newBase user@(SegGroup {}, _) = \_old_shape -> let (users_shape, user_ids) = getNumUsers user- root_ixfun = IxFun.iota $ map pe64 (shapeDims users_shape) ++ old_shape- offset_ixfun =- IxFun.slice root_ixfun . Slice $- map DimFix user_ids ++ map untouched old_shape- in offset_ixfun+ dims = map pe64 (shapeDims users_shape)+ in ( flattenIndex dims user_ids,+ product dims+ ) expandedInvariantAllocations :: SubExp ->@@ -524,10 +522,7 @@ let variant_allocs' :: [(VName, (SubExp, SubExp, Space))] variant_allocs' = concat $- zipWith- memInfo- (map snd sizes_to_blocks)- (zip offsets size_sums)+ zipWith memInfo (map snd sizes_to_blocks) (zip offsets size_sums) memInfo blocks (offset, total_size) = [(mem, (Var offset, Var total_size, space)) | (mem, space) <- blocks] @@ -547,20 +542,16 @@ num_threads' = pe64 num_threads gtid = le64 $ segFlat kspace - untouched d = DimSlice 0 d 1- -- For the variant allocations, we add an inner dimension, -- which is then offset by a thread-specific amount.- newBase (old_shape, _pt) =- let root_ixfun = IxFun.iota $ old_shape ++ [num_threads']- offset_ixfun =- IxFun.slice root_ixfun . Slice $- map untouched old_shape ++ [DimFix gtid]- in offset_ixfun+ newBase _old_shape =+ (gtid, num_threads') --- | A map from memory block names to new index function bases.-type RebaseMap = M.Map VName (([TPrimExp Int64 VName], PrimType) -> IxFun)+type Expansion = (Exp64, Exp64) +-- | A map from memory block names to index function embeddings..+type RebaseMap = M.Map VName ([Exp64] -> Expansion)+ newtype OffsetM a = OffsetM ( ReaderT@@ -589,7 +580,7 @@ scope <- ask lift $ local f $ runReaderT m scope -lookupNewBase :: VName -> ([TPrimExp Int64 VName], PrimType) -> OffsetM (Maybe IxFun)+lookupNewBase :: VName -> [Exp64] -> OffsetM (Maybe Expansion) lookupNewBase name x = do offsets <- askRebaseMap pure $ ($ x) <$> M.lookup name offsets@@ -657,14 +648,18 @@ where onPE (PatElem name (MemArray pt shape u (ArrayIn mem _)))- (MemArray _ _ _ (Just (ReturnsNewBlock _ _ ixfun))) =- pure . PatElem name . MemArray pt shape u . ArrayIn mem $- fmap (fmap unExt) ixfun+ (MemArray _ _ _ info)+ | Just ixfun <- getIxFun info =+ pure . PatElem name . MemArray pt shape u . ArrayIn mem $+ fmap (fmap unExt) ixfun onPE pe _ = do new_dec <- offsetMemoryInMemBound (patElemName pe) $ patElemDec pe pure pe {patElemDec = new_dec} unExt (Ext i) = patElemName (pes !! i) unExt (Free v) = v+ getIxFun (Just (ReturnsNewBlock _ _ ixfun)) = Just ixfun+ getIxFun (Just (ReturnsInBlock _ ixfun)) = Just ixfun+ getIxFun _ = Nothing offsetMemoryInParam :: Param (MemBound u) -> OffsetM (Param (MemBound u)) offsetMemoryInParam fparam = do@@ -673,42 +668,45 @@ offsetMemoryInMemBound :: VName -> MemBound u -> OffsetM (MemBound u) offsetMemoryInMemBound v summary@(MemArray pt shape u (ArrayIn mem ixfun)) = do- new_base <- lookupNewBase mem (IxFun.base ixfun, pt)- case new_base of+ embedding <- lookupNewBase mem $ IxFun.shape ixfun+ case embedding of Nothing -> pure summary- Just new_base' -> do+ Just (o, p) -> do let problem = throwError . unlines $ [ "offsetMemoryInMemBound", prettyString v,- prettyString new_base',+ prettyString (o, p), prettyString ixfun ]- ixfun' <- maybe problem pure $ IxFun.rebase new_base' ixfun+ ixfun' <- maybe problem pure $ IxFun.expand o p ixfun pure $ MemArray pt shape u $ ArrayIn mem ixfun' offsetMemoryInMemBound _ summary = pure summary offsetMemoryInBodyReturns :: BodyReturns -> OffsetM BodyReturns offsetMemoryInBodyReturns br@(MemArray pt shape u (ReturnsInBlock mem ixfun)) | Just ixfun' <- isStaticIxFun ixfun = do- new_base <- lookupNewBase mem (IxFun.base ixfun', pt)- case new_base of+ embedding <- lookupNewBase mem $ IxFun.shape ixfun'+ case embedding of Nothing -> pure br- Just new_base' -> do+ Just (o, p) -> do let problem = throwError . unlines $ [ "offsetMemoryInBodyReturns",- prettyString new_base',+ prettyString (o, p), prettyString ixfun ]- ixfun'' <- maybe problem pure $ IxFun.rebase (fmap (fmap Free) new_base') ixfun+ ixfun'' <-+ maybe problem pure $+ IxFun.expand (Free <$> o) (fmap Free p) ixfun pure $ MemArray pt shape u $ ReturnsInBlock mem ixfun'' offsetMemoryInBodyReturns br = pure br offsetMemoryInLambda :: Lambda GPUMem -> OffsetM (Lambda GPUMem)-offsetMemoryInLambda lam = inScopeOf lam $ do- body <- offsetMemoryInBody $ lambdaBody lam- pure $ lam {lambdaBody = body}+offsetMemoryInLambda lam = do+ body <- inScopeOf lam $ offsetMemoryInBody $ lambdaBody lam+ params <- mapM offsetMemoryInParam $ lambdaParams lam+ pure $ lam {lambdaBody = body, lambdaParams = params} -- A loop may have memory parameters, and those memory blocks may -- be expanded. We assume (but do not check - FIXME) that if the@@ -731,13 +729,13 @@ onParamArg rm _ = rm offsetMemoryInExp :: Exp GPUMem -> OffsetM (Exp GPUMem)-offsetMemoryInExp (DoLoop merge form body) = do+offsetMemoryInExp (Loop merge form body) = do offsetMemoryInLoopParams merge $ \merge' -> do body' <- localScope (scopeOfFParams (map fst merge') <> scopeOf form) (offsetMemoryInBody body)- pure $ DoLoop merge' form body'+ pure $ Loop merge' form body' offsetMemoryInExp e = mapExpM recurse e where recurse =
src/Futhark/Pass/ExplicitAllocations.hs view
@@ -130,7 +130,7 @@ askDefaultSpace = asks allocSpace runAllocM ::- MonadFreshNames m =>+ (MonadFreshNames m) => Space -> (Op fromrep -> AllocM fromrep torep (Op torep)) -> (Exp torep -> AllocM fromrep torep [ExpHint]) ->@@ -148,14 +148,14 @@ envExpHints = hints } -elemSize :: Num a => Type -> a+elemSize :: (Num a) => Type -> a elemSize = primByteSize . elemType arraySizeInBytesExp :: Type -> PrimExp VName arraySizeInBytesExp t = untyped $ foldl' (*) (elemSize t) $ map pe64 (arrayDims t) -arraySizeInBytesExpM :: MonadBuilder m => Type -> m (PrimExp VName)+arraySizeInBytesExpM :: (MonadBuilder m) => Type -> m (PrimExp VName) arraySizeInBytesExpM t = do let dim_prod_i64 = product $ map pe64 (arrayDims t) elm_size_i64 = elemSize t@@ -164,7 +164,7 @@ untyped $ dim_prod_i64 * elm_size_i64 -arraySizeInBytes :: MonadBuilder m => Type -> m SubExp+arraySizeInBytes :: (MonadBuilder m) => Type -> m SubExp arraySizeInBytes = letSubExp "bytes" <=< toExp <=< arraySizeInBytesExpM allocForArray' ::@@ -178,7 +178,7 @@ -- | Allocate memory for a value of the given type. allocForArray ::- Allocable fromrep torep inner =>+ (Allocable fromrep torep inner) => Type -> Space -> AllocM fromrep torep VName@@ -245,7 +245,7 @@ rts <- fromMaybe (error "patWithAllocations: ill-typed") <$> expReturns e Pat <$> allocsForPat def_space idents rts hints -mkMissingIdents :: MonadFreshNames m => [Ident] -> [ExpReturns] -> m [Ident]+mkMissingIdents :: (MonadFreshNames m) => [Ident] -> [ExpReturns] -> m [Ident] mkMissingIdents idents rts = reverse <$> zipWithM f (reverse rts) (map Just (reverse idents) ++ repeat Nothing) where@@ -301,7 +301,7 @@ inst (Free v) = v inst (Ext i) = getIdent idents i -instantiateIxFun :: Monad m => ExtIxFun -> m IxFun+instantiateIxFun :: (Monad m) => ExtIxFun -> m IxFun instantiateIxFun = traverse $ traverse inst where inst Ext {} = error "instantiateIxFun: not yet"@@ -377,8 +377,7 @@ mem_space <- lookupMemSpace mem default_space <- askDefaultSpace let space = fromMaybe default_space space_ok- if IxFun.permutation ixfun == [0 .. IxFun.rank ixfun - 1]- && length (IxFun.base ixfun) == IxFun.rank ixfun+ if length (IxFun.base ixfun) == IxFun.rank ixfun && maybe True (== mem_space) space_ok then pure (mem, v) else allocLinearArray space (baseString v) v@@ -569,7 +568,6 @@ mem_space <- lookupMemSpace mem default_space <- askDefaultSpace if length (IxFun.base ixfun) == length (IxFun.shape ixfun)- && IxFun.permutation ixfun == perm && maybe True (== mem_space) space_ok then pure (mem, v) else allocPermArray (fromMaybe default_space space_ok) perm (baseString v) v@@ -630,7 +628,7 @@ allocInFun consts (FunDef entry attrs fname rettype params fbody) = runAllocM space handleOp hints . inScopeOf consts $- allocInFParams (zip params $ repeat space) $ \params' -> do+ allocInFParams (map (,space) params) $ \params' -> do (fbody', mem_rets) <- allocInFunBody (map (const $ Just space) rettype) fbody let num_extra_params = length params' - length params@@ -750,7 +748,7 @@ addStm =<< allocsForStm (map patElemIdent pes) =<< allocInExp e allocInLambda ::- Allocable fromrep torep inner =>+ (Allocable fromrep torep inner) => [LParam torep] -> Body fromrep -> AllocM fromrep torep (Lambda torep)@@ -758,14 +756,14 @@ mkLambda params . allocInStms (bodyStms body) $ pure $ bodyResult body data MemReq- = MemReq Space [Int] Rank+ = MemReq Space Rank | NeedsNormalisation Space deriving (Eq, Show) combMemReqs :: MemReq -> MemReq -> MemReq combMemReqs x@NeedsNormalisation {} _ = x combMemReqs _ y@NeedsNormalisation {} = y-combMemReqs x@(MemReq x_space _ _) y@MemReq {} =+combMemReqs x@(MemReq x_space _) y@MemReq {} = if x == y then x else NeedsNormalisation x_space type MemReqType = MemInfo (Ext SubExp) NoUniqueness MemReq@@ -776,7 +774,7 @@ combMemReqTypes x _ = x contextRets :: MemReqType -> [MemInfo d u r]-contextRets (MemArray _ shape _ (MemReq space _ (Rank base_rank))) =+contextRets (MemArray _ shape _ (MemReq space (Rank base_rank))) = -- Memory + offset + base_rank + (stride,size)*rank. MemMem space : MemPrim int64@@ -809,10 +807,7 @@ (Array pt shape u, MemArray _ _ _ (ArrayIn mem ixfun)) -> do space <- lookupMemSpace mem pure . MemArray pt shape u $- MemReq- space- (IxFun.permutation ixfun)- (Rank $ length $ IxFun.base ixfun)+ MemReq space (Rank $ length $ IxFun.base ixfun) (_, MemMem space) -> pure $ MemMem space (_, MemPrim pt) -> pure $ MemPrim pt (_, MemAcc acc ispace ts u) -> pure $ MemAcc acc ispace ts u@@ -834,15 +829,15 @@ ) arrayInfo rank (NeedsNormalisation space) =- (space, [0 .. rank - 1], rank)- arrayInfo _ (MemReq space perm (Rank base_rank)) =- (space, perm, base_rank)+ (space, rank)+ arrayInfo _ (MemReq space (Rank base_rank)) =+ (space, base_rank) inspect ctx_offset (MemArray pt shape u req) = let shape' = fmap (adjustExt num_new_ctx) shape- (space, perm, base_rank) = arrayInfo (shapeRank shape) req+ (space, base_rank) = arrayInfo (shapeRank shape) req in MemArray pt shape' u . ReturnsNewBlock space ctx_offset $- convert <$> IxFun.mkExistential base_rank perm (ctx_offset + 1)+ convert <$> IxFun.mkExistential base_rank (shapeRank shape) (ctx_offset + 1) inspect _ (MemAcc acc ispace ts u) = MemAcc acc ispace ts u inspect _ (MemPrim pt) = MemPrim pt inspect _ (MemMem space) = MemMem space@@ -891,7 +886,7 @@ -- Futhark.Optimise.EntryPointMem for a very specialised version of -- the idea, but which could perhaps be generalised. simplifyMatch ::- Mem rep inner =>+ (Mem rep inner) => [Case (Body rep)] -> Body rep -> [BranchTypeMem] ->@@ -932,7 +927,7 @@ (Allocable fromrep torep inner) => Exp fromrep -> AllocM fromrep torep (Exp torep)-allocInExp (DoLoop merge form (Body () bodystms bodyres)) =+allocInExp (Loop merge form (Body () bodystms bodyres)) = allocInMergeParams merge $ \merge' mk_loop_val -> do form' <- allocInLoopForm form localScope (scopeOf form') $ do@@ -940,7 +935,7 @@ buildBody_ . allocInStms bodystms $ do (valctx, valres') <- mk_loop_val $ map resSubExp bodyres pure $ subExpsRes valctx <> zipWith SubExpRes (map resCerts bodyres) valres'- pure $ DoLoop merge' form' body'+ pure $ Loop merge' form' body' allocInExp (Apply fname args rettype loc) = do args' <- funcallArgs args space <- askDefaultSpace@@ -1062,11 +1057,11 @@ instance SizeSubst (NoOp rep) -instance SizeSubst (op rep) => SizeSubst (MemOp op rep) where+instance (SizeSubst (op rep)) => SizeSubst (MemOp op rep) where opIsConst (Inner op) = opIsConst op opIsConst _ = False -stmConsts :: SizeSubst (Op rep) => Stm rep -> S.Set VName+stmConsts :: (SizeSubst (Op rep)) => Stm rep -> S.Set VName stmConsts (Let pat _ (Op op)) | opIsConst op = S.fromList $ patNames pat stmConsts _ = mempty@@ -1113,7 +1108,7 @@ nohints = map (const NoHint) names simplifyMemOp ::- Engine.SimplifiableRep rep =>+ (Engine.SimplifiableRep rep) => ( inner (Engine.Wise rep) -> Engine.SimpleM rep (inner (Engine.Wise rep), Stms (Engine.Wise rep)) ) ->@@ -1144,7 +1139,7 @@ ) -> SimpleOps rep simplifiable innerUsage simplifyInnerOp =- SimpleOps mkExpDecS' mkBodyS' protectOp opUsage simplifyPat (simplifyMemOp simplifyInnerOp)+ SimpleOps mkExpDecS' mkBodyS' protectOp opUsage (simplifyMemOp simplifyInnerOp) where mkExpDecS' _ pat e = pure $ Engine.mkWiseExpDec pat () e@@ -1167,26 +1162,6 @@ mempty opUsage (Inner inner) = innerUsage inner-- simplifyPat (Pat pes) e = do- rets <- fromMaybe (error "simplifyPat: ill-typed") <$> expReturns e- Pat <$> zipWithM update pes rets- where- names = map patElemName pes- update- (PatElem pe_v (MemArray pt shape u (ArrayIn mem _)))- (MemArray _ _ _ (Just (ReturnsInBlock _ ixfun)))- | Just ixfun' <- traverse (traverse inst) ixfun =- PatElem pe_v- <$> ( MemArray pt- <$> Engine.simplify shape- <*> pure u- <*> (ArrayIn <$> Engine.simplify mem <*> pure ixfun')- )- where- inst (Ext i) = maybeNth i names- inst (Free v) = Just v- update pe _ = traverse Engine.simplify pe data ExpHint = NoHint
src/Futhark/Pass/ExplicitAllocations/GPU.hs view
@@ -40,19 +40,25 @@ AllocM GPU GPUMem (SegOp SegLevel GPUMem) handleSegOp outer_lvl op = do num_threads <-- letSubExp "num_threads"- =<< case maybe_grid of- Just grid ->- pure . BasicOp $- BinOp- (Mul Int64 OverflowUndef)- (unCount (gridNumGroups grid))- (unCount (gridGroupSize grid))- Nothing ->- foldBinOp- (Mul Int64 OverflowUndef)- (intConst Int64 1)- (segSpaceDims $ segSpace op)+ case (outer_lvl, segLevel op) of+ -- This implies we are in the intragroup parallelism situation.+ -- Just allocate for a single group; memory expansion will+ -- handle the rest later.+ (Just (SegGroup _ (Just grid)), _) -> pure $ unCount $ gridGroupSize grid+ _ ->+ letSubExp "num_threads"+ =<< case maybe_grid of+ Just grid ->+ pure . BasicOp $+ BinOp+ (Mul Int64 OverflowUndef)+ (unCount (gridNumGroups grid))+ (unCount (gridGroupSize grid))+ Nothing ->+ foldBinOp+ (Mul Int64 OverflowUndef)+ (intConst Int64 1)+ (segSpaceDims $ segSpace op) allocAtLevel (segLevel op) $ mapSegOpM (mapper num_threads) op where maybe_grid =
src/Futhark/Pass/ExplicitAllocations/SegOp.hs view
@@ -15,7 +15,7 @@ instance SizeSubst (SegOp lvl rep) allocInKernelBody ::- Allocable fromrep torep inner =>+ (Allocable fromrep torep inner) => KernelBody fromrep -> AllocM fromrep torep (KernelBody torep) allocInKernelBody (KernelBody () stms res) =@@ -23,7 +23,7 @@ <$> collectStms (allocInStms stms (pure res)) allocInLambda ::- Allocable fromrep torep inner =>+ (Allocable fromrep torep inner) => [LParam torep] -> Body fromrep -> AllocM fromrep torep (Lambda torep)@@ -33,7 +33,7 @@ bodyResult body allocInBinOpParams ::- Allocable fromrep torep inner =>+ (Allocable fromrep torep inner) => SubExp -> TPrimExp Int64 VName -> TPrimExp Int64 VName ->@@ -45,11 +45,10 @@ alloc x y = case paramType x of Array pt shape u -> do+ let name = maybe "num_threads" baseString (subExpVar num_threads) twice_num_threads <-- letSubExp "twice_num_threads" $- BasicOp $- BinOp (Mul Int64 OverflowUndef) num_threads $- intConst Int64 2+ letSubExp ("twice_" <> name) . BasicOp $+ BinOp (Mul Int64 OverflowUndef) num_threads (intConst Int64 2) let t = paramType x `arrayOfRow` twice_num_threads mem <- allocForArray t =<< askDefaultSpace -- XXX: this iota ixfun is a bit inefficient; leading to@@ -84,7 +83,7 @@ ) allocInBinOpLambda ::- Allocable fromrep torep inner =>+ (Allocable fromrep torep inner) => SubExp -> SegSpace -> Lambda fromrep ->
src/Futhark/Pass/ExtractKernels.hs view
@@ -279,7 +279,7 @@ w `subExpBound` bound unbalancedStm _ Op {} = False- unbalancedStm _ DoLoop {} = False+ unbalancedStm _ Loop {} = False unbalancedStm bound (WithAcc _ lam) = unbalancedBody bound (lambdaBody lam) unbalancedStm bound (Match ses cases defbody _) =@@ -363,9 +363,9 @@ where transformInput (shape, arrs, op) = (shape, arrs, fmap (first soacsLambdaToGPU) op)-transformStm path (Let pat aux (DoLoop merge form body)) =+transformStm path (Let pat aux (Loop merge form body)) = localScope (castScope (scopeOf form) <> scopeOfFParams params) $- oneStm . Let pat aux . DoLoop merge form' <$> transformBody path body+ oneStm . Let pat aux . Loop merge form' <$> transformBody path body where params = map fst merge form' = case form of@@ -432,7 +432,7 @@ if not (lambdaContainsParallelism map_lam) || "sequential_inner"- `inAttrs` stmAuxAttrs aux+ `inAttrs` stmAuxAttrs aux then paralleliseOuter else do ((outer_suff, outer_suff_key), suff_stms) <-@@ -519,7 +519,7 @@ mapLike w lam' | Op (Scatter w _ lam' _) <- stmExp stm = mapLike w lam'- | DoLoop _ _ body <- stmExp stm =+ | Loop _ _ body <- stmExp stm = bodyInterest body * 10 | Match _ cases defbody _ <- stmExp stm = foldl@@ -562,7 +562,7 @@ else bodyInterest (lambdaBody lam') | Op Scatter {} <- stmExp stm = 0 -- Basically a map.- | DoLoop _ ForLoop {} body <- stmExp stm =+ | Loop _ ForLoop {} body <- stmExp stm = bodyInterest body * 10 | WithAcc _ withacc_lam <- stmExp stm = bodyInterest (lambdaBody withacc_lam)@@ -634,7 +634,7 @@ AttrComp "incremental_flattening" ["no_outer"] `inAttrs` attrs || AttrComp "incremental_flattening" ["only_inner"]- `inAttrs` attrs+ `inAttrs` attrs mayExploitIntra :: Attrs -> Bool mayExploitIntra attrs =@@ -642,7 +642,7 @@ AttrComp "incremental_flattening" ["no_intra"] `inAttrs` attrs || AttrComp "incremental_flattening" ["only_inner"]- `inAttrs` attrs+ `inAttrs` attrs -- The minimum amount of inner parallelism we require (by default) in -- intra-group versions. Less than this is usually pointless on a GPU
src/Futhark/Pass/ExtractKernels/BlockedKernel.hs view
@@ -44,7 +44,7 @@ type MkSegLevel rep m = [SubExp] -> String -> ThreadRecommendation -> BuilderT rep m (SegOpLevel rep) -mkSegSpace :: MonadFreshNames m => [(VName, SubExp)] -> m SegSpace+mkSegSpace :: (MonadFreshNames m) => [(VName, SubExp)] -> m SegSpace mkSegSpace dims = SegSpace <$> newVName "phys_tid" <*> pure dims prepareRedOrScan ::@@ -127,7 +127,7 @@ SegMap lvl kspace (lambdaReturnType map_lam) kbody dummyDim ::- MonadBuilder m =>+ (MonadBuilder m) => Pat Type -> m (Pat Type, [(VName, SubExp)], m ()) dummyDim pat = do
src/Futhark/Pass/ExtractKernels/DistributeNests.hs view
@@ -57,7 +57,7 @@ import Futhark.Util import Futhark.Util.Log -scopeForSOACs :: SameScope rep SOACS => Scope rep -> Scope SOACS+scopeForSOACs :: (SameScope rep SOACS) => Scope rep -> Scope SOACS scopeForSOACs = castScope data MapLoop = MapLoop (Pat Type) (StmAux ()) SubExp (Lambda SOACS) [VName]@@ -104,7 +104,7 @@ instance Monoid (PostStms rep) where mempty = PostStms mempty -typeEnvFromDistAcc :: DistRep rep => DistAcc rep -> Scope rep+typeEnvFromDistAcc :: (DistRep rep) => DistAcc rep -> Scope rep typeEnvFromDistAcc = scopeOfPat . fst . outerTarget . distTargets addStmsToAcc :: Stms rep -> DistAcc rep -> DistAcc rep@@ -148,7 +148,7 @@ inner_scope <- askScope localScope (outer_scope `M.difference` inner_scope) m -instance MonadFreshNames m => MonadFreshNames (DistNestT rep m) where+instance (MonadFreshNames m) => MonadFreshNames (DistNestT rep m) where getNameSource = DistNestT $ lift getNameSource putNameSource = DistNestT . lift . putNameSource @@ -159,7 +159,7 @@ localScope types = local $ \env -> env {distScope = types <> distScope env} -instance Monad m => MonadLogger (DistNestT rep m) where+instance (Monad m) => MonadLogger (DistNestT rep m) where addLog msgs = tell mempty {accLog = msgs} runDistNestT ::@@ -194,10 +194,10 @@ certify cs . Let (Pat [pe]) (defAux ()) . BasicOp $ Replicate (Shape [loopNestingWidth outermost]) se -addPostStms :: Monad m => PostStms rep -> DistNestT rep m ()+addPostStms :: (Monad m) => PostStms rep -> DistNestT rep m () addPostStms ks = tell $ mempty {accPostStms = ks} -postStm :: Monad m => Stms rep -> DistNestT rep m ()+postStm :: (Monad m) => Stms rep -> DistNestT rep m () postStm stms = addPostStms $ PostStms stms withStm ::@@ -320,8 +320,8 @@ isMap BasicOp {} = False isMap Apply {} = False isMap Match {} = False- isMap (DoLoop _ ForLoop {} body) = bodyContainsParallelism body- isMap (DoLoop _ WhileLoop {} _) = False+ isMap (Loop _ ForLoop {} body) = bodyContainsParallelism body+ isMap (Loop _ WhileLoop {} _) = False isMap (WithAcc _ lam) = bodyContainsParallelism $ lambdaBody lam isMap Op {} = True @@ -349,12 +349,12 @@ -- situation that stm is in scope of itself. withStm stm $ maybeDistributeStm stm =<< onStms acc stms -onInnerMap :: Monad m => MapLoop -> DistAcc rep -> DistNestT rep m (DistAcc rep)+onInnerMap :: (Monad m) => MapLoop -> DistAcc rep -> DistNestT rep m (DistAcc rep) onInnerMap loop acc = do f <- asks distOnInnerMap f loop acc -onTopLevelStms :: Monad m => Stms SOACS -> DistNestT rep m ()+onTopLevelStms :: (Monad m) => Stms SOACS -> DistNestT rep m () onTopLevelStms stms = do f <- asks distOnTopLevelStms postStm =<< f stms@@ -378,7 +378,7 @@ distributeIfPossible acc >>= \case Nothing -> addStmToAcc stm acc Just acc' -> distribute =<< onInnerMap (MapLoop pat (stmAux stm) w lam arrs) acc'-maybeDistributeStm stm@(Let pat aux (DoLoop merge form@ForLoop {} body)) acc+maybeDistributeStm stm@(Let pat aux (Loop merge form@ForLoop {} body)) acc | all (`notNameIn` freeIn (patTypes pat)) (patNames pat), bodyContainsParallelism body = distributeSingleStm acc stm >>= \case@@ -996,7 +996,7 @@ =<< segHist lvl orig_pat hist_w ispace inputs' ops' lam arrs determineReduceOp ::- MonadBuilder m =>+ (MonadBuilder m) => Lambda SOACS -> [SubExp] -> m (Lambda SOACS, [SubExp], Shape)@@ -1161,7 +1161,7 @@ -- Add extra pattern elements to every kernel nesting level. expandKernelNest ::- MonadFreshNames m => [PatElem Type] -> KernelNest -> m KernelNest+ (MonadFreshNames m) => [PatElem Type] -> KernelNest -> m KernelNest expandKernelNest pes (outer_nest, inner_nests) = do let outer_size = loopNestingWidth outer_nest
src/Futhark/Pass/ExtractKernels/Distribution.hs view
@@ -108,10 +108,10 @@ x : xs -> Just (t, Targets x $ reverse xs) [] -> Nothing -targetScope :: DistRep rep => Target -> Scope rep+targetScope :: (DistRep rep) => Target -> Scope rep targetScope = scopeOfPat . fst -targetsScope :: DistRep rep => Targets -> Scope rep+targetsScope :: (DistRep rep) => Targets -> Scope rep targetsScope (Targets t ts) = mconcat $ map targetScope $ t : ts data LoopNesting = MapNesting@@ -225,7 +225,7 @@ kernelNestLoops :: KernelNest -> [LoopNesting] kernelNestLoops (loop, loops) = loop : loops -scopeOfKernelNest :: LParamInfo rep ~ Type => KernelNest -> Scope rep+scopeOfKernelNest :: (LParamInfo rep ~ Type) => KernelNest -> Scope rep scopeOfKernelNest = foldMap scopeOfLoopNesting . kernelNestLoops boundInKernelNest :: KernelNest -> Names@@ -248,7 +248,7 @@ constructKernel mk_lvl kernel_nest inner_body = runBuilderT' $ do (ispace, inps) <- flatKernel kernel_nest let aux = loopNestingAux first_nest- ispace_scope = M.fromList $ zip (map fst ispace) $ repeat $ IndexName Int64+ ispace_scope = M.fromList $ map ((,IndexName Int64) . fst) ispace pat = loopNestingPat first_nest rts = map (stripArray (length ispace)) $ patTypes pat @@ -273,7 +273,7 @@ -- -- (2) The kernel inputs - note that some of these may be unused. flatKernel ::- MonadFreshNames m =>+ (MonadFreshNames m) => KernelNest -> m ([(VName, SubExp)], [KernelInput]) flatKernel (MapNesting _ _ nesting_w params_and_arrs, []) = do@@ -319,7 +319,7 @@ distributionInnerPat = fst . innerTarget . distributionTarget distributionBodyFromStms ::- ASTRep rep =>+ (ASTRep rep) => Targets -> Stms rep -> (DistributionBody, Result)@@ -340,7 +340,7 @@ ) distributionBodyFromStm ::- ASTRep rep =>+ (ASTRep rep) => Targets -> Stm rep -> (DistributionBody, Result)
src/Futhark/Pass/ExtractKernels/ISRWIM.hs view
@@ -160,7 +160,7 @@ | otherwise = Nothing -transposedArrays :: MonadBuilder m => [VName] -> m [VName]+transposedArrays :: (MonadBuilder m) => [VName] -> m [VName] transposedArrays arrs = forM arrs $ \arr -> do t <- lookupType arr let perm = [1, 0] ++ [2 .. arrayRank t - 1]
src/Futhark/Pass/ExtractKernels/Interchange.hs view
@@ -41,7 +41,7 @@ seqLoopStm :: SeqLoop -> Stm SOACS seqLoopStm (SeqLoop _ pat merge form body) =- Let pat (defAux ()) $ DoLoop merge form body+ Let pat (defAux ()) $ Loop merge form body interchangeLoop :: (MonadBuilder m, Rep m ~ SOACS) =>
src/Futhark/Pass/ExtractKernels/Intragroup.hs view
@@ -106,7 +106,7 @@ addStms w_stms read_input_stms <- runBuilder_ $ mapM readGroupKernelInput used_inps- space <- mkSegSpace ispace+ space <- SegSpace <$> newVName "phys_group_id" <*> pure ispace pure (intra_avail_par, space, read_input_stms) let kbody' = kbody {kernelBodyStms = read_input_stms <> kernelBodyStms kbody}@@ -184,19 +184,29 @@ stms <- collectStms_ $ intraGroupStms $ bodyStms body pure $ mkBody stms $ bodyResult body +intraGroupLambda :: Lambda SOACS -> IntraGroupM (Lambda GPU)+intraGroupLambda lam =+ mkLambda (lambdaParams lam) $+ bodyBind =<< intraGroupBody (lambdaBody lam)++intraGroupWithAccInput :: WithAccInput SOACS -> IntraGroupM (WithAccInput GPU)+intraGroupWithAccInput (shape, arrs, Nothing) =+ pure (shape, arrs, Nothing)+intraGroupWithAccInput (shape, arrs, Just (lam, nes)) = do+ lam' <- intraGroupLambda lam+ pure (shape, arrs, Just (lam', nes))+ intraGroupStm :: Stm SOACS -> IntraGroupM () intraGroupStm stm@(Let pat aux e) = do scope <- askScope let lvl = SegThread SegNoVirt Nothing case e of- DoLoop merge form loopbody ->- localScope (scopeOf form') $- localScope (scopeOfFParams $ map fst merge) $ do- loopbody' <- intraGroupBody loopbody- certifying (stmAuxCerts aux) $- letBind pat $- DoLoop merge form' loopbody'+ Loop merge form loopbody ->+ localScope (scopeOf form' <> scopeOfFParams (map fst merge)) $ do+ loopbody' <- intraGroupBody loopbody+ certifying (stmAuxCerts aux) . letBind pat $+ Loop merge form' loopbody' where form' = case form of ForLoop i it bound inps -> ForLoop i it bound inps@@ -206,6 +216,10 @@ defbody' <- intraGroupBody defbody certifying (stmAuxCerts aux) . letBind pat $ Match cond cases' defbody' ifdec+ WithAcc inputs lam -> do+ inputs' <- mapM intraGroupWithAccInput inputs+ lam' <- intraGroupLambda lam+ certifying (stmAuxCerts aux) . letBind pat $ WithAcc inputs' lam' Op soac | "sequential_outer" `inAttrs` stmAuxAttrs aux -> intraGroupStms . fmap (certify (stmAuxCerts aux))
src/Futhark/Pass/ExtractKernels/StreamKernel.hs view
@@ -59,7 +59,7 @@ -- | Like 'segThread', but cap the thread count to the input size. -- This is more efficient for small kernels, e.g. summing a small -- array.-segThreadCapped :: MonadFreshNames m => MkSegLevel GPU m+segThreadCapped :: (MonadFreshNames m) => MkSegLevel GPU m segThreadCapped ws desc r = do w <- letSubExp "nest_size"
src/Futhark/Pass/ExtractMulticore.hs view
@@ -94,7 +94,7 @@ op'' <- transformLambda op' pure (stms, MC.HistOp num_bins rf dests nes' shape op'') -mkSegSpace :: MonadFreshNames m => SubExp -> m (VName, SegSpace)+mkSegSpace :: (MonadFreshNames m) => SubExp -> m (VName, SegSpace) mkSegSpace w = do flat <- newVName "flat_tid" gtid <- newVName "gtid"@@ -110,12 +110,12 @@ pure $ oneStm $ Let pat aux $ BasicOp op transformStm (Let pat aux (Apply f args ret info)) = pure $ oneStm $ Let pat aux $ Apply f args ret info-transformStm (Let pat aux (DoLoop merge form body)) = do+transformStm (Let pat aux (Loop merge form body)) = do let form' = transformLoopForm form body' <- localScope (scopeOfFParams (map fst merge) <> scopeOf form') $ transformBody body- pure $ oneStm $ Let pat aux $ DoLoop merge form' body'+ pure $ oneStm $ Let pat aux $ Loop merge form' body' transformStm (Let pat aux (Match ses cases defbody ret)) = oneStm . Let pat aux <$> (Match ses <$> mapM transformCase cases <*> transformBody defbody <*> pure ret)@@ -164,7 +164,7 @@ data NeedsRename = DoRename | DoNotRename -renameIfNeeded :: Rename a => NeedsRename -> a -> ExtractM a+renameIfNeeded :: (Rename a) => NeedsRename -> a -> ExtractM a renameIfNeeded DoRename = renameSomething renameIfNeeded DoNotRename = pure
src/Futhark/Pass/FirstOrderTransform.hs view
@@ -26,7 +26,7 @@ import Futhark.Transform.FirstOrderTransform (FirstOrderRep, transformConsts, transformFunDef) -- | The first-order transformation pass.-firstOrderTransform :: FirstOrderRep rep => Pass SOACS rep+firstOrderTransform :: (FirstOrderRep rep) => Pass SOACS rep firstOrderTransform = Pass "first order transform"
src/Futhark/Pass/KernelBabysitting.hs view
@@ -126,7 +126,7 @@ traverseKernelBodyArrayIndexes :: forall f.- Monad f =>+ (Monad f) => Names -> Names -> Scope GPU ->@@ -195,7 +195,7 @@ type Replacements = M.Map (VName, Slice SubExp) VName ensureCoalescedAccess ::- MonadBuilder m =>+ (MonadBuilder m) => ExpMap -> [(VName, SubExp)] -> ArrayIndexTransform (StateT Replacements m)@@ -360,7 +360,7 @@ [num_is .. rank - 1] ++ [0 .. num_is - 1] rearrangeInput ::- MonadBuilder m =>+ (MonadBuilder m) => Maybe (Maybe [Int]) -> [Int] -> VName ->@@ -384,7 +384,7 @@ Manifest perm manifested rowMajorArray ::- MonadBuilder m =>+ (MonadBuilder m) => VName -> m VName rowMajorArray arr = do
src/Futhark/Pass/LiftAllocations.hs view
@@ -74,9 +74,9 @@ cases' <- mapM (\(Case p b) -> Case p <$> liftAllocationsInBody b) cases body' <- liftAllocationsInBody body pure stm {stmExp = Match cond_ses cases' body' dec}-liftInsideStm stm@(Let _ _ (DoLoop params form body)) = do+liftInsideStm stm@(Let _ _ (Loop params form body)) = do body' <- liftAllocationsInBody body- pure stm {stmExp = DoLoop params form body'}+ pure stm {stmExp = Loop params form body'} liftInsideStm stm = pure stm liftAllocationsInStms ::
src/Futhark/Pass/LowerAllocations.hs view
@@ -82,9 +82,9 @@ let stm' = stm {stmExp = Match cond_ses cases' body' dec} (alloc', acc') = insertLoweredAllocs (freeIn stm) alloc acc lowerAllocationsInStms stms alloc' (acc' :|> stm')-lowerAllocationsInStms (stm@(Let _ _ (DoLoop params form body)) :<| stms) alloc acc = do+lowerAllocationsInStms (stm@(Let _ _ (Loop params form body)) :<| stms) alloc acc = do body' <- lowerAllocationsInBody body- let stm' = stm {stmExp = DoLoop params form body'}+ let stm' = stm {stmExp = Loop params form body'} (alloc', acc') = insertLoweredAllocs (freeIn stm) alloc acc lowerAllocationsInStms stms alloc' (acc' :|> stm') lowerAllocationsInStms (stm :<| stms) alloc acc = do
src/Futhark/Pipeline.hs view
@@ -153,7 +153,7 @@ -- | Construct a pipeline from a single compiler pass. onePass ::- Checkable torep =>+ (Checkable torep) => Pass fromrep torep -> Pipeline fromrep torep onePass pass = Pipeline perform@@ -193,13 +193,13 @@ -- | Create a pipeline from a list of passes. passes ::- Checkable rep =>+ (Checkable rep) => [Pass rep rep] -> Pipeline rep rep passes = foldl (>>>) id . map onePass validationError ::- PrettyRep rep =>+ (PrettyRep rep) => Pass fromrep torep -> Prog rep -> String ->
src/Futhark/Pkg/Info.hs view
@@ -80,7 +80,7 @@ -- | Create memoisation around a 'GetManifest' action to ensure that -- multiple inspections of the same revisions will not result in -- potentially expensive IO operations.-memoiseGetManifest :: MonadIO m => GetManifest m -> m (GetManifest m)+memoiseGetManifest :: (MonadIO m) => GetManifest m -> m (GetManifest m) memoiseGetManifest (GetManifest m) = do ref <- liftIO $ newIORef Nothing pure $@@ -271,7 +271,7 @@ -- | Given a package path, look up information about that package. lookupPackage ::- MonadPkgRegistry m =>+ (MonadPkgRegistry m) => CacheDir -> PkgPath -> m (PkgInfo m)@@ -286,7 +286,7 @@ pure pinfo lookupPackageCommit ::- MonadPkgRegistry m =>+ (MonadPkgRegistry m) => CacheDir -> PkgPath -> Maybe T.Text ->@@ -306,7 +306,7 @@ -- | Look up information about a specific version of a package. lookupPackageRev ::- MonadPkgRegistry m =>+ (MonadPkgRegistry m) => CacheDir -> PkgPath -> SemVer ->@@ -346,7 +346,7 @@ -- | Find the newest version of a package. lookupNewestRev ::- MonadPkgRegistry m =>+ (MonadPkgRegistry m) => CacheDir -> PkgPath -> m SemVer
src/Futhark/Pkg/Solve.hs view
@@ -75,7 +75,7 @@ -- | Run the solver, producing both a package registry containing -- a cache of the lookups performed, as well as a build list. solveDeps ::- MonadPkgRegistry m =>+ (MonadPkgRegistry m) => CacheDir -> PkgRevDeps -> m BuildList
src/Futhark/Script.hs view
@@ -63,7 +63,7 @@ type TypeMap = M.Map TypeName (Maybe [(Name, TypeName)]) -typeMap :: MonadIO m => Server -> m TypeMap+typeMap :: (MonadIO m) => Server -> m TypeMap typeMap server = do liftIO $ either (pure mempty) onTypes =<< cmdTypes server where@@ -88,7 +88,7 @@ -- | Run an action with a 'ScriptServer' produced by an existing -- 'Server', without shutting it down at the end.-withScriptServer' :: MonadIO m => Server -> (ScriptServer -> m a) -> m a+withScriptServer' :: (MonadIO m) => Server -> (ScriptServer -> m a) -> m a withScriptServer' server f = do counter <- liftIO $ newIORef 0 types <- typeMap server
src/Futhark/Test.hs view
@@ -236,7 +236,7 @@ -- approach here seems robust enough for now, but certainly it could -- be made even better. The race condition that remains should mostly -- result in duplicate work, not crashes or data corruption.-getGenFile :: MonadIO m => FutharkExe -> FilePath -> GenValue -> m FilePath+getGenFile :: (MonadIO m) => FutharkExe -> FilePath -> GenValue -> m FilePath getGenFile futhark dir gen = do liftIO $ createDirectoryIfMissing True $ dir </> "data" exists_and_proper_size <-@@ -257,7 +257,7 @@ where file = "data" </> genFileName gen -getGenBS :: MonadIO m => FutharkExe -> FilePath -> GenValue -> m BS.ByteString+getGenBS :: (MonadIO m) => FutharkExe -> FilePath -> GenValue -> m BS.ByteString getGenBS futhark dir gen = liftIO . BS.readFile . (dir </>) =<< getGenFile futhark dir gen genValues :: FutharkExe -> [GenValue] -> IO SBS.ByteString@@ -300,11 +300,11 @@ testRunReferenceOutput prog entry tr = "data" </> takeBaseName prog- <> ":"- <> T.unpack entry- <> "-"- <> map clean (T.unpack (runDescription tr))- <.> "out"+ <> ":"+ <> T.unpack entry+ <> "-"+ <> map clean (T.unpack (runDescription tr))+ <.> "out" where clean '/' = '_' -- Would this ever happen? clean ' ' = '_'@@ -457,7 +457,7 @@ -- | Determine the @--tuning@ options to pass to the program. The first -- argument is the extension of the tuning file, or 'Nothing' if none -- should be used.-determineTuning :: MonadIO m => Maybe FilePath -> FilePath -> m ([String], String)+determineTuning :: (MonadIO m) => Maybe FilePath -> FilePath -> m ([String], String) determineTuning Nothing _ = pure ([], mempty) determineTuning (Just ext) program = do exists <- liftIO $ doesFileExist (program <.> ext)
src/Futhark/Test/Values.hs view
@@ -48,7 +48,7 @@ traverse f (ValueTuple vs) = ValueTuple <$> traverse (traverse f) vs traverse f (ValueRecord m) = ValueRecord <$> traverse (traverse f) m -instance Pretty v => Pretty (Compound v) where+instance (Pretty v) => Pretty (Compound v) where pretty (ValueAtom v) = pretty v pretty (ValueTuple vs) = parens $ commasep $ map pretty vs pretty (ValueRecord m) = braces $ commasep $ map field $ M.toList m
src/Futhark/Transform/CopyPropagate.hs view
@@ -17,7 +17,7 @@ -- | Run copy propagation on an entire program. copyPropagateInProg ::- SimplifiableRep rep =>+ (SimplifiableRep rep) => SimpleOps rep -> Prog rep -> PassM (Prog rep)
src/Futhark/Transform/FirstOrderTransform.hs view
@@ -103,7 +103,7 @@ -- Produce scratch "arrays" for the Map and Scan outputs of Screma. -- "Arrays" is in quotes because some of those may be accumulators.-resultArray :: Transformer m => [VName] -> [Type] -> m [VName]+resultArray :: (Transformer m) => [VName] -> [Type] -> m [VName] resultArray arrs ts = do arrs_ts <- mapM lookupType arrs let oneArray t@Acc {}@@ -117,7 +117,7 @@ -- is untouched, and may or may not contain further 'SOAC's depending -- on the given rep. transformSOAC ::- Transformer m =>+ (Transformer m) => Pat (LetDec (Rep m)) -> SOAC (Rep m) -> m ()@@ -225,7 +225,7 @@ names <- (++ patNames pat) <$> replicateM (length scanacc_params) (newVName "discard")- letBindNames names $ DoLoop merge loopform loop_body+ letBindNames names $ Loop merge loopform loop_body transformSOAC pat (Stream w arrs nes lam) = do -- Create a loop that repeatedly applies the lambda body to a -- chunksize of 1. Hopefully this will lead to this outer loop@@ -280,7 +280,7 @@ mkBodyM mempty $ subExpsRes $ res' ++ mapout_res' - letBind pat $ DoLoop merge loop_form loop_body+ letBind pat $ Loop merge loop_form loop_body transformSOAC pat (Scatter len ivs lam as) = do iter <- newVName "write_iter" @@ -308,7 +308,7 @@ foldM saveInArray arr indexes' pure $ resultBody (map Var ress)- letBind pat $ DoLoop merge (ForLoop iter Int64 len []) loopBody+ letBind pat $ Loop merge (ForLoop iter Int64 len []) loopBody transformSOAC pat (Hist len imgs ops bucket_fun) = do iter <- newVName "iter" @@ -364,7 +364,7 @@ pure $ resultBody $ map Var $ concat hists_out'' -- Wrap up the above into a for-loop.- letBind pat $ DoLoop merge (ForLoop iter Int64 len []) loopBody+ letBind pat $ Loop merge (ForLoop iter Int64 len []) loopBody -- | Recursively first-order-transform a lambda. transformLambda ::@@ -385,7 +385,7 @@ transformBody body pure $ Lambda params body' rettype -letwith :: Transformer m => [VName] -> SubExp -> [SubExp] -> m [VName]+letwith :: (Transformer m) => [VName] -> SubExp -> [SubExp] -> m [VName] letwith ks i vs = do let update k v = do k_t <- lookupType k@@ -397,7 +397,7 @@ zipWithM update ks vs bindLambda ::- Transformer m =>+ (Transformer m) => AST.Lambda (Rep m) -> [AST.Exp (Rep m)] -> m Result@@ -409,7 +409,7 @@ bodyBind body loopMerge :: [Ident] -> [SubExp] -> [(Param DeclType, SubExp)]-loopMerge vars = loopMerge' $ zip vars $ repeat Unique+loopMerge vars = loopMerge' $ map (,Unique) vars loopMerge' :: [(Ident, Uniqueness)] -> [SubExp] -> [(Param DeclType, SubExp)] loopMerge' vars vals =
src/Futhark/Transform/Rename.hs view
@@ -149,7 +149,7 @@ -- | Perform a renaming using the 'Substitute' instance. This only -- works if the argument does not itself perform any name binding, but -- it can save on boilerplate for simple types.-substituteRename :: Substitute a => a -> RenameM a+substituteRename :: (Substitute a) => a -> RenameM a substituteRename x = do substs <- renamerSubstitutions pure $ substituteNames substs x@@ -164,7 +164,7 @@ instance Rename VName where rename name = asks (fromMaybe name . M.lookup name . envNameMap) -instance Rename a => Rename [a] where+instance (Rename a) => Rename [a] where rename = mapM rename instance (Rename a, Rename b) => Rename (a, b) where@@ -177,7 +177,7 @@ c' <- rename c pure (a', b', c') -instance Rename a => Rename (Maybe a) where+instance (Rename a) => Rename (Maybe a) where rename = maybe (pure Nothing) (fmap Just . rename) instance Rename Bool where@@ -207,7 +207,7 @@ -- | Rename some statements, then execute an action with the name -- substitutions induced by the statements active.-renamingStms :: Renameable rep => Stms rep -> (Stms rep -> RenameM a) -> RenameM a+renamingStms :: (Renameable rep) => Stms rep -> (Stms rep -> RenameM a) -> RenameM a renamingStms stms m = descend mempty stms where descend stms' rem_stms = case stmsHead rem_stms of@@ -216,7 +216,7 @@ stm' <- rename stm descend (stms' <> oneStm stm') rem_stms' -instance Renameable rep => Rename (FunDef rep) where+instance (Renameable rep) => Rename (FunDef rep) where rename (FunDef entry attrs fname ret params body) = renameBound (map paramName params) $ do params' <- mapM rename params@@ -228,14 +228,14 @@ rename (Var v) = Var <$> rename v rename (Constant v) = pure $ Constant v -instance Rename dec => Rename (Param dec) where+instance (Rename dec) => Rename (Param dec) where rename (Param attrs name dec) = Param <$> rename attrs <*> rename name <*> rename dec -instance Rename dec => Rename (Pat dec) where+instance (Rename dec) => Rename (Pat dec) where rename (Pat xs) = Pat <$> rename xs -instance Rename dec => Rename (PatElem dec) where+instance (Rename dec) => Rename (PatElem dec) where rename (PatElem ident dec) = PatElem <$> rename ident <*> rename dec instance Rename Certs where@@ -244,26 +244,26 @@ instance Rename Attrs where rename = pure -instance Rename dec => Rename (StmAux dec) where+instance (Rename dec) => Rename (StmAux dec) where rename (StmAux cs attrs dec) = StmAux <$> rename cs <*> rename attrs <*> rename dec instance Rename SubExpRes where rename (SubExpRes cs se) = SubExpRes <$> rename cs <*> rename se -instance Renameable rep => Rename (Body rep) where+instance (Renameable rep) => Rename (Body rep) where rename (Body dec stms res) = do dec' <- rename dec renamingStms stms $ \stms' -> Body dec' stms' <$> rename res -instance Renameable rep => Rename (Stm rep) where+instance (Renameable rep) => Rename (Stm rep) where rename (Let pat dec e) = Let <$> rename pat <*> rename dec <*> rename e -instance Renameable rep => Rename (Exp rep) where+instance (Renameable rep) => Rename (Exp rep) where rename (WithAcc inputs lam) = WithAcc <$> rename inputs <*> rename lam- rename (DoLoop merge form loopbody) = do+ rename (Loop merge form loopbody) = do let (params, args) = unzip merge args' <- mapM rename args case form of@@ -280,7 +280,7 @@ i' <- rename i loopbody' <- rename loopbody pure $- DoLoop+ Loop (zip params' args') (ForLoop i' it boundexp' $ zip arr_params' loop_arrs') loopbody'@@ -289,7 +289,7 @@ params' <- mapM rename params loopbody' <- rename loopbody cond' <- rename cond- pure $ DoLoop (zip params' args') (WhileLoop cond') loopbody'+ pure $ Loop (zip params' args') (WhileLoop cond') loopbody' rename e = mapExpM mapper e where mapper =@@ -307,14 +307,14 @@ instance Rename PrimType where rename = pure -instance Rename shape => Rename (TypeBase shape u) where+instance (Rename shape) => Rename (TypeBase shape u) where rename (Array et size u) = Array <$> rename et <*> rename size <*> pure u rename (Prim t) = pure $ Prim t rename (Mem space) = pure $ Mem space rename (Acc acc ispace ts u) = Acc <$> rename acc <*> rename ispace <*> rename ts <*> pure u -instance Renameable rep => Rename (Lambda rep) where+instance (Renameable rep) => Rename (Lambda rep) where rename (Lambda params body ret) = renameBound (map paramName params) $ do params' <- mapM rename params@@ -328,7 +328,7 @@ instance Rename Rank where rename = pure -instance Rename d => Rename (ShapeBase d) where+instance (Rename d) => Rename (ShapeBase d) where rename (Shape l) = Shape <$> mapM rename l instance Rename ExtSize where@@ -341,7 +341,7 @@ instance Rename (NoOp rep) where rename NoOp = pure NoOp -instance Rename d => Rename (DimIndex d) where+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
@@ -31,10 +31,10 @@ -- names in @e@ are unique, i.e. there is no shadowing. substituteNames :: M.Map VName VName -> a -> a -instance Substitute a => Substitute [a] where+instance (Substitute a) => Substitute [a] where substituteNames substs = map $ substituteNames substs -instance Substitute (Stm rep) => Substitute (Stms rep) where+instance (Substitute (Stm rep)) => Substitute (Stms rep) where substituteNames substs = fmap $ substituteNames substs instance (Substitute a, Substitute b) => Substitute (a, b) where@@ -56,7 +56,7 @@ substituteNames substs u ) -instance Substitute a => Substitute (Maybe a) where+instance (Substitute a) => Substitute (Maybe a) where substituteNames substs = fmap $ substituteNames substs instance Substitute Bool where@@ -69,24 +69,24 @@ substituteNames substs (Var v) = Var $ substituteNames substs v substituteNames _ (Constant v) = Constant v -instance Substitutable rep => Substitute (Exp rep) where+instance (Substitutable rep) => Substitute (Exp rep) where substituteNames substs = mapExp $ replace substs -instance Substitute dec => Substitute (PatElem dec) where+instance (Substitute dec) => Substitute (PatElem dec) where substituteNames substs (PatElem ident dec) = PatElem (substituteNames substs ident) (substituteNames substs dec) instance Substitute Attrs where substituteNames _ attrs = attrs -instance Substitute dec => Substitute (StmAux dec) where+instance (Substitute dec) => Substitute (StmAux dec) where substituteNames substs (StmAux cs attrs dec) = StmAux (substituteNames substs cs) (substituteNames substs attrs) (substituteNames substs dec) -instance Substitute dec => Substitute (Param dec) where+instance (Substitute dec) => Substitute (Param dec) where substituteNames substs (Param attrs name dec) = Param (substituteNames substs attrs)@@ -97,7 +97,7 @@ substituteNames substs (SubExpRes cs se) = SubExpRes (substituteNames substs cs) (substituteNames substs se) -instance Substitute dec => Substitute (Pat dec) where+instance (Substitute dec) => Substitute (Pat dec) where substituteNames substs (Pat xs) = Pat (substituteNames substs xs) @@ -105,21 +105,21 @@ substituteNames substs (Certs cs) = Certs $ substituteNames substs cs -instance Substitutable rep => Substitute (Stm rep) where+instance (Substitutable rep) => Substitute (Stm rep) where substituteNames substs (Let pat annot e) = Let (substituteNames substs pat) (substituteNames substs annot) (substituteNames substs e) -instance Substitutable rep => Substitute (Body rep) where+instance (Substitutable rep) => Substitute (Body rep) where substituteNames substs (Body dec stms res) = Body (substituteNames substs dec) (substituteNames substs stms) (substituteNames substs res) -replace :: Substitutable rep => M.Map VName VName -> Mapper rep rep Identity+replace :: (Substitutable rep) => M.Map VName VName -> Mapper rep rep Identity replace substs = Mapper { mapOnVName = pure . substituteNames substs,@@ -141,11 +141,11 @@ instance Substitute (NoOp rep) where substituteNames _ = id -instance Substitute d => Substitute (ShapeBase d) where+instance (Substitute d) => Substitute (ShapeBase d) where substituteNames substs (Shape es) = Shape $ map (substituteNames substs) es -instance Substitute d => Substitute (Ext d) where+instance (Substitute d) => Substitute (Ext d) where substituteNames substs (Free x) = Free $ substituteNames substs x substituteNames _ (Ext x) = Ext x @@ -155,7 +155,7 @@ instance Substitute PrimType where substituteNames _ t = t -instance Substitute shape => Substitute (TypeBase shape u) where+instance (Substitute shape) => Substitute (TypeBase shape u) where substituteNames _ (Prim et) = Prim et substituteNames substs (Acc acc ispace ts u) =@@ -169,7 +169,7 @@ substituteNames _ (Mem space) = Mem space -instance Substitutable rep => Substitute (Lambda rep) where+instance (Substitutable rep) => Substitute (Lambda rep) where substituteNames substs (Lambda params body rettype) = Lambda (substituteNames substs params)@@ -183,26 +183,26 @@ identType = substituteNames substs $ identType v } -instance Substitute d => Substitute (DimIndex d) where+instance (Substitute d) => Substitute (DimIndex d) where substituteNames substs = fmap $ substituteNames substs -instance Substitute d => Substitute (Slice d) where+instance (Substitute d) => Substitute (Slice d) where substituteNames substs = fmap $ substituteNames substs -instance Substitute d => Substitute (FlatDimIndex d) where+instance (Substitute d) => Substitute (FlatDimIndex d) where substituteNames substs = fmap $ substituteNames substs -instance Substitute d => Substitute (FlatSlice d) where+instance (Substitute d) => Substitute (FlatSlice d) where substituteNames substs = fmap $ substituteNames substs -instance Substitute v => Substitute (PrimExp v) where+instance (Substitute v) => Substitute (PrimExp v) where substituteNames substs = fmap $ substituteNames substs -instance Substitute v => Substitute (TPrimExp t v) where+instance (Substitute v) => Substitute (TPrimExp t v) where substituteNames substs = TPrimExp . fmap (substituteNames substs) . untyped -instance Substitutable rep => Substitute (NameInfo rep) where+instance (Substitutable rep) => Substitute (NameInfo rep) where substituteNames subst (LetName dec) = LetName $ substituteNames subst dec substituteNames subst (FParamName dec) =
src/Futhark/Util.hs view
@@ -89,7 +89,7 @@ import Text.Read (readMaybe) -- | Like @nub@, but without the quadratic runtime.-nubOrd :: Ord a => [a] -> [a]+nubOrd :: (Ord a) => [a] -> [a] nubOrd = nubByOrd compare -- | Like @nubBy@, but without the quadratic runtime.@@ -171,7 +171,7 @@ Nothing -> helper (acc1, x : acc2) xs -- | Return the list element at the given index, if the index is valid.-maybeNth :: Integral int => int -> [a] -> Maybe a+maybeNth :: (Integral int) => int -> [a] -> Maybe a maybeNth i l | i >= 0, v : _ <- genericDrop i l = Just v | otherwise = Nothing@@ -194,7 +194,7 @@ -- | Return the list element at the given index, if the index is -- valid, along with the elements before and after.-focusNth :: Integral int => int -> [a] -> Maybe ([a], a, [a])+focusNth :: (Integral int) => int -> [a] -> Maybe ([a], a, [a]) focusNth i xs | (bef, x : aft) <- genericSplitAt i xs = Just (bef, x, aft) | otherwise = Nothing@@ -215,7 +215,7 @@ T.decodeUtf8With T.lenientDecode . Base16.encode . MD5.hash . T.encodeUtf8 -- | Like 'show', but produces text.-showText :: Show a => a -> T.Text+showText :: (Show a) => a -> T.Text showText = T.pack . show {-# NOINLINE unixEnvironment #-}@@ -463,7 +463,7 @@ traverseFold f = fmap fold . traverse f -- | Perform fixpoint iteration.-fixPoint :: Eq a => (a -> a) -> a -> a+fixPoint :: (Eq a) => (a -> a) -> a -> a fixPoint f x = let x' = f x in if x' == x then x else fixPoint f x'
src/Futhark/Util/IntegralExp.hs view
@@ -25,7 +25,7 @@ -- | A twist on the 'Integral' type class that is more friendly to -- symbolic representations.-class Num e => IntegralExp e where+class (Num e) => IntegralExp e where quot :: e -> e -> e rem :: e -> e -> e div :: e -> e -> e@@ -44,7 +44,7 @@ newtype Wrapped a = Wrapped {wrappedValue :: a} deriving (Eq, Ord, Show) -instance Enum a => Enum (Wrapped a) where+instance (Enum a) => Enum (Wrapped a) where toEnum a = Wrapped $ toEnum a fromEnum (Wrapped a) = fromEnum a @@ -61,7 +61,7 @@ Wrapped a liftOp2 op (Wrapped x) (Wrapped y) = Wrapped $ x `op` y -instance Num a => Num (Wrapped a) where+instance (Num a) => Num (Wrapped a) where (+) = liftOp2 (Prelude.+) (-) = liftOp2 (Prelude.-) (*) = liftOp2 (Prelude.*)@@ -70,7 +70,7 @@ fromInteger = Wrapped . Prelude.fromInteger negate = liftOp Prelude.negate -instance Integral a => IntegralExp (Wrapped a) where+instance (Integral a) => IntegralExp (Wrapped a) where quot = liftOp2 Prelude.quot rem = liftOp2 Prelude.rem div = liftOp2 Prelude.div
src/Futhark/Util/Log.hs view
@@ -43,19 +43,19 @@ -- | Typeclass for monads that support logging. class (Applicative m, Monad m) => MonadLogger m where -- | Add one log entry.- logMsg :: ToLog a => a -> m ()+ logMsg :: (ToLog a) => a -> m () logMsg = addLog . toLog -- | Append an entire log. addLog :: Log -> m () -instance Monad m => MonadLogger (WriterT Log m) where+instance (Monad m) => MonadLogger (WriterT Log m) where addLog = tell -instance Monad m => MonadLogger (Control.Monad.RWS.Lazy.RWST r Log s m) where+instance (Monad m) => MonadLogger (Control.Monad.RWS.Lazy.RWST r Log s m) where addLog = tell -instance Monad m => MonadLogger (Control.Monad.RWS.Strict.RWST r Log s m) where+instance (Monad m) => MonadLogger (Control.Monad.RWS.Strict.RWST r Log s m) where addLog = tell instance MonadLogger IO where
src/Futhark/Util/Options.hs view
@@ -71,7 +71,7 @@ exitWith $ ExitFailure 1 -- | Short-hand for 'liftIO . hPutStrLn stderr'-errput :: MonadIO m => String -> m ()+errput :: (MonadIO m) => String -> m () errput = liftIO . hPutStrLn stderr -- | Common definitions for @-v@ and @-h@, given the list of all other
src/Futhark/Util/Pretty.hs view
@@ -93,15 +93,15 @@ else Prettyprinter.Render.Text.renderStrict sds -- | Prettyprint a value to a 'String', appropriately wrapped.-prettyString :: Pretty a => a -> String+prettyString :: (Pretty a) => a -> String prettyString = T.unpack . prettyText -- | Prettyprint a value to a 'String' on a single line.-prettyStringOneLine :: Pretty a => a -> String+prettyStringOneLine :: (Pretty a) => a -> String prettyStringOneLine = T.unpack . prettyTextOneLine -- | Prettyprint a value to a 'Text', appropriately wrapped.-prettyText :: Pretty a => a -> Text+prettyText :: (Pretty a) => a -> Text prettyText = docText . pretty -- | Convert a 'Doc' to text. Thsi ignores any annotations (i.e. it@@ -113,7 +113,7 @@ layoutSmart defaultLayoutOptions {layoutPageWidth = Unbounded} -- | Prettyprint a value to a 'Text' on a single line.-prettyTextOneLine :: Pretty a => a -> Text+prettyTextOneLine :: (Pretty a) => a -> Text prettyTextOneLine = Prettyprinter.Render.Text.renderStrict . layoutSmart oneLineLayout . group . pretty where oneLineLayout = defaultLayoutOptions {layoutPageWidth = Unbounded}@@ -125,11 +125,11 @@ ppTupleLines' ets = braces $ commastack $ map align ets -- | Prettyprint a list enclosed in curly braces.-prettyTuple :: Pretty a => [a] -> Text+prettyTuple :: (Pretty a) => [a] -> Text prettyTuple = docText . ppTuple' . map pretty -- | Like 'prettyTuple', but put a linebreak after every element.-prettyTupleLines :: Pretty a => [a] -> Text+prettyTupleLines :: (Pretty a) => [a] -> Text prettyTupleLines = docText . ppTupleLines' . map pretty -- | The document @'apply' ds@ separates @ds@ with commas and encloses them with
src/Language/Futhark/Core.hs view
@@ -118,7 +118,7 @@ -- -- This function assumes that both start and end position is in the -- same file (it is not clear what the alternative would even mean).-locStr :: Located a => a -> String+locStr :: (Located a) => a -> String locStr a = case locOf a of NoLoc -> "unknown location"@@ -150,7 +150,7 @@ _ -> locStr b -- | 'locStr', but for text.-locText :: Located a => a -> T.Text+locText :: (Located a) => a -> T.Text locText = T.pack . locStr -- | 'locStrRel', but for text.
src/Language/Futhark/FreeVars.hs view
@@ -84,7 +84,7 @@ OpSectionRight _ _ e _ _ _ -> freeInExp e ProjectSection {} -> mempty IndexSection idxs _ _ -> foldMap freeInDimIndex idxs- AppExp (DoLoop sparams pat e1 form e3 _) _ ->+ AppExp (Loop sparams pat e1 form e3 _) _ -> let (e2fv, e2ident) = formVars form in freeInExp e1 <> ( (e2fv <> freeInExp e3)
src/Language/Futhark/Interpreter.hs view
@@ -305,15 +305,25 @@ TermPoly (Maybe T.BoundV) (StructType -> Eval -> EvalM Value) | TermModule Module +instance Show TermBinding where+ show (TermValue bv v) = unwords ["TermValue", show bv, show v]+ show (TermPoly bv _) = unwords ["TermPoly", show bv]+ show (TermModule m) = unwords ["TermModule", show m]+ data Module = Module Env | ModuleFun (Module -> EvalM Module) +instance Show Module where+ show (Module env) = "(" <> unwords ["Module", show env] <> ")"+ show (ModuleFun _) = "(ModuleFun _)"+ -- | The actual type- and value environment. data Env = Env { envTerm :: M.Map VName TermBinding, envType :: M.Map VName T.TypeBinding }+ deriving (Show) instance Monoid Env where mempty = Env mempty mempty@@ -530,7 +540,7 @@ writeArray slice x y = runIdentity $ updateArray (\_ y' -> pure y') slice x y updateArray ::- Monad m =>+ (Monad m) => (Value -> Value -> m Value) -> [Indexing] -> Value ->@@ -584,7 +594,7 @@ -- | Expand type based on information that was not available at -- type-checking time (the structure of abstract types).-expandType :: Env -> TypeBase Size u -> TypeBase Size u+expandType :: (Pretty u) => Env -> TypeBase Size u -> TypeBase Size u expandType _ (Scalar (Prim pt)) = Scalar $ Prim pt expandType env (Scalar (Record fs)) = Scalar $ Record $ fmap (expandType env) fs expandType env (Scalar (Arrow u p d t1 (RetType dims t2))) =@@ -649,12 +659,14 @@ case lookupVar qv env of Just (TermPoly _ v) -> v (expandType env t) =<< evalWithExts env Just (TermValue _ v) -> pure v- _ -> do+ x -> do ss <- map (locText . srclocOf) <$> stacktrace error $ prettyString qv <> " is not bound to a value.\n" <> T.unpack (prettyStacktrace 0 ss)+ <> "Bound to\n"+ <> show x typeValueShape :: Env -> StructType -> EvalM ValueShape typeValueShape env t = do@@ -853,7 +865,7 @@ eval (valEnv (M.singleton (identName dest) (Just t, dest')) <> env) body where oob = bad loc env "Update out of bounds"-evalAppExp env (DoLoop sparams pat init_e form body _) = do+evalAppExp env (Loop sparams pat init_e form body _) = do init_v <- eval env init_e case form of For iv bound -> do@@ -1118,7 +1130,13 @@ Just (TermModule m) -> pure m _ -> error $ prettyString qv <> " is not bound to a module." -evalModExp :: Env -> ModExp -> EvalM Module+-- We also return a new Env here, because we want the definitions+-- inside any constructed modules to also be in scope at the top+-- level. This is because types may contain un-qualified references to+-- definitions in modules, and sometimes those definitions may not+-- actually *have* any qualified name! See tests/modules/sizes7.fut.+-- This occurs solely because of evalType.+evalModExp :: Env -> ModExp -> EvalM (Env, Module) evalModExp _ (ModImport _ (Info f) _) = do f' <- lookupImport f known <- asks snd@@ -1129,33 +1147,47 @@ [ "Unknown interpreter import: " ++ show f, "Known: " ++ show (M.keys known) ]- Just m -> pure $ Module m+ Just m -> pure (mempty, Module m) evalModExp env (ModDecs ds _) = do Env terms types <- foldM evalDec env ds -- Remove everything that was present in the original Env.- pure $- Module $- Env+ pure+ ( Env (terms `M.difference` envTerm env)- (types `M.difference` envType env)+ (types `M.difference` envType env),+ Module $+ Env+ (terms `M.difference` envTerm env)+ (types `M.difference` envType env)+ ) evalModExp env (ModVar qv _) =- evalModuleVar env qv+ (mempty,) <$> evalModuleVar env qv evalModExp env (ModAscript me _ (Info substs) _) =- substituteInModule substs <$> evalModExp env me-evalModExp env (ModParens me _) = evalModExp env me+ bimap substituteInEnv (substituteInModule substs) <$> evalModExp env me+ where+ substituteInEnv env' =+ let Module env'' = substituteInModule substs (Module env') in env''+evalModExp env (ModParens me _) =+ evalModExp env me evalModExp env (ModLambda p ret e loc) =- pure $- ModuleFun $ \am -> do- let env' = env {envTerm = M.insert (modParamName p) (TermModule am) $ envTerm env}- evalModExp env' $ case ret of- Nothing -> e- Just (se, rsubsts) -> ModAscript e se rsubsts loc+ pure+ ( mempty,+ ModuleFun $ \am -> do+ let env' = env {envTerm = M.insert (modParamName p) (TermModule am) $ envTerm env}+ fmap snd . evalModExp env' $ case ret of+ Nothing -> e+ Just (se, rsubsts) -> ModAscript e se rsubsts loc+ ) evalModExp env (ModApply f e (Info psubst) (Info rsubst) _) = do- f' <- evalModExp env f+ (f_env, f') <- evalModExp env f+ (e_env, e') <- evalModExp env e case f' of ModuleFun f'' -> do- e' <- evalModExp env e- substituteInModule rsubst <$> f'' (substituteInModule psubst e')+ res_mod <- substituteInModule rsubst <$> f'' (substituteInModule psubst e')+ let res_env = case res_mod of+ Module x -> x+ _ -> mempty+ pure (f_env <> e_env <> res_env, res_mod) _ -> error "Expected ModuleFun." evalDec :: Env -> Dec -> EvalM Env@@ -1165,9 +1197,9 @@ pure $ env {envTerm = M.insert v binding $ envTerm env} <> sizes evalDec env (OpenDec me _) = do- me' <- evalModExp env me+ (me_env, me') <- evalModExp env me case me' of- Module me'' -> pure $ me'' <> env+ Module me'' -> pure $ me'' <> me_env <> env _ -> error "Expected Module" evalDec env (ImportDec name name' loc) = evalDec env $ LocalDec (OpenDec (ModImport name name' loc) loc) loc@@ -1177,8 +1209,8 @@ let abbr = T.TypeAbbr l ps . RetType dims $ expandType env t pure env {envType = M.insert v abbr $ envType env} evalDec env (ModDec (ModBind v ps ret body _ loc)) = do- mod <- evalModExp env $ wrapInLambda ps- pure $ modEnv (M.singleton v mod) <> env+ (mod_env, mod) <- evalModExp env $ wrapInLambda ps+ pure $ modEnv (M.singleton v mod) <> mod_env <> env where wrapInLambda [] = case ret of Just (se, substs) -> ModAscript body se substs loc@@ -1960,7 +1992,9 @@ | null param_ts = "Entry point " <> dquotes (prettyName entry) <> " is not a function." | otherwise =- "Entry point " <> dquotes (prettyName entry) <> " expects input of type(s)"+ "Entry point "+ <> dquotes (prettyName entry)+ <> " expects input of type(s)" </> indent 2 (stack (map pretty param_ts)) -- | Execute the named function on the given arguments; may fail@@ -1994,12 +2028,18 @@ updateType _ t = Right t - -- FIXME: we don't check array sizes. checkInput :: ValueType -> StructType -> Either T.Text () checkInput (Scalar (Prim vt)) (Scalar (Prim pt)) | vt /= pt = badPrim vt pt checkInput (Array _ _ (Prim vt)) (Array _ _ (Prim pt)) | vt /= pt = badPrim vt pt+ checkInput vArr@(Array _ (F.Shape vd) _) pArr@(Array _ (F.Shape pd) _)+ | length vd /= length pd = badDim vArr pArr+ | not . and $ zipWith sameShape vd pd = badDim vArr pArr+ where+ sameShape :: Int64 -> Size -> Bool+ sameShape shape0 (IntLit shape1 _ _) = fromIntegral shape0 == shape1+ sameShape _ _ = True checkInput _ _ = Right () @@ -2010,3 +2050,11 @@ <+> align (pretty pt) </> "Got: " <+> align (pretty vt)++ badDim vd pd =+ Left . docText $+ "Invalid argument dimensions."+ </> "Expected:"+ <+> align (pretty pd)+ </> "Got: "+ <+> align (pretty vd)
src/Language/Futhark/Interpreter/Values.hs view
@@ -62,7 +62,7 @@ -- | The shape of an array. type ValueShape = Shape Int64 -instance Pretty d => Pretty (Shape d) where+instance (Pretty d) => Pretty (Shape d) where pretty ShapeLeaf = mempty pretty (ShapeDim d s) = brackets (pretty d) <> pretty s pretty (ShapeRecord m) = prettyRecord pretty m@@ -206,7 +206,7 @@ where shape = ShapeDim (genericLength vs) rowshape -arrayLength :: Integral int => Array Int (Value m) -> int+arrayLength :: (Integral int) => Array Int (Value m) -> int arrayLength = fromIntegral . (+ 1) . snd . bounds toTuple :: [Value m] -> Value m@@ -220,7 +220,7 @@ fromDataShape = foldr (ShapeDim . fromIntegral) ShapeLeaf . SVec.toList fromDataValueWith ::- SVec.Storable a =>+ (SVec.Storable a) => (a -> PrimValue) -> SVec.Vector Int -> SVec.Vector a ->
src/Language/Futhark/Parser/Lexer/Tokens.hs view
@@ -140,7 +140,7 @@ suffZero :: T.Text -> T.Text suffZero s = if T.last s == '.' then s <> "0" else s -tryRead :: Read a => String -> T.Text -> a+tryRead :: (Read a) => String -> T.Text -> a tryRead desc s = case reads s' of [(x, "")] -> x _ -> error $ "Invalid " ++ desc ++ " literal: `" ++ T.unpack s ++ "'."@@ -152,7 +152,7 @@ tokenC v _ = v {-# INLINE decToken #-}-decToken :: Integral a => (a -> Token) -> BS.ByteString -> Token+decToken :: (Integral a) => (a -> Token) -> BS.ByteString -> Token decToken f = f . BS.foldl' digit 0 where digit x c =@@ -161,7 +161,7 @@ else x {-# INLINE binToken #-}-binToken :: Integral a => (a -> Token) -> BS.ByteString -> Token+binToken :: (Integral a) => (a -> Token) -> BS.ByteString -> Token binToken f = f . BS.foldl' digit 0 where digit x c =@@ -170,7 +170,7 @@ else x {-# INLINE hexToken #-}-hexToken :: Integral a => (a -> Token) -> BS.ByteString -> Token+hexToken :: (Integral a) => (a -> Token) -> BS.ByteString -> Token hexToken f = f . BS.foldl' digit 0 where digit x c@@ -184,7 +184,7 @@ x {-# INLINE romToken #-}-romToken :: Integral a => (a -> Token) -> BS.ByteString -> Token+romToken :: (Integral a) => (a -> Token) -> BS.ByteString -> Token romToken f = tokenS $ f . fromRoman {-# INLINE tokenS #-}@@ -209,7 +209,7 @@ | otherwise = SYMBOL (leadingOperator q) [] q symbol qs q = SYMBOL (leadingOperator q) qs q -romanNumerals :: Integral a => [(T.Text, a)]+romanNumerals :: (Integral a) => [(T.Text, a)] romanNumerals = reverse [ ("I", 1),@@ -227,13 +227,13 @@ ("M", 1000) ] -fromRoman :: Integral a => T.Text -> a+fromRoman :: (Integral a) => T.Text -> a fromRoman s = case find ((`T.isPrefixOf` s) . fst) romanNumerals of Nothing -> 0 Just (d, n) -> n + fromRoman (T.drop (T.length d) s) -readHexRealLit :: RealFloat a => T.Text -> a+readHexRealLit :: (RealFloat a) => T.Text -> a readHexRealLit s = let num = T.drop 2 s in -- extract number into integer, fractional and (optional) exponent
src/Language/Futhark/Parser/Monad.hs view
@@ -84,7 +84,7 @@ parseErrorAt loc . Just $ "Only the keyword '" <> expected <> "' may appear here." -mustBeEmpty :: Located loc => loc -> ValueType -> ParserMonad ()+mustBeEmpty :: (Located loc) => loc -> ValueType -> ParserMonad () mustBeEmpty _ (Array _ (Shape dims) _) | 0 `elem` dims = pure () mustBeEmpty loc t =@@ -203,7 +203,7 @@ "Expected one of the following: " <> T.unwords (map T.pack expected) ] -parseErrorAt :: Located loc => loc -> Maybe T.Text -> ParserMonad a+parseErrorAt :: (Located loc) => loc -> Maybe T.Text -> ParserMonad a parseErrorAt loc Nothing = throwError $ SyntaxError (locOf loc) "Syntax error." parseErrorAt loc (Just s) = throwError $ SyntaxError (locOf loc) s
src/Language/Futhark/Parser/Parser.y view
@@ -769,9 +769,9 @@ LoopExp :: { UncheckedExp } : loop Pat LoopForm do Exp %prec ifprec- {% fmap (\t -> AppExp (DoLoop [] (fmap (toParam Observe) $2) t $3 $5 (srcspan $1 $>)) NoInfo) (patternExp $2) }+ {% fmap (\t -> AppExp (Loop [] (fmap (toParam Observe) $2) t $3 $5 (srcspan $1 $>)) NoInfo) (patternExp $2) } | loop Pat '=' Exp LoopForm do Exp %prec ifprec- { AppExp (DoLoop [] (fmap (toParam Observe) $2) $4 $5 $7 (srcspan $1 $>)) NoInfo }+ { AppExp (Loop [] (fmap (toParam Observe) $2) $4 $5 $7 (srcspan $1 $>)) NoInfo } MatchExp :: { UncheckedExp } : match Exp Cases
src/Language/Futhark/Pretty.hs view
@@ -155,7 +155,7 @@ instance (Pretty (Shape dim), Pretty u) => Pretty (TypeBase dim u) where pretty = prettyType 0 -prettyTypeArg :: Pretty (Shape dim) => Int -> TypeArg dim -> Doc a+prettyTypeArg :: (Pretty (Shape dim)) => Int -> TypeArg dim -> Doc a prettyTypeArg _ (TypeArgDim d) = pretty $ Shape [d] prettyTypeArg p (TypeArgType t) = prettyType p t @@ -187,11 +187,11 @@ pretty (TypeArgExpSize d) = pretty d pretty (TypeArgExpType t) = pretty t -instance IsName vn => Pretty (QualName vn) where+instance (IsName vn) => Pretty (QualName vn) where pretty (QualName names name) = mconcat $ punctuate "." $ map prettyName names ++ [prettyName name] -instance IsName vn => Pretty (IdentBase f vn t) where+instance (IsName vn) => Pretty (IdentBase f vn t) where pretty = prettyName . identName hasArrayLit :: ExpBase ty vn -> Bool@@ -215,7 +215,7 @@ pretty (DimSlice i Nothing Nothing) = maybe mempty pretty i <> ":" -instance IsName vn => Pretty (SizeBinder vn) where+instance (IsName vn) => Pretty (SizeBinder vn) where pretty (SizeBinder v _) = brackets $ prettyName v letBody :: (Eq vn, IsName vn, Annot f) => ExpBase f vn -> Doc a@@ -226,7 +226,7 @@ prettyAppExp :: (Eq vn, IsName vn, Annot f) => Int -> AppExpBase f vn -> Doc a prettyAppExp p (BinOp (bop, _) _ (x, _) (y, _) _) = prettyBinOp p bop x y prettyAppExp _ (Match e cs _) = "match" <+> pretty e </> (stack . map pretty) (NE.toList cs)-prettyAppExp _ (DoLoop sizeparams pat initexp form loopbody _) =+prettyAppExp _ (Loop sizeparams pat initexp form loopbody _) = "loop" <+> align ( hsep (map (brackets . prettyName) sizeparams ++ [pretty pat])@@ -257,7 +257,7 @@ prettyAppExp _ (LetFun fname (tparams, params, retdecl, rettype, e) body _) = "let" <+> hsep (prettyName fname : map pretty tparams ++ map pretty params)- <> retdecl'+ <> retdecl' <+> equals </> indent 2 (pretty e) </> letBody body@@ -268,7 +268,8 @@ prettyAppExp _ (LetWith dest src idxs ve body _) | dest == src = "let"- <+> pretty dest <> list (map pretty idxs)+ <+> pretty dest+ <> list (map pretty idxs) <+> equals <+> align (pretty ve) </> letBody body@@ -313,7 +314,7 @@ "@" <> parens (align $ pretty t') _ -> mempty -prettyAttr :: Pretty a => a -> Doc ann+prettyAttr :: (Pretty a) => a -> Doc ann prettyAttr attr = "#[" <> pretty attr <> "]" operatorName :: Name -> Bool@@ -370,7 +371,9 @@ "assert" <+> prettyExp 10 e1 <+> prettyExp 10 e2 prettyExp p (Lambda params body rettype _ _) = parensIf (p /= -1) $- "\\" <> hsep (map pretty params) <> ppAscription rettype+ "\\"+ <> hsep (map pretty params)+ <> ppAscription rettype <+> "->" </> indent 2 (align (pretty body)) prettyExp _ (OpSection binop _ _) =@@ -396,17 +399,17 @@ not $ null ext = parens (prettyAppExp i e) </> "@"- <> parens (pretty t <> "," <+> brackets (commasep $ map prettyName ext))+ <> parens (pretty t <> "," <+> brackets (commasep $ map prettyName ext)) | otherwise = prettyAppExp i e instance (Eq vn, IsName vn, Annot f) => Pretty (ExpBase f vn) where pretty = prettyExp (-1) -instance IsName vn => Pretty (AttrAtom vn) where+instance (IsName vn) => Pretty (AttrAtom vn) where pretty (AtomName v) = pretty v pretty (AtomInt x) = pretty x -instance IsName vn => Pretty (AttrInfo vn) where+instance (IsName vn) => Pretty (AttrInfo vn) where pretty (AttrAtom attr _) = pretty attr pretty (AttrComp f attrs _) = pretty f <> parens (commasep $ map pretty attrs) @@ -447,7 +450,7 @@ pretty (PatConstr n _ ps _) = "#" <> pretty n <+> sep (map pretty ps) pretty (PatAttr attr p _) = "#[" <> pretty attr <> "]" </> pretty p -ppAscription :: Pretty t => Maybe t -> Doc a+ppAscription :: (Pretty t) => Maybe t -> Doc a ppAscription Nothing = mempty ppAscription (Just t) = colon <> align (pretty t) @@ -463,22 +466,34 @@ pretty (LocalDec dec _) = "local" <+> pretty dec pretty (ImportDec x _ _) = "import" <+> pretty x -instance (Eq vn, IsName vn, Annot f) => Pretty (ModExpBase f vn) where- pretty (ModVar v _) = pretty v- pretty (ModParens e _) = parens $ pretty e- pretty (ModImport v _ _) = "import" <+> pretty (show v)- pretty (ModDecs ds _) = nestedBlock "{" "}" (stack $ punctuate line $ map pretty ds)- pretty (ModApply f a _ _ _) = parens $ pretty f <+> parens (pretty a)- pretty (ModAscript me se _ _) = pretty me <> colon <+> pretty se- pretty (ModLambda param maybe_sig body _) =- "\\" <> pretty param <> maybe_sig'+prettyModExp :: (Eq vn, IsName vn, Annot f) => Int -> ModExpBase f vn -> Doc a+prettyModExp _ (ModVar v _) =+ pretty v+prettyModExp _ (ModParens e _) =+ align $ parens $ pretty e+prettyModExp _ (ModImport v _ _) =+ "import" <+> pretty (show v)+prettyModExp _ (ModDecs ds _) =+ nestedBlock "{" "}" $ stack $ punctuate line $ map pretty ds+prettyModExp p (ModApply f a _ _ _) =+ parensIf (p >= 10) $ prettyModExp 0 f <+> prettyModExp 10 a+prettyModExp p (ModAscript me se _ _) =+ parensIf (p /= -1) $ pretty me <> colon <+> pretty se+prettyModExp p (ModLambda param maybe_sig body _) =+ parensIf (p /= -1) $+ "\\"+ <> pretty param+ <> maybe_sig' <+> "->" </> indent 2 (pretty body)- where- maybe_sig' = case maybe_sig of- Nothing -> mempty- Just (sig, _) -> colon <+> pretty sig+ where+ maybe_sig' = case maybe_sig of+ Nothing -> mempty+ Just (sig, _) -> colon <+> pretty sig +instance (Eq vn, IsName vn, Annot f) => Pretty (ModExpBase f vn) where+ pretty = prettyModExp (-1)+ instance Pretty Liftedness where pretty Unlifted = "" pretty SizeLifted = "~"@@ -555,7 +570,7 @@ Nothing -> mempty Just (s, _) -> " " <> colon <+> pretty s <> " " -ppBinOp :: IsName v => QualName v -> Doc a+ppBinOp :: (IsName v) => QualName v -> Doc a ppBinOp bop = case leading of Backtick -> "`" <> pretty bop <> "`"
src/Language/Futhark/Primitive.hs view
@@ -237,7 +237,7 @@ pretty (Int64Value v) = pretty $ show v ++ "i64" -- | Create an t'IntValue' from a type and an 'Integer'.-intValue :: Integral int => IntType -> int -> IntValue+intValue :: (Integral int) => IntType -> int -> IntValue intValue Int8 = Int8Value . fromIntegral intValue Int16 = Int16Value . fromIntegral intValue Int32 = Int32Value . fromIntegral@@ -251,7 +251,7 @@ intValueType Int64Value {} = Int64 -- | Convert an t'IntValue' to any 'Integral' type.-valueIntegral :: Integral int => IntValue -> int+valueIntegral :: (Integral int) => IntValue -> int valueIntegral (Int8Value v) = fromIntegral v valueIntegral (Int16Value v) = fromIntegral v valueIntegral (Int32Value v) = fromIntegral v@@ -313,7 +313,7 @@ | otherwise = pretty $ show v ++ "f64" -- | Create a t'FloatValue' from a type and a 'Rational'.-floatValue :: Real num => FloatType -> num -> FloatValue+floatValue :: (Real num) => FloatType -> num -> FloatValue floatValue Float16 = Float16Value . fromRational . toRational floatValue Float32 = Float32Value . fromRational . toRational floatValue Float64 = Float64Value . fromRational . toRational@@ -1688,21 +1688,21 @@ -- -- Warning: note that this is 0 for 'Unit', but a 'Unit' takes up a -- byte in the binary data format.-primByteSize :: Num a => PrimType -> a+primByteSize :: (Num a) => PrimType -> a primByteSize (IntType t) = intByteSize t primByteSize (FloatType t) = floatByteSize t primByteSize Bool = 1 primByteSize Unit = 0 -- | The size of a value of a given integer type in eight-bit bytes.-intByteSize :: Num a => IntType -> a+intByteSize :: (Num a) => IntType -> a intByteSize Int8 = 1 intByteSize Int16 = 2 intByteSize Int32 = 4 intByteSize Int64 = 8 -- | The size of a value of a given floating-point type in eight-bit bytes.-floatByteSize :: Num a => FloatType -> a+floatByteSize :: (Num a) => FloatType -> a floatByteSize Float16 = 2 floatByteSize Float32 = 4 floatByteSize Float64 = 8
src/Language/Futhark/Prop.hs view
@@ -182,7 +182,7 @@ -- occurrence of the dimension. traverseDims :: forall f fdim tdim als.- Applicative f =>+ (Applicative f) => (S.Set VName -> DimPos -> fdim -> f tdim) -> TypeBase fdim als -> f (TypeBase tdim als)@@ -380,7 +380,7 @@ matchDims onDims = matchDims' mempty where matchDims' ::- forall u'. Monoid u' => [VName] -> TypeBase d1 u' -> TypeBase d2 u' -> m (TypeBase d1 u')+ forall u'. (Monoid u') => [VName] -> TypeBase d1 u' -> TypeBase d2 u' -> m (TypeBase d1 u') matchDims' bound t1 t2 = case (t1, t2) of (Array u1 shape1 et1, Array u2 shape2 et2) ->@@ -1176,7 +1176,7 @@ -- | Is the position of this thing builtin as per 'isBuiltin'? Things -- without location are considered not built-in.-isBuiltinLoc :: Located a => a -> Bool+isBuiltinLoc :: (Located a) => a -> Bool isBuiltinLoc x = case locOf x of NoLoc -> False
src/Language/Futhark/Query.hs view
@@ -94,7 +94,7 @@ <> mconcat (map patternDefs params) AppExp (LetWith v _ _ _ _ _) _ -> identDefs v- AppExp (DoLoop _ merge _ form _ _) _ ->+ AppExp (Loop _ merge _ form _ _) _ -> patternDefs merge <> case form of For i _ -> identDefs i@@ -198,7 +198,7 @@ data RawAtPos = RawAtName (QualName VName) Loc -contains :: Located a => a -> Pos -> Bool+contains :: (Located a) => a -> Pos -> Bool contains a pos = case locOf a of Loc start end -> pos >= start && pos <= end@@ -268,7 +268,7 @@ atPosInExp (AppExp (LetWith a b _ _ _ _) _) pos | a `contains` pos = Just $ RawAtName (qualName $ identName a) (locOf a) | b `contains` pos = Just $ RawAtName (qualName $ identName b) (locOf b)-atPosInExp (AppExp (DoLoop _ merge _ _ _ _) _) pos+atPosInExp (AppExp (Loop _ merge _ _ _ _) _) pos | merge `contains` pos = atPosInPat merge pos atPosInExp (Ascript _ te _) pos | te `contains` pos = atPosInTypeExp te pos
src/Language/Futhark/Syntax.hs view
@@ -415,7 +415,7 @@ deriving instance Show (SizeExp Info VName) -deriving instance Show vn => Show (SizeExp NoInfo vn)+deriving instance (Show vn) => Show (SizeExp NoInfo vn) deriving instance Eq (SizeExp NoInfo VName) @@ -443,7 +443,7 @@ deriving instance Show (TypeExp Info VName) -deriving instance Show vn => Show (TypeExp NoInfo vn)+deriving instance (Show vn) => Show (TypeExp NoInfo vn) deriving instance Eq (TypeExp NoInfo VName) @@ -472,7 +472,7 @@ deriving instance Show (TypeArgExp Info VName) -deriving instance Show vn => Show (TypeArgExp NoInfo vn)+deriving instance (Show vn) => Show (TypeArgExp NoInfo vn) deriving instance Eq (TypeArgExp NoInfo VName) @@ -509,14 +509,14 @@ identSrcLoc :: SrcLoc } -deriving instance Show (Info t) => Show (IdentBase Info VName t)+deriving instance (Show (Info t)) => Show (IdentBase Info VName t) deriving instance (Show (Info t), Show vn) => Show (IdentBase NoInfo vn t) -instance Eq vn => Eq (IdentBase ty vn t) where+instance (Eq vn) => Eq (IdentBase ty vn t) where x == y = identName x == identName y -instance Ord vn => Ord (IdentBase ty vn t) where+instance (Ord vn) => Ord (IdentBase ty vn t) where compare = comparing identName instance Located (IdentBase ty vn t) where@@ -574,7 +574,7 @@ | UpToExclusive a deriving (Eq, Ord, Show) -instance Located a => Located (Inclusiveness a) where+instance (Located a) => Located (Inclusiveness a) where locOf (DownToExclusive x) = locOf x locOf (ToInclusive x) = locOf x locOf (UpToExclusive x) = locOf x@@ -600,7 +600,7 @@ deriving instance Show (DimIndexBase Info VName) -deriving instance Show vn => Show (DimIndexBase NoInfo vn)+deriving instance (Show vn) => Show (DimIndexBase NoInfo vn) deriving instance Eq (DimIndexBase NoInfo VName) @@ -693,7 +693,7 @@ (ExpBase f vn) SrcLoc | If (ExpBase f vn) (ExpBase f vn) (ExpBase f vn) SrcLoc- | DoLoop+ | Loop [VName] -- Size parameters. (PatBase f vn ParamType) -- Merge variable pattern. (ExpBase f vn) -- Initial values of merge variables.@@ -719,7 +719,7 @@ deriving instance Show (AppExpBase Info VName) -deriving instance Show vn => Show (AppExpBase NoInfo vn)+deriving instance (Show vn) => Show (AppExpBase NoInfo vn) deriving instance Eq (AppExpBase NoInfo VName) @@ -738,7 +738,7 @@ locOf (LetFun _ _ _ loc) = locOf loc locOf (LetWith _ _ _ _ _ loc) = locOf loc locOf (Index _ _ loc) = locOf loc- locOf (DoLoop _ _ _ _ _ loc) = locOf loc+ locOf (Loop _ _ _ _ _ loc) = locOf loc locOf (Match _ _ loc) = locOf loc -- | An annotation inserted by the type checker on constructs that are@@ -830,7 +830,7 @@ deriving instance Show (ExpBase Info VName) -deriving instance Show vn => Show (ExpBase NoInfo vn)+deriving instance (Show vn) => Show (ExpBase NoInfo vn) deriving instance Eq (ExpBase NoInfo VName) @@ -877,7 +877,7 @@ deriving instance Show (FieldBase Info VName) -deriving instance Show vn => Show (FieldBase NoInfo vn)+deriving instance (Show vn) => Show (FieldBase NoInfo vn) deriving instance Eq (FieldBase NoInfo VName) @@ -896,7 +896,7 @@ deriving instance Show (CaseBase Info VName) -deriving instance Show vn => Show (CaseBase NoInfo vn)+deriving instance (Show vn) => Show (CaseBase NoInfo vn) deriving instance Eq (CaseBase NoInfo VName) @@ -917,7 +917,7 @@ deriving instance Show (LoopFormBase Info VName) -deriving instance Show vn => Show (LoopFormBase NoInfo vn)+deriving instance (Show vn) => Show (LoopFormBase NoInfo vn) deriving instance Eq (LoopFormBase NoInfo VName) @@ -947,17 +947,17 @@ | PatConstr Name (f t) [PatBase f vn t] SrcLoc | PatAttr (AttrInfo vn) (PatBase f vn t) SrcLoc -deriving instance Show (Info t) => Show (PatBase Info VName t)+deriving instance (Show (Info t)) => Show (PatBase Info VName t) deriving instance (Show (NoInfo t), Show vn) => Show (PatBase NoInfo vn t) -deriving instance Eq (NoInfo t) => Eq (PatBase NoInfo VName t)+deriving instance (Eq (NoInfo t)) => Eq (PatBase NoInfo VName t) -deriving instance Eq (Info t) => Eq (PatBase Info VName t)+deriving instance (Eq (Info t)) => Eq (PatBase Info VName t) -deriving instance Ord (NoInfo t) => Ord (PatBase NoInfo VName t)+deriving instance (Ord (NoInfo t)) => Ord (PatBase NoInfo VName t) -deriving instance Ord (Info t) => Ord (PatBase Info VName t)+deriving instance (Ord (Info t)) => Ord (PatBase Info VName t) instance Located (PatBase f vn t) where locOf (TuplePat _ loc) = locOf loc@@ -970,10 +970,10 @@ locOf (PatConstr _ _ _ loc) = locOf loc locOf (PatAttr _ _ loc) = locOf loc -instance Traversable f => Functor (PatBase f vn) where+instance (Traversable f) => Functor (PatBase f vn) where fmap = fmapDefault -instance Traversable f => Foldable (PatBase f vn) where+instance (Traversable f) => Foldable (PatBase f vn) where foldMap = foldMapDefault instance (Traversable f) => Traversable (PatBase f vn) where
src/Language/Futhark/Traversals.hs view
@@ -35,14 +35,14 @@ -- given child. data ASTMapper m = ASTMapper { mapOnExp :: ExpBase Info VName -> m (ExpBase Info VName),- mapOnName :: VName -> m VName,+ mapOnName :: QualName VName -> m (QualName VName), mapOnStructType :: StructType -> m StructType, mapOnParamType :: ParamType -> m ParamType, mapOnResRetType :: ResRetType -> m ResRetType } -- | An 'ASTMapper' that just leaves its input unchanged.-identityMapper :: Monad m => ASTMapper m+identityMapper :: (Monad m) => ASTMapper m identityMapper = ASTMapper { mapOnExp = pure,@@ -58,10 +58,7 @@ -- object. Importantly, the 'astMap' action is not invoked for -- the object itself, and the mapping does not descend recursively -- into subexpressions. The mapping is done left-to-right.- astMap :: Monad m => ASTMapper m -> x -> m x--instance ASTMappable (QualName VName) where- astMap tv = traverse (mapOnName tv)+ astMap :: (Monad m) => ASTMapper m -> x -> m x instance ASTMappable (AppExpBase Info VName) where astMap tv (Range start next end loc) =@@ -85,13 +82,11 @@ _ -> Apply f' args' loc astMap tv (LetPat sizes pat e body loc) =- LetPat <$> astMap tv sizes <*> astMap tv pat <*> mapOnExp tv e <*> mapOnExp tv body <*> pure loc- astMap tv (LetFun name (fparams, params, ret, t, e) body loc) =- LetFun- <$> mapOnName tv name- <*> ( (,,,,)- <$> mapM (astMap tv) fparams- <*> mapM (astMap tv) params+ LetPat sizes <$> astMap tv pat <*> mapOnExp tv e <*> mapOnExp tv body <*> pure loc+ astMap tv (LetFun name (tparams, params, ret, t, e) body loc) =+ LetFun name+ <$> ( (tparams,,,,)+ <$> mapM (astMap tv) params <*> traverse (astMap tv) ret <*> traverse (mapOnResRetType tv) t <*> mapOnExp tv e@@ -108,15 +103,14 @@ <*> pure loc astMap tv (BinOp (fname, fname_loc) t (x, xext) (y, yext) loc) = BinOp- <$> ((,) <$> astMap tv fname <*> pure fname_loc)+ <$> ((,) <$> mapOnName tv fname <*> pure fname_loc) <*> traverse (mapOnStructType tv) t <*> ((,) <$> mapOnExp tv x <*> pure xext) <*> ((,) <$> mapOnExp tv y <*> pure yext) <*> pure loc- astMap tv (DoLoop sparams mergepat mergeexp form loopbody loc) =- DoLoop- <$> mapM (mapOnName tv) sparams- <*> astMap tv mergepat+ astMap tv (Loop sparams mergepat mergeexp form loopbody loc) =+ Loop sparams+ <$> astMap tv mergepat <*> mapOnExp tv mergeexp <*> astMap tv form <*> mapOnExp tv loopbody@@ -127,7 +121,7 @@ instance ASTMappable (ExpBase Info VName) where astMap tv (Var name t loc) = Var- <$> astMap tv name+ <$> mapOnName tv name <*> traverse (mapOnStructType tv) t <*> pure loc astMap tv (Hole t loc) =@@ -144,7 +138,7 @@ Parens <$> mapOnExp tv e <*> pure loc astMap tv (QualParens (name, nameloc) e loc) = QualParens- <$> ((,) <$> astMap tv name <*> pure nameloc)+ <$> ((,) <$> mapOnName tv name <*> pure nameloc) <*> mapOnExp tv e <*> pure loc astMap tv (TupLit els loc) =@@ -187,23 +181,23 @@ <*> pure loc astMap tv (OpSection name t loc) = OpSection- <$> astMap tv name+ <$> mapOnName tv name <*> traverse (mapOnStructType tv) t <*> pure loc astMap tv (OpSectionLeft name t arg (Info (pa, t1a, argext), Info (pb, t1b)) (ret, retext) loc) = OpSectionLeft- <$> astMap tv name+ <$> mapOnName tv name <*> traverse (mapOnStructType tv) t <*> mapOnExp tv arg <*> ( (,) <$> (Info <$> ((pa,,) <$> mapOnParamType tv t1a <*> pure argext)) <*> (Info <$> ((pb,) <$> mapOnParamType tv t1b)) )- <*> ((,) <$> traverse (mapOnResRetType tv) ret <*> traverse (mapM (mapOnName tv)) retext)+ <*> ((,) <$> traverse (mapOnResRetType tv) ret <*> pure retext) <*> pure loc astMap tv (OpSectionRight name t arg (Info (pa, t1a), Info (pb, t1b, argext)) t2 loc) = OpSectionRight- <$> astMap tv name+ <$> mapOnName tv name <*> traverse (mapOnStructType tv) t <*> mapOnExp tv arg <*> ( (,)@@ -233,7 +227,7 @@ instance ASTMappable (TypeExp Info VName) where astMap tv (TEVar qn loc) =- TEVar <$> astMap tv qn <*> pure loc+ TEVar <$> mapOnName tv qn <*> pure loc astMap tv (TEParens te loc) = TEParens <$> astMap tv te <*> pure loc astMap tv (TETuple ts loc) =@@ -261,9 +255,6 @@ astMap tv (SizeExp e loc) = SizeExp <$> mapOnExp tv e <*> pure loc astMap _ (SizeExpAny loc) = pure $ SizeExpAny loc -instance ASTMappable (TypeParamBase VName) where- astMap = traverse . mapOnName- instance ASTMappable (DimIndexBase Info VName) where astMap tv (DimFix j) = DimFix <$> mapOnExp tv j astMap tv (DimSlice i j stride) =@@ -284,7 +275,7 @@ f (t dim2 als2) traverseScalarType ::- Applicative f =>+ (Applicative f) => TypeTraverser f ScalarTypeBase dim1 als1 dims als2 traverseScalarType _ _ _ (Prim t) = pure $ Prim t traverseScalarType f g h (Record fs) = Record <$> traverse (traverseType f g h) fs@@ -300,14 +291,14 @@ traverseScalarType f g h (Sum cs) = Sum <$> (traverse . traverse) (traverseType f g h) cs -traverseType :: Applicative f => TypeTraverser f TypeBase dim1 als1 dims als2+traverseType :: (Applicative f) => TypeTraverser f TypeBase dim1 als1 dims als2 traverseType f g h (Array als shape et) = Array <$> h als <*> traverse g shape <*> traverseScalarType f g pure et traverseType f g h (Scalar t) = Scalar <$> traverseScalarType f g h t traverseTypeArg ::- Applicative f =>+ (Applicative f) => (QualName VName -> f (QualName VName)) -> (dim1 -> f dim2) -> TypeArg dim1 ->@@ -318,26 +309,22 @@ TypeArgType <$> traverseType f g pure t instance ASTMappable StructType where- astMap tv = traverseType (astMap tv) (mapOnExp tv) pure+ astMap tv = traverseType (mapOnName tv) (mapOnExp tv) pure instance ASTMappable ParamType where- astMap tv = traverseType (astMap tv) (mapOnExp tv) pure+ astMap tv = traverseType (mapOnName tv) (mapOnExp tv) pure instance ASTMappable (TypeBase Size Uniqueness) where- astMap tv = traverseType (astMap tv) (mapOnExp tv) pure+ astMap tv = traverseType (mapOnName tv) (mapOnExp tv) pure instance ASTMappable ResRetType where astMap tv (RetType ext t) = RetType ext <$> astMap tv t instance ASTMappable (IdentBase Info VName StructType) where astMap tv (Ident name (Info t) loc) =- Ident <$> mapOnName tv name <*> (Info <$> mapOnStructType tv t) <*> pure loc--instance ASTMappable (SizeBinder VName) where- astMap tv (SizeBinder name loc) =- SizeBinder <$> mapOnName tv name <*> pure loc+ Ident name <$> (Info <$> mapOnStructType tv t) <*> pure loc -traversePat :: Monad m => (t1 -> m t2) -> PatBase Info VName t1 -> m (PatBase Info VName t2)+traversePat :: (Monad m) => (t1 -> m t2) -> PatBase Info VName t1 -> m (PatBase Info VName t2) traversePat f (Id name (Info t) loc) = Id name <$> (Info <$> f t) <*> pure loc traversePat f (TuplePat pats loc) =@@ -368,7 +355,7 @@ RecordFieldExplicit name <$> mapOnExp tv e <*> pure loc astMap tv (RecordFieldImplicit name t loc) = RecordFieldImplicit- <$> mapOnName tv name+ <$> (qualLeaf <$> mapOnName tv (QualName [] name)) <*> traverse (mapOnStructType tv) t <*> pure loc @@ -376,13 +363,13 @@ astMap tv (CasePat pat e loc) = CasePat <$> astMap tv pat <*> mapOnExp tv e <*> pure loc -instance ASTMappable a => ASTMappable (Info a) where+instance (ASTMappable a) => ASTMappable (Info a) where astMap tv = traverse $ astMap tv -instance ASTMappable a => ASTMappable [a] where+instance (ASTMappable a) => ASTMappable [a] where astMap tv = traverse $ astMap tv -instance ASTMappable a => ASTMappable (NE.NonEmpty a) where+instance (ASTMappable a) => ASTMappable (NE.NonEmpty a) where astMap tv = traverse $ astMap tv instance (ASTMappable a, ASTMappable b) => ASTMappable (a, b) where@@ -494,8 +481,8 @@ case appexp of Match e cases loc -> Match (bareExp e) (fmap bareCase cases) loc- DoLoop _ mergepat mergeexp form loopbody loc ->- DoLoop+ Loop _ mergepat mergeexp form loopbody loc ->+ Loop [] (barePat mergepat) (bareExp mergeexp)
src/Language/Futhark/TypeChecker.hs view
@@ -148,7 +148,7 @@ pure (FileModule abs env (Prog doc decs') full_env) dupDefinitionError ::- MonadTypeChecker m =>+ (MonadTypeChecker m) => Namespace -> Name -> SrcLoc ->@@ -158,9 +158,11 @@ typeError loc1 mempty $ "Duplicate definition of" <+> pretty space- <+> prettyName name <> "."+ <+> prettyName name+ <> "." </> "Previously defined at"- <+> pretty (locStr loc2) <> "."+ <+> pretty (locStr loc2)+ <> "." checkForDuplicateDecs :: [DecBase NoInfo Name] -> TypeM () checkForDuplicateDecs =@@ -228,7 +230,8 @@ typeError loc mempty $ "All function parameters must have non-anonymous sizes." </> "Hint: add size parameters to"- <+> dquotes (prettyName name') <> "."+ <+> dquotes (prettyName name')+ <> "." pure (tparams', vtype', vtype_t) @@ -588,7 +591,8 @@ typeError loc mempty $ "Non-lifted type abbreviations may not use existential sizes in their definition." </> "Hint: use 'type~' or add size parameters to"- <+> dquotes (prettyName name) <> "."+ <+> dquotes (prettyName name)+ <> "." _ -> pure () bindSpaced [(Type, name)] $ do@@ -710,12 +714,12 @@ vb ) -nastyType :: Monoid als => TypeBase dim als -> Bool+nastyType :: (Monoid als) => TypeBase dim als -> Bool nastyType (Scalar Prim {}) = False nastyType t@Array {} = nastyType $ stripArray 1 t nastyType _ = True -nastyReturnType :: Monoid als => Maybe (TypeExp Info VName) -> TypeBase dim als -> Bool+nastyReturnType :: (Monoid als) => Maybe (TypeExp Info VName) -> TypeBase dim als -> Bool nastyReturnType Nothing (Scalar (Arrow _ _ _ t1 (RetType _ t2))) = nastyType t1 || nastyReturnType Nothing t2 nastyReturnType (Just (TEArrow _ te1 te2 _)) (Scalar (Arrow _ _ _ t1 (RetType _ t2))) =
src/Language/Futhark/TypeChecker/Consumption.hs view
@@ -156,7 +156,7 @@ where f = Nonconsumable . entryAliases -addError :: Located loc => loc -> Notes -> Doc () -> CheckM ()+addError :: (Located loc) => loc -> Notes -> Doc () -> CheckM () addError loc notes e = modify $ \s -> s {stateErrors = DL.snoc (stateErrors s) (TypeError (locOf loc) notes e)} @@ -410,7 +410,7 @@ delve (Scalar (Record fs)) = foldl' (M.unionWith (+)) mempty $ map delve $ M.elems fs delve t =- M.fromList $ zip (map aliasVar $ S.toList (aliases t)) $ repeat (1 :: Int)+ M.fromList $ map ((,1 :: Int) . aliasVar) $ S.toList $ aliases t consumingParams :: [Pat ParamType] -> Names consumingParams =@@ -454,7 +454,7 @@ | otherwise = t `setUniqueness` Nonunique -checkSubExps :: ASTMappable e => e -> CheckM e+checkSubExps :: (ASTMappable e) => e -> CheckM e checkSubExps = astMap identityMapper {mapOnExp = fmap fst . checkExp} noAliases :: Exp -> CheckM (Exp, TypeAliases)@@ -481,8 +481,8 @@ consumeAsNeeded loc pt t = when (diet pt == Consume) $ consumeAliases loc $ aliases t -checkArg :: ParamType -> Exp -> CheckM (Exp, TypeAliases)-checkArg p_t e = do+checkArg :: [(Exp, TypeAliases)] -> ParamType -> Exp -> CheckM (Exp, TypeAliases)+checkArg prev p_t e = do ((e', e_als), e_cons) <- contain $ checkExp e consumed e_cons let e_t = typeOf e'@@ -494,7 +494,21 @@ when (diet p_t == Consume) $ do noSelfAliases (locOf e) e_als consumeAsNeeded (locOf e) p_t e_als+ case mapMaybe prevAlias $ S.toList $ boundAliases $ aliases e_als of+ [] -> pure ()+ (v, prev_arg) : _ ->+ addError (locOf e) mempty $+ "Argument is consumed, but aliases"+ </> indent 2 (prettyName v)+ </> "which is also aliased by other argument"+ </> indent 2 (pretty prev_arg)+ </> "at"+ <+> pretty (locTextRel (locOf e) (locOf prev_arg))+ <> "." pure (e', e_als)+ where+ prevAlias v =+ (v,) . fst <$> find (S.member v . boundAliases . aliases . snd) prev -- | @returnType appres ret_type arg_diet arg_type@ gives result of applying -- an argument the given types to a function with the given return@@ -643,7 +657,7 @@ param' <- convergeLoopParam loop_loc param (M.keysSet body_cons) body_als let param_t = patternType param'- ((arg', arg_als), arg_cons) <- contain $ checkArg param_t arg+ ((arg', arg_als), arg_cons) <- contain $ checkArg [] param_t arg consumed arg_cons free_bound <- boundFreeInExp body @@ -652,7 +666,8 @@ v' <- describeVar v addError loop_loc mempty $ "Loop body uses"- <+> v' <> " (or an alias),"+ <+> v'+ <> " (or an alias)," </> "but this is consumed by the initial loop argument." v <- VName "internal_loop_result" <$> incCounter@@ -667,24 +682,23 @@ ) checkFuncall ::- Foldable f =>+ (Foldable f) => SrcLoc -> Maybe (QualName VName) -> TypeAliases -> f TypeAliases -> CheckM TypeAliases-checkFuncall loc fname f_als args_als = do+checkFuncall loc fname f_als arg_als = do v <- VName "internal_app_result" <$> incCounter modify $ \s -> s {stateNames = M.insert v (NameAppRes fname loc) $ stateNames s}- pure $ foldl applyArg (second (S.insert (AliasFree v)) f_als) args_als+ pure $ foldl applyArg (second (S.insert (AliasFree v)) f_als) arg_als checkExp :: Exp -> CheckM (Exp, TypeAliases) -- First we have the complicated cases. -- checkExp (AppExp (Apply f args loc) appres) = do- -- Note Futhark uses right-to-left evaluation of applications.- (args', args_als) <- NE.unzip . NE.reverse <$> traverse checkArg' (NE.reverse args)+ (args', args_als) <- NE.unzip <$> checkArgs args (f', f_als) <- checkExp f res_als <- checkFuncall loc (fname f) f_als args_als pure (AppExp (Apply f' args' loc) appres, res_als)@@ -692,15 +706,21 @@ fname (Var v _ _) = Just v fname (AppExp (Apply e _ _) _) = fname e fname _ = Nothing- checkArg' (Info (d, p), e) = do- (e', e_als) <- checkArg (second (const d) (typeOf e)) e+ checkArg' prev (Info (d, p), e) = do+ (e', e_als) <- checkArg prev (second (const d) (typeOf e)) e pure ((Info (d, p), e'), e_als) + checkArgs (x NE.:| args') = do+ -- Note Futhark uses right-to-left evaluation of applications.+ args'' <- maybe (pure []) (fmap NE.toList . checkArgs) $ NE.nonEmpty args'+ (x', x_als) <- checkArg' (map (first snd) args'') x+ pure $ (x', x_als) NE.:| args''+ ---checkExp (AppExp (DoLoop sparams pat args form body loc) appres) = do+checkExp (AppExp (Loop sparams pat args form body loc) appres) = do ((pat', args', form', body'), als) <- checkLoop (locOf loc) (pat, args, form, body) pure- ( AppExp (DoLoop sparams pat' args' form' body' loc) appres,+ ( AppExp (Loop sparams pat' args' form' body' loc) appres, als ) @@ -777,8 +797,8 @@ checkExp (AppExp (BinOp (op, oploc) opt (x, xp) (y, yp) loc) appres) = do op_als <- observeVar (locOf oploc) (qualLeaf op) (unInfo opt) let at1 : at2 : _ = fst $ unfoldFunType op_als- (x', x_als) <- checkArg at1 x- (y', y_als) <- checkArg at2 y+ (x', x_als) <- checkArg [] at1 x+ (y', y_als) <- checkArg [(x', x_als)] at2 y res_als <- checkFuncall loc (Just op) op_als [x_als, y_als] pure ( AppExp (BinOp (op, oploc) opt (x', xp) (y', yp) loc) appres,
src/Language/Futhark/TypeChecker/Modules.hs view
@@ -280,7 +280,8 @@ "Module defines" </> indent 2 (ppTypeAbbr abs name mod_t) </> "but module type requires"- <+> what <> "."+ <+> what+ <> "." where what = case name_l of Unlifted -> "a non-lifted type"@@ -332,17 +333,17 @@ resolve' name _ = M.lookup (namespace, baseName name) $ envNameMap mod_env -missingType :: Pretty a => Loc -> a -> Either TypeError b+missingType :: (Pretty a) => Loc -> a -> Either TypeError b missingType loc name = Left . TypeError loc mempty $ "Module does not define a type named" <+> pretty name <> "." -missingVal :: Pretty a => Loc -> a -> Either TypeError b+missingVal :: (Pretty a) => Loc -> a -> Either TypeError b missingVal loc name = Left . TypeError loc mempty $ "Module does not define a value named" <+> pretty name <> "." -missingMod :: Pretty a => Loc -> a -> Either TypeError b+missingMod :: (Pretty a) => Loc -> a -> Either TypeError b missingMod loc name = Left . TypeError loc mempty $ "Module does not define a module named" <+> pretty name <> "."
src/Language/Futhark/TypeChecker/Monad.hs view
@@ -52,6 +52,7 @@ import Control.Monad import Control.Monad.Except+import Control.Monad.Identity import Control.Monad.Reader import Control.Monad.State.Strict import Data.Either@@ -65,6 +66,7 @@ import Futhark.Util.Pretty hiding (space) import Language.Futhark import Language.Futhark.Semantic+import Language.Futhark.Traversals import Language.Futhark.Warnings import Paths_futhark qualified import Prelude hiding (mapM, mod)@@ -121,13 +123,13 @@ ] -- | An unexpected functor appeared!-unappliedFunctor :: MonadTypeChecker m => SrcLoc -> m a+unappliedFunctor :: (MonadTypeChecker m) => SrcLoc -> m a unappliedFunctor loc = typeError loc mempty "Cannot have parametric module here." -- | An unknown variable was referenced. unknownVariable ::- MonadTypeChecker m =>+ (MonadTypeChecker m) => Namespace -> QualName Name -> SrcLoc ->@@ -137,13 +139,13 @@ "Unknown" <+> pretty space <+> dquotes (pretty name) -- | An unknown type was referenced.-unknownType :: MonadTypeChecker m => SrcLoc -> QualName Name -> m a+unknownType :: (MonadTypeChecker m) => SrcLoc -> QualName Name -> m a unknownType loc name = typeError loc mempty $ "Unknown type" <+> pretty name <> "." -- | A name prefixed with an underscore was used. underscoreUse ::- MonadTypeChecker m =>+ (MonadTypeChecker m) => SrcLoc -> QualName Name -> m a@@ -273,8 +275,8 @@ -- | Monads that support type checking. The reason we have this -- internal interface is because we use distinct monads for checking -- expressions and declarations.-class Monad m => MonadTypeChecker m where- warn :: Located loc => loc -> Doc () -> m ()+class (Monad m) => MonadTypeChecker m where+ warn :: (Located loc) => loc -> Doc () -> m () warnings :: Warnings -> m () newName :: VName -> m VName@@ -292,16 +294,16 @@ checkExpForSize :: UncheckedExp -> m Exp - typeError :: Located loc => loc -> Notes -> Doc () -> m a+ typeError :: (Located loc) => loc -> Notes -> Doc () -> m a -- | Elaborate the given name in the given namespace at the given -- location, producing the corresponding unique 'VName'.-checkName :: MonadTypeChecker m => Namespace -> Name -> SrcLoc -> m VName+checkName :: (MonadTypeChecker m) => Namespace -> Name -> SrcLoc -> m VName checkName space name loc = qualLeaf <$> checkQualName space (qualName name) loc -- | Map source-level names do fresh unique internal names, and -- evaluate a type checker context with the mapping active.-bindSpaced :: MonadTypeChecker m => [(Namespace, Name)] -> m a -> m a+bindSpaced :: (MonadTypeChecker m) => [(Namespace, Name)] -> m a -> m a bindSpaced names body = do names' <- mapM (newID . snd) names let mapping = M.fromList (zip names $ map qualName names')@@ -442,8 +444,9 @@ onTypeArg except (TypeArgType t) = TypeArgType $ onType except t - onDim except (Var qn typ loc) = Var (qual except qn) typ loc- onDim _ d = d+ onDim except e = runIdentity $ onDimM except e+ onDimM except (Var qn typ loc) = pure $ Var (qual except qn) typ loc+ onDimM except e = astMap (identityMapper {mapOnExp = onDimM except}) e qual except (QualName orig_qs name) | name `elem` except || reachable orig_qs name outer_env =@@ -520,7 +523,7 @@ map (nameFromText . prettyText) [minBound .. (maxBound :: BinOp)]- fun_names = S.fromList $ map nameFromString ["shape"]+ fun_names = S.fromList [nameFromString "shape"] available _ = False -- | Construct the name of a new type variable given a base@@ -534,7 +537,7 @@ subscript = flip lookup $ zip "0123456789" "₀₁₂₃₄₅₆₇₈₉" -- | Type-check an attribute.-checkAttr :: MonadTypeChecker m => AttrInfo Name -> m (AttrInfo VName)+checkAttr :: (MonadTypeChecker m) => AttrInfo Name -> m (AttrInfo VName) checkAttr (AttrComp f attrs loc) = AttrComp f <$> mapM checkAttr attrs <*> pure loc checkAttr (AttrAtom (AtomName v) loc) =
src/Language/Futhark/TypeChecker/Terms.hs view
@@ -27,7 +27,7 @@ import Data.Map.Strict qualified as M import Data.Maybe import Data.Set qualified as S-import Futhark.Util (mapAccumLM, topologicalSort)+import Futhark.Util (mapAccumLM, nubOrd, topologicalSort) import Futhark.Util.Pretty hiding (space) import Language.Futhark import Language.Futhark.Primitive (intByteSize)@@ -35,7 +35,7 @@ import Language.Futhark.TypeChecker.Consumption qualified as Consumption import Language.Futhark.TypeChecker.Match import Language.Futhark.TypeChecker.Monad hiding (BoundV)-import Language.Futhark.TypeChecker.Terms.DoLoop+import Language.Futhark.TypeChecker.Terms.Loop import Language.Futhark.TypeChecker.Terms.Monad import Language.Futhark.TypeChecker.Terms.Pat import Language.Futhark.TypeChecker.Types@@ -46,7 +46,7 @@ hasBinding Lambda {} = True hasBinding (AppExp LetPat {} _) = True hasBinding (AppExp LetFun {} _) = True-hasBinding (AppExp DoLoop {} _) = True+hasBinding (AppExp Loop {} _) = True hasBinding (AppExp LetWith {} _) = True hasBinding (AppExp Match {} _) = True hasBinding e = isNothing $ astMap m e@@ -839,12 +839,12 @@ (t', retext) <- sliceShape Nothing slice' t let ft = Scalar $ Arrow mempty Unnamed Observe t $ RetType retext $ toRes Nonunique t' pure $ IndexSection slice' (Info ft) loc-checkExp (AppExp (DoLoop _ mergepat mergeexp form loopbody loc) _) = do+checkExp (AppExp (Loop _ mergepat mergeexp form loopbody loc) _) = do ((sparams, mergepat', mergeexp', form', loopbody'), appres) <-- checkDoLoop checkExp (mergepat, mergeexp, form, loopbody) loc+ checkLoop checkExp (mergepat, mergeexp, form, loopbody) loc pure $ AppExp- (DoLoop sparams mergepat' mergeexp' form' loopbody' loc)+ (Loop sparams mergepat' mergeexp' form' loopbody' loc) (Info appres) checkExp (Constr name es NoInfo loc) = do t <- newTypeVar loc "t"@@ -1060,13 +1060,16 @@ else "Cannot apply" <+> fname'- <+> "to argument #" <> pretty (prev_applied + 1)- <+> dquotes (shorten $ group $ pretty argexp) <> ","+ <+> "to argument #"+ <> pretty (prev_applied + 1)+ <+> dquotes (shorten $ group $ pretty argexp)+ <> "," </> "as" <+> fname' <+> "only takes" <+> pretty prev_applied- <+> arguments <> "."+ <+> arguments+ <> "." where arguments | prev_applied == 1 = "argument"@@ -1224,12 +1227,14 @@ "Causality check: size" <+> dquotes (prettyName d) <+> "needed for type of"- <+> what <> colon+ <+> what+ <> colon </> indent 2 (pretty t) </> "But" <+> dquotes (prettyName d) <+> "is computed at"- <+> pretty (locStrRel loc dloc) <> "."+ <+> pretty (locStrRel loc dloc)+ <> "." </> "" </> "Hint:" <+> align@@ -1381,7 +1386,8 @@ | otherwise = typeError usage mempty . withIndexLink "ambiguous-type" $ "Type is ambiguous (could be one of"- <+> commasep (map pretty ots) <> ")."+ <+> commasep (map pretty ots)+ <> ")." </> "Add a type annotation to disambiguate the type." fixOverloaded (v, NoConstraint _ usage) = do -- See #1552.@@ -1403,7 +1409,8 @@ fixOverloaded (_, HasConstrs _ cs usage) = typeError usage mempty . withIndexLink "ambiguous-type" $ "Type is ambiguous (must be a sum type with constructors:"- <+> pretty (Sum cs) <> ")."+ <+> pretty (Sum cs)+ <> ")." </> "Add a type annotation to disambiguate the type." fixOverloaded (v, Size Nothing (Usage Nothing loc)) = typeError loc mempty . withIndexLink "ambiguous-size" $@@ -1480,6 +1487,18 @@ letGeneralise fname loc tparams' params'' =<< unscopeUnknown rettype + when+ ( null params+ && any isSizeParam tparams''+ && not (null (retDims rettype'))+ )+ $ typeError loc mempty+ $ textwrap "A size-polymorphic value binding may not have a type with an existential size."+ </> "Type of this binding is:"+ </> indent 2 (pretty rettype')+ </> "with the following type parameters:"+ </> indent 2 (sep $ map pretty $ filter isSizeParam tparams'')+ pure (tparams'', params''', maybe_retdecl'', rettype', body') -- | Extract all the shape names that occur in positive position@@ -1515,13 +1534,13 @@ <+> dquotes (pretty p) </> "refers to size" <+> dquotes (prettyName d)- <> comma+ <> comma </> textwrap "which will not be accessible to the caller"- <> comma+ <> comma </> textwrap "possibly because it is nested in a tuple or record." </> textwrap "Consider ascribing an explicit type that does not reference "- <> dquotes (prettyName d)- <> "."+ <> dquotes (prettyName d)+ <> "." | otherwise = verifyParams forbidden' ps where forbidden' =@@ -1553,7 +1572,7 @@ deeper (Scalar (Record fs)) = Scalar $ Record $ M.map deeper fs deeper (Scalar (Sum cs)) = Scalar $ Sum $ M.map (map deeper) cs deeper (Scalar (Arrow als p d1 t1 (RetType t2_ext t2))) =- Scalar $ Arrow als p d1 t1 $ injectExt (ext_there <> t2_ext) t2+ Scalar $ Arrow als p d1 t1 $ injectExt (nubOrd (ext_there <> t2_ext)) t2 deeper (Scalar (TypeVar u tn targs)) = Scalar $ TypeVar u tn $ map deeperArg targs deeper t@Array {} = t@@ -1584,7 +1603,7 @@ _ -> Nothing pure ( tparams ++ more_tparams,- injectExt (retext ++ mapMaybe mkExt (S.toList $ fvVars $ freeInType ret)) ret+ injectExt (nubOrd $ retext ++ mapMaybe mkExt (S.toList $ fvVars $ freeInType ret)) ret ) where -- Diet does not matter here.@@ -1613,7 +1632,7 @@ <+> dquotes (prettyName k) <+> "in parameter of" <+> dquotes (prettyName defname)- <> ", which is inferred as:"+ <> ", which is inferred as:" </> indent 2 (pretty t) | k `S.member` produced_sizes = pure $ Just $ Right k@@ -1627,7 +1646,7 @@ [Pat ParamType] -> ResType -> TermTypeM ([TypeParam], [Pat ParamType], ResRetType)-letGeneralise defname defloc tparams params rettype =+letGeneralise defname defloc tparams params restype = onFailure (CheckingLetGeneralise defname) $ do now_substs <- getConstraints @@ -1651,19 +1670,19 @@ let candidate k (lvl, _) = (k `S.notMember` keep_type_vars) && lvl >= cur_lvl new_substs = M.filterWithKey candidate now_substs - (tparams', RetType ret_dims rettype') <-+ (tparams', RetType ret_dims restype') <- closeOverTypes defname defloc tparams (map patternStructType params)- rettype+ restype new_substs - rettype'' <- updateTypes rettype'+ restype'' <- updateTypes restype' let used_sizes =- freeInType rettype'' <> foldMap (freeInType . patternType) params+ freeInType restype'' <> foldMap (freeInType . patternType) params case filter ((`S.notMember` fvVars used_sizes) . typeParamName) $ filter isSizeParam tparams' of [] -> pure ()@@ -1673,7 +1692,7 @@ -- let-generalisation. modifyConstraints $ M.filterWithKey $ \k _ -> k `notElem` map typeParamName tparams' - pure (tparams', params, RetType ret_dims rettype'')+ pure (tparams', params, RetType ret_dims restype'') checkFunBody :: [Pat ParamType] ->
− src/Language/Futhark/TypeChecker/Terms/DoLoop.hs
@@ -1,288 +0,0 @@--- | Type inference of @loop@. This is complicated because of the--- uniqueness and size inference, so the implementation is separate--- from the main type checker.-module Language.Futhark.TypeChecker.Terms.DoLoop- ( UncheckedLoop,- CheckedLoop,- checkDoLoop,- )-where--import Control.Monad-import Control.Monad.Reader-import Control.Monad.State-import Data.Bifunctor-import Data.Bitraversable-import Data.List qualified as L-import Data.Map.Strict qualified as M-import Data.Maybe-import Data.Set qualified as S-import Futhark.Util (nubOrd)-import Futhark.Util.Pretty hiding (group, space)-import Language.Futhark-import Language.Futhark.TypeChecker.Monad hiding (BoundV)-import Language.Futhark.TypeChecker.Terms.Monad-import Language.Futhark.TypeChecker.Terms.Pat-import Language.Futhark.TypeChecker.Types-import Language.Futhark.TypeChecker.Unify-import Prelude hiding (mod)---- | Retrieve an oracle that can be used to decide whether two are in--- the same equivalence class (i.e. have been unified). This is an--- exotic operation.-getAreSame :: MonadUnify m => m (VName -> VName -> Bool)-getAreSame = check <$> getConstraints- where- check constraints x y =- case (M.lookup x constraints, M.lookup y constraints) of- (Just (_, Size (Just (Var x' _ _)) _), _) ->- check constraints (qualLeaf x') y- (_, Just (_, Size (Just (Var y' _ _)) _)) ->- check constraints x (qualLeaf y')- _ ->- x == y---- | Replace specified sizes with distinct fresh size variables.-someDimsFreshInType ::- SrcLoc ->- Name ->- [VName] ->- TypeBase Size als ->- TermTypeM (TypeBase Size als)-someDimsFreshInType loc desc fresh t = do- areSameSize <- getAreSame- let freshen v = any (areSameSize v) fresh- bitraverse (onDim freshen) pure t- where- onDim freshen (Var d _ _)- | freshen $ qualLeaf d = do- v <- newFlexibleDim (mkUsage' loc) desc- pure $ sizeFromName (qualName v) loc- onDim _ d = pure d---- | Replace the specified sizes with fresh size variables of the--- specified ridigity. Returns the new fresh size variables.-freshDimsInType ::- Usage ->- Rigidity ->- Name ->- [VName] ->- TypeBase Size u ->- TermTypeM (TypeBase Size u, [VName])-freshDimsInType usage r desc fresh t = do- areSameSize <- getAreSame- second (map snd) <$> runStateT (bitraverse (onDim areSameSize) pure t) mempty- where- onDim areSameSize (Var (QualName _ d) _ _)- | any (areSameSize d) fresh = do- prev_subst <- gets $ L.find (areSameSize d . fst)- case prev_subst of- Just (_, d') -> pure $ sizeFromName (qualName d') $ srclocOf usage- Nothing -> do- v <- lift $ newDimVar usage r desc- modify ((d, v) :)- pure $ sizeFromName (qualName v) $ srclocOf usage- onDim _ d = pure d--data ArgSource = Initial | BodyResult--wellTypedLoopArg :: ArgSource -> [VName] -> Pat ParamType -> Exp -> TermTypeM ()-wellTypedLoopArg src sparams pat arg = do- (merge_t, _) <-- freshDimsInType (mkUsage arg desc) Nonrigid "loop" sparams $- toStruct (patternType pat)- arg_t <- toStruct <$> expTypeFully arg- onFailure (checking merge_t arg_t) $- unify (mkUsage arg desc) merge_t arg_t- where- (checking, desc) =- case src of- Initial -> (CheckingLoopInitial, "matching initial loop values to pattern")- BodyResult -> (CheckingLoopBody, "matching loop body to pattern")---- | An un-checked loop.-type UncheckedLoop =- (UncheckedPat ParamType, UncheckedExp, LoopFormBase NoInfo Name, UncheckedExp)---- | A loop that has been type-checked.-type CheckedLoop =- ([VName], Pat ParamType, Exp, LoopFormBase Info VName, Exp)---- | Type-check a @loop@ expression, passing in a function for--- type-checking subexpressions.-checkDoLoop ::- (UncheckedExp -> TermTypeM Exp) ->- UncheckedLoop ->- SrcLoc ->- TermTypeM (CheckedLoop, AppRes)-checkDoLoop checkExp (mergepat, mergeexp, form, loopbody) loc = do- mergeexp' <- checkExp mergeexp- known_before <- M.keysSet <$> getConstraints- zeroOrderType- (mkUsage mergeexp "use as loop variable")- "type used as loop variable"- . toStruct- =<< expTypeFully mergeexp'-- -- The handling of dimension sizes is a bit intricate, but very- -- similar to checking a function, followed by checking a call to- -- it. The overall procedure is as follows:- --- -- (1) All empty dimensions in the merge pattern are instantiated- -- with nonrigid size variables. All explicitly specified- -- dimensions are preserved.- --- -- (2) The body of the loop is type-checked. The result type is- -- combined with the merge pattern type to determine which sizes are- -- variant, and these are turned into size parameters for the merge- -- pattern.- --- -- (3) We now conceptually have a function parameter type and- -- return type. We check that it can be called with the body type- -- as argument.- --- -- (4) Similarly to (3), we check that the "function" can be- -- called with the initial merge values as argument. The result- -- of this is the type of the loop as a whole.-- (merge_t, new_dims_map) <-- -- dim handling (1)- allDimsFreshInType (mkUsage loc "loop parameter type inference") Nonrigid "loop_d"- =<< expTypeFully mergeexp'- let new_dims_to_initial_dim = M.toList new_dims_map- new_dims = map fst new_dims_to_initial_dim-- -- dim handling (2)- let checkLoopReturnSize mergepat' loopbody' = do- loopbody_t <- expTypeFully loopbody'- pat_t <-- someDimsFreshInType loc "loop" new_dims- =<< normTypeFully (patternType mergepat')-- -- We are ignoring the dimensions here, because any mismatches- -- should be turned into fresh size variables.- onFailure (CheckingLoopBody (toStruct pat_t) (toStruct loopbody_t)) $- unify- (mkUsage loopbody "matching loop body to loop pattern")- (toStruct pat_t)- (toStruct loopbody_t)-- -- Figure out which of the 'new_dims' dimensions are variant.- -- This works because we know that each dimension from- -- new_dims in the pattern is unique and distinct.- areSameSize <- getAreSame- let onDims _ x y- | x == y = pure x- onDims _ e d = do- forM_ (fvVars $ freeInExp e) $ \v -> do- case L.find (areSameSize v . fst) new_dims_to_initial_dim of- Just (_, e') ->- if e' == d- then modify $ first $ M.insert v $ ExpSubst e'- else- unless (v `S.member` known_before) $- modify (second (v :))- _ ->- pure ()- pure e- loopbody_t' <- normTypeFully loopbody_t- merge_t' <- normTypeFully merge_t-- let (init_substs, sparams) =- execState (matchDims onDims merge_t' loopbody_t') mempty-- -- Make sure that any of new_dims that are invariant will be- -- replaced with the invariant size in the loop body. Failure- -- to do this can cause type annotations to still refer to- -- new_dims.- let dimToInit (v, ExpSubst e) =- constrain v $ Size (Just e) (mkUsage loc "size of loop parameter")- dimToInit _ =- pure ()- mapM_ dimToInit $ M.toList init_substs-- mergepat'' <- applySubst (`M.lookup` init_substs) <$> updateTypes mergepat'-- -- Eliminate those new_dims that turned into sparams so it won't- -- look like we have ambiguous sizes lying around.- modifyConstraints $ M.filterWithKey $ \k _ -> k `notElem` sparams-- -- dim handling (3)- --- -- The only trick here is that we have to turn any instances- -- of loop parameters in the type of loopbody' rigid,- -- because we are no longer in a position to change them,- -- really.- wellTypedLoopArg BodyResult sparams mergepat'' loopbody'-- pure (nubOrd sparams, mergepat'')-- (sparams, mergepat', form', loopbody') <-- case form of- For i uboundexp -> do- uboundexp' <-- require "being the bound in a 'for' loop" anySignedType- =<< checkExp uboundexp- bound_t <- expTypeFully uboundexp'- bindingIdent i bound_t $ \i' ->- bindingPat [] mergepat merge_t $- \mergepat' -> incLevel $ do- loopbody' <- checkExp loopbody- (sparams, mergepat'') <- checkLoopReturnSize mergepat' loopbody'- pure- ( sparams,- mergepat'',- For i' uboundexp',- loopbody'- )- ForIn xpat e -> do- (arr_t, _) <- newArrayType (mkUsage' (srclocOf e)) "e" 1- e' <- unifies "being iterated in a 'for-in' loop" arr_t =<< checkExp e- t <- expTypeFully e'- case t of- _- | Just t' <- peelArray 1 t ->- bindingPat [] xpat t' $ \xpat' ->- bindingPat [] mergepat merge_t $- \mergepat' -> incLevel $ do- loopbody' <- checkExp loopbody- (sparams, mergepat'') <- checkLoopReturnSize mergepat' loopbody'- pure- ( sparams,- mergepat'',- ForIn (fmap toStruct xpat') e',- loopbody'- )- | otherwise ->- typeError (srclocOf e) mempty $- "Iteratee of a for-in loop must be an array, but expression has type"- <+> pretty t- While cond ->- bindingPat [] mergepat merge_t $ \mergepat' ->- incLevel $ do- cond' <-- checkExp cond- >>= unifies "being the condition of a 'while' loop" (Scalar $ Prim Bool)- loopbody' <- checkExp loopbody- (sparams, mergepat'') <- checkLoopReturnSize mergepat' loopbody'- pure- ( sparams,- mergepat'',- While cond',- loopbody'- )-- -- dim handling (4)- wellTypedLoopArg Initial sparams mergepat' mergeexp'-- (loopt, retext) <-- freshDimsInType- (mkUsage loc "inference of loop result type")- (Rigid RigidLoop)- "loop"- sparams- (patternType mergepat')- pure- ( (sparams, mergepat', mergeexp', form', loopbody'),- AppRes (toStruct loopt) retext- )
+ src/Language/Futhark/TypeChecker/Terms/Loop.hs view
@@ -0,0 +1,288 @@+-- | Type inference of @loop@. This is complicated because of the+-- uniqueness and size inference, so the implementation is separate+-- from the main type checker.+module Language.Futhark.TypeChecker.Terms.Loop+ ( UncheckedLoop,+ CheckedLoop,+ checkLoop,+ )+where++import Control.Monad+import Control.Monad.Reader+import Control.Monad.State+import Data.Bifunctor+import Data.Bitraversable+import Data.List qualified as L+import Data.Map.Strict qualified as M+import Data.Maybe+import Data.Set qualified as S+import Futhark.Util (nubOrd)+import Futhark.Util.Pretty hiding (group, space)+import Language.Futhark+import Language.Futhark.TypeChecker.Monad hiding (BoundV)+import Language.Futhark.TypeChecker.Terms.Monad+import Language.Futhark.TypeChecker.Terms.Pat+import Language.Futhark.TypeChecker.Types+import Language.Futhark.TypeChecker.Unify+import Prelude hiding (mod)++-- | Retrieve an oracle that can be used to decide whether two are in+-- the same equivalence class (i.e. have been unified). This is an+-- exotic operation.+getAreSame :: (MonadUnify m) => m (VName -> VName -> Bool)+getAreSame = check <$> getConstraints+ where+ check constraints x y =+ case (M.lookup x constraints, M.lookup y constraints) of+ (Just (_, Size (Just (Var x' _ _)) _), _) ->+ check constraints (qualLeaf x') y+ (_, Just (_, Size (Just (Var y' _ _)) _)) ->+ check constraints x (qualLeaf y')+ _ ->+ x == y++-- | Replace specified sizes with distinct fresh size variables.+someDimsFreshInType ::+ SrcLoc ->+ Name ->+ [VName] ->+ TypeBase Size als ->+ TermTypeM (TypeBase Size als)+someDimsFreshInType loc desc fresh t = do+ areSameSize <- getAreSame+ let freshen v = any (areSameSize v) fresh+ bitraverse (onDim freshen) pure t+ where+ onDim freshen (Var d _ _)+ | freshen $ qualLeaf d = do+ v <- newFlexibleDim (mkUsage' loc) desc+ pure $ sizeFromName (qualName v) loc+ onDim _ d = pure d++-- | Replace the specified sizes with fresh size variables of the+-- specified ridigity. Returns the new fresh size variables.+freshDimsInType ::+ Usage ->+ Rigidity ->+ Name ->+ [VName] ->+ TypeBase Size u ->+ TermTypeM (TypeBase Size u, [VName])+freshDimsInType usage r desc fresh t = do+ areSameSize <- getAreSame+ second (map snd) <$> runStateT (bitraverse (onDim areSameSize) pure t) mempty+ where+ onDim areSameSize (Var (QualName _ d) _ _)+ | any (areSameSize d) fresh = do+ prev_subst <- gets $ L.find (areSameSize d . fst)+ case prev_subst of+ Just (_, d') -> pure $ sizeFromName (qualName d') $ srclocOf usage+ Nothing -> do+ v <- lift $ newDimVar usage r desc+ modify ((d, v) :)+ pure $ sizeFromName (qualName v) $ srclocOf usage+ onDim _ d = pure d++data ArgSource = Initial | BodyResult++wellTypedLoopArg :: ArgSource -> [VName] -> Pat ParamType -> Exp -> TermTypeM ()+wellTypedLoopArg src sparams pat arg = do+ (merge_t, _) <-+ freshDimsInType (mkUsage arg desc) Nonrigid "loop" sparams $+ toStruct (patternType pat)+ arg_t <- toStruct <$> expTypeFully arg+ onFailure (checking merge_t arg_t) $+ unify (mkUsage arg desc) merge_t arg_t+ where+ (checking, desc) =+ case src of+ Initial -> (CheckingLoopInitial, "matching initial loop values to pattern")+ BodyResult -> (CheckingLoopBody, "matching loop body to pattern")++-- | An un-checked loop.+type UncheckedLoop =+ (UncheckedPat ParamType, UncheckedExp, LoopFormBase NoInfo Name, UncheckedExp)++-- | A loop that has been type-checked.+type CheckedLoop =+ ([VName], Pat ParamType, Exp, LoopFormBase Info VName, Exp)++-- | Type-check a @loop@ expression, passing in a function for+-- type-checking subexpressions.+checkLoop ::+ (UncheckedExp -> TermTypeM Exp) ->+ UncheckedLoop ->+ SrcLoc ->+ TermTypeM (CheckedLoop, AppRes)+checkLoop checkExp (mergepat, mergeexp, form, loopbody) loc = do+ mergeexp' <- checkExp mergeexp+ known_before <- M.keysSet <$> getConstraints+ zeroOrderType+ (mkUsage mergeexp "use as loop variable")+ "type used as loop variable"+ . toStruct+ =<< expTypeFully mergeexp'++ -- The handling of dimension sizes is a bit intricate, but very+ -- similar to checking a function, followed by checking a call to+ -- it. The overall procedure is as follows:+ --+ -- (1) All empty dimensions in the merge pattern are instantiated+ -- with nonrigid size variables. All explicitly specified+ -- dimensions are preserved.+ --+ -- (2) The body of the loop is type-checked. The result type is+ -- combined with the merge pattern type to determine which sizes are+ -- variant, and these are turned into size parameters for the merge+ -- pattern.+ --+ -- (3) We now conceptually have a function parameter type and+ -- return type. We check that it can be called with the body type+ -- as argument.+ --+ -- (4) Similarly to (3), we check that the "function" can be+ -- called with the initial merge values as argument. The result+ -- of this is the type of the loop as a whole.++ (merge_t, new_dims_map) <-+ -- dim handling (1)+ allDimsFreshInType (mkUsage loc "loop parameter type inference") Nonrigid "loop_d"+ =<< expTypeFully mergeexp'+ let new_dims_to_initial_dim = M.toList new_dims_map+ new_dims = map fst new_dims_to_initial_dim++ -- dim handling (2)+ let checkLoopReturnSize mergepat' loopbody' = do+ loopbody_t <- expTypeFully loopbody'+ pat_t <-+ someDimsFreshInType loc "loop" new_dims+ =<< normTypeFully (patternType mergepat')++ -- We are ignoring the dimensions here, because any mismatches+ -- should be turned into fresh size variables.+ onFailure (CheckingLoopBody (toStruct pat_t) (toStruct loopbody_t)) $+ unify+ (mkUsage loopbody "matching loop body to loop pattern")+ (toStruct pat_t)+ (toStruct loopbody_t)++ -- Figure out which of the 'new_dims' dimensions are variant.+ -- This works because we know that each dimension from+ -- new_dims in the pattern is unique and distinct.+ areSameSize <- getAreSame+ let onDims _ x y+ | x == y = pure x+ onDims _ e d = do+ forM_ (fvVars $ freeInExp e) $ \v -> do+ case L.find (areSameSize v . fst) new_dims_to_initial_dim of+ Just (_, e') ->+ if e' == d+ then modify $ first $ M.insert v $ ExpSubst e'+ else+ unless (v `S.member` known_before) $+ modify (second (v :))+ _ ->+ pure ()+ pure e+ loopbody_t' <- normTypeFully loopbody_t+ merge_t' <- normTypeFully merge_t++ let (init_substs, sparams) =+ execState (matchDims onDims merge_t' loopbody_t') mempty++ -- Make sure that any of new_dims that are invariant will be+ -- replaced with the invariant size in the loop body. Failure+ -- to do this can cause type annotations to still refer to+ -- new_dims.+ let dimToInit (v, ExpSubst e) =+ constrain v $ Size (Just e) (mkUsage loc "size of loop parameter")+ dimToInit _ =+ pure ()+ mapM_ dimToInit $ M.toList init_substs++ mergepat'' <- applySubst (`M.lookup` init_substs) <$> updateTypes mergepat'++ -- Eliminate those new_dims that turned into sparams so it won't+ -- look like we have ambiguous sizes lying around.+ modifyConstraints $ M.filterWithKey $ \k _ -> k `notElem` sparams++ -- dim handling (3)+ --+ -- The only trick here is that we have to turn any instances+ -- of loop parameters in the type of loopbody' rigid,+ -- because we are no longer in a position to change them,+ -- really.+ wellTypedLoopArg BodyResult sparams mergepat'' loopbody'++ pure (nubOrd sparams, mergepat'')++ (sparams, mergepat', form', loopbody') <-+ case form of+ For i uboundexp -> do+ uboundexp' <-+ require "being the bound in a 'for' loop" anySignedType+ =<< checkExp uboundexp+ bound_t <- expTypeFully uboundexp'+ bindingIdent i bound_t $ \i' ->+ bindingPat [] mergepat merge_t $+ \mergepat' -> incLevel $ do+ loopbody' <- checkExp loopbody+ (sparams, mergepat'') <- checkLoopReturnSize mergepat' loopbody'+ pure+ ( sparams,+ mergepat'',+ For i' uboundexp',+ loopbody'+ )+ ForIn xpat e -> do+ (arr_t, _) <- newArrayType (mkUsage' (srclocOf e)) "e" 1+ e' <- unifies "being iterated in a 'for-in' loop" arr_t =<< checkExp e+ t <- expTypeFully e'+ case t of+ _+ | Just t' <- peelArray 1 t ->+ bindingPat [] xpat t' $ \xpat' ->+ bindingPat [] mergepat merge_t $+ \mergepat' -> incLevel $ do+ loopbody' <- checkExp loopbody+ (sparams, mergepat'') <- checkLoopReturnSize mergepat' loopbody'+ pure+ ( sparams,+ mergepat'',+ ForIn (fmap toStruct xpat') e',+ loopbody'+ )+ | otherwise ->+ typeError (srclocOf e) mempty $+ "Iteratee of a for-in loop must be an array, but expression has type"+ <+> pretty t+ While cond ->+ bindingPat [] mergepat merge_t $ \mergepat' ->+ incLevel $ do+ cond' <-+ checkExp cond+ >>= unifies "being the condition of a 'while' loop" (Scalar $ Prim Bool)+ loopbody' <- checkExp loopbody+ (sparams, mergepat'') <- checkLoopReturnSize mergepat' loopbody'+ pure+ ( sparams,+ mergepat'',+ While cond',+ loopbody'+ )++ -- dim handling (4)+ wellTypedLoopArg Initial sparams mergepat' mergeexp'++ (loopt, retext) <-+ freshDimsInType+ (mkUsage loc "inference of loop result type")+ (Rigid RigidLoop)+ "loop"+ sparams+ (patternType mergepat')+ pure+ ( (sparams, mergepat', mergeexp', form', loopbody'),+ AppRes (toStruct loopt) retext+ )
src/Language/Futhark/TypeChecker/Terms/Monad.hs view
@@ -157,7 +157,8 @@ <+> align (pretty actual) pretty (CheckingRecordUpdate fs expected actual) = "Type mismatch when updating record field"- <+> dquotes fs' <> "."+ <+> dquotes fs'+ <> "." </> "Existing:" <+> align (pretty expected) </> "New: "@@ -166,12 +167,14 @@ fs' = mconcat $ punctuate "." $ map pretty fs pretty (CheckingRequired [expected] actual) = "Expression must must have type"- <+> pretty expected <> "."+ <+> pretty expected+ <> "." </> "Actual type:" <+> align (pretty actual) pretty (CheckingRequired expected actual) = "Type of expression must must be one of "- <+> expected' <> "."+ <+> expected'+ <> "." </> "Actual type:" <+> align (pretty actual) where@@ -362,7 +365,7 @@ -- | Create a new type name and insert it (unconstrained) in the -- substitution map. instantiateTypeParam ::- Monoid as =>+ (Monoid as) => QualName VName -> SrcLoc -> TypeParam ->@@ -585,7 +588,7 @@ pure $ sizeFromName (qualName v) $ srclocOf usage -- | Replace all type variables with their concrete types.-updateTypes :: ASTMappable e => e -> TermTypeM e+updateTypes :: (ASTMappable e) => e -> TermTypeM e updateTypes = astMap tv where tv =
src/Language/Futhark/TypeChecker/Terms/Pat.hs view
@@ -211,7 +211,9 @@ | Just (f, fp) <- find (("_" `isPrefixOf`) . nameToString . fst) p_fs = typeError fp mempty $ "Underscore-prefixed fields are not allowed."- </> "Did you mean" <> dquotes (pretty (drop 1 (nameToString f)) <> "=_") <> "?"+ </> "Did you mean"+ <> dquotes (pretty (drop 1 (nameToString f)) <> "=_")+ <> "?" checkPat' sizes (RecordPat p_fs loc) (Ascribed (Scalar (Record t_fs))) | sort (map fst p_fs) == sort (M.keys t_fs) = RecordPat . M.toList <$> check <*> pure loc
src/Language/Futhark/TypeChecker/Types.hs view
@@ -61,7 +61,7 @@ mustBeExplicitInBinding :: StructType -> S.Set VName mustBeExplicitInBinding bind_t = let (ts, ret) = unfoldFunType bind_t- alsoRet = M.unionWith (&&) $ M.fromList $ zip (S.toList (fvVars (freeInType ret))) (repeat True)+ alsoRet = M.unionWith (&&) $ M.fromList $ map (,True) (S.toList (fvVars (freeInType ret))) in S.fromList $ M.keys $ M.filter id $ alsoRet $ foldl' onType mempty $ map toStruct ts where onType uses t = uses <> mustBeExplicitAux t -- Left-biased union.@@ -74,7 +74,7 @@ -- | Ensure that the dimensions of the RetType are unique by -- generating new names for them. This is to avoid name capture.-renameRetType :: MonadTypeChecker m => ResRetType -> m ResRetType+renameRetType :: (MonadTypeChecker m) => ResRetType -> m ResRetType renameRetType (RetType dims st) | dims /= mempty = do dims' <- mapM newName dims@@ -86,7 +86,7 @@ pure $ RetType dims st evalTypeExp ::- MonadTypeChecker m =>+ (MonadTypeChecker m) => TypeExp NoInfo Name -> m (TypeExp Info VName, [VName], ResRetType, Liftedness) evalTypeExp (TEVar name loc) = do@@ -273,7 +273,7 @@ tloc = srclocOf ote rootAndArgs ::- MonadTypeChecker m =>+ (MonadTypeChecker m) => TypeExp NoInfo Name -> m (QualName Name, SrcLoc, [TypeArgExp NoInfo Name]) rootAndArgs (TEVar qn loc) = pure (qn, loc, [])@@ -323,7 +323,7 @@ -- * The elaborated type. -- * The liftedness of the type. checkTypeExp ::- MonadTypeChecker m =>+ (MonadTypeChecker m) => TypeExp NoInfo Name -> m (TypeExp Info VName, [VName], ResRetType, Liftedness) checkTypeExp te = do@@ -332,7 +332,7 @@ -- | Check for duplication of names inside a binding group. checkForDuplicateNames ::- MonadTypeChecker m => [UncheckedTypeParam] -> [UncheckedPat t] -> m ()+ (MonadTypeChecker m) => [UncheckedTypeParam] -> [UncheckedPat t] -> m () checkForDuplicateNames tps pats = (`evalStateT` mempty) $ do mapM_ checkTypeParam tps mapM_ checkPat pats@@ -369,7 +369,7 @@ -- since it is likely an error, but it's easy to assign a semantics to -- it (normal name shadowing). checkForDuplicateNamesInType ::- MonadTypeChecker m =>+ (MonadTypeChecker m) => TypeExp NoInfo Name -> m () checkForDuplicateNamesInType = check mempty@@ -413,7 +413,7 @@ -- invokes the continuation @m@ with the checked parameters, while -- extending the monadic name map with @ps@. checkTypeParams ::- MonadTypeChecker m =>+ (MonadTypeChecker m) => [TypeParamBase Name] -> ([TypeParamBase VName] -> m a) -> m a@@ -456,7 +456,7 @@ data Subst t = Subst [TypeParam] t | ExpSubst Exp deriving (Show) -instance Pretty t => Pretty (Subst t) where+instance (Pretty t) => Pretty (Subst t) where pretty (Subst [] t) = pretty t pretty (Subst tps t) = mconcat (map pretty tps) <> colon <+> pretty t pretty (ExpSubst e) = pretty e@@ -514,7 +514,7 @@ mapOnResRetType = pure . applySubst f } -instance Substitutable d => Substitutable (Shape d) where+instance (Substitutable d) => Substitutable (Shape d) where applySubst f = fmap $ applySubst f instance Substitutable (Pat StructType) where@@ -542,7 +542,7 @@ } applyType ::- Monoid als =>+ (Monoid als) => [TypeParam] -> TypeBase Size als -> [StructTypeArg] ->@@ -559,7 +559,7 @@ error $ "applyType mkSubst: cannot substitute " ++ prettyString a ++ " for " ++ prettyString p substTypesRet ::- Monoid as =>+ (Monoid as) => (VName -> Maybe (Subst (RetTypeBase Size as))) -> TypeBase Size as -> RetTypeBase Size as@@ -590,7 +590,7 @@ onType :: forall as.- Monoid as =>+ (Monoid as) => TypeBase Size as -> State [VName] (TypeBase Size as) @@ -637,7 +637,7 @@ -- | Perform substitutions, from type names to types, on a type. Works -- regardless of what shape and uniqueness information is attached to the type. substTypesAny ::- Monoid as =>+ (Monoid as) => (VName -> Maybe (Subst (RetTypeBase Size as))) -> TypeBase Size as -> TypeBase Size as
src/Language/Futhark/TypeChecker/Unify.hs view
@@ -93,12 +93,12 @@ deriving (Show) -- | Construct a 'Usage' from a location and a description.-mkUsage :: Located a => a -> T.Text -> Usage+mkUsage :: (Located a) => a -> T.Text -> Usage mkUsage = flip (Usage . Just) . srclocOf -- | Construct a 'Usage' that has just a location, but no particular -- description.-mkUsage' :: Located a => a -> Usage+mkUsage' :: (Located a) => a -> Usage mkUsage' = Usage Nothing . srclocOf instance Pretty Usage where@@ -200,14 +200,17 @@ </> "passed to" <+> fname' <+> "at"- <+> pretty (locStrRel ctx loc) <> "."+ <+> pretty (locStrRel ctx loc)+ <> "." where fname' = maybe "function" (dquotes . pretty) fname prettySource ctx loc (RigidSlice d slice) = "is size produced by slice" </> indent 2 (shorten (pretty slice))- </> d_desc <> "at"- <+> pretty (locStrRel ctx loc) <> "."+ </> d_desc+ <> "at"+ <+> pretty (locStrRel ctx loc)+ <> "." where d_desc = case d of Just d' -> "of dimension of size " <> dquotes (pretty d') <> " "@@ -219,7 +222,9 @@ prettySource ctx loc (RigidBound bound) = "generated from expression" </> indent 2 (shorten (pretty bound))- </> "used in range at " <> pretty (locStrRel ctx loc) <> "."+ </> "used in range at "+ <> pretty (locStrRel ctx loc)+ <> "." prettySource ctx loc (RigidOutOfScope boundloc v) = "is an unknown size arising from " <> dquotes (prettyName v)@@ -227,8 +232,8 @@ <> pretty (locStrRel ctx loc) <> "." </> "Originally bound at "- <> pretty (locStrRel ctx boundloc)- <> "."+ <> pretty (locStrRel ctx boundloc)+ <> "." prettySource ctx loc RigidCoerce = "is an unknown size arising from empty dimension in coercion at" <+> pretty (locStrRel ctx loc) <> "."@@ -239,9 +244,9 @@ <> pretty (locStrRel ctx loc) <> "." </> "One branch returns array of type: "- <> align (pretty t1)+ <> align (pretty t1) </> "The other an array of type: "- <> align (pretty t2)+ <> align (pretty t2) -- | Retrieve notes describing the purpose or origin of the given -- t'Size'. The location is used as the *current* location, for the@@ -264,7 +269,7 @@ . fvVars . freeInType -typeVarNotes :: MonadUnify m => VName -> m Notes+typeVarNotes :: (MonadUnify m) => VName -> m Notes typeVarNotes v = maybe mempty (note . snd) . M.lookup v <$> getConstraints where note (HasConstrs _ cs _) =@@ -287,7 +292,7 @@ -- | Monads that which to perform unification must implement this type -- class.-class Monad m => MonadUnify m where+class (Monad m) => MonadUnify m where getConstraints :: m Constraints putConstraints :: Constraints -> m () modifyConstraints :: (Constraints -> Constraints) -> m ()@@ -295,9 +300,9 @@ x <- getConstraints putConstraints $ f x - newTypeVar :: Monoid als => SrcLoc -> Name -> m (TypeBase dim als)+ newTypeVar :: (Monoid als) => SrcLoc -> Name -> m (TypeBase dim als) newDimVar :: Usage -> Rigidity -> Name -> m VName- newRigidDim :: Located a => a -> RigidSource -> Name -> m VName+ newRigidDim :: (Located a) => a -> RigidSource -> Name -> m VName newRigidDim loc = newDimVar (mkUsage' loc) . Rigid newFlexibleDim :: Usage -> Name -> m VName newFlexibleDim usage = newDimVar usage Nonrigid@@ -305,7 +310,7 @@ curLevel :: m Level matchError ::- Located loc =>+ (Located loc) => loc -> Notes -> BreadCrumbs ->@@ -314,7 +319,7 @@ m a unifyError ::- Located loc =>+ (Located loc) => loc -> Notes -> BreadCrumbs ->@@ -328,7 +333,7 @@ pure $ applySubst (`lookupSubst` constraints) t -- | Replace any top-level type variable with its substitution.-normType :: MonadUnify m => StructType -> m StructType+normType :: (MonadUnify m) => StructType -> m StructType normType t@(Scalar (TypeVar _ (QualName [] v) [])) = do constraints <- getConstraints case snd <$> M.lookup v constraints of@@ -371,7 +376,7 @@ onDims bcs bound nonrigid t2 t1 unifyWith ::- MonadUnify m =>+ (MonadUnify m) => UnifySizes m -> Usage -> [VName] ->@@ -486,8 +491,8 @@ (Size Nothing $ Usage Nothing mempty) (UnknownSize mempty RigidUnify) lvl <- curLevel- modifyConstraints (M.fromList (zip b1_dims $ repeat (lvl, r1)) <>)- modifyConstraints (M.fromList (zip b2_dims $ repeat (lvl, r2)) <>)+ modifyConstraints (M.fromList (map (,(lvl, r1)) b1_dims) <>)+ modifyConstraints (M.fromList (map (,(lvl, r2)) b2_dims) <>) let bound' = bound <> mapMaybe pname [p1, p2] <> b1_dims <> b2_dims subunify@@ -542,7 +547,7 @@ anyBound :: [VName] -> ExpBase Info VName -> Bool anyBound bound e = any (`S.member` fvVars (freeInExp e)) bound -unifySizes :: MonadUnify m => Usage -> UnifySizes m+unifySizes :: (MonadUnify m) => Usage -> UnifySizes m unifySizes usage bcs bound nonrigid e1 e2 | Just es <- similarExps e1 e2 = mapM_ (uncurry $ unifySizes usage bcs bound nonrigid) es@@ -564,11 +569,11 @@ <+> "do not match." -- | Unifies two types.-unify :: MonadUnify m => Usage -> StructType -> StructType -> m ()+unify :: (MonadUnify m) => Usage -> StructType -> StructType -> m () unify usage = unifyWith (unifySizes usage) usage mempty noBreadCrumbs occursCheck ::- MonadUnify m =>+ (MonadUnify m) => Usage -> BreadCrumbs -> VName ->@@ -583,7 +588,7 @@ <+> pretty tp <> "." scopeCheck ::- MonadUnify m =>+ (MonadUnify m) => Usage -> BreadCrumbs -> VName ->@@ -619,7 +624,7 @@ <+> "is rigidly bound in a deeper scope." linkVarToType ::- MonadUnify m =>+ (MonadUnify m) => UnifySizes m -> Usage -> [VName] ->@@ -693,7 +698,8 @@ <+> "must be one of" <+> commasep (map pretty ts) </> "due to"- <+> pretty old_usage <> "."+ <+> pretty old_usage+ <> "." Just (HasFields l required_fields old_usage) -> do when (l == Unlifted) $ arrayElemTypeWith usage (unliftedBcs old_usage) tp case tp of@@ -735,7 +741,8 @@ <+> "must be a record with fields" </> indent 2 (pretty (Record required_fields)) </> "due to"- <+> pretty old_usage <> "."+ <+> pretty old_usage+ <> "." -- See Note [Linking variables to sum types] Just (HasConstrs l required_cs old_usage) -> do when (l == Unlifted) $ arrayElemTypeWith usage (unliftedBcs old_usage) tp@@ -791,7 +798,7 @@ "Cannot unify a record type with a non-record type." linkVarToDim ::- MonadUnify m =>+ (MonadUnify m) => Usage -> BreadCrumbs -> VName ->@@ -833,7 +840,7 @@ checkVar _ _ = pure () -- | Assert that this type must be one of the given primitive types.-mustBeOneOf :: MonadUnify m => [PrimType] -> Usage -> StructType -> m ()+mustBeOneOf :: (MonadUnify m) => [PrimType] -> Usage -> StructType -> m () mustBeOneOf [req_t] usage t = unify usage (Scalar (Prim req_t)) t mustBeOneOf ts usage t = do t' <- normType t@@ -852,7 +859,7 @@ <+> dquotes (pretty t) <+> "with any of " <> commasep (map pretty ts) <> "." -linkVarToTypes :: MonadUnify m => Usage -> VName -> [PrimType] -> m ()+linkVarToTypes :: (MonadUnify m) => Usage -> VName -> [PrimType] -> m () linkVarToTypes usage vn ts = do vn_constraint <- M.lookup vn <$> getConstraints case vn_constraint of@@ -926,7 +933,7 @@ "Type" <+> prettyName vn <+> "does not support equality." zeroOrderTypeWith ::- MonadUnify m =>+ (MonadUnify m) => Usage -> BreadCrumbs -> StructType ->@@ -957,7 +964,7 @@ -- | Assert that this type must be zero-order. zeroOrderType ::- MonadUnify m => Usage -> T.Text -> StructType -> m ()+ (MonadUnify m) => Usage -> T.Text -> StructType -> m () zeroOrderType usage desc = zeroOrderTypeWith usage $ breadCrumb bc noBreadCrumbs where@@ -1003,7 +1010,7 @@ bc = Matching $ "When checking" <+> textwrap desc unifySharedFields ::- MonadUnify m =>+ (MonadUnify m) => UnifySizes m -> Usage -> [VName] ->@@ -1016,7 +1023,7 @@ unifyWith onDims usage bound (breadCrumb (MatchingFields [f]) bcs) t1 t2 unifySharedConstructors ::- MonadUnify m =>+ (MonadUnify m) => UnifySizes m -> Usage -> [VName] ->@@ -1039,7 +1046,7 @@ -- | In @mustHaveConstr usage c t fs@, the type @t@ must have a -- constructor named @c@ that takes arguments of types @ts@. mustHaveConstr ::- MonadUnify m =>+ (MonadUnify m) => Usage -> Name -> StructType ->@@ -1076,7 +1083,7 @@ unify usage t $ Scalar $ Sum $ M.singleton c fs mustHaveFieldWith ::- MonadUnify m =>+ (MonadUnify m) => UnifySizes m -> Usage -> [VName] ->@@ -1118,7 +1125,7 @@ -- | Assert that some type must have a field with this name and type. mustHaveField ::- MonadUnify m =>+ (MonadUnify m) => Usage -> Name -> StructType ->@@ -1126,7 +1133,7 @@ mustHaveField usage = mustHaveFieldWith (unifySizes usage) usage mempty noBreadCrumbs newDimOnMismatch ::- MonadUnify m =>+ (MonadUnify m) => SrcLoc -> StructType -> StructType ->@@ -1152,7 +1159,7 @@ -- | Like unification, but creates new size variables where mismatches -- occur. Returns the new dimensions thus created. unifyMostCommon ::- MonadUnify m =>+ (MonadUnify m) => Usage -> StructType -> StructType ->
unittests/Futhark/IR/Mem/IxFun/Alg.hs view
@@ -9,7 +9,7 @@ coerce, slice, flatSlice,- rebase,+ expand, shape, index, disjoint,@@ -47,10 +47,10 @@ | Reshape (IxFun num) (Shape num) | Coerce (IxFun num) (Shape num) | OffsetIndex (IxFun num) num- | Rebase (IxFun num) (IxFun num)+ | Expand num num (IxFun num) deriving (Eq, Show) -instance Pretty num => Pretty (IxFun num) where+instance (Pretty num) => Pretty (IxFun num) where pretty (Direct dims) = "Direct" <> parens (commasep $ map pretty dims) pretty (Permute fun perm) = pretty fun <> pretty perm@@ -66,8 +66,8 @@ <> parens (pretty oldshape) pretty (OffsetIndex fun i) = pretty fun <> "->offset_index" <> parens (pretty i)- pretty (Rebase new_base fun) =- "rebase(" <> pretty new_base <> ", " <> pretty fun <> ")"+ pretty (Expand o p fun) =+ "expand(" <> pretty o <> "," <+> pretty p <> "," <+> pretty fun <> ")" iota :: Shape num -> IxFun num iota = Direct@@ -84,8 +84,8 @@ flatSlice :: IxFun num -> FlatSlice num -> IxFun num flatSlice = FlatIndex -rebase :: IxFun num -> IxFun num -> IxFun num-rebase = Rebase+expand :: num -> num -> IxFun num -> IxFun num+expand = Expand reshape :: IxFun num -> Shape num -> IxFun num reshape = Reshape@@ -94,7 +94,7 @@ coerce = Reshape shape ::- IntegralExp num =>+ (IntegralExp num) => IxFun num -> Shape num shape (Direct dims) =@@ -111,7 +111,7 @@ dims shape (OffsetIndex ixfun _) = shape ixfun-shape (Rebase _ ixfun) =+shape (Expand _ _ ixfun) = shape ixfun index ::@@ -147,27 +147,8 @@ d : ds -> index (Index fun (Slice (DimSlice i (d - i) 1 : map (unitSlice 0) ds))) is [] -> error "index: OffsetIndex: underlying index function has rank zero"-index (Rebase new_base fun) is =- let fun' = case fun of- Direct old_shape ->- if old_shape == shape new_base- then new_base- else reshape new_base old_shape- Permute ixfun perm ->- permute (rebase new_base ixfun) perm- Index ixfun iis ->- slice (rebase new_base ixfun) iis- FlatIndex ixfun iis ->- flatSlice (rebase new_base ixfun) iis- Reshape ixfun new_shape ->- reshape (rebase new_base ixfun) new_shape- Coerce ixfun new_shape ->- coerce (rebase new_base ixfun) new_shape- OffsetIndex ixfun s ->- offsetIndex (rebase new_base ixfun) s- r@Rebase {} ->- r- in index fun' is+index (Expand o p ixfun) is =+ o + p * index ixfun is allPoints :: (IntegralExp num, Enum num) => [num] -> [[num]] allPoints dims =
unittests/Futhark/IR/Mem/IxFunTests.hs view
@@ -5,6 +5,7 @@ ) where +import Data.Bifunctor import Data.Function ((&)) import Data.List qualified as L import Data.Map qualified as M@@ -57,14 +58,22 @@ resAlg = map (IxFunAlg.index ixfunAlg) points errorMessage = T.unpack . docText $- "lmad ixfun: " <> pretty ixfunLMAD- </> "alg ixfun: " <> pretty ixfunAlg- </> "lmad shape: " <> pretty lmadShape- </> "alg shape: " <> pretty algShape- </> "lmad points length: " <> pretty (length resLMAD)- </> "alg points length: " <> pretty (length resAlg)- </> "lmad points: " <> pretty resLMAD- </> "alg points: " <> pretty resAlg+ "lmad ixfun: "+ <> pretty ixfunLMAD+ </> "alg ixfun: "+ <> pretty ixfunAlg+ </> "lmad shape: "+ <> pretty lmadShape+ </> "alg shape: "+ <> pretty algShape+ </> "lmad points length: "+ <> pretty (length resLMAD)+ </> "alg points length: "+ <> pretty (length resAlg)+ </> "lmad points: "+ <> pretty resLMAD+ </> "alg points: "+ <> pretty resAlg in (lmadShape == algShape && resLMAD == resAlg) @? errorMessage compareIxFuns Nothing ixfunAlg = assertFailure $@@ -81,8 +90,10 @@ compareOpsFailure (Just ixfunLMAD, ixfunAlg) = assertFailure . T.unpack . docText $ "Not supposed to be representable as LMAD."- </> "lmad ixfun: " <> pretty ixfunLMAD- </> "alg ixfun: " <> pretty ixfunAlg+ </> "lmad ixfun: "+ <> pretty ixfunLMAD+ </> "alg ixfun: "+ <> pretty ixfunAlg -- XXX: Clean this up. n :: Int@@ -111,12 +122,10 @@ test_reshape_slice_iota3, test_complex1, test_complex2,- test_rebase1,- test_rebase2,- test_rebase3,- test_rebase4_5,- test_rebase6,- test_rebase7,+ test_expand1,+ test_expand2,+ test_expand3,+ test_expand4, test_flatSlice_iota, test_slice_flatSlice_iota, test_flatSlice_flatSlice_iota,@@ -235,105 +244,44 @@ ixfun' = slice ixfun slice1 in ixfun' -test_rebase1 :: [TestTree]-test_rebase1 =- singleton . testCase "rebase 1" . compareOpsFailure $- let slice_base =- Slice- [ DimFix (n `P.div` 2),- DimSlice 2 (n - 2) 1,- DimSlice 3 (n - 3) 1- ]- ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]- ixfn_orig = permute (iota [n - 3, n - 2]) [1, 0]- ixfn_rebase = rebase ixfn_base ixfn_orig- in ixfn_rebase--test_rebase2 :: [TestTree]-test_rebase2 =- singleton . testCase "rebase 2" . compareOpsFailure $- let slice_base =- Slice- [ DimFix (n `P.div` 2),- DimSlice (n - 1) (n - 2) (-1),- DimSlice (n - 1) (n - 3) (-1)- ]- slice_orig =- Slice- [ DimSlice (n - 4) (n - 3) (-1),- DimSlice (n - 3) (n - 2) (-1)- ]- ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]- ixfn_orig = permute (slice (iota [n - 3, n - 2]) slice_orig) [1, 0]- ixfn_rebase = rebase ixfn_base ixfn_orig- in ixfn_rebase--test_rebase3 :: [TestTree]-test_rebase3 =- singleton . testCase "rebase full orig but not monotonic" . compareOpsFailure $- let n2 = (n - 2) `P.div` 3- n3 = (n - 3) `P.div` 2- slice_base =- Slice- [ DimFix (n `P.div` 2),- DimSlice (n - 1) n2 (-3),- DimSlice (n - 1) n3 (-2)- ]- slice_orig =- Slice- [ DimSlice (n3 - 1) n3 (-1),- DimSlice (n2 - 1) n2 (-1)- ]- ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]- ixfn_orig = permute (slice (iota [n3, n2]) slice_orig) [1, 0]- ixfn_rebase = rebase ixfn_base ixfn_orig- in ixfn_rebase--test_rebase4_5 :: [TestTree]-test_rebase4_5 =- let n2 = (n - 2) `P.div` 3- n3 = (n - 3) `P.div` 2- slice_base =- Slice- [ DimFix (n `P.div` 2),- DimSlice (n - 1) n2 (-3),- DimSlice 3 n3 2- ]- slice_orig =- Slice- [ DimSlice (n3 - 1) n3 (-1),- DimSlice 0 n2 1- ]- ixfn_base = permute (slice (iota [n, n, n]) slice_base) [1, 0]- ixfn_orig = permute (slice (iota [n3, n2]) slice_orig) [1, 0]- in [ testCase "rebase mixed monotonicities" . compareOpsFailure $- rebase ixfn_base ixfn_orig- ]- -- Imitates a case from memory expansion.-test_rebase6 :: [TestTree]-test_rebase6 =- [ testCase "rebase . slice1 . iota" . compareOps $- rebase- (slice (iota [n, n, n]) (Slice [DimSlice 0 n 1, DimSlice 0 n 1]))- ( slice- (iota [n, n])- (Slice [DimSlice 1 (n - 1) 1, DimSlice 0 n 1])- )+test_expand1 :: [TestTree]+test_expand1 =+ [ testCase "expand . iota1d" . compareOps $+ expand t nt (iota [n]) ]+ where+ t = 3+ nt = 7 -- Imitates another case from memory expansion.-test_rebase7 :: [TestTree]-test_rebase7 =- [ testCase "rebase . slice2 . iota" . compareOps $- rebase- (slice (iota [n, n, n]) (Slice [DimSlice 0 n 1, DimSlice 0 n 1]))- ( slice- (iota [n, n])- (Slice [DimSlice 0 (n - 1) 1, DimSlice 0 n 1])- )+test_expand2 :: [TestTree]+test_expand2 =+ [ testCase "expand . iota2d" . compareOps $+ expand t nt (iota [n, n]) ]+ where+ t = 3+ nt = 7 +test_expand3 :: [TestTree]+test_expand3 =+ [ testCase "expand . permute . iota2d" . compareOps $+ expand t nt (permute (iota [n, n `div` 2]) [1, 0])+ ]+ where+ t = 3+ nt = 7++test_expand4 :: [TestTree]+test_expand4 =+ [ testCase "expand . slice . iota1d" . compareOps $+ expand t nt (slice (iota [n]) (Slice [DimSlice (n `div` 2) (n `div` 2) 1]))+ ]+ where+ t = 3+ nt = 7+ test_flatSlice_iota :: [TestTree] test_flatSlice_iota = singleton . testCase "flatSlice . iota" . compareOps $@@ -365,7 +313,7 @@ test_flatSlice_transpose_slice_iota :: [TestTree] test_flatSlice_transpose_slice_iota =- singleton . testCase "flatSlice . transpose . slice . iota " . compareOpsFailure $+ singleton . testCase "flatSlice . transpose . slice . iota " . compareOps $ flatSlice (permute (slice (iota [20, 20]) $ Slice [DimSlice 1 5 2, DimSlice 0 5 2]) [1, 0]) flat_slice_1 where flat_slice_1 = FlatSlice 1 [FlatDimIndex 2 2]@@ -464,37 +412,37 @@ lm1 = IxFunLMAD.LMAD (add_nw64 (mul64 block_size_12121 i_12214) (mul_nw64 (add_nw64 gtid_12553 1) (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))- [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (add64 1 i_12214) gtid_12553) 1) 0,- IxFunLMAD.LMADDim 1 (block_size_12121 + 1) 1+ [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (add64 1 i_12214) gtid_12553) 1),+ IxFunLMAD.LMADDim 1 (block_size_12121 + 1) ] lm2 = IxFunLMAD.LMAD (block_size_12121 * i_12214)- [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0,- IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1+ [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553,+ IxFunLMAD.LMADDim 1 (1 + block_size_12121) ] lm_w = IxFunLMAD.LMAD (add_nw64 (add64 (add64 1 n_blab) (mul64 block_size_12121 i_12214)) (mul_nw64 gtid_12553 (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))- [ IxFunLMAD.LMADDim n_blab block_size_12121 0,- IxFunLMAD.LMADDim 1 block_size_12121 1+ [ IxFunLMAD.LMADDim n_blab block_size_12121,+ IxFunLMAD.LMADDim 1 block_size_12121 ] lm_blocks = IxFunLMAD.LMAD (block_size_12121 * i_12214 + n_blab + 1)- [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (i_12214 + 1) 0,- IxFunLMAD.LMADDim n_blab block_size_12121 1,- IxFunLMAD.LMADDim 1 block_size_12121 2+ [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (i_12214 + 1),+ IxFunLMAD.LMADDim n_blab block_size_12121,+ IxFunLMAD.LMADDim 1 block_size_12121 ] lm_lower_per = IxFunLMAD.LMAD (block_size_12121 * i_12214)- [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (i_12214 + 1) 0,- IxFunLMAD.LMADDim 1 (block_size_12121 + 1) 1+ [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (i_12214 + 1),+ IxFunLMAD.LMADDim 1 (block_size_12121 + 1) ] res1 = disjointTester asserts lessthans lm1 lm_w@@ -523,36 +471,40 @@ lm1 = IxFunLMAD.LMAD (add_nw64 (add64 n_blab (sub64 (sub64 (mul64 n_blab (add64 1 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) 1)) (mul_nw64 (add_nw64 gtid_12553 1) (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))- [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (sub64 (sub64 (sdiv64 (sub64 n_blab 1) block_size_12121) i_12214) 1) gtid_12553) 1) 0,- IxFunLMAD.LMADDim n_blab block_size_12121 1+ [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (sub64 (sub64 (sdiv64 (sub64 n_blab 1) block_size_12121) i_12214) 1) gtid_12553) 1),+ IxFunLMAD.LMADDim n_blab block_size_12121 ] lm2 = IxFunLMAD.LMAD (add_nw64 (sub64 (sub64 (mul64 n_blab (add64 1 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) 1) (mul_nw64 (add_nw64 gtid_12553 1) (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))- [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (sub64 (sub64 (sdiv64 (sub64 n_blab 1) block_size_12121) i_12214) 1) gtid_12553) 1) 0,- IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1+ [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) (sub_nw64 (sub_nw64 (sub64 (sub64 (sdiv64 (sub64 n_blab 1) block_size_12121) i_12214) 1) gtid_12553) 1),+ IxFunLMAD.LMADDim 1 (1 + block_size_12121) ] lm3 = IxFunLMAD.LMAD (add64 n_blab (sub64 (sub64 (mul64 n_blab (add64 1 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) 1))- [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0,- IxFunLMAD.LMADDim n_blab block_size_12121 1+ [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553,+ IxFunLMAD.LMADDim n_blab block_size_12121 ] lm4 = IxFunLMAD.LMAD (sub64 (sub64 (mul64 n_blab (add64 1 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) 1)- [ IxFunLMAD.LMADDim (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121)) gtid_12553 0,- IxFunLMAD.LMADDim 1 (1 + block_size_12121) 1+ [ IxFunLMAD.LMADDim+ (add_nw64 (mul_nw64 block_size_12121 n_blab) (mul_nw64 (-1) block_size_12121))+ gtid_12553,+ IxFunLMAD.LMADDim+ 1+ (1 + block_size_12121) ] lm_w = IxFunLMAD.LMAD (add_nw64 (sub64 (mul64 n_blab (add64 2 (mul64 block_size_12121 (add64 1 i_12214)))) block_size_12121) (mul_nw64 gtid_12553 (sub64 (mul64 block_size_12121 n_blab) block_size_12121)))- [ IxFunLMAD.LMADDim n_blab block_size_12121 0,- IxFunLMAD.LMADDim 1 block_size_12121 1+ [ IxFunLMAD.LMADDim n_blab block_size_12121,+ IxFunLMAD.LMADDim 1 block_size_12121 ] res1 = disjointTester asserts lessthans lm1 lm_w@@ -562,9 +514,11 @@ in res1 && res2 && res3 && res4 @? "Failed " <> show [res1, res2, res3, res4], testCase "lud long" $ let lessthans =- [ (step, num_blocks - 1 :: TPrimExp Int64 VName)+ [ bimap+ (head . namesToList . freeIn)+ untyped+ (step, num_blocks - 1 :: TPrimExp Int64 VName) ]- & map (\(v, p) -> (head $ namesToList $ freeIn v, untyped p)) step = TPrimExp $ LeafExp (foo "step" 1337) $ IntType Int64 @@ -573,29 +527,29 @@ lm1 = IxFunLMAD.LMAD (1024 * num_blocks * (1 + step) + 1024 * step)- [ IxFunLMAD.LMADDim (1024 * num_blocks) (num_blocks - step - 1) 0,- IxFunLMAD.LMADDim 32 32 1,- IxFunLMAD.LMADDim 1 32 2+ [ IxFunLMAD.LMADDim (1024 * num_blocks) (num_blocks - step - 1),+ IxFunLMAD.LMADDim 32 32,+ IxFunLMAD.LMADDim 1 32 ] lm_w1 = IxFunLMAD.LMAD (1024 * num_blocks * step + 1024 * step)- [ IxFunLMAD.LMADDim 32 32 0,- IxFunLMAD.LMADDim 1 32 1+ [ IxFunLMAD.LMADDim 32 32,+ IxFunLMAD.LMADDim 1 32 ] lm_w2 = IxFunLMAD.LMAD ((1 + step) * 1024 * num_blocks + (1 + step) * 1024)- [ IxFunLMAD.LMADDim (1024 * num_blocks) (num_blocks - step - 1) 0,- IxFunLMAD.LMADDim 1024 (num_blocks - step - 1) 1,- IxFunLMAD.LMADDim 1024 1 2,- IxFunLMAD.LMADDim 32 1 3,- IxFunLMAD.LMADDim 128 8 4,- IxFunLMAD.LMADDim 4 8 5,- IxFunLMAD.LMADDim 32 4 6,- IxFunLMAD.LMADDim 1 4 7+ [ IxFunLMAD.LMADDim (1024 * num_blocks) (num_blocks - step - 1),+ IxFunLMAD.LMADDim 1024 (num_blocks - step - 1),+ IxFunLMAD.LMADDim 1024 1,+ IxFunLMAD.LMADDim 32 1,+ IxFunLMAD.LMADDim 128 8,+ IxFunLMAD.LMADDim 4 8,+ IxFunLMAD.LMADDim 32 4,+ IxFunLMAD.LMADDim 1 4 ] asserts =
unittests/Futhark/IR/Mem/IxFunWrapper.hs view
@@ -8,7 +8,7 @@ coerce, slice, flatSlice,- rebase,+ expand, ) where @@ -25,13 +25,13 @@ type IxFun num = (Maybe (I.IxFun num), IA.IxFun num) iota ::- IntegralExp num =>+ (IntegralExp num) => Shape num -> IxFun num iota x = (Just $ I.iota x, IA.iota x) permute ::- IntegralExp num =>+ (IntegralExp num) => IxFun num -> Permutation -> IxFun num@@ -63,11 +63,12 @@ IxFun num -> FlatSlice num -> IxFun num-flatSlice (l, a) x = (join (I.flatSlice <$> l <*> pure x), IA.flatSlice a x)+flatSlice (l, a) x = (I.flatSlice <$> l <*> pure x, IA.flatSlice a x) -rebase ::+expand :: (Eq num, IntegralExp num) =>- IxFun num ->+ num ->+ num -> IxFun num -> IxFun num-rebase (l, a) (l1, a1) = (join (I.rebase <$> l <*> l1), IA.rebase a a1)+expand o p (lf, af) = (I.expand o p =<< lf, IA.expand o p af)
unittests/Language/Futhark/SyntaxTests.hs view
@@ -54,7 +54,7 @@ let (s', '_' : tag) = span (/= '_') s in VName (fromString s') (read tag) -instance IsString v => IsString (QualName v) where+instance (IsString v) => IsString (QualName v) where fromString = QualName [] . fromString instance IsString UncheckedTypeExp where