packages feed

futhark 0.20.6 → 0.20.7

raw patch · 80 files changed

+1664/−1039 lines, 80 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Futhark.CodeGen.ImpCode: Index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> ExpLeaf
- Futhark.CodeGen.ImpCode: ScalarVar :: VName -> ExpLeaf
- Futhark.CodeGen.ImpCode: data ExpLeaf
- Futhark.CodeGen.ImpCode: index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp
- Futhark.CodeGen.ImpCode: instance Futhark.IR.Prop.Names.FreeIn Futhark.CodeGen.ImpCode.ExpLeaf
- Futhark.CodeGen.ImpCode: instance GHC.Classes.Eq Futhark.CodeGen.ImpCode.ExpLeaf
- Futhark.CodeGen.ImpCode: instance GHC.Show.Show Futhark.CodeGen.ImpCode.ExpLeaf
- Futhark.CodeGen.ImpCode: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.CodeGen.ImpCode.ExpLeaf
- Futhark.CodeGen.ImpCode: vi32 :: VName -> TExp Int32
- Futhark.CodeGen.ImpCode: vi64 :: VName -> TExp Int64
- Futhark.CodeGen.ImpCode.GPU: Index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> ExpLeaf
- Futhark.CodeGen.ImpCode.GPU: ScalarVar :: VName -> ExpLeaf
- Futhark.CodeGen.ImpCode.GPU: data ExpLeaf
- Futhark.CodeGen.ImpCode.GPU: index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp
- Futhark.CodeGen.ImpCode.GPU: vi32 :: VName -> TExp Int32
- Futhark.CodeGen.ImpCode.GPU: vi64 :: VName -> TExp Int64
- Futhark.CodeGen.ImpCode.Multicore: Index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> ExpLeaf
- Futhark.CodeGen.ImpCode.Multicore: ScalarVar :: VName -> ExpLeaf
- Futhark.CodeGen.ImpCode.Multicore: data ExpLeaf
- Futhark.CodeGen.ImpCode.Multicore: index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp
- Futhark.CodeGen.ImpCode.Multicore: vi32 :: VName -> TExp Int32
- Futhark.CodeGen.ImpCode.Multicore: vi64 :: VName -> TExp Int64
- Futhark.CodeGen.ImpCode.OpenCL: Index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> ExpLeaf
- Futhark.CodeGen.ImpCode.OpenCL: ScalarVar :: VName -> ExpLeaf
- Futhark.CodeGen.ImpCode.OpenCL: data ExpLeaf
- Futhark.CodeGen.ImpCode.OpenCL: index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp
- Futhark.CodeGen.ImpCode.OpenCL: vi32 :: VName -> TExp Int32
- Futhark.CodeGen.ImpCode.OpenCL: vi64 :: VName -> TExp Int64
- Futhark.CodeGen.ImpCode.Sequential: Index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> ExpLeaf
- Futhark.CodeGen.ImpCode.Sequential: ScalarVar :: VName -> ExpLeaf
- Futhark.CodeGen.ImpCode.Sequential: data ExpLeaf
- Futhark.CodeGen.ImpCode.Sequential: index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp
- Futhark.CodeGen.ImpCode.Sequential: vi32 :: VName -> TExp Int32
- Futhark.CodeGen.ImpCode.Sequential: vi64 :: VName -> TExp Int64
- Futhark.Optimise.Simplify.Engine: type SimplifiedBody rep a = ((a, UsageTable), Stms (Wise rep))
+ Futhark.Analysis.UsageTable: consumedU :: Usages
+ Futhark.CodeGen.ImpCode: Read :: VName -> VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Code a
+ Futhark.CodeGen.ImpCode.GPU: f32le :: a -> TPrimExp Float a
+ Futhark.CodeGen.ImpCode.GPU: f32pe :: SubExp -> TPrimExp Float VName
+ Futhark.CodeGen.ImpCode.GPU: f64le :: a -> TPrimExp Double a
+ Futhark.CodeGen.ImpCode.GPU: f64pe :: SubExp -> TPrimExp Double VName
+ Futhark.CodeGen.ImpCode.GPU: instance GHC.Classes.Eq Futhark.CodeGen.ImpCode.GPU.Fence
+ Futhark.CodeGen.ImpCode.GPU: instance GHC.Classes.Ord Futhark.CodeGen.ImpCode.GPU.Fence
+ Futhark.CodeGen.ImpCode.GPU: le32 :: a -> TPrimExp Int32 a
+ Futhark.CodeGen.ImpCode.GPU: le64 :: a -> TPrimExp Int64 a
+ Futhark.CodeGen.ImpCode.GPU: pe32 :: SubExp -> TPrimExp Int32 VName
+ Futhark.CodeGen.ImpCode.GPU: pe64 :: SubExp -> TPrimExp Int64 VName
+ Futhark.CodeGen.ImpCode.GPU: primExpFromExp :: (MonadFail m, RepTypes rep) => (VName -> m (PrimExp v)) -> Exp rep -> m (PrimExp v)
+ Futhark.CodeGen.ImpCode.GPU: primExpFromSubExp :: PrimType -> SubExp -> PrimExp VName
+ Futhark.CodeGen.ImpCode.GPU: primExpFromSubExpM :: Applicative m => (VName -> m (PrimExp v)) -> SubExp -> m (PrimExp v)
+ Futhark.CodeGen.ImpCode.GPU: primExpSlice :: Slice SubExp -> Slice (TPrimExp Int64 VName)
+ Futhark.CodeGen.ImpCode.GPU: replaceInPrimExp :: (a -> PrimType -> PrimExp b) -> PrimExp a -> PrimExp b
+ Futhark.CodeGen.ImpCode.GPU: replaceInPrimExpM :: Monad m => (a -> PrimType -> m (PrimExp b)) -> PrimExp a -> m (PrimExp b)
+ Futhark.CodeGen.ImpCode.GPU: subExpSlice :: MonadBuilder m => Slice (TPrimExp Int64 VName) -> m (Slice SubExp)
+ Futhark.CodeGen.ImpCode.GPU: substituteInPrimExp :: Ord v => Map v (PrimExp v) -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: f32le :: a -> TPrimExp Float a
+ Futhark.CodeGen.ImpCode.Multicore: f32pe :: SubExp -> TPrimExp Float VName
+ Futhark.CodeGen.ImpCode.Multicore: f64le :: a -> TPrimExp Double a
+ Futhark.CodeGen.ImpCode.Multicore: f64pe :: SubExp -> TPrimExp Double VName
+ Futhark.CodeGen.ImpCode.Multicore: le32 :: a -> TPrimExp Int32 a
+ Futhark.CodeGen.ImpCode.Multicore: le64 :: a -> TPrimExp Int64 a
+ Futhark.CodeGen.ImpCode.Multicore: pe32 :: SubExp -> TPrimExp Int32 VName
+ Futhark.CodeGen.ImpCode.Multicore: pe64 :: SubExp -> TPrimExp Int64 VName
+ Futhark.CodeGen.ImpCode.Multicore: primExpFromExp :: (MonadFail m, RepTypes rep) => (VName -> m (PrimExp v)) -> Exp rep -> m (PrimExp v)
+ Futhark.CodeGen.ImpCode.Multicore: primExpFromSubExp :: PrimType -> SubExp -> PrimExp VName
+ Futhark.CodeGen.ImpCode.Multicore: primExpFromSubExpM :: Applicative m => (VName -> m (PrimExp v)) -> SubExp -> m (PrimExp v)
+ Futhark.CodeGen.ImpCode.Multicore: primExpSlice :: Slice SubExp -> Slice (TPrimExp Int64 VName)
+ Futhark.CodeGen.ImpCode.Multicore: replaceInPrimExp :: (a -> PrimType -> PrimExp b) -> PrimExp a -> PrimExp b
+ Futhark.CodeGen.ImpCode.Multicore: replaceInPrimExpM :: Monad m => (a -> PrimType -> m (PrimExp b)) -> PrimExp a -> m (PrimExp b)
+ Futhark.CodeGen.ImpCode.Multicore: subExpSlice :: MonadBuilder m => Slice (TPrimExp Int64 VName) -> m (Slice SubExp)
+ Futhark.CodeGen.ImpCode.Multicore: substituteInPrimExp :: Ord v => Map v (PrimExp v) -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.OpenCL: f32le :: a -> TPrimExp Float a
+ Futhark.CodeGen.ImpCode.OpenCL: f32pe :: SubExp -> TPrimExp Float VName
+ Futhark.CodeGen.ImpCode.OpenCL: f64le :: a -> TPrimExp Double a
+ Futhark.CodeGen.ImpCode.OpenCL: f64pe :: SubExp -> TPrimExp Double VName
+ Futhark.CodeGen.ImpCode.OpenCL: le32 :: a -> TPrimExp Int32 a
+ Futhark.CodeGen.ImpCode.OpenCL: le64 :: a -> TPrimExp Int64 a
+ Futhark.CodeGen.ImpCode.OpenCL: pe32 :: SubExp -> TPrimExp Int32 VName
+ Futhark.CodeGen.ImpCode.OpenCL: pe64 :: SubExp -> TPrimExp Int64 VName
+ Futhark.CodeGen.ImpCode.OpenCL: primExpFromExp :: (MonadFail m, RepTypes rep) => (VName -> m (PrimExp v)) -> Exp rep -> m (PrimExp v)
+ Futhark.CodeGen.ImpCode.OpenCL: primExpFromSubExp :: PrimType -> SubExp -> PrimExp VName
+ Futhark.CodeGen.ImpCode.OpenCL: primExpFromSubExpM :: Applicative m => (VName -> m (PrimExp v)) -> SubExp -> m (PrimExp v)
+ Futhark.CodeGen.ImpCode.OpenCL: primExpSlice :: Slice SubExp -> Slice (TPrimExp Int64 VName)
+ Futhark.CodeGen.ImpCode.OpenCL: replaceInPrimExp :: (a -> PrimType -> PrimExp b) -> PrimExp a -> PrimExp b
+ Futhark.CodeGen.ImpCode.OpenCL: replaceInPrimExpM :: Monad m => (a -> PrimType -> m (PrimExp b)) -> PrimExp a -> m (PrimExp b)
+ Futhark.CodeGen.ImpCode.OpenCL: subExpSlice :: MonadBuilder m => Slice (TPrimExp Int64 VName) -> m (Slice SubExp)
+ Futhark.CodeGen.ImpCode.OpenCL: substituteInPrimExp :: Ord v => Map v (PrimExp v) -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Sequential: f32le :: a -> TPrimExp Float a
+ Futhark.CodeGen.ImpCode.Sequential: f32pe :: SubExp -> TPrimExp Float VName
+ Futhark.CodeGen.ImpCode.Sequential: f64le :: a -> TPrimExp Double a
+ Futhark.CodeGen.ImpCode.Sequential: f64pe :: SubExp -> TPrimExp Double VName
+ Futhark.CodeGen.ImpCode.Sequential: le32 :: a -> TPrimExp Int32 a
+ Futhark.CodeGen.ImpCode.Sequential: le64 :: a -> TPrimExp Int64 a
+ Futhark.CodeGen.ImpCode.Sequential: pe32 :: SubExp -> TPrimExp Int32 VName
+ Futhark.CodeGen.ImpCode.Sequential: pe64 :: SubExp -> TPrimExp Int64 VName
+ Futhark.CodeGen.ImpCode.Sequential: primExpFromExp :: (MonadFail m, RepTypes rep) => (VName -> m (PrimExp v)) -> Exp rep -> m (PrimExp v)
+ Futhark.CodeGen.ImpCode.Sequential: primExpFromSubExp :: PrimType -> SubExp -> PrimExp VName
+ Futhark.CodeGen.ImpCode.Sequential: primExpFromSubExpM :: Applicative m => (VName -> m (PrimExp v)) -> SubExp -> m (PrimExp v)
+ Futhark.CodeGen.ImpCode.Sequential: primExpSlice :: Slice SubExp -> Slice (TPrimExp Int64 VName)
+ Futhark.CodeGen.ImpCode.Sequential: replaceInPrimExp :: (a -> PrimType -> PrimExp b) -> PrimExp a -> PrimExp b
+ Futhark.CodeGen.ImpCode.Sequential: replaceInPrimExpM :: Monad m => (a -> PrimType -> m (PrimExp b)) -> PrimExp a -> m (PrimExp b)
+ Futhark.CodeGen.ImpCode.Sequential: subExpSlice :: MonadBuilder m => Slice (TPrimExp Int64 VName) -> m (Slice SubExp)
+ Futhark.CodeGen.ImpCode.Sequential: substituteInPrimExp :: Ord v => Map v (PrimExp v) -> PrimExp v -> PrimExp v
+ Futhark.Optimise.Simplify.Engine: simplifyStmsWithUsage :: SimplifiableRep rep => UsageTable -> Stms (Wise rep) -> SimpleM rep (Stms (Wise rep))
+ Futhark.Optimise.Simplify.Rep: addOpWisdom :: CanBeWise op => op -> OpWithWisdom op
+ Futhark.Optimise.Simplify.Rep: informFunDef :: Informing rep => FunDef rep -> FunDef (Wise rep)
+ Futhark.Optimise.Simplify.Rep: informLambda :: Informing rep => Lambda rep -> Lambda (Wise rep)
+ Futhark.Optimise.Simplify.Rep: informStms :: Informing rep => Stms rep -> Stms (Wise rep)
+ Futhark.Optimise.Simplify.Rep: type Informing rep = (ASTRep rep, CanBeWise (Op rep))
+ Futhark.Pass.ExtractKernels.Distribution: scopeOfKernelNest :: LParamInfo rep ~ Type => KernelNest -> Scope rep
+ Futhark.Util: nubByOrd :: (a -> a -> Ordering) -> [a] -> [a]
+ Language.Futhark.Prop: valBindBound :: ValBindBase Info VName -> [VName]
+ Language.Futhark.TypeChecker.Types: renameRetType :: MonadTypeChecker m => StructRetType -> m StructRetType
- Futhark.Analysis.PrimExp.Parse: pPrimExp :: Parser (v, PrimType) -> Parser (PrimExp v)
+ Futhark.Analysis.PrimExp.Parse: pPrimExp :: PrimType -> Parser v -> Parser (PrimExp v)
- Futhark.CodeGen.ImpCode: type Exp = PrimExp ExpLeaf
+ Futhark.CodeGen.ImpCode: type Exp = PrimExp VName
- Futhark.CodeGen.ImpCode: type TExp t = TPrimExp t ExpLeaf
+ Futhark.CodeGen.ImpCode: type TExp t = TPrimExp t VName
- Futhark.CodeGen.ImpCode.GPU: pattern Write :: () => VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp -> Code a
+ Futhark.CodeGen.ImpCode.GPU: pattern Read :: () => VName -> VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Code a
- Futhark.CodeGen.ImpCode.GPU: type Exp = PrimExp ExpLeaf
+ Futhark.CodeGen.ImpCode.GPU: type Exp = PrimExp VName
- Futhark.CodeGen.ImpCode.GPU: type TExp t = TPrimExp t ExpLeaf
+ Futhark.CodeGen.ImpCode.GPU: type TExp t = TPrimExp t VName
- Futhark.CodeGen.ImpCode.Multicore: pattern Write :: () => VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp -> Code a
+ Futhark.CodeGen.ImpCode.Multicore: pattern Read :: () => VName -> VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Code a
- Futhark.CodeGen.ImpCode.Multicore: type Exp = PrimExp ExpLeaf
+ Futhark.CodeGen.ImpCode.Multicore: type Exp = PrimExp VName
- Futhark.CodeGen.ImpCode.Multicore: type TExp t = TPrimExp t ExpLeaf
+ Futhark.CodeGen.ImpCode.Multicore: type TExp t = TPrimExp t VName
- Futhark.CodeGen.ImpCode.OpenCL: pattern Write :: () => VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp -> Code a
+ Futhark.CodeGen.ImpCode.OpenCL: pattern Read :: () => VName -> VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Code a
- Futhark.CodeGen.ImpCode.OpenCL: type Exp = PrimExp ExpLeaf
+ Futhark.CodeGen.ImpCode.OpenCL: type Exp = PrimExp VName
- Futhark.CodeGen.ImpCode.OpenCL: type TExp t = TPrimExp t ExpLeaf
+ Futhark.CodeGen.ImpCode.OpenCL: type TExp t = TPrimExp t VName
- Futhark.CodeGen.ImpCode.Sequential: pattern Write :: () => VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp -> Code a
+ Futhark.CodeGen.ImpCode.Sequential: pattern Read :: () => VName -> VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Code a
- Futhark.CodeGen.ImpCode.Sequential: type Exp = PrimExp ExpLeaf
+ Futhark.CodeGen.ImpCode.Sequential: type Exp = PrimExp VName
- Futhark.CodeGen.ImpCode.Sequential: type TExp t = TPrimExp t ExpLeaf
+ Futhark.CodeGen.ImpCode.Sequential: type TExp t = TPrimExp t VName
- Futhark.CodeGen.ImpGen: dArray :: VName -> PrimType -> ShapeBase SubExp -> MemBind -> ImpM rep r op ()
+ Futhark.CodeGen.ImpGen: dArray :: VName -> PrimType -> ShapeBase SubExp -> VName -> IxFun -> ImpM rep r op ()
- Futhark.CodeGen.ImpGen: sArray :: String -> PrimType -> ShapeBase SubExp -> MemBind -> ImpM rep r op VName
+ Futhark.CodeGen.ImpGen: sArray :: String -> PrimType -> ShapeBase SubExp -> VName -> IxFun -> ImpM rep r op VName
- Futhark.IR.GPU.Simplify: simplifyKernelOp :: (SimplifiableRep rep, BodyDec rep ~ ()) => SimplifyOp rep op -> HostOp rep op -> SimpleM rep (HostOp (Wise rep) (OpWithWisdom op), Stms (Wise rep))
+ Futhark.IR.GPU.Simplify: simplifyKernelOp :: (SimplifiableRep rep, BodyDec rep ~ ()) => SimplifyOp rep op -> HostOp (Wise rep) op -> SimpleM rep (HostOp (Wise rep) op, Stms (Wise rep))
- Futhark.IR.GPUMem: simplifyStms :: (HasScope GPUMem m, MonadFreshNames m) => Stms GPUMem -> m (SymbolTable (Wise GPUMem), Stms GPUMem)
+ Futhark.IR.GPUMem: simplifyStms :: (HasScope GPUMem m, MonadFreshNames m) => Stms GPUMem -> m (Stms GPUMem)
- Futhark.IR.MC.Op: simplifyMCOp :: (SimplifiableRep rep, BodyDec rep ~ ()) => SimplifyOp rep op -> MCOp rep op -> SimpleM rep (MCOp (Wise rep) (OpWithWisdom op), Stms (Wise rep))
+ Futhark.IR.MC.Op: simplifyMCOp :: (SimplifiableRep rep, BodyDec rep ~ ()) => SimplifyOp rep op -> MCOp (Wise rep) op -> SimpleM rep (MCOp (Wise rep) op, Stms (Wise rep))
- Futhark.IR.Mem.Simplify: simpleGeneric :: SimplifyMemory rep inner => (OpWithWisdom inner -> UsageTable) -> SimplifyOp rep inner -> SimpleOps rep
+ Futhark.IR.Mem.Simplify: simpleGeneric :: SimplifyMemory rep inner => (OpWithWisdom inner -> UsageTable) -> SimplifyOp rep (OpWithWisdom inner) -> SimpleOps rep
- Futhark.IR.Mem.Simplify: simplifyStmsGeneric :: (HasScope rep m, MonadFreshNames m, SimplifyMemory rep inner) => SimpleOps rep -> Stms rep -> m (SymbolTable (Wise rep), Stms rep)
+ Futhark.IR.Mem.Simplify: simplifyStmsGeneric :: (HasScope rep m, MonadFreshNames m, SimplifyMemory rep inner) => SimpleOps rep -> Stms rep -> m (Stms rep)
- Futhark.IR.SOACS.Simplify: simplifyConsts :: MonadFreshNames m => Stms SOACS -> m (SymbolTable (Wise SOACS), Stms SOACS)
+ Futhark.IR.SOACS.Simplify: simplifyConsts :: MonadFreshNames m => Stms SOACS -> m (Stms SOACS)
- Futhark.IR.SOACS.Simplify: simplifySOAC :: SimplifiableRep rep => SimplifyOp rep (SOAC rep)
+ Futhark.IR.SOACS.Simplify: simplifySOAC :: SimplifiableRep rep => SimplifyOp rep (SOAC (Wise rep))
- Futhark.IR.SOACS.Simplify: simplifyStms :: (HasScope SOACS m, MonadFreshNames m) => Stms SOACS -> m (SymbolTable (Wise SOACS), Stms SOACS)
+ Futhark.IR.SOACS.Simplify: simplifyStms :: (HasScope SOACS m, MonadFreshNames m) => Stms SOACS -> m (Stms SOACS)
- Futhark.IR.SegOp: simplifySegOp :: (SimplifiableRep rep, BodyDec rep ~ (), Simplifiable lvl) => SegOp lvl rep -> SimpleM rep (SegOp lvl (Wise rep), Stms (Wise rep))
+ Futhark.IR.SegOp: simplifySegOp :: (SimplifiableRep rep, BodyDec rep ~ (), Simplifiable lvl) => SegOp lvl (Wise rep) -> SimpleM rep (SegOp lvl (Wise rep), Stms (Wise rep))
- Futhark.Optimise.Simplify: SimpleOps :: (SymbolTable (Wise rep) -> Pat (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 rep) -> SimpleOps rep
+ Futhark.Optimise.Simplify: SimpleOps :: (SymbolTable (Wise rep) -> Pat (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: [simplifyOpS] :: SimpleOps rep -> SimplifyOp rep (Op rep)
+ Futhark.Optimise.Simplify: [simplifyOpS] :: SimpleOps rep -> SimplifyOp rep (Op (Wise rep))
- Futhark.Optimise.Simplify: bindableSimpleOps :: (SimplifiableRep rep, Buildable rep) => SimplifyOp rep (Op rep) -> SimpleOps rep
+ Futhark.Optimise.Simplify: bindableSimpleOps :: (SimplifiableRep rep, Buildable rep) => SimplifyOp rep (Op (Wise rep)) -> SimpleOps rep
- Futhark.Optimise.Simplify: simplifyStms :: (MonadFreshNames m, SimplifiableRep rep) => SimpleOps rep -> RuleBook (Wise rep) -> HoistBlockers rep -> Scope rep -> Stms rep -> m (SymbolTable (Wise rep), Stms rep)
+ Futhark.Optimise.Simplify: simplifyStms :: (MonadFreshNames m, SimplifiableRep rep) => SimpleOps rep -> RuleBook (Wise rep) -> HoistBlockers rep -> Scope rep -> Stms rep -> m (Stms rep)
- Futhark.Optimise.Simplify: type SimplifyOp rep op = op -> SimpleM rep (OpWithWisdom op, Stms (Wise rep))
+ Futhark.Optimise.Simplify: type SimplifyOp rep op = op -> SimpleM rep (op, Stms (Wise rep))
- Futhark.Optimise.Simplify.Engine: SimpleOps :: (SymbolTable (Wise rep) -> Pat (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 rep) -> SimpleOps rep
+ Futhark.Optimise.Simplify.Engine: SimpleOps :: (SymbolTable (Wise rep) -> Pat (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: [simplifyOpS] :: SimpleOps rep -> SimplifyOp rep (Op rep)
+ Futhark.Optimise.Simplify.Engine: [simplifyOpS] :: SimpleOps rep -> SimplifyOp rep (Op (Wise rep))
- Futhark.Optimise.Simplify.Engine: bindableSimpleOps :: (SimplifiableRep rep, Buildable rep) => SimplifyOp rep (Op rep) -> SimpleOps rep
+ Futhark.Optimise.Simplify.Engine: bindableSimpleOps :: (SimplifiableRep rep, Buildable rep) => SimplifyOp rep (Op (Wise rep)) -> SimpleOps rep
- Futhark.Optimise.Simplify.Engine: blockIf :: SimplifiableRep rep => BlockPred (Wise rep) -> SimpleM rep (SimplifiedBody rep a) -> SimpleM rep ((Stms (Wise rep), a), Stms (Wise rep))
+ Futhark.Optimise.Simplify.Engine: blockIf :: SimplifiableRep rep => BlockPred (Wise rep) -> Stms (Wise rep) -> SimpleM rep (a, UsageTable) -> SimpleM rep (a, Stms (Wise rep), Stms (Wise rep))
- Futhark.Optimise.Simplify.Engine: hoistStms :: SimplifiableRep rep => RuleBook (Wise rep) -> BlockPred (Wise rep) -> SymbolTable (Wise rep) -> UsageTable -> Stms (Wise rep) -> SimpleM rep (Stms (Wise rep), Stms (Wise rep))
+ Futhark.Optimise.Simplify.Engine: hoistStms :: SimplifiableRep rep => RuleBook (Wise rep) -> BlockPred (Wise rep) -> Stms (Wise rep) -> SimpleM rep (a, UsageTable) -> SimpleM rep (a, Stms (Wise rep), Stms (Wise rep))
- Futhark.Optimise.Simplify.Engine: simplifyBody :: SimplifiableRep rep => [Diet] -> Body rep -> SimpleM rep (SimplifiedBody rep Result)
+ Futhark.Optimise.Simplify.Engine: simplifyBody :: SimplifiableRep rep => BlockPred (Wise rep) -> UsageTable -> [Usages] -> Body (Wise rep) -> SimpleM rep (Stms (Wise rep), Body (Wise rep))
- Futhark.Optimise.Simplify.Engine: simplifyFun :: SimplifiableRep rep => FunDef rep -> SimpleM rep (FunDef (Wise rep))
+ Futhark.Optimise.Simplify.Engine: simplifyFun :: SimplifiableRep rep => FunDef (Wise rep) -> SimpleM rep (FunDef (Wise rep))
- Futhark.Optimise.Simplify.Engine: simplifyLambda :: SimplifiableRep rep => Lambda rep -> SimpleM rep (Lambda (Wise rep), Stms (Wise rep))
+ Futhark.Optimise.Simplify.Engine: simplifyLambda :: SimplifiableRep rep => Lambda (Wise rep) -> SimpleM rep (Lambda (Wise rep), Stms (Wise rep))
- Futhark.Optimise.Simplify.Engine: simplifyLambdaNoHoisting :: SimplifiableRep rep => Lambda rep -> SimpleM rep (Lambda (Wise rep))
+ Futhark.Optimise.Simplify.Engine: simplifyLambdaNoHoisting :: SimplifiableRep rep => Lambda (Wise rep) -> SimpleM rep (Lambda (Wise rep))
- Futhark.Optimise.Simplify.Engine: simplifyStms :: SimplifiableRep rep => Stms rep -> SimpleM rep (a, Stms (Wise rep)) -> SimpleM rep (a, Stms (Wise rep))
+ Futhark.Optimise.Simplify.Engine: simplifyStms :: SimplifiableRep rep => Stms (Wise rep) -> SimpleM rep (Stms (Wise rep))
- Futhark.Optimise.Simplify.Engine: type SimplifyOp rep op = op -> SimpleM rep (OpWithWisdom op, Stms (Wise rep))
+ Futhark.Optimise.Simplify.Engine: type SimplifyOp rep op = op -> SimpleM rep (op, Stms (Wise rep))
- Futhark.Pass.ExplicitAllocations: simplifiable :: (SimplifiableRep rep, ExpDec rep ~ (), BodyDec rep ~ (), Mem rep inner) => (OpWithWisdom inner -> UsageTable) -> (inner -> SimpleM rep (OpWithWisdom inner, Stms (Wise rep))) -> SimpleOps rep
+ Futhark.Pass.ExplicitAllocations: simplifiable :: (SimplifiableRep rep, ExpDec rep ~ (), BodyDec rep ~ (), Mem rep inner) => (OpWithWisdom inner -> UsageTable) -> (OpWithWisdom inner -> SimpleM rep (OpWithWisdom inner, Stms (Wise rep))) -> SimpleOps rep
- Futhark.Pass.ExplicitAllocations.Seq: simplifiable :: (SimplifiableRep rep, ExpDec rep ~ (), BodyDec rep ~ (), Mem rep inner) => (OpWithWisdom inner -> UsageTable) -> (inner -> SimpleM rep (OpWithWisdom inner, Stms (Wise rep))) -> SimpleOps rep
+ Futhark.Pass.ExplicitAllocations.Seq: simplifiable :: (SimplifiableRep rep, ExpDec rep ~ (), BodyDec rep ~ (), Mem rep inner) => (OpWithWisdom inner -> UsageTable) -> (OpWithWisdom inner -> SimpleM rep (OpWithWisdom inner, Stms (Wise rep))) -> SimpleOps rep
- Futhark.Pass.ExtractKernels.BlockedKernel: segRed :: (MonadFreshNames m, DistRep rep, HasScope rep m) => SegOpLevel rep -> Pat rep -> SubExp -> [SegBinOp rep] -> Lambda rep -> [VName] -> [(VName, SubExp)] -> [KernelInput] -> m (Stms rep)
+ Futhark.Pass.ExtractKernels.BlockedKernel: segRed :: (MonadFreshNames m, DistRep rep, HasScope rep m) => SegOpLevel rep -> Pat rep -> Certs -> SubExp -> [SegBinOp rep] -> Lambda rep -> [VName] -> [(VName, SubExp)] -> [KernelInput] -> m (Stms rep)
- Futhark.Pass.ExtractKernels.BlockedKernel: segScan :: (MonadFreshNames m, DistRep rep, HasScope rep m) => SegOpLevel rep -> Pat rep -> SubExp -> [SegBinOp rep] -> Lambda rep -> [VName] -> [(VName, SubExp)] -> [KernelInput] -> m (Stms rep)
+ Futhark.Pass.ExtractKernels.BlockedKernel: segScan :: (MonadFreshNames m, DistRep rep, HasScope rep m) => SegOpLevel rep -> Pat rep -> Certs -> SubExp -> [SegBinOp rep] -> Lambda rep -> [VName] -> [(VName, SubExp)] -> [KernelInput] -> m (Stms rep)
- Futhark.Pass.ExtractKernels.Distribution: scopeOfLoopNesting :: DistRep rep => LoopNesting -> Scope rep
+ Futhark.Pass.ExtractKernels.Distribution: scopeOfLoopNesting :: LParamInfo rep ~ Type => LoopNesting -> Scope rep
- Futhark.Transform.CopyPropagate: copyPropagateInStms :: (MonadFreshNames m, SimplifiableRep rep) => SimpleOps rep -> Scope rep -> Stms rep -> m (SymbolTable (Wise rep), Stms rep)
+ Futhark.Transform.CopyPropagate: copyPropagateInStms :: (MonadFreshNames m, SimplifiableRep rep) => SimpleOps rep -> Scope rep -> Stms rep -> m (Stms rep)
- Language.Futhark.Syntax: ValBind :: Maybe (f EntryPoint) -> vn -> Maybe (TypeExp vn) -> f (StructRetType, [VName]) -> [TypeParamBase vn] -> [PatBase f vn] -> ExpBase f vn -> Maybe DocComment -> [AttrInfo vn] -> SrcLoc -> ValBindBase f vn
+ Language.Futhark.Syntax: ValBind :: Maybe (f EntryPoint) -> vn -> Maybe (TypeExp vn) -> f StructRetType -> [TypeParamBase vn] -> [PatBase f vn] -> ExpBase f vn -> Maybe DocComment -> [AttrInfo vn] -> SrcLoc -> ValBindBase f vn
- Language.Futhark.Syntax: [valBindRetType] :: ValBindBase f vn -> f (StructRetType, [VName])
+ Language.Futhark.Syntax: [valBindRetType] :: ValBindBase f vn -> f StructRetType
- Language.Futhark.TypeChecker.Terms: checkFunDef :: (Name, Maybe UncheckedTypeExp, [UncheckedTypeParam], [UncheckedPat], UncheckedExp, SrcLoc) -> TypeM (VName, [TypeParam], [Pat], Maybe (TypeExp VName), StructRetType, [VName], Exp)
+ Language.Futhark.TypeChecker.Terms: checkFunDef :: (Name, Maybe UncheckedTypeExp, [UncheckedTypeParam], [UncheckedPat], UncheckedExp, SrcLoc) -> TypeM (VName, [TypeParam], [Pat], Maybe (TypeExp VName), StructRetType, Exp)

Files

docs/conf.py view
@@ -35,7 +35,7 @@ # ones. extensions = [     'sphinx.ext.todo',-    'sphinx.ext.mathjax',+    'sphinx.ext.mathjax' ]  # Add any paths that contain templates here, relative to this directory.@@ -83,7 +83,7 @@  # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files.-exclude_patterns = ['_build']+exclude_patterns = ['_build', 'lib']  # The reST default role (used for this markup: `text`) to use for all # documents.@@ -109,8 +109,8 @@     tokens = {         'root': [             (r'(if|then|else|let|loop|in|val|for|do|with|local|open|include|import|type|entry|module|while|module)\b', token.Keyword),-            (r"[a-zA-Z_][a-zA-Z0-9_']*", token.Name),-            (r"-- .*", token.Comment),+            (r"#?[a-zA-Z_][a-zA-Z0-9_']*", token.Name),+            (r"--.*", token.Comment),             (r'.', token.Text)         ]     }
docs/index.rst view
@@ -33,6 +33,7 @@    c-api.rst    js-api.rst    package-management.rst+   performance.rst    error-index.rst    server-protocol.rst    c-porting-guide.rst
docs/man/futhark-autotune.rst view
@@ -14,14 +14,14 @@ DESCRIPTION =========== -``futhark-autotune`` attemps to find optimal values for threshold+``futhark autotune`` attemps to find optimal values for threshold parameters given representative datasets.  This is done by repeatedly running running the program through :ref:`futhark-bench(1)` with-different values for the threshold parameters.  When-``futhark-autotune`` finishes tuning a program ``foo.fut``, the-results are written to ``foo.fut.tuning``, which will then-automatically be picked up by subsequent uses of-:ref:`futhark-bench(1)` and :ref:`futhark-test(1)`.+different values for the threshold parameters.  When ``futhark+autotune`` finishes tuning a program ``foo.fut``, the results are+written to ``foo.fut.tuning``, which will then automatically be picked+up by subsequent uses of :ref:`futhark-bench(1)` and+:ref:`futhark-test(1)`.   OPTIONS
+ docs/performance.rst view
@@ -0,0 +1,424 @@+.. _performance:++Writing Fast Futhark Programs+=============================++This document contains tips, tricks, and hints for writing efficient+Futhark code.  Ideally you'd need to know nothing more than an+abstract cost model, but sometimes it is useful to have an idea of how+the compiler will transform your program, what values look like in+memory, and what kind of code the compiler will generate for you.+These details are documented below.  Don't be discouraged by the+complexities mentioned here - most Futhark programs are written+without worrying about any of these details, and they still manage to+run with good performance.  This document focuses on corner cases and+pitfalls, which easily makes for depressing reading.++Parallelism+-----------++The Futhark compiler only generates parallel code for explicitly+parallel constructs such as ``map`` and ``reduce``.  A plain ``loop``+will *not* result in parallel code (unless the loop body itself+contains parallel operations).  The most important parallel constructs+are the *second-order array combinators* (SOACs) such as ``map`` and+``reduce``, but functions such as ``copy`` are also parallel.++When describing the asymptotic cost of a Futhark function, it is not+enough to give a traditional big-O measure of the total amount of+work.  Both ``foldl`` and ``reduce`` involve *O(n)* work, where *n* is+the size of the input array, but ``foldl`` is sequential while+``reduce`` is parallel, and this is an important distinction.  To make+this distinction, each function is described by *two* costs: the+*work*, which is the total amount of operations, and the *span*+(sometimes called *depth*) which is intuitively the "longest chain of+sequential dependencies".  We say that ``foldl`` has span *O(n)*,+while ``reduce`` has span *O(log(n))*.  This explains that+``reduce`` is more parallel than ``foldl``.  The documentation for a+Futhark function should mention both its work and span.  `See this+<https://sigkill.dk/writings/par/cost.html>`_ for more details on+parallel cost models and pointers to literature.++Scans and reductions+~~~~~~~~~~~~~~~~~~~~++The ``scan`` and ``reduce`` SOACs are rather inefficient when their+operators are on arrays.  If possible, use tuples instead (see+:ref:`performance-small-arrays`).  The one exception is when the+operator is a ``map2`` or equivalent.  Example::++  reduce (map2 (+)) (replicate n 0) xss++Such "vectorised" operators are typically handled quite efficiently.+Although to be on the safe side, you can rewrite the above by+interchanging the ``reduce`` and ``map``::++  map (reduce (+) 0) (transpose xss)++Avoid reductions over tiny arrays, e.g. ``reduce (+) 0 [x,y,z]``.  In+such cases the compiler will generate complex code to exploit a+negligible amount of parallelism.  Instead, just unroll the loop+manually (``x+y+z``) or perhaps use ``foldl (+) 0 [x,z,y]``, which+produces a sequential loop.++Histograms+~~~~~~~~~~++The ``reduce_by_index`` construct ("generalised histogram") has a+clever and adaptive implementation that handles multiple updates of+the same bin efficiently.  Its main weakness is when computing a very+large histogram (many millions of bins) where only a tiny fraction of+the bins are updated.  This is because the main mechanism for+optimising conflicts is by duplicating the histogram in memory, but+this is not efficient when it is very large.  If you know your program+involves such a situation, it may be better to implement the histogram+operation by sorting and then performing an irregular segmented+reduction.++Particularly with the GPU backends, ``reduce_by_index`` is much faster+when the operator involves a single 32-bit or 64-bit value.  Even if+you really want an 8-bit or 16-bit result, it may be faster to compute+it with a 32-bit or 64-bit type and manually mask off the excess bits.++Nested parallelism+~~~~~~~~~~~~~~~~~~++Futhark allows nested parallelism, understood as a parallel construct+used inside some other parallel construct.  The simplest example is+nested SOACs.  Example::++  map (\xs -> reduce (+) 0 xs) xss++Nested parallelism is allowed and encouraged, but its compilation to+efficient code is rather complicated, depending on the compiler+backend that is used.  The problem is that sometimes exploiting all+levels of parallelism is not optimal, yet how much to exploit depends+on run-time information that is not available to the compiler.++Sequential backends+!!!!!!!!!!!!!!!!!!!++The sequential backends are straightforward: all parallel operations+are compiled into sequential loops.  Due to Futhark's low-overhead+data representation (see below), this is often surprisingly efficient.++Multicore backend+!!!!!!!!!!!!!!!!!++Whenever the multicore backend encounters nested parallelism, it+generates two code versions: one where the nested parallel constructs+are also parallelised (possibly recursively involving further nested+parallelism), and one where they are turned into sequential loops.  At+runtime, based on the amount of work available and self-tuning+heuristics, the scheduler picks the version that it believes best+balances overhead with exploitation of parallelism.++GPU backends+!!!!!!!!!!!!++The GPU backends handle parallelism through an elaborate program+transformation called *incremental flattening*.  The full details are+beyond the scope of this document, but some properties are useful to+know of.  `See this paper+<https://futhark-lang.org/publications/ppopp19.pdf>`_ for more+details.++The main restriction is that the GPU backends can only handle+*regular* nested parallelism, meaning that the sizes of inner parallel+dimensions are invariant to the outer parallel dimensions.  For+example, this expression contains *irregular* nested parallelism::++  map (\i -> reduce (+) 0 (iota i)) is++This is because the size of the nested parallel construct is ``i``,+and ``i`` has a different value for every iteration of the outer+``map``.  The Futhark compiler will currently turn the irregular+constructs (here, the ``reduce``) into a sequential loop.  Depending+on how complicated the irregularity is, it may even refuse to generate+code entirely.++Incremental flattening is based on generating multiple code versions+to cater to different classes of datasets.  At run-time, one of these+versions will be picked for execution by comparing properties of the+input (its size) with a *threshold parameter*.  These threshold+parameters have sensible defaults, but for optimal performance, they+can be tuned with :ref:`futhark-autotune(1)`.++Value Representation+--------------------++The compiler discards all type abstraction when compiling.  Using the+module system to make a type abstract causes no run-time overhead.++Scalars+~~~~~~~++Scalar values (``i32``, ``f64``, ``bool``, etc) are represented as+themselves.  The internal representation does not distinguish signs,+so ``i32`` and ``u32`` have the same representation, and converting+between types that differ only in sign is free.++Tuples+~~~~~~++Tuples are flattened and then represented directly by their individual+components - there are no *tuple objects* at runtime.  A function that+takes an argument of type ``(f64,f64)`` corresponds to a C function+that takes two arguments of type ``double``.  This has one performance+implication: whenever you pass a tuple to a function, the *entire*+tuple is copied (except any embedded arrays, which are always passed+by reference, see below).  Due to the compiler's heavy use of+inlining, this is rarely a problem in practice, but it can be a+concern when using the ``loop`` construct with a large tuple as the+loop variant parameter.++Records+~~~~~~~++Records are turned into tuples by simply sorting their fields and+discarding the labels.  This means there is no overhead to using a+record compared to using a tuple.++Sum Types+~~~~~~~~~++A starting point, a sum type is turned into a tuple containing all the+payload components in order, prefixed with an `i8` tag to identify the+constructor.  For example,++.. code-block:: futhark++   #foo i32 bool | #bar i32++would be represented as a tuple of type++.. code-block:: futhark++   (i8, i32, bool, i32)++where the value++.. code-block:: futhark++   #foo 42 false++is represented as++.. code-block:: futhark++   (1, 42, false, 0)++where ``#foo`` is assigned the tag ``1`` because it is alphabetically+after ``#bar``.++To shrink the tuples, if multiple constructors have payload elements+of the *same* type, the compiler assigns them to the same elements in+the result tuple. The representation of the above sum type is actually+the following:++.. code-block:: futhark++   (i8, i32, bool)++The types must be the *same* for deduplication to take place - despite+`i32` and `f32` being of the same size, they cannot be assigned the+same tuple element.  This means that the type++.. code-block:: futhark++   #foo [n]i32 | #bar [n]i32++is efficiently represented as++.. code-block:: futhark++   (u8, [n]i32)+++.. code-block:: futhark++   #foo [n]i32 | #bar [n]f32++becomes++.. code-block:: futhark++   (u8, [n]i32, [n]f32)++which is not great.  Take caution when you use sum types with large+arrays in their payloads.++Functions+~~~~~~~~~++Higher-order functions are implemented via defunctionalisation.  At+run-time, they are represented by a record containing their lexical+closure.  Since the type system forbids putting functions in arrays,+this is essentially a constant cost, and not worth worrying about.++Arrays+~~~~~~++Arrays are the only Futhark values that are boxed - that is, are+stored on the heap.++The elements of an array are unboxed, stored adjacent to each other in+memory.  There is zero memory overhead except for the minuscule amount+needed to track the shape of the array.++Multidimensional arrays+!!!!!!!!!!!!!!!!!!!!!!!++At the surface language level, Futhark may appear to support "arrays+of arrays", and this is indeed a convenient aspect of its programming+model, but at runtime multi-dimensional arrays are stored in flattened+form.  A value of type ``[x][y]i32`` is laid out in memory simply as+one array containing *x\*y* integers.  This means that constructing an+array ``[x,y,x]`` can be (relatively) expensive if ``x``, ``y``, ``z``+are themselves large arrays, as they must be copied in their entirety.++Since arrays cannot contain other arrays, memory management only has+to be concerned with one level of indirection.  In practice, it means+that Futhark can use straightforward reference counting to keep track+of when to free the memory backing an array, as circular references+are not possible.  Further, since arrays tend to be large and+relatively few in number, the usual performance impact of naive+reference counting is not present.++Arrays of tuples+!!!!!!!!!!!!!!!!++For arrays of tuples, Futhark uses the so-called `structure of arrays+<https://en.wikipedia.org/wiki/AoS_and_SoA>`_ representation.  In+Futhark terms, an array ``[n](a,b,c)`` is at runtime represented as+the tuple ``([n]a,[n]b,[n]c)``.  This means that the final memory+representation always consists of arrays of scalars.++This has some significant implications.  For example, ``zip`` and+``unzip`` are very cheap, as the actual runtime representation is in+always "unzipped", so these functions don't actually have to do+anything.++Since records and sum types are represented as tuples, this also+explains how arrays of these are represented.++Element order+!!!!!!!!!!!!!++The exact in-memory element ordering is up to the compiler, and+depends on how the array is constructed and how it is used.  Absent+any other information, Futhark represents multidimensional arrays in+row-major order.  However, depending on how the array is traversed,+the compiler may insert code to represent it in some other order.  For+particularly tricky programs, an array may even be duplicated in+memory, represented in different ways, to ensure efficient traversal.+This means you should normally *not* worry about how to represent your+arrays to ensure coalesced access on GPUs or similar.  That is the+compiler's job.++Crucial Optimisations+---------------------++Some of the optimisations done by the Futhark compiler are important,+complex, or subtle enough that it may be useful to know how they work,+and how to write code that caters to their quirks.++Fusion+~~~~~~++Futhark performs fusion of SOACs.  For an expression ``map f (map g+A)``, then the compiler will optimise this into a single ``map`` with+the composition of ``f`` and ``g``, which prevents us from storing an+intermediate array in memory.  This is called *vertical fusion* or+*producer-consumer fusion*.  In this case the *producer* is ``map g``+and the *consumer* is ``map f``.++Fusion does not depend on the expressions being adjacent as in this+example, as the optimisation is performed on a data dependency graph+representing the program.  This means that you can decompose your+programs into many small parallel operations without worrying about+the overhead, as the compiler will fuse them together automatically.++Not all producer-consumer relationships between SOACs can be fused.+Generally, ``map`` can always be fused as a producer, but ``scan``,+``reduce``, and similar SOACs can only act as consumers.++*Horizontal fusion* occurs when two SOACs take as input the same+array, but are not themselves in a producer-consumer relationship.+Example::++   (map f xs, map g xs)++Such cases are fused into a single operation that traverses ``xs``+just once.  More than two SOACs can be involved in horizontal fusion,+and they need not be of the same kind (e.g. one could be a ``map`` and+the other a ``reduce``).++Free Operations+---------------++Some operations such as array slicing, ``take``, ``drop``,+``transpose`` and ``reverse`` are "free" in the sense that they merely+return a different view of some underlying array.  In most cases they+have constant cost, no matter the size of the array they operate on.+This is because they are index space transformations that simply+result in different code being generated when the arrays are+eventually used.++However, there are some cases where the compiler is forced to manifest+such a "view" as an actual array in memory, which involves a full+copy.  An incomplete list follows:++* Any array returned by an entry point is converted to row-major+  order.++* An array returned by an ``if`` branch may be copied if its+  representation is substantially different from that of the other+  branch.++* An array returned by a ``loop`` body may be copied if its+  representation is substantially different from that of the initial+  loop values.++* An array is copied whenever it becomes the element of another+  multidimensional array.  This is most obviously the case for array+  literals (``[x,y,z]``), but also for ``map`` expressions where the+  mapped function returns an array.++Note that this notion of "views" is not part of the Futhark type+system - it is merely an implementation detail.  Strictly speaking,+all functions that return an array (e.g. ``reverse``) should be+considered to have a cost proportional to the size of the array, even+if that cost will almost never actually be paid at run-time.  If you+want to be sure no copy takes place, it may be better to explicitly+maintain tuples of indexes into some other array.++.. _performance-small-arrays:++Small Arrays+------------++The compiler assumes arrays are "large", which for example means that+operations across them are worth parallelising.  It also means they+are boxed and heap-allocated, even when the size is a small constant.+This can cause unexpectedly bad performance when using small+constant-size arrays (say, five elements or less).  Consider using+tuples or records instead.  `This post+<https://futhark-lang.org/blog/2019-01-13-giving-programmers-what-they-want.html>`_+contains more information on how and why.  If in doubt, try both and+measure which is faster.++Inlining+--------++The compiler currently inlines all functions at their call site,+unless they have been marked with the ``noinline`` attribute (see+:ref:`attributes`).  This can lead to code explosion, which mostly+results in slow compile times, but can also affect run-time+performance.  In many cases this is currently unavoidable, but+sometimes the program can be rewritten such that instead of calling+the same function in multiple places, it is called in a single place,+in a loop.  E.g. we might rewrite ``f x (f y (f z v))`` as::++  loop acc = v for a in [z,y,x] do+    f a acc
docs/requirements.txt view
@@ -1,2 +1,2 @@ pyyaml>=4.2b1-sphinx==3.0.3+sphinx>=4.2.0
futhark.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name:           futhark-version:        0.20.6+version:        0.20.7 synopsis:       An optimising compiler for a functional, array-oriented language.  description:    Futhark is a small programming language designed to be compiled to
prelude/prelude.fut view
@@ -16,6 +16,10 @@ -- | Create integer from double-precision float. let t64 (x: f64): i32 = i32.f64 x +-- | Negate a boolean.  `not x` is the same as `!x`.  This function is+-- mostly useful for passing to `map+let not (x: bool): bool = !x+ -- | Semantically just identity, but serves as an optimisation -- inhibitor.  The compiler will treat this function as a black box. -- You can use this to work around optimisation deficiencies (or
rts/python/scalar.py view
@@ -104,10 +104,10 @@   return signed(max(unsigned(x),unsigned(y)))  def fminN(x,y):-  return min(x,y)+  return np.fmin(x,y)  def fmaxN(x,y):-  return max(x,y)+  return np.fmax(x,y)  def powN(x,y):   return x ** y
rts/python/values.py view
@@ -621,7 +621,7 @@         out.write("%di32" % v)     elif type(v) == np.int64:         out.write("%di64" % v)-    elif type(v) in [np.bool, np.bool_]:+    elif type(v) in [bool, np.bool_]:         if v:             out.write("true")         else:
src/Futhark/Analysis/PrimExp/Parse.hs view
@@ -45,14 +45,27 @@ parens = between (lexeme "(") (lexeme ")")  -- | Parse a 'PrimExp' given a leaf parser.-pPrimExp :: Parser (v, PrimType) -> Parser (PrimExp v)-pPrimExp pLeaf =+pPrimExp :: PrimType -> Parser v -> Parser (PrimExp v)+pPrimExp t pLeaf =   choice-    [ uncurry LeafExp <$> pLeaf,+    [ flip LeafExp t <$> pLeaf,       ValueExp <$> pPrimValue,-      BinOpExp <$> pBinOp <*> pPrimExp pLeaf <*> pPrimExp pLeaf,-      CmpOpExp <$> pCmpOp <*> pPrimExp pLeaf <*> pPrimExp pLeaf,-      ConvOpExp <$> pConvOp <*> pPrimExp pLeaf,-      UnOpExp <$> pUnOp <*> pPrimExp pLeaf,-      parens $ pPrimExp pLeaf+      pBinOp >>= binOpExp,+      pCmpOp >>= cmpOpExp,+      pConvOp >>= convOpExp,+      pUnOp >>= unOpExp,+      parens $ pPrimExp t pLeaf     ]+  where+    binOpExp op =+      BinOpExp op+        <$> pPrimExp (binOpType op) pLeaf+        <*> pPrimExp (binOpType op) pLeaf+    cmpOpExp op =+      CmpOpExp op+        <$> pPrimExp (cmpOpType op) pLeaf+        <*> pPrimExp (cmpOpType op) pLeaf+    convOpExp op =+      ConvOpExp op <$> pPrimExp (fst (convOpType op)) pLeaf+    unOpExp op =+      UnOpExp op <$> pPrimExp (unOpType op) pLeaf
src/Futhark/Analysis/UsageTable.hs view
@@ -19,6 +19,7 @@     sizeUsage,     sizeUsages,     Usages,+    consumedU,     usageInStm,   ) where
src/Futhark/CodeGen/Backends/GenericC.hs view
@@ -271,8 +271,9 @@     [dest]       | isBuiltInFunction fname ->         stm [C.cstm|$id:dest = $id:(funName fname)($args:args');|]-    _ ->-      item [C.citem|if ($id:(funName fname)($args:args') != 0) { err = 1; goto cleanup; }|]+    _ -> do+      free_all_mem <- freeAllocatedMem+      item [C.citem|if ($id:(funName fname)($args:args') != 0) { $items:free_all_mem err = 1; goto cleanup; }|]  -- | A set of operations that fail for every operation involving -- non-default memory spaces.  Uses plain pointers and @malloc@ for@@ -1902,7 +1903,7 @@   return $ derefPointer dest i [C.cty|$tyquals:quals' $ty:elemtype*|]  compileExpToName :: String -> PrimType -> Exp -> CompilerM op s VName-compileExpToName _ _ (LeafExp (ScalarVar v) _) =+compileExpToName _ _ (LeafExp v _) =   return v compileExpToName desc t e = do   desc' <- newVName desc@@ -1911,29 +1912,7 @@   return desc'  compileExp :: Exp -> CompilerM op s C.Exp-compileExp = compilePrimExp compileLeaf-  where-    compileLeaf (ScalarVar src) =-      return [C.cexp|$id:src|]-    compileLeaf (Index _ _ Unit __ _) =-      pure $ C.toExp UnitValue mempty-    compileLeaf (Index src (Count iexp) restype DefaultSpace vol) = do-      src' <- rawMem src-      fmap (fromStorage restype) $-        derefPointer src'-          <$> compileExp (untyped iexp)-          <*> pure [C.cty|$tyquals:(volQuals vol) $ty:(primStorageType restype)*|]-    compileLeaf (Index src (Count iexp) restype (Space space) vol) =-      fmap (fromStorage restype) . join $-        asks envReadScalar-          <*> rawMem src-          <*> compileExp (untyped iexp)-          <*> pure (primStorageType restype)-          <*> pure space-          <*> pure vol-    compileLeaf (Index src (Count iexp) _ ScalarSpace {} _) = do-      iexp' <- compileExp $ untyped iexp-      return [C.cexp|$id:src[$exp:iexp']|]+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@@ -2146,6 +2125,29 @@       <*> pure space       <*> pure vol       <*> (toStorage elemtype <$> compileExp elemexp)+compileCode (Read x _ _ Unit __ _) =+  stm [C.cstm|$id:x = $exp:(UnitValue);|]+compileCode (Read x src (Count iexp) restype DefaultSpace vol) = do+  src' <- rawMem src+  e <-+    fmap (fromStorage restype) $+      derefPointer src'+        <$> compileExp (untyped iexp)+        <*> pure [C.cty|$tyquals:(volQuals vol) $ty:(primStorageType restype)*|]+  stm [C.cstm|$id:x = $exp:e;|]+compileCode (Read x src (Count iexp) restype (Space space) vol) = do+  e <-+    fmap (fromStorage restype) . join $+      asks envReadScalar+        <*> rawMem src+        <*> compileExp (untyped iexp)+        <*> pure (primStorageType restype)+        <*> pure space+        <*> pure vol+  stm [C.cstm|$id:x = $exp:e;|]+compileCode (Read x src (Count iexp) _ ScalarSpace {} _) = do+  iexp' <- compileExp $ untyped iexp+  stm [C.cstm|$id:x = $id:src[$exp:iexp'];|] compileCode (DeclareMem name space) =   declMem name space compileCode (DeclareScalar name vol t) = do@@ -2178,7 +2180,7 @@ -- For assignments of the form 'x = x OP e', we generate C assignment -- operators to make the resulting code slightly nicer.  This has no -- effect on performance.-compileCode (SetScalar dest (BinOpExp op (LeafExp (ScalarVar x) _) y))+compileCode (SetScalar dest (BinOpExp op (LeafExp x _) y))   | dest == x,     Just f <- assignmentOperator op = do     y' <- compileExp y
src/Futhark/CodeGen/Backends/GenericPython.hs view
@@ -1172,24 +1172,7 @@   simpleCall (futharkFun (pretty h)) <$> mapM (compilePrimExp f) args  compileExp :: Imp.Exp -> CompilerM op s PyExp-compileExp = compilePrimExp compileLeaf-  where-    compileLeaf (Imp.ScalarVar vname) =-      compileVar vname-    compileLeaf (Imp.Index _ _ Unit _ _) =-      return $ compilePrimValue UnitValue-    compileLeaf (Imp.Index src (Imp.Count iexp) restype (Imp.Space space) _) =-      join $-        asks envReadScalar-          <*> compileVar src-          <*> compileExp (Imp.untyped iexp)-          <*> pure restype-          <*> pure space-    compileLeaf (Imp.Index src (Imp.Count iexp) bt _ _) = do-      iexp' <- compileExp $ Imp.untyped iexp-      let bt' = compilePrimType bt-      src' <- compileVar src-      return $ fromStorage bt $ simpleCall "indexArray" [src', iexp', Var bt']+compileExp = compilePrimExp compileVar  errorMsgString :: Imp.ErrorMsg Imp.Exp -> CompilerM op s (String, [PyExp]) errorMsgString (Imp.ErrorMsg parts) = do@@ -1351,4 +1334,22 @@   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+  x' <- compileVar x+  iexp' <- compileExp $ Imp.untyped iexp+  let bt' = compilePrimType bt+  src' <- compileVar src+  stm $ Assign x' $ fromStorage bt $ simpleCall "indexArray" [src', iexp', Var bt'] compileCode Imp.Skip = return ()
src/Futhark/CodeGen/ImpCode.hs view
@@ -27,15 +27,11 @@     SpaceId,     Code (..),     PrimValue (..),-    ExpLeaf (..),     Exp,     TExp,     Volatility (..),     Arg (..),     var,-    vi32,-    vi64,-    index,     ErrorMsg (..),     ErrorMsgPart (..),     errorMsgArgTypes,@@ -56,6 +52,7 @@     module Language.Futhark.Core,     module Futhark.IR.Primitive,     module Futhark.Analysis.PrimExp,+    module Futhark.Analysis.PrimExp.Convert,     module Futhark.IR.GPU.Sizes,     module Futhark.IR.Prop.Names,   )@@ -66,6 +63,7 @@ import qualified Data.Set as S import Data.Traversable import Futhark.Analysis.PrimExp+import Futhark.Analysis.PrimExp.Convert import Futhark.IR.GPU.Sizes (Count (..)) import Futhark.IR.Pretty () import Futhark.IR.Primitive@@ -244,10 +242,14 @@     -- @mem@ offset by @i@ elements of type @t@.  The     -- 'Space' argument is the memory space of @mem@     -- (technically redundant, but convenient).  Note that-    -- /reading/ is done with an 'Exp' ('Index').+    -- /reading/ is done with an 'Exp' ('Read').     Write VName (Count Elements (TExp Int64)) PrimType Space Volatility Exp   | -- | Set a scalar variable.     SetScalar VName Exp+  | -- | Read a scalar from memory from memory.  The first 'VName' is+    -- the target scalar variable, and the remaining arguments have+    -- the same meaning as with 'Write'.+    Read VName VName (Count Elements (TExp Int64)) PrimType Space Volatility   | -- | Must be in same space.     SetMem VName VName Space   | -- | Function call.  The results are written to the@@ -338,22 +340,12 @@ calledFuncs (Call _ f _) = S.singleton f calledFuncs _ = mempty --- | The leaves of an 'Exp'.-data ExpLeaf-  = -- | A scalar variable.  The type is stored in the-    -- 'LeafExp' constructor itself.-    ScalarVar VName-  | -- | Reading a value from memory.  The arguments have-    -- the same meaning as with 'Write'.-    Index VName (Count Elements (TExp Int64)) PrimType Space Volatility-  deriving (Eq, Show)- -- | A side-effect free expression whose execution will produce a -- single primitive value.-type Exp = PrimExp ExpLeaf+type Exp = PrimExp VName  -- | Like 'Exp', but with a required/known type.-type TExp t = TPrimExp t ExpLeaf+type TExp t = TPrimExp t VName  -- | A function call argument. data Arg@@ -380,21 +372,9 @@ withElemType :: Count Elements (TExp Int64) -> PrimType -> Count Bytes (TExp Int64) withElemType (Count e) t = bytes $ sExt64 e * primByteSize t --- | Turn a 'VName' into a 'Imp.ScalarVar'.+-- | Turn a 'VName' into a 'Exp'. var :: VName -> PrimType -> Exp-var = LeafExp . ScalarVar---- | Turn a 'VName' into a v'Int32' 'Imp.ScalarVar'.-vi32 :: VName -> TExp Int32-vi32 = TPrimExp . flip var (IntType Int32)---- | Turn a 'VName' into a v'Int64' 'Imp.ScalarVar'.-vi64 :: VName -> TExp Int64-vi64 = TPrimExp . flip var (IntType Int64)---- | Concise wrapper for using 'Index'.-index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp-index arr i t s vol = LeafExp (Index arr i t s vol) t+var = LeafExp  -- Prettyprinting definitions. @@ -495,6 +475,13 @@       vol' = case vol of         Volatile -> text "volatile "         Nonvolatile -> mempty+  ppr (Read name v is bt space vol) =+    ppr name <+> text "<-"+      <+> ppr v <> langle <> vol' <> ppr bt <> ppr space <> rangle <> brackets (ppr is)+    where+      vol' = case vol of+        Volatile -> text "volatile "+        Nonvolatile -> mempty   ppr (SetScalar name val) =     ppr name <+> text "<-" <+> ppr val   ppr (SetMem dest from space) =@@ -533,16 +520,6 @@   ppr (MemArg m) = ppr m   ppr (ExpArg e) = ppr e -instance Pretty ExpLeaf where-  ppr (ScalarVar v) =-    ppr v-  ppr (Index v is bt space vol) =-    ppr v <> langle <> vol' <> ppr bt <> ppr space <> rangle <> brackets (ppr is)-    where-      vol' = case vol of-        Volatile -> text "volatile "-        Nonvolatile -> mempty- instance Functor Functions where   fmap = fmapDefault @@ -598,6 +575,8 @@     pure $ Copy dest destoffset destspace src srcoffset srcspace size   traverse _ (Write name i bt val space vol) =     pure $ Write name i bt val space vol+  traverse _ (Read x name i bt space vol) =+    pure $ Read x name i bt space vol   traverse _ (SetScalar name val) =     pure $ SetScalar name val   traverse _ (SetMem dest from space) =@@ -669,6 +648,8 @@     freeIn' x <> freeIn' y   freeIn' (Write v i _ _ _ e) =     freeIn' v <> freeIn' i <> freeIn' e+  freeIn' (Read x v i _ _ _) =+    freeIn' x <> freeIn' v <> freeIn' i   freeIn' (SetScalar x y) =     freeIn' x <> freeIn' y   freeIn' (Call dests _ args) =@@ -685,10 +666,6 @@     maybe mempty freeIn' v   freeIn' (TracePrint msg) =     foldMap freeIn' msg--instance FreeIn ExpLeaf where-  freeIn' (Index v e _ _ _) = freeIn' v <> freeIn' e-  freeIn' (ScalarVar v) = freeIn' v  instance FreeIn Arg where   freeIn' (MemArg m) = freeIn' m
src/Futhark/CodeGen/ImpCode/GPU.hs view
@@ -136,9 +136,9 @@         )  -- | When we do a barrier or fence, is it at the local or global--- level?+-- level?  By the 'Ord' instance, global is greater than local. data Fence = FenceLocal | FenceGlobal-  deriving (Show)+  deriving (Show, Eq, Ord)  -- | An operation that occurs within a kernel body. data KernelOp
src/Futhark/CodeGen/ImpGen.hs view
@@ -194,7 +194,7 @@       opsAllocCompilers = mempty     } --- | When an array is dared, this is where it is stored.+-- | When an array is declared, this is where it is stored. data MemLoc = MemLoc   { memLocName :: VName,     memLocShape :: [Imp.DimSize],@@ -499,14 +499,11 @@   ImpM rep r op (Either Imp.Param ArrayDecl) compileInParam fparam = case paramDec fparam of   MemPrim bt ->-    return $ Left $ Imp.ScalarParam name bt+    pure $ Left $ Imp.ScalarParam name bt   MemMem space ->-    return $ Left $ Imp.MemParam name space+    pure $ Left $ Imp.MemParam name space   MemArray bt shape _ (ArrayIn mem ixfun) ->-    return $-      Right $-        ArrayDecl name bt $-          MemLoc mem (shapeDims shape) $ fmap (fmap Imp.ScalarVar) ixfun+    pure $ Right $ ArrayDecl name bt $ MemLoc mem (shapeDims shape) ixfun   MemAcc {} ->     error "Functions may not have accumulator parameters."   where@@ -787,7 +784,7 @@     ForLoop i _ bound loopvars -> do       let setLoopParam (p, a)             | Prim _ <- paramType p =-              copyDWIM (paramName p) [] (Var a) [DimFix $ Imp.vi64 i]+              copyDWIM (paramName p) [] (Var a) [DimFix $ Imp.le64 i]             | otherwise =               return () @@ -901,7 +898,7 @@   | otherwise = do     ds' <- mapM toExp ds     is <- replicateM (length ds) (newVName "i")-    copy_elem <- collect $ copyDWIM (patElemName pe) (map (DimFix . Imp.vi64) is) se []+    copy_elem <- collect $ copyDWIM (patElemName pe) (map (DimFix . Imp.le64) is) se []     emit $ foldl (.) id (zipWith Imp.For is ds') copy_elem defCompileBasicOp _ Scratch {} =   return ()@@ -1091,7 +1088,7 @@ 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) $ fmap (fmap Imp.ScalarVar) ixfun+  let location = MemLoc mem (shapeDims shape) ixfun    in ArrayVar         e         ArrayEntry@@ -1134,10 +1131,12 @@   ImpM rep r op () dScope e = mapM_ (uncurry $ dInfo e) . M.toList -dArray :: VName -> PrimType -> ShapeBase SubExp -> MemBind -> ImpM rep r op ()-dArray name bt shape membind =-  addVar name $-    memBoundToVarEntry Nothing $ MemArray bt shape NoUniqueness membind+dArray :: VName -> PrimType -> ShapeBase SubExp -> VName -> IxFun -> ImpM rep r op ()+dArray name pt shape mem ixfun =+  addVar name $ ArrayVar Nothing $ ArrayEntry location pt+  where+    location =+      MemLoc mem (shapeDims shape) ixfun  everythingVolatile :: ImpM rep r op a -> ImpM rep r op a everythingVolatile = local $ \env -> env {envVolatility = Imp.Volatile}@@ -1207,8 +1206,8 @@   toExp' t (Var v) = Imp.var v t  instance ToExp (PrimExp VName) where-  toExp = pure . fmap Imp.ScalarVar-  toExp' _ = fmap Imp.ScalarVar+  toExp = pure+  toExp' _ = id  addVar :: VName -> VarEntry rep -> ImpM rep r op () addVar name entry =@@ -1489,14 +1488,18 @@ copyElementWise bt dest src = do   let bounds = IxFun.shape $ memLocIxFun src   is <- replicateM (length bounds) (newVName "i")-  let ivars = map Imp.vi64 is+  let ivars = map Imp.le64 is   (destmem, destspace, destidx) <- fullyIndexArray' dest ivars   (srcmem, srcspace, srcidx) <- fullyIndexArray' src ivars   vol <- asks envVolatility+  tmp <- newVName "tmp"   emit $     foldl (.) id (zipWith Imp.For is $ map untyped bounds) $-      Imp.Write destmem destidx bt destspace vol $-        Imp.index srcmem srcidx bt srcspace vol+      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+        ]  -- | Copy from here to there; both destination and source may be -- indexeded.@@ -1522,9 +1525,10 @@       (srcmem, srcspace, srcoffset) <-         fullyIndexArray' srclocation srcis       vol <- asks envVolatility-      return $-        Imp.Write targetmem targetoffset bt destspace vol $-          Imp.index srcmem srcoffset bt srcspace vol+      collect $ do+        tmp <- tvVar <$> dPrim "tmp" bt+        emit $ Imp.Read tmp srcmem srcoffset bt srcspace vol+        emit $ Imp.Write targetmem targetoffset bt destspace vol $ Imp.var tmp bt     | otherwise = do       let destslice' = fullSliceNum (map toInt64Exp destshape) destslice           srcslice' = fullSliceNum (map toInt64Exp srcshape) srcslice@@ -1609,7 +1613,7 @@         (mem, space, i) <-           fullyIndexArray' (entryArrayLoc arr) src_is         vol <- asks envVolatility-        emit $ Imp.SetScalar name $ Imp.index mem i bt space vol+        emit $ Imp.Read name mem i bt space vol       | otherwise ->         error $           unwords@@ -1778,18 +1782,17 @@   sAlloc_ name' size space   return name' -sArray :: String -> PrimType -> ShapeBase SubExp -> MemBind -> ImpM rep r op VName-sArray name bt shape membind = do+sArray :: String -> PrimType -> ShapeBase SubExp -> VName -> IxFun -> ImpM rep r op VName+sArray name bt shape mem ixfun = do   name' <- newVName name-  dArray name' bt shape membind+  dArray name' bt shape mem ixfun   return name'  -- | Declare an array in row-major order in the given memory block. sArrayInMem :: String -> PrimType -> ShapeBase SubExp -> VName -> ImpM rep r op VName sArrayInMem name pt shape mem =-  sArray name pt shape $-    ArrayIn mem $-      IxFun.iota $ map (isInt64 . primExpFromSubExp int64) $ shapeDims shape+  sArray name pt shape mem $+    IxFun.iota $ map (isInt64 . primExpFromSubExp int64) $ shapeDims shape  -- | Like 'sAllocArray', but permute the in-memory representation of the indices as specified. sAllocArrayPerm :: String -> PrimType -> ShapeBase SubExp -> Space -> [Int] -> ImpM rep r op VName@@ -1797,8 +1800,8 @@   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-  sArray name pt shape $-    ArrayIn mem $ IxFun.permute iota_ixfun $ rearrangeInverse perm+  sArray name pt shape mem $+    IxFun.permute iota_ixfun $ rearrangeInverse perm  -- | Uses linear/iota index function. sAllocArray :: String -> PrimType -> ShapeBase SubExp -> Space -> ImpM rep r op VName@@ -1815,7 +1818,7 @@   mem <- newVNameForFun $ name ++ "_mem"   emit $ Imp.DeclareArray mem space pt vs   addVar mem $ MemVar Nothing $ MemEntry space-  sArray name pt shape $ ArrayIn mem $ IxFun.iota [fromIntegral num_elems]+  sArray name pt shape mem $ IxFun.iota [fromIntegral num_elems]  sWrite :: VName -> [Imp.TExp Int64] -> Imp.Exp -> ImpM rep r op () sWrite arr is v = do@@ -1891,7 +1894,7 @@   where     loop ((v, size) : rest) i = do       dPrimV_ v (i `quot` size)-      i' <- dPrimVE "remnant" $ i - Imp.vi64 v * size+      i' <- dPrimVE "remnant" $ i - Imp.le64 v * size       loop rest i'     loop _ _ = pure () @@ -1905,4 +1908,4 @@ dIndexSpace' desc ds j = do   ivs <- replicateM (length ds) (newVName desc)   dIndexSpace (zip ivs ds) j-  pure $ map Imp.vi64 ivs+  pure $ map Imp.le64 ivs
src/Futhark/CodeGen/ImpGen/GPU.hs view
@@ -367,18 +367,18 @@     -- 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.vi32 num_arrays .==. 1-          height_is_one = Imp.vi32 y .==. 1-          width_is_one = Imp.vi32 x .==. 1+      let onearr = Imp.le32 num_arrays .==. 1+          height_is_one = Imp.le32 y .==. 1+          width_is_one = Imp.le32 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 Int32),-            Imp.SetScalar muly $ untyped $ block_dim `quot` Imp.vi32 x,+            Imp.SetScalar muly $ untyped $ block_dim `quot` Imp.le32 x,             Imp.DeclareScalar mulx Imp.Nonvolatile (IntType Int32),-            Imp.SetScalar mulx $ untyped $ block_dim `quot` Imp.vi32 y,+            Imp.SetScalar mulx $ untyped $ block_dim `quot` Imp.le32 y,             Imp.If can_use_copy copy_code $               Imp.If should_use_lowwidth (callTransposeKernel TransposeLowWidth) $                 Imp.If should_use_lowheight (callTransposeKernel TransposeLowHeight) $@@ -387,28 +387,28 @@           ]      input_is_empty =-      Imp.vi32 num_arrays .==. 0 .||. Imp.vi32 x .==. 0 .||. Imp.vi32 y .==. 0+      Imp.le32 num_arrays .==. 0 .||. Imp.le32 x .==. 0 .||. Imp.le32 y .==. 0      should_use_small =-      Imp.vi32 x .<=. (block_dim `quot` 2)-        .&&. Imp.vi32 y .<=. (block_dim `quot` 2)+      Imp.le32 x .<=. (block_dim `quot` 2)+        .&&. Imp.le32 y .<=. (block_dim `quot` 2)      should_use_lowwidth =-      Imp.vi32 x .<=. (block_dim `quot` 2)-        .&&. block_dim .<. Imp.vi32 y+      Imp.le32 x .<=. (block_dim `quot` 2)+        .&&. block_dim .<. Imp.le32 y      should_use_lowheight =-      Imp.vi32 y .<=. (block_dim `quot` 2)-        .&&. block_dim .<. Imp.vi32 x+      Imp.le32 y .<=. (block_dim `quot` 2)+        .&&. block_dim .<. Imp.le32 x      copy_code =-      let num_bytes = sExt64 $ Imp.vi32 x * Imp.vi32 y * primByteSize bt+      let num_bytes = sExt64 $ Imp.le32 x * Imp.le32 y * primByteSize bt        in Imp.Copy             destmem-            (Imp.Count $ sExt64 $ Imp.vi32 destoffset)+            (Imp.Count $ sExt64 $ Imp.le32 destoffset)             space             srcmem-            (Imp.Count $ sExt64 $ Imp.vi32 srcoffset)+            (Imp.Count $ sExt64 $ Imp.le32 srcoffset)             space             (Imp.Count num_bytes) @@ -418,14 +418,14 @@           (mapTransposeName bt)           block_dim_int           ( destmem,-            Imp.vi32 destoffset,+            Imp.le32 destoffset,             srcmem,-            Imp.vi32 srcoffset,-            Imp.vi32 x,-            Imp.vi32 y,-            Imp.vi32 mulx,-            Imp.vi32 muly,-            Imp.vi32 num_arrays,+            Imp.le32 srcoffset,+            Imp.le32 x,+            Imp.le32 y,+            Imp.le32 mulx,+            Imp.le32 muly,+            Imp.le32 num_arrays,             block           )           bt
src/Futhark/CodeGen/ImpGen/GPU/Base.hs view
@@ -36,7 +36,7 @@ where  import Control.Monad.Except-import Data.List (zip4)+import Data.List (foldl', zip4) import qualified Data.Map.Strict as M import Data.Maybe import qualified Data.Set as S@@ -350,10 +350,8 @@               locks_t = Array int32 (Shape [unCount group_size]) NoUniqueness            locks_mem <- sAlloc "locks_mem" (typeSize locks_t) $ Space "local"-          dArray locks int32 (arrayShape locks_t) $-            ArrayIn locks_mem $-              IxFun.iota $-                map pe64 $ arrayDims locks_t+          dArray locks int32 (arrayShape locks_t) locks_mem $+            IxFun.iota $ map pe64 $ arrayDims locks_t            sComment "All locks start out unlocked" $             groupCoverSpace [kernelGroupSize constants] $ \is ->@@ -372,6 +370,21 @@       then m       else sWhen (isActive $ unSegSpace space) m +-- Which fence do we need to protect shared access to this memory space?+fenceForSpace :: Space -> Imp.Fence+fenceForSpace (Space "local") = Imp.FenceLocal+fenceForSpace _ = Imp.FenceGlobal++-- If we are touching these arrays, which kind of fence do we need?+fenceForArrays :: [VName] -> InKernelGen Imp.Fence+fenceForArrays = fmap (foldl' max Imp.FenceLocal) . mapM need+  where+    need arr =+      fmap (fenceForSpace . entryMemSpace) . lookupMemory+        . memLocName+        . entryArrayLoc+        =<< lookupArray arr+ compileGroupOp :: OpCompiler GPUMem KernelEnv Imp.KernelOp compileGroupOp pat (Alloc size space) =   kernelAlloc pat size space@@ -380,11 +393,10 @@ compileGroupOp pat (Inner (SegOp (SegMap lvl space _ body))) = do   void $ compileGroupSpace lvl space -  whenActive lvl space $-    localOps threadOperations $-      compileStms mempty (kernelBodyStms body) $-        zipWithM_ (compileThreadResult space) (patElems pat) $-          kernelBodyResult body+  whenActive lvl space . localOps threadOperations $+    compileStms mempty (kernelBodyStms body) $+      zipWithM_ (compileThreadResult space) (patElems pat) $+        kernelBodyResult body    sOp $ Imp.ErrorSync Imp.FenceLocal compileGroupOp pat (Inner (SegOp (SegScan lvl space scans _ body))) = do@@ -392,16 +404,17 @@   let (ltids, dims) = unzip $ unSegSpace space       dims' = map toInt64Exp dims -  whenActive lvl space $+  whenActive lvl space . localOps threadOperations $     compileStms mempty (kernelBodyStms body) $       forM_ (zip (patNames pat) $ kernelBodyResult body) $ \(dest, res) ->         copyDWIMFix           dest-          (map Imp.vi64 ltids)+          (map Imp.le64 ltids)           (kernelResultSubExp res)           [] -  sOp $ Imp.ErrorSync Imp.FenceLocal+  fence <- fenceForArrays $ patNames pat+  sOp $ Imp.ErrorSync fence    let segment_size = last dims'       crossesSegment from to =@@ -409,11 +422,10 @@    -- groupScan needs to treat the scan output as a one-dimensional   -- array of scan elements, so we invent some new flattened arrays-  -- here.  XXX: this assumes that the original index function is just-  -- row-major, but does not actually verify it.+  -- here.   dims_flat <- dPrimV "dims_flat" $ product dims'   let flattened pe = do-        MemLoc mem _ _ <-+        MemLoc mem _ ixfun <-           entryArrayLoc <$> lookupArray (patElemName pe)         let pe_t = typeOf pe             arr_dims = Var (tvVar dims_flat) : drop (length dims') (arrayDims pe_t)@@ -421,7 +433,8 @@           (baseString (patElemName pe) ++ "_flat")           (elemType pe_t)           (Shape arr_dims)-          $ ArrayIn mem $ IxFun.iota $ map pe64 arr_dims+          mem+          $ IxFun.reshape ixfun $ map (DimNew . pe64) arr_dims        num_scan_results = sum $ map (length . segBinOpNeutral) scans @@ -445,12 +458,12 @@   tmp_arrs <- mapM mkTempArr $ concatMap (lambdaReturnType . segBinOpLambda) ops   let tmps_for_ops = chunks (map (length . segBinOpNeutral) ops) tmp_arrs -  whenActive lvl space $+  whenActive lvl space . localOps threadOperations $     compileStms mempty (kernelBodyStms body) $ do       let (red_res, map_res) =             splitAt (segBinOpResults ops) $ kernelBodyResult body       forM_ (zip tmp_arrs red_res) $ \(dest, res) ->-        copyDWIMFix dest (map Imp.vi64 ltids) (kernelResultSubExp res) []+        copyDWIMFix dest (map Imp.le64 ltids) (kernelResultSubExp res) []       zipWithM_ (compileThreadResult space) map_pes map_res    sOp $ Imp.ErrorSync Imp.FenceLocal@@ -481,9 +494,8 @@                   Shape $                     Var (tvVar dims_flat) :                     drop (length ltids) (memLocShape arr_loc)-            sArray "red_arr_flat" pt flat_shape $-              ArrayIn (memLocName arr_loc) $-                IxFun.iota $ map pe64 $ shapeDims flat_shape+            sArray "red_arr_flat" pt flat_shape (memLocName arr_loc) $+              IxFun.iota $ map pe64 $ shapeDims flat_shape        let segment_size = last dims'           crossesSegment from to =@@ -524,7 +536,7 @@   -- Ensure that all locks have been initialised.   sOp $ Imp.Barrier Imp.FenceLocal -  whenActive lvl space $+  whenActive lvl space . localOps threadOperations $     compileStms mempty (kernelBodyStms kbody) $ do       let (red_res, map_res) = splitAt num_red_res $ kernelBodyResult kbody           (red_is, red_vs) = splitAt (length ops) $ map kernelResultSubExp red_res@@ -537,7 +549,7 @@           let bin' = toInt64Exp bin               dest_w' = toInt64Exp dest_w               bin_in_bounds = 0 .<=. bin' .&&. bin' .<. dest_w'-              bin_is = map Imp.vi64 (init ltids) ++ [bin']+              bin_is = map Imp.le64 (init ltids) ++ [bin']               vs_params = takeLast (length op_vs) $ lambdaParams lam            sComment "perform atomic updates" $@@ -703,9 +715,7 @@           sComment "update global result" $             zipWithM_ (writeArray bucket) arrs $ map (Var . paramName) acc_params -      fence = case space of-        Space "local" -> sOp $ Imp.MemFence Imp.FenceLocal-        _ -> sOp $ Imp.MemFence Imp.FenceGlobal+      fence = sOp $ Imp.MemFence $ fenceForSpace space    -- While-loop: Try to insert your value   sWhile (tvExp continue) $ do@@ -823,8 +833,7 @@   ImpM rep r op (Maybe Imp.KernelConstExp) isConstExp vtable size = do   fname <- askFunction-  let onLeaf (Imp.ScalarVar name) _ = lookupConstExp name-      onLeaf Imp.Index {} _ = Nothing+  let onLeaf name _ = lookupConstExp name       lookupConstExp name =         constExp =<< hasExp =<< M.lookup name vtable       constExp (Op (Inner (SizeOp (GetSize key _)))) =@@ -887,16 +896,16 @@   inner_group_size <- newVName "group_size"   let constants =         KernelConstants-          (Imp.vi32 global_tid)-          (Imp.vi32 local_tid)-          (Imp.vi32 group_id)+          (Imp.le32 global_tid)+          (Imp.le32 local_tid)+          (Imp.le32 group_id)           global_tid           local_tid           group_id           num_groups           group_size           (sExt32 (group_size * num_groups))-          (Imp.vi32 wave_size)+          (Imp.le32 wave_size)           true           mempty @@ -922,7 +931,7 @@   where     (is, ws) = unzip limit     actives = zipWith active is $ map toInt64Exp ws-    active i = (Imp.vi64 i .<.)+    active i = (Imp.le64 i .<.)  -- | Change every memory block to be in the global address space, -- except those who are in the local memory space.  This only affects@@ -1056,6 +1065,8 @@    ltid_in_bounds <- dPrimVE "ltid_in_bounds" $ ltid .<. w +  fence <- fenceForArrays arrs+   -- The scan works by splitting the group into blocks, which are   -- scanned separately.  Typically, these blocks are smaller than   -- the lockstep width, which enables barrier-free execution inside@@ -1085,7 +1096,7 @@         | array_scan =           sOp $ Imp.Barrier Imp.FenceGlobal         | otherwise =-          sOp $ Imp.Barrier Imp.FenceLocal+          sOp $ Imp.Barrier fence        group_offset = sExt64 (kernelGroupId constants) * kernelGroupSize constants @@ -1311,9 +1322,9 @@    return     ( KernelConstants-        (Imp.vi32 thread_gtid)-        (Imp.vi32 thread_ltid)-        (Imp.vi32 group_id)+        (Imp.le32 thread_gtid)+        (Imp.le32 thread_ltid)+        (Imp.le32 group_id)         thread_gtid         thread_ltid         group_id@@ -1321,7 +1332,7 @@         group_size         (sExt32 (group_size * num_groups))         0-        (Imp.vi64 thread_gtid .<. kernel_size)+        (Imp.le64 thread_gtid .<. kernel_size)         mempty,       set_constants     )@@ -1356,7 +1367,7 @@     sOp $ Imp.Barrier Imp.FenceGlobal virtualiseGroups _ _ m = do   gid <- kernelGroupIdVar . kernelConstants <$> askEnv-  m $ Imp.vi32 gid+  m $ Imp.le32 gid  sKernelThread ::   String ->@@ -1509,10 +1520,8 @@         shape = Shape [Var num_elems]     function fname [] params $ do       arr <--        sArray "arr" bt shape $-          ArrayIn mem $-            IxFun.iota $-              map pe64 $ shapeDims shape+        sArray "arr" bt shape mem $+          IxFun.iota $ map pe64 $ shapeDims shape       sReplicateKernel arr $ Var val    return fname@@ -1600,16 +1609,14 @@             Imp.ScalarParam s $ IntType bt           ]         shape = Shape [Var n]-        n' = Imp.vi64 n+        n' = Imp.le64 n         x' = Imp.var x $ IntType bt         s' = Imp.var s $ IntType bt      function fname [] params $ do       arr <--        sArray "arr" (IntType bt) shape $-          ArrayIn mem $-            IxFun.iota $-              map pe64 $ shapeDims shape+        sArray "arr" (IntType bt) shape mem $+          IxFun.iota $ map pe64 $ shapeDims shape       sIotaKernel arr (sExt64 n') x' s' bt    return fname@@ -1635,7 +1642,7 @@     else sIotaKernel arr n x s et  sCopy :: CopyCompiler GPUMem HostEnv Imp.HostOp-sCopy bt destloc@(MemLoc destmem _ _) srcloc@(MemLoc srcmem srcdims _) = do+sCopy pt destloc@(MemLoc destmem _ _) srcloc@(MemLoc srcmem srcdims _) = do   -- Note that the shape of the destination and the source are   -- necessarily the same.   let shape = map toInt64Exp srcdims@@ -1658,10 +1665,10 @@     (_, destspace, destidx) <- fullyIndexArray' destloc is     (_, srcspace, srcidx) <- fullyIndexArray' srcloc is -    sWhen (gtid .<. kernel_size) $-      emit $-        Imp.Write destmem destidx bt destspace Imp.Nonvolatile $-          Imp.index srcmem srcidx bt srcspace Imp.Nonvolatile+    sWhen (gtid .<. kernel_size) $ do+      tmp <- tvVar <$> dPrim "tmp" pt+      emit $ Imp.Read tmp srcmem srcidx pt srcspace Imp.Nonvolatile+      emit $ Imp.Write destmem destidx pt destspace Imp.Nonvolatile $ Imp.var tmp pt  compileGroupResult ::   SegSpace ->@@ -1691,7 +1698,7 @@ compileGroupResult space pe (TileReturns _ dims what) = do   let gids = map fst $ unSegSpace space       out_tile_sizes = map (toInt64Exp . snd) dims-      group_is = zipWith (*) (map Imp.vi64 gids) out_tile_sizes+      group_is = zipWith (*) (map Imp.le64 gids) out_tile_sizes   local_is <- localThreadIDs $ map snd dims   is_for_thread <-     mapM (dPrimV "thread_out_index") $@@ -1709,7 +1716,7 @@       reg_tiles' = map toInt64Exp reg_tiles    -- Which group tile is this group responsible for?-  let group_tile_is = map Imp.vi64 gids+  let group_tile_is = map Imp.le64 gids    -- Within the group tile, which register tile is this thread   -- responsible for?@@ -1739,7 +1746,7 @@ compileGroupResult space pe (Returns _ _ what) = do   constants <- kernelConstants <$> askEnv   in_local_memory <- arrayInLocalMemory what-  let gids = map (Imp.vi64 . fst) $ unSegSpace space+  let gids = map (Imp.le64 . fst) $ unSegSpace space    if not in_local_memory     then@@ -1764,7 +1771,7 @@ compileThreadResult _ _ RegTileReturns {} =   compilerLimitationS "compileThreadResult: RegTileReturns not yet handled." compileThreadResult space pe (Returns _ _ what) = do-  let is = map (Imp.vi64 . fst) $ unSegSpace space+  let is = map (Imp.le64 . fst) $ unSegSpace space   copyDWIMFix (patElemName pe) is what [] compileThreadResult _ pe (ConcatReturns _ SplitContiguous _ per_thread_elems what) = do   constants <- kernelConstants <$> askEnv
src/Futhark/CodeGen/ImpGen/GPU/SegHist.hs view
@@ -107,16 +107,13 @@     let subhistos_shape =           Shape (map snd segment_dims ++ [tvSize num_subhistos])             <> stripDims num_segments (arrayShape dest_t)-        subhistos_membind =-          ArrayIn subhistos_mem $-            IxFun.iota $-              map pe64 $ shapeDims subhistos_shape     subhistos <-       sArray         (baseString dest ++ "_subhistos")         (elemType dest_t)         subhistos_shape-        subhistos_membind+        subhistos_mem+        $ IxFun.iota $ map pe64 $ shapeDims subhistos_shape      return $       SubhistosInfo subhistos $ do@@ -436,7 +433,7 @@             forM_ (zip map_pes map_res) $ \(pe, res) ->               copyDWIMFix                 (patElemName pe)-                (map (Imp.vi64 . fst) $ unSegSpace space)+                (map (Imp.le64 . fst) $ unSegSpace space)                 (kernelResultSubExp res)                 [] @@ -463,7 +460,7 @@                    sWhen bucket_in_bounds $ do                     let bucket_is =-                          map Imp.vi64 (init space_is)+                          map Imp.le64 (init space_is)                             ++ [sExt64 subhisto_ind, bucket']                     dLParams $ lambdaParams lam                     sLoopNest shape $ \is -> do@@ -705,7 +702,7 @@         sComment "initialize histograms in local memory" $           onAllHistograms $ \dest_local dest_global op ne local_subhisto_i global_subhisto_i local_bucket_is global_bucket_is ->             sComment "First subhistogram is initialised from global memory; others with neutral element." $ do-              let global_is = map Imp.vi64 segment_is ++ [0] ++ global_bucket_is+              let global_is = map Imp.le64 segment_is ++ [0] ++ global_bucket_is                   local_is = sExt64 local_subhisto_i : local_bucket_is               sIf                 (global_subhisto_i .==. 0)@@ -735,7 +732,7 @@                 forM_ (zip map_pes map_res) $ \(pe, se) ->                   copyDWIMFix                     (patElemName pe)-                    (map Imp.vi64 space_is)+                    (map Imp.le64 space_is)                     se                     [] @@ -815,7 +812,7 @@                  sComment "Put final bucket value in global memory." $ do                   let global_is =-                        map Imp.vi64 segment_is+                        map Imp.le64 segment_is                           ++ [sExt64 group_id `rem` unCount groups_per_segment]                           ++ global_bucket_is                   forM_ (zip xparams global_dests) $ \(xp, global_dest) ->@@ -1142,7 +1139,7 @@           red_cont $             flip map subhistos $ \subhisto ->               ( Var subhisto,-                map Imp.vi64 $+                map Imp.le64 $                   map fst segment_dims ++ [subhistogram_id, bucket_id] ++ vector_ids               ) 
src/Futhark/CodeGen/ImpGen/GPU/SegRed.hs view
@@ -138,8 +138,8 @@     case paramDec p of       MemArray pt shape _ (ArrayIn mem _) -> do         let shape' = Shape [num_threads] <> shape-        sArray "red_arr" pt shape' $-          ArrayIn mem $ IxFun.iota $ map pe64 $ shapeDims shape'+        sArray "red_arr" pt shape' mem $+          IxFun.iota $ map pe64 $ shapeDims shape'       _ -> do         let pt = elemType $ paramType p             shape = Shape [group_size]@@ -183,7 +183,7 @@       dims' = map toInt64Exp dims       num_groups' = fmap toInt64Exp num_groups       group_size' = fmap toInt64Exp group_size-      global_tid = Imp.vi64 $ segFlat space+      global_tid = Imp.le64 $ segFlat space       w = last dims'    counter <-@@ -478,7 +478,7 @@                   pes                   group_id                   flat_segment_id-                  (map Imp.vi64 segment_gtids)+                  (map Imp.le64 segment_gtids)                   (sExt64 first_group_for_segment)                   groups_per_segment                   slug@@ -498,7 +498,7 @@               forM_ (zip slugs segred_pes) $ \(slug, pes) ->                 sWhen (local_tid .==. 0) $                   forM_ (zip pes (slugAccs slug)) $ \(v, (acc, acc_is)) ->-                    copyDWIMFix (patElemName v) (map Imp.vi64 segment_gtids) (Var acc) acc_is+                    copyDWIMFix (patElemName v) (map Imp.le64 segment_gtids) (Var acc) acc_is        sIf (groups_per_segment .==. 1) one_group_per_segment multiple_groups_per_segment @@ -635,7 +635,7 @@     gtid       <-- case comm of         Commutative ->-          global_tid + Imp.vi64 threads_per_segment * i+          global_tid + Imp.le64 threads_per_segment * i         Noncommutative ->           let index_in_segment = global_tid `quot` kernelGroupSize constants            in sExt64 local_tid
src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs view
@@ -85,7 +85,8 @@         "local_prefix_arr"         ty         (Shape [groupSize])-        $ ArrayIn localMem $ IxFun.iotaOffset off' [pe64 groupSize]+        localMem+        $ IxFun.iotaOffset off' [pe64 groupSize]    warpscan <- sArrayInMem "warpscan" int8 (Shape [constant (warpSize :: Int64)]) localMem   warpExchanges <-@@ -95,7 +96,8 @@         "warp_exchange"         ty         (Shape [constant (warpSize :: Int64)])-        $ ArrayIn localMem $ IxFun.iotaOffset off' [warpSize]+        localMem+        $ IxFun.iotaOffset off' [warpSize]    return (sharedId, transposedArrays, prefixArrays, warpscan, warpExchanges) @@ -245,10 +247,10 @@       m :: Num a => a       m = fromIntegral $ max 1 $ min mem_constraint reg_constraint -  emit $ Imp.DebugPrint "SegScan: number of elements processed sequentially per thread is m:" $ Just $ untyped (m :: TPrimExp Int32 Imp.ExpLeaf)-  emit $ Imp.DebugPrint "SegScan: memory constraints is: " $ Just $ untyped (fromIntegral mem_constraint :: TPrimExp Int32 Imp.ExpLeaf)-  emit $ Imp.DebugPrint "SegScan: register constraints is: " $ Just $ untyped (fromIntegral reg_constraint :: TPrimExp Int32 Imp.ExpLeaf)-  emit $ Imp.DebugPrint "SegScan: sumT' is: " $ Just $ untyped (fromIntegral sumT' :: TPrimExp Int32 Imp.ExpLeaf)+  emit $ Imp.DebugPrint "SegScan: number of elements processed sequentially per thread is m:" $ Just $ untyped (m :: Imp.TExp Int32)+  emit $ Imp.DebugPrint "SegScan: memory constraints is: " $ Just $ untyped (fromIntegral mem_constraint :: Imp.TExp Int32)+  emit $ Imp.DebugPrint "SegScan: register constraints is: " $ Just $ untyped (fromIntegral reg_constraint :: Imp.TExp Int32)+  emit $ Imp.DebugPrint "SegScan: sumT' is: " $ Just $ untyped (fromIntegral sumT' :: Imp.TExp Int32)    -- Allocate the shared memory for output component   numThreads <- dPrimV "numThreads" num_threads@@ -324,7 +326,7 @@                  -- Write map results to their global memory destinations                 forM_ (zip (takeLast (length map_res) all_pes) map_res) $ \(dest, src) ->-                  copyDWIMFix (patElemName dest) (map Imp.vi64 gtids) (kernelResultSubExp src) []+                  copyDWIMFix (patElemName dest) (map Imp.le64 gtids) (kernelResultSubExp src) []                  -- Write to-scan results to private memory.                 forM_ (zip privateArrays $ map kernelResultSubExp all_scan_res) $ \(dest, src) ->@@ -620,7 +622,7 @@           sWhen (flat_idx .<. n) $ do             copyDWIMFix               dest-              (map Imp.vi64 gtids)+              (map Imp.le64 gtids)               (Var locmem)               [sExt64 $ flat_idx - tvExp blockOff]         sOp localBarrier
src/Futhark/CodeGen/ImpGen/GPU/SegScan/TwoPass.hs view
@@ -42,9 +42,8 @@             MemArray pt shape _ (ArrayIn mem _) -> do               let shape' = Shape [num_threads] <> shape               arr <--                lift $-                  sArray "scan_arr" pt shape' $-                    ArrayIn mem $ IxFun.iota $ map pe64 $ shapeDims shape'+                lift . sArray "scan_arr" pt shape' mem $+                  IxFun.iota $ map pe64 $ shapeDims shape'               return (arr, [])             _ -> do               let pt = elemType $ paramType p@@ -100,7 +99,7 @@     forM_ (zip pes scan_res) $ \(pe, res) ->       copyDWIMFix         (patElemName pe)-        (map Imp.vi64 gtids)+        (map Imp.le64 gtids)         (kernelResultSubExp res)         []   | otherwise =@@ -196,7 +195,7 @@       let per_scan_pes = segBinOpChunks scans all_pes            in_bounds =-            foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi64 gtids) dims'+            foldl1 (.&&.) $ zipWith (.<.) (map Imp.le64 gtids) dims'            when_in_bounds = compileStms mempty (kernelBodyStms kbody) $ do             let (all_scan_res, map_res) =@@ -212,7 +211,7 @@               forM_ (zip (takeLast (length map_res) all_pes) map_res) $ \(pe, se) ->                 copyDWIMFix                   (patElemName pe)-                  (map Imp.vi64 gtids)+                  (map Imp.le64 gtids)                   (kernelResultSubExp se)                   [] @@ -236,7 +235,7 @@                 sIf                   in_bounds                   ( do-                      readToScanValues (map Imp.vi64 gtids ++ vec_is) pes scan+                      readToScanValues (map Imp.le64 gtids ++ vec_is) pes scan                       readCarries j (tvExp chunk_offset) dims' vec_is pes scan                   )                   ( forM_ (zip (yParams scan) (segBinOpNeutral scan)) $ \(p, ne) ->@@ -272,7 +271,7 @@                   forM_ (zip3 rets pes local_arrs) $ \(t, pe, arr) ->                     copyDWIMFix                       (patElemName pe)-                      (map Imp.vi64 gtids ++ vec_is)+                      (map Imp.le64 gtids ++ vec_is)                       (Var arr)                       [localArrayIndex constants t] @@ -356,10 +355,10 @@     forM_ (zip4 scans per_scan_local_arrs per_scan_rets per_scan_pes) $       \(SegBinOp _ scan_op nes vec_shape, local_arrs, rets, pes) ->         sLoopNest vec_shape $ \vec_is -> do-          let glob_is = map Imp.vi64 gtids ++ vec_is+          let glob_is = map Imp.le64 gtids ++ vec_is                in_bounds =-                foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi64 gtids) dims'+                foldl1 (.&&.) $ zipWith (.<.) (map Imp.le64 gtids) dims'                when_in_bounds = forM_ (zip3 rets local_arrs pes) $ \(t, arr, pe) ->                 copyDWIMFix@@ -437,7 +436,7 @@       -- then the carry was updated in stage 2), and we are not crossing       -- a segment boundary.       let in_bounds =-            foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi64 gtids) dims'+            foldl1 (.&&.) $ zipWith (.<.) (map Imp.le64 gtids) dims'           crosses_segment =             fromMaybe false $               crossesSegment@@ -468,14 +467,14 @@                     (paramName p)                     []                     (Var $ patElemName pe)-                    (map Imp.vi64 gtids ++ vec_is)+                    (map Imp.le64 gtids ++ vec_is)                  compileBody' scan_x_params $ lambdaBody scan_op                  forM_ (zip scan_x_params pes) $ \(p, pe) ->                   copyDWIMFix                     (patElemName pe)-                    (map Imp.vi64 gtids ++ vec_is)+                    (map Imp.le64 gtids ++ vec_is)                     (Var $ paramName p)                     [] 
src/Futhark/CodeGen/ImpGen/GPU/ToOpenCL.hs view
@@ -584,7 +584,7 @@ kernelArgs = mapMaybe useToArg . kernelUses   where     useToArg (MemoryUse mem) = Just $ MemKArg mem-    useToArg (ScalarUse v bt) = Just $ ValueKArg (LeafExp (ScalarVar v) bt) bt+    useToArg (ScalarUse v pt) = Just $ ValueKArg (LeafExp v pt) pt     useToArg ConstUse {} = Nothing  nextErrorLabel :: GC.CompilerM KernelOp KernelState String@@ -668,7 +668,7 @@         pendingError False         GC.stm [C.cstm|$id:label: barrier($exp:(fence f));|]         GC.stm [C.cstm|if (local_failure) { return; }|]-      GC.stm [C.cstm|barrier(CLK_LOCAL_MEM_FENCE);|] -- intentional+      GC.stm [C.cstm|barrier($exp:(fence f));|]       GC.modifyUserState $ \s -> s {kernelHasBarriers = True}       incErrorLabel     kernelOps (Atomic space aop) = atomicOps space aop@@ -853,6 +853,8 @@     typesInExp e1 <> typesInExp e2 <> typesInExp e3 typesInCode (Write _ (Count (TPrimExp e1)) t _ _ e2) =   typesInExp e1 <> S.singleton t <> typesInExp e2+typesInCode (Read _ _ (Count (TPrimExp e1)) t _ _) =+  typesInExp e1 <> S.singleton t typesInCode (SetScalar _ e) = typesInExp e typesInCode SetMem {} = mempty typesInCode (Call _ _ es) = mconcat $ map typesInArg es@@ -876,5 +878,4 @@     (from, to) = convOpType op typesInExp (UnOpExp _ e) = typesInExp e typesInExp (FunExp _ args t) = S.singleton t <> mconcat (map typesInExp args)-typesInExp (LeafExp (Index _ (Count (TPrimExp e)) t _ _) _) = S.singleton t <> typesInExp e-typesInExp (LeafExp ScalarVar {} _) = mempty+typesInExp LeafExp {} = mempty
src/Futhark/CodeGen/ImpGen/GPU/Transpose.hs view
@@ -45,95 +45,106 @@     TransposeSmall ->       mconcat         [ get_ids,-          dec our_array_offset $ vi32 get_global_id_0 `quot` (height * width) * (height * width),-          dec x_index $ (vi32 get_global_id_0 `rem` (height * width)) `quot` height,-          dec y_index $ vi32 get_global_id_0 `rem` height,+          dec our_array_offset $ le32 get_global_id_0 `quot` (height * width) * (height * width),+          dec x_index $ (le32 get_global_id_0 `rem` (height * width)) `quot` height,+          dec y_index $ le32 get_global_id_0 `rem` height,+          DeclareScalar val Nonvolatile t,           dec odata_offset $-            (basic_odata_offset `quot` primByteSize t) + vi32 our_array_offset,+            (basic_odata_offset `quot` primByteSize t) + le32 our_array_offset,           dec idata_offset $-            (basic_idata_offset `quot` primByteSize t) + vi32 our_array_offset,-          dec index_in $ vi32 y_index * width + vi32 x_index,-          dec index_out $ vi32 x_index * height + vi32 y_index,+            (basic_idata_offset `quot` primByteSize t) + le32 our_array_offset,+          dec index_in $ le32 y_index * width + le32 x_index,+          dec index_out $ le32 x_index * height + le32 y_index,           when-            (vi32 get_global_id_0 .<. width * height * num_arrays)-            ( Write odata (elements $ sExt64 $ vi32 odata_offset + vi32 index_out) t (Space "global") Nonvolatile $-                index idata (elements $ sExt64 $ vi32 idata_offset + vi32 index_in) t (Space "global") Nonvolatile+            (le32 get_global_id_0 .<. width * height * num_arrays)+            ( mconcat+                [ Read val idata (elements $ sExt64 $ le32 idata_offset + le32 index_in) t (Space "global") Nonvolatile,+                  Write odata (elements $ sExt64 $ le32 odata_offset + le32 index_out) t (Space "global") Nonvolatile (var val t)+                ]             )         ]     TransposeLowWidth ->       mkTranspose $         lowDimBody-          (vi32 get_group_id_0 * block_dim + (vi32 get_local_id_0 `quot` muly))-          ( vi32 get_group_id_1 * block_dim * muly + vi32 get_local_id_1-              + (vi32 get_local_id_0 `rem` muly) * block_dim+          (le32 get_group_id_0 * block_dim + (le32 get_local_id_0 `quot` muly))+          ( le32 get_group_id_1 * block_dim * muly + le32 get_local_id_1+              + (le32 get_local_id_0 `rem` muly) * block_dim           )-          ( vi32 get_group_id_1 * block_dim * muly + vi32 get_local_id_0-              + (vi32 get_local_id_1 `rem` muly) * block_dim+          ( le32 get_group_id_1 * block_dim * muly + le32 get_local_id_0+              + (le32 get_local_id_1 `rem` muly) * block_dim           )-          (vi32 get_group_id_0 * block_dim + (vi32 get_local_id_1 `quot` muly))+          (le32 get_group_id_0 * block_dim + (le32 get_local_id_1 `quot` muly))     TransposeLowHeight ->       mkTranspose $         lowDimBody-          ( vi32 get_group_id_0 * block_dim * mulx + vi32 get_local_id_0-              + (vi32 get_local_id_1 `rem` mulx) * block_dim+          ( le32 get_group_id_0 * block_dim * mulx + le32 get_local_id_0+              + (le32 get_local_id_1 `rem` mulx) * block_dim           )-          (vi32 get_group_id_1 * block_dim + (vi32 get_local_id_1 `quot` mulx))-          (vi32 get_group_id_1 * block_dim + (vi32 get_local_id_0 `quot` mulx))-          ( vi32 get_group_id_0 * block_dim * mulx + vi32 get_local_id_1-              + (vi32 get_local_id_0 `rem` mulx) * block_dim+          (le32 get_group_id_1 * block_dim + (le32 get_local_id_1 `quot` mulx))+          (le32 get_group_id_1 * block_dim + (le32 get_local_id_0 `quot` mulx))+          ( le32 get_group_id_0 * block_dim * mulx + le32 get_local_id_1+              + (le32 get_local_id_0 `rem` mulx) * block_dim           )     TransposeNormal ->       mkTranspose $         mconcat-          [ dec x_index $ vi32 get_global_id_0,-            dec y_index $ vi32 get_group_id_1 * tile_dim + vi32 get_local_id_1,-            when (vi32 x_index .<. width) $+          [ dec x_index $ le32 get_global_id_0,+            dec y_index $ le32 get_group_id_1 * tile_dim + le32 get_local_id_1,+            DeclareScalar val Nonvolatile t,+            when (le32 x_index .<. width) $               For j (untyped elemsPerThread) $-                let i = vi32 j * (tile_dim `quot` elemsPerThread)+                let i = le32 j * (tile_dim `quot` elemsPerThread)                  in mconcat-                      [ dec index_in $ (vi32 y_index + i) * width + vi32 x_index,-                        when (vi32 y_index + i .<. height) $-                          Write-                            block-                            ( elements $-                                sExt64 $-                                  (vi32 get_local_id_1 + i) * (tile_dim + 1)-                                    + vi32 get_local_id_0-                            )-                            t-                            (Space "local")-                            Nonvolatile-                            $ index-                              idata-                              (elements $ sExt64 $ vi32 idata_offset + vi32 index_in)-                              t-                              (Space "global")-                              Nonvolatile+                      [ dec index_in $ (le32 y_index + i) * width + le32 x_index,+                        when (le32 y_index + i .<. height) $+                          mconcat+                            [ Read+                                val+                                idata+                                (elements $ sExt64 $ le32 idata_offset + le32 index_in)+                                t+                                (Space "global")+                                Nonvolatile,+                              Write+                                block+                                ( elements $+                                    sExt64 $+                                      (le32 get_local_id_1 + i) * (tile_dim + 1)+                                        + le32 get_local_id_0+                                )+                                t+                                (Space "local")+                                Nonvolatile+                                (var val t)+                            ]                       ],             Op $ Barrier FenceLocal,-            SetScalar x_index $ untyped $ vi32 get_group_id_1 * tile_dim + vi32 get_local_id_0,-            SetScalar y_index $ untyped $ vi32 get_group_id_0 * tile_dim + vi32 get_local_id_1,-            when (vi32 x_index .<. height) $+            SetScalar x_index $ untyped $ le32 get_group_id_1 * tile_dim + le32 get_local_id_0,+            SetScalar y_index $ untyped $ le32 get_group_id_0 * tile_dim + le32 get_local_id_1,+            when (le32 x_index .<. height) $               For j (untyped elemsPerThread) $-                let i = vi32 j * (tile_dim `quot` elemsPerThread)+                let i = le32 j * (tile_dim `quot` elemsPerThread)                  in mconcat-                      [ dec index_out $ (vi32 y_index + i) * height + vi32 x_index,-                        when (vi32 y_index + i .<. width) $-                          Write-                            odata-                            (elements $ sExt64 $ vi32 odata_offset + vi32 index_out)-                            t-                            (Space "global")-                            Nonvolatile-                            $ index-                              block-                              ( elements $-                                  sExt64 $-                                    vi32 get_local_id_0 * (tile_dim + 1) + vi32 get_local_id_1 + i-                              )-                              t-                              (Space "local")-                              Nonvolatile+                      [ dec index_out $ (le32 y_index + i) * height + le32 x_index,+                        when (le32 y_index + i .<. width) $+                          mconcat+                            [ Read+                                val+                                block+                                ( elements . sExt64 $+                                    le32 get_local_id_0 * (tile_dim + 1) + le32 get_local_id_1 + i+                                )+                                t+                                (Space "local")+                                Nonvolatile,+                              Write+                                odata+                                (elements $ sExt64 $ le32 odata_offset + le32 index_out)+                                t+                                (Space "global")+                                Nonvolatile+                                (var val t)+                            ]                       ]           ]   where@@ -174,7 +185,8 @@       get_group_id_0,       get_group_id_1,       get_group_id_2,-      j+      j,+      val       ] =         zipWith (flip VName) [30 ..] $           map@@ -192,7 +204,8 @@               "get_group_id_0",               "get_group_id_1",               "get_group_id_2",-              "j"+              "j",+              "val"             ]      get_ids =@@ -214,11 +227,11 @@     mkTranspose body =       mconcat         [ get_ids,-          dec our_array_offset $ vi32 get_group_id_2 * width * height,+          dec our_array_offset $ le32 get_group_id_2 * width * height,           dec odata_offset $-            (basic_odata_offset `quot` primByteSize t) + vi32 our_array_offset,+            (basic_odata_offset `quot` primByteSize t) + le32 our_array_offset,           dec idata_offset $-            (basic_idata_offset `quot` primByteSize t) + vi32 our_array_offset,+            (basic_idata_offset `quot` primByteSize t) + le32 our_array_offset,           body         ] @@ -226,37 +239,46 @@       mconcat         [ dec x_index x_in_index,           dec y_index y_in_index,-          dec index_in $ vi32 y_index * width + vi32 x_index,-          when (vi32 x_index .<. width .&&. vi32 y_index .<. height) $-            Write-              block-              (elements $ sExt64 $ vi32 get_local_id_1 * (block_dim + 1) + vi32 get_local_id_0)-              t-              (Space "local")-              Nonvolatile-              $ index-                idata-                (elements $ sExt64 $ vi32 idata_offset + vi32 index_in)-                t-                (Space "global")-                Nonvolatile,+          DeclareScalar val Nonvolatile t,+          dec index_in $ le32 y_index * width + le32 x_index,+          when (le32 x_index .<. width .&&. le32 y_index .<. height) $+            mconcat+              [ Read+                  val+                  idata+                  (elements $ sExt64 $ le32 idata_offset + le32 index_in)+                  t+                  (Space "global")+                  Nonvolatile,+                Write+                  block+                  (elements $ sExt64 $ le32 get_local_id_1 * (block_dim + 1) + le32 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 $ vi32 y_index * height + vi32 x_index,-          when (vi32 x_index .<. height .&&. vi32 y_index .<. width) $-            Write-              odata-              (elements $ sExt64 (vi32 odata_offset + vi32 index_out))-              t-              (Space "global")-              Nonvolatile-              $ index-                block-                (elements $ sExt64 $ vi32 get_local_id_0 * (block_dim + 1) + vi32 get_local_id_1)-                t-                (Space "local")-                Nonvolatile+          dec index_out $ le32 y_index * height + le32 x_index,+          when (le32 x_index .<. height .&&. le32 y_index .<. width) $+            mconcat+              [ Read+                  val+                  block+                  (elements $ sExt64 $ le32 get_local_id_0 * (block_dim + 1) + le32 get_local_id_1)+                  t+                  (Space "local")+                  Nonvolatile,+                Write+                  odata+                  (elements $ sExt64 (le32 odata_offset + le32 index_out))+                  t+                  (Space "global")+                  Nonvolatile+                  (var val t)+              ]         ]  -- | Generate a transpose kernel.  There is special support to handle
src/Futhark/CodeGen/ImpGen/Multicore/Base.hs view
@@ -117,7 +117,7 @@   KernelResult ->   MulticoreGen () compileThreadResult space pe (Returns _ _ what) = do-  let is = map (Imp.vi64 . fst) $ unSegSpace space+  let is = map (Imp.le64 . fst) $ unSegSpace space   copyDWIMFix (patElemName pe) is what [] compileThreadResult _ _ ConcatReturns {} =   compilerBugS "compileThreadResult: ConcatReturn unhandled."
src/Futhark/CodeGen/ImpGen/Multicore/SegHist.hs view
@@ -122,11 +122,11 @@            sComment "save map-out results" $             forM_ (zip map_pes map_res) $ \(pe, res) ->-              copyDWIMFix (patElemName pe) (map Imp.vi64 is) (kernelResultSubExp res) []+              copyDWIMFix (patElemName pe) (map Imp.le64 is) (kernelResultSubExp res) []            sComment "perform updates" $             sWhen bucket_in_bounds $ do-              let bucket_is = map Imp.vi64 (init is) ++ [bucket']+              let bucket_is = map Imp.le64 (init is) ++ [bucket']               dLParams $ lambdaParams lam               sLoopNest shape $ \is' -> do                 forM_ (zip vs_params vs') $ \(p, res) ->@@ -186,7 +186,7 @@       let shape = Shape [tvSize num_histos] <> arrayShape t       sAllocArray "subhistogram" (elemType t) shape DefaultSpace -  let tid' = Imp.vi64 $ segFlat space+  let tid' = Imp.le64 $ segFlat space       flat_idx' = tvExp flat_idx    (local_subhistograms, prebody) <- collect' $ do@@ -221,7 +221,7 @@         forM_ (zip map_pes map_res) $ \(pe, res) ->           copyDWIMFix             (patElemName pe)-            (map Imp.vi64 is)+            (map Imp.le64 is)             (kernelResultSubExp res)             [] @@ -274,7 +274,7 @@       red_cont $         flip map hists $ \subhisto ->           ( Var subhisto,-            map Imp.vi64 $+            map Imp.le64 $               map fst segment_dims ++ [subhistogram_id, bucket_id]           ) @@ -343,7 +343,7 @@              sComment "save map-out results" $               forM_ (zip map_pes map_res) $ \(pe, res) ->-                copyDWIMFix (patElemName pe) (map Imp.vi64 is) res []+                copyDWIMFix (patElemName pe) (map Imp.le64 is) res []              sComment "perform updates" $               sWhen bucket_in_bounds $ do@@ -352,10 +352,10 @@                   -- Index                   let buck = toInt64Exp bucket                   forM_ (zip red_pes is_params) $ \(pe, p) ->-                    copyDWIMFix (paramName p) [] (Var $ patElemName pe) (map Imp.vi64 (init is) ++ [buck] ++ vec_is)+                    copyDWIMFix (paramName p) [] (Var $ patElemName pe) (map Imp.le64 (init is) ++ [buck] ++ vec_is)                   -- Value at index                   forM_ (zip vs_params vs') $ \(p, v) ->                     copyDWIMFix (paramName p) [] v vec_is                   compileStms mempty (bodyStms $ lambdaBody lam) $                     forM_ (zip red_pes $ map resSubExp $ bodyResult $ lambdaBody lam) $-                      \(pe, se) -> copyDWIMFix (patElemName pe) (map Imp.vi64 (init is) ++ [buck] ++ vec_is) se []+                      \(pe, se) -> copyDWIMFix (patElemName pe) (map Imp.le64 (init is) ++ [buck] ++ vec_is) se []
src/Futhark/CodeGen/ImpGen/Multicore/SegMap.hs view
@@ -17,7 +17,7 @@   KernelResult ->   MulticoreGen () writeResult is pe (Returns _ _ se) =-  copyDWIMFix (patElemName pe) (map Imp.vi64 is) se []+  copyDWIMFix (patElemName pe) (map Imp.le64 is) se [] writeResult _ pe (WriteReturns _ (Shape rws) _ idx_vals) = do   let (iss, vs) = unzip idx_vals       rws' = map toInt64Exp rws
src/Futhark/CodeGen/ImpGen/Multicore/SegRed.hs view
@@ -156,7 +156,7 @@   postbody <- collect $     forM_ (zip slugs slug_local_accs) $ \(slug, local_accs) ->       forM (zip (slugResArrs slug) local_accs) $ \(acc, local_acc) ->-        copyDWIMFix acc [Imp.vi64 $ segFlat space] (Var local_acc) []+        copyDWIMFix acc [Imp.le64 $ segFlat space] (Var local_acc) []    free_params <- freeParams (prebody <> fbody <> postbody) (segFlat space : [tvVar flat_idx])   let (body_allocs, fbody') = extractAllocations fbody@@ -170,7 +170,7 @@   MulticoreGen () reductionStage2 pat space nsubtasks slugs = do   let per_red_pes = segBinOpChunks (map slugOp slugs) $ patElems pat-      phys_id = Imp.vi64 (segFlat space)+      phys_id = Imp.le64 (segFlat space)   sComment "neutral-initialise the output" $     forM_ (zip (map slugOp slugs) per_red_pes) $ \(red, red_res) ->       forM_ (zip red_res $ segBinOpNeutral red) $ \(pe, ne) ->@@ -235,7 +235,7 @@       forM_ (zip per_red_pes reds) $ \(pes, red) ->         forM_ (zip pes (segBinOpNeutral red)) $ \(pe, ne) ->           sLoopNest (segBinOpShape red) $ \vec_is ->-            copyDWIMFix (patElemName pe) (map Imp.vi64 (init is) ++ vec_is) ne []+            copyDWIMFix (patElemName pe) (map Imp.le64 (init is) ++ vec_is) ne []      sComment "main body" $ do       dScope Nothing $ scopeOfLParams $ concatMap (lambdaParams . segBinOpLambda) reds@@ -252,7 +252,7 @@               sComment "load accum" $ do                 let acc_params = take (length (segBinOpNeutral red)) $ (lambdaParams . segBinOpLambda) red                 forM_ (zip acc_params pes) $ \(p, pe) ->-                  copyDWIMFix (paramName p) [] (Var $ patElemName pe) (map Imp.vi64 (init is) ++ vec_is)+                  copyDWIMFix (paramName p) [] (Var $ patElemName pe) (map Imp.le64 (init is) ++ vec_is)                sComment "load new val" $ do                 let next_params = drop (length (segBinOpNeutral red)) $ (lambdaParams . segBinOpLambda) red@@ -264,4 +264,4 @@                 compileStms mempty (bodyStms lbody) $                   sComment "write back to res" $                     forM_ (zip pes $ map resSubExp $ bodyResult lbody) $-                      \(pe, se') -> copyDWIMFix (patElemName pe) (map Imp.vi64 (init is) ++ vec_is) se' []+                      \(pe, se') -> copyDWIMFix (patElemName pe) (map Imp.le64 (init is) ++ vec_is) se' []
src/Futhark/CodeGen/ImpGen/Multicore/SegScan.hs view
@@ -120,7 +120,7 @@             compileStms mempty (bodyStms $ lamBody scan_op) $               forM_ (zip3 acc pes $ map resSubExp $ bodyResult $ lamBody scan_op) $                 \(acc', pe, se) -> do-                  copyDWIMFix (patElemName pe) (map Imp.vi64 is ++ vec_is) se []+                  copyDWIMFix (patElemName pe) (map Imp.le64 is ++ vec_is) se []                   copyDWIMFix acc' vec_is se []    free_params <- freeParams (prebody <> body) (segFlat space : [tvVar iter])@@ -240,7 +240,7 @@             compileStms mempty (bodyStms $ lamBody scan_op) $               forM_ (zip3 pes (map resSubExp $ bodyResult $ lamBody scan_op) acc) $                 \(pe, se, acc') -> do-                  copyDWIMFix (patElemName pe) (map Imp.vi64 is ++ vec_is) se []+                  copyDWIMFix (patElemName pe) (map Imp.le64 is ++ vec_is) se []                   copyDWIMFix acc' vec_is se []    free_params' <- freeParams (prebody <> body) (segFlat space : [tvVar iter])@@ -298,10 +298,10 @@            sComment "write mapped values results to memory" $             forM_ (zip (drop (length $ segBinOpNeutral scan_op) $ patElems pat) map_res) $ \(pe, se) ->-              copyDWIMFix (patElemName pe) (map Imp.vi64 is) (kernelResultSubExp se) []+              copyDWIMFix (patElemName pe) (map Imp.le64 is) (kernelResultSubExp se) []            sComment "combine with carry and write to memory" $             compileStms mempty (bodyStms $ lambdaBody $ segBinOpLambda scan_op) $               forM_ (zip3 scan_x_params scan_pes $ map resSubExp $ bodyResult $ lambdaBody $ segBinOpLambda scan_op) $ \(p, pe, se) -> do-                copyDWIMFix (patElemName pe) (map Imp.vi64 is) se []+                copyDWIMFix (patElemName pe) (map Imp.le64 is) se []                 copyDWIMFix (paramName p) [] se []
src/Futhark/CodeGen/ImpGen/Transpose.hs view
@@ -46,9 +46,9 @@     []     params     ( mconcat-        [ dec r $ vi64 re - vi64 rb,-          dec c $ vi64 ce - vi64 cb,-          If (vi64 num_arrays .==. 1) doTranspose doMapTranspose+        [ dec r $ le64 re - le64 rb,+          dec c $ le64 ce - le64 cb,+          If (le64 num_arrays .==. 1) doTranspose doMapTranspose         ]     )     []@@ -85,7 +85,8 @@       r,       c,       i,-      j+      j,+      val       ] =         zipWith           (VName . nameFromString)@@ -103,38 +104,44 @@             "r",             "c",             "i",-            "j" -- local+            "j", -- local+            "val"           ]           [0 ..]      dec v e = DeclareScalar v Nonvolatile int32 <> SetScalar v (untyped e)      naiveTranspose =-      For j (untyped $ vi64 c) $-        For i (untyped $ vi64 r) $-          let i' = vi64 i + vi64 rb-              j' = vi64 j + vi64 cb-           in Write-                destmem-                (elements $ vi64 destoffset + j' * vi64 n + i')-                pt-                DefaultSpace-                Nonvolatile-                $ index-                  srcmem-                  (elements $ vi64 srcoffset + i' * vi64 m + j')-                  pt-                  DefaultSpace-                  Nonvolatile+      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 $ vi64 destoffset,+        ExpArg $ untyped $ le64 destoffset,         MemArg srcmem,-        ExpArg $ untyped $ vi64 srcoffset,-        ExpArg $ untyped $ vi64 num_arrays,-        ExpArg $ untyped $ vi64 m,-        ExpArg $ untyped $ vi64 n,+        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',@@ -145,28 +152,28 @@     doTranspose =       mconcat         [ If-            (vi64 r .<=. cutoff .&&. vi64 c .<=. cutoff)+            (le64 r .<=. cutoff .&&. le64 c .<=. cutoff)             naiveTranspose             $ If-              (vi64 r .>=. vi64 c)+              (le64 r .>=. le64 c)               ( Call                   []                   fname                   ( recArgs-                      ( vi64 cb,-                        vi64 ce,-                        vi64 rb,-                        vi64 rb + (vi64 r `quot` 2)+                      ( le64 cb,+                        le64 ce,+                        le64 rb,+                        le64 rb + (le64 r `quot` 2)                       )                   )                   <> Call                     []                     fname                     ( recArgs-                        ( vi64 cb,-                          vi64 ce,-                          vi64 rb + vi64 r `quot` 2,-                          vi64 re+                        ( le64 cb,+                          le64 ce,+                          le64 rb + le64 r `quot` 2,+                          le64 re                         )                     )               )@@ -174,20 +181,20 @@                   []                   fname                   ( recArgs-                      ( vi64 cb,-                        vi64 cb + (vi64 c `quot` 2),-                        vi64 rb,-                        vi64 re+                      ( le64 cb,+                        le64 cb + (le64 c `quot` 2),+                        le64 rb,+                        le64 re                       )                   )                   <> Call                     []                     fname                     ( recArgs-                        ( vi64 cb + vi64 c `quot` 2,-                          vi64 ce,-                          vi64 rb,-                          vi64 re+                        ( le64 cb + le64 c `quot` 2,+                          le64 ce,+                          le64 rb,+                          le64 re                         )                     )               )@@ -196,19 +203,19 @@     doMapTranspose =       -- In the map-transpose case, we assume that cb==rb==0, ce==m,       -- re==n.-      For i (untyped $ vi64 num_arrays) $+      For i (untyped $ le64 num_arrays) $         Call           []           fname           [ MemArg destmem,-            ExpArg $ untyped $ vi64 destoffset + vi64 i * vi64 m * vi64 n,+            ExpArg $ untyped $ le64 destoffset + le64 i * le64 m * le64 n,             MemArg srcmem,-            ExpArg $ untyped $ vi64 srcoffset + vi64 i * vi64 m * vi64 n,+            ExpArg $ untyped $ le64 srcoffset + le64 i * le64 m * le64 n,             ExpArg $ untyped (1 :: TExp Int64),-            ExpArg $ untyped $ vi64 m,-            ExpArg $ untyped $ vi64 n,-            ExpArg $ untyped $ vi64 cb,-            ExpArg $ untyped $ vi64 ce,-            ExpArg $ untyped $ vi64 rb,-            ExpArg $ untyped $ vi64 re+            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/SetDefaultSpace.hs view
@@ -56,7 +56,7 @@  setCodeSpace :: Space -> Code op -> Code op setCodeSpace space (Allocate v e old_space) =-  Allocate v (fmap (setTExpSpace space) e) $ setSpace space old_space+  Allocate v e $ setSpace space old_space setCodeSpace space (Free v old_space) =   Free v $ setSpace space old_space setCodeSpace space (DeclareMem name old_space) =@@ -64,66 +64,42 @@ setCodeSpace space (DeclareArray name _ t vs) =   DeclareArray name space t vs setCodeSpace space (Copy dest dest_offset dest_space src src_offset src_space n) =-  Copy-    dest-    (fmap (setTExpSpace space) dest_offset)-    dest_space'-    src-    (fmap (setTExpSpace space) src_offset)-    src_space'-    $ fmap (setTExpSpace space) n+  Copy dest dest_offset dest_space' src src_offset src_space' n   where     dest_space' = setSpace space dest_space     src_space' = setSpace space src_space setCodeSpace space (Write dest dest_offset bt dest_space vol e) =-  Write-    dest-    (fmap (setTExpSpace space) dest_offset)-    bt-    (setSpace space dest_space)-    vol-    (setExpSpace space e)+  Write dest dest_offset bt (setSpace space dest_space) vol e+setCodeSpace space (Read x dest dest_offset bt dest_space vol) =+  Read x dest dest_offset bt (setSpace space dest_space) vol setCodeSpace space (c1 :>>: c2) =   setCodeSpace space c1 :>>: setCodeSpace space c2 setCodeSpace space (For i e body) =-  For i (setExpSpace space e) $ setCodeSpace space body+  For i e $ setCodeSpace space body setCodeSpace space (While e body) =-  While (setTExpSpace space e) $ setCodeSpace space body+  While e $ setCodeSpace space body setCodeSpace space (If e c1 c2) =-  If (setTExpSpace space e) (setCodeSpace space c1) (setCodeSpace space c2)+  If e (setCodeSpace space c1) (setCodeSpace space c2) setCodeSpace space (Comment s c) =   Comment s $ setCodeSpace space c setCodeSpace _ Skip =   Skip setCodeSpace _ (DeclareScalar name vol bt) =   DeclareScalar name vol bt-setCodeSpace space (SetScalar name e) =-  SetScalar name $ setExpSpace space e+setCodeSpace _ (SetScalar name e) =+  SetScalar name e setCodeSpace space (SetMem to from old_space) =   SetMem to from $ setSpace space old_space-setCodeSpace space (Call dests fname args) =-  Call dests fname $ map setArgSpace args-  where-    setArgSpace (MemArg m) = MemArg m-    setArgSpace (ExpArg e) = ExpArg $ setExpSpace space e-setCodeSpace space (Assert e msg loc) =-  Assert (setExpSpace space e) (fmap (setExpSpace space) msg) loc-setCodeSpace space (DebugPrint s v) =-  DebugPrint s $ fmap (setExpSpace space) v-setCodeSpace space (TracePrint msg) =-  TracePrint $ fmap (setExpSpace space) msg+setCodeSpace _ (Call dests fname args) =+  Call dests fname args+setCodeSpace _ (Assert e msg loc) =+  Assert e msg loc+setCodeSpace _ (DebugPrint s v) =+  DebugPrint s v+setCodeSpace _ (TracePrint msg) =+  TracePrint msg setCodeSpace _ (Op op) =   Op op--setExpSpace :: Space -> Exp -> Exp-setExpSpace space = fmap setLeafSpace-  where-    setLeafSpace (Index mem i bt DefaultSpace vol) =-      Index mem i bt space vol-    setLeafSpace e = e--setTExpSpace :: Space -> TExp t -> TExp t-setTExpSpace space = TPrimExp . setExpSpace space . untyped  setSpace :: Space -> Space -> Space setSpace space DefaultSpace = space
src/Futhark/Doc/Generator.hs view
@@ -396,7 +396,7 @@   return $ specRow lhs (mhs <> " : ") rhs  valBindHtml :: Html -> ValBind -> DocM (Html, Html, Html)-valBindHtml name (ValBind _ _ retdecl (Info (rettype, _)) tparams params _ _ _ _) = do+valBindHtml name (ValBind _ _ retdecl (Info rettype) tparams params _ _ _ _) = do   let tparams' = mconcat $ map ((" " <>) . typeParamHtml) tparams       noLink' =         noLink $@@ -836,7 +836,7 @@ valBindWhat :: ValBind -> IndexWhat valBindWhat vb   | null (valBindParams vb),-    RetType _ t <- fst $ unInfo $ valBindRetType vb,+    RetType _ t <- unInfo $ valBindRetType vb,     orderZero t =     IndexValue   | otherwise =
src/Futhark/IR/Aliases.hs view
@@ -169,7 +169,7 @@     als' ->       Just $         PP.oneLine $-          PP.text "-- Result of " <> PP.ppr name <> PP.text " aliases "+          PP.text "-- Result for " <> PP.ppr name <> PP.text " aliases "             <> PP.commasep (map PP.ppr als')  removeAliases :: CanBeAliased (Op rep) => Rephraser Identity (Aliases rep) rep
src/Futhark/IR/GPU/Op.hs view
@@ -310,6 +310,10 @@   removeOpWisdom (OtherOp op) = OtherOp $ removeOpWisdom op   removeOpWisdom (SizeOp op) = SizeOp op +  addOpWisdom (SegOp op) = SegOp $ addOpWisdom op+  addOpWisdom (OtherOp op) = OtherOp $ addOpWisdom op+  addOpWisdom (SizeOp op) = SizeOp op+ instance (ASTRep rep, ST.IndexOp op) => ST.IndexOp (HostOp rep op) where   indexOp vtable k (SegOp op) is = ST.indexOp vtable k op is   indexOp vtable k (OtherOp op) is = ST.indexOp vtable k op is
src/Futhark/IR/GPU/Simplify.hs view
@@ -47,8 +47,8 @@     BodyDec rep ~ ()   ) =>   Simplify.SimplifyOp rep op ->-  HostOp rep op ->-  Engine.SimpleM rep (HostOp (Wise rep) (OpWithWisdom op), Stms (Wise rep))+  HostOp (Wise rep) op ->+  Engine.SimpleM rep (HostOp (Wise rep) op, Stms (Wise rep)) simplifyKernelOp f (OtherOp op) = do   (op', stms) <- f op   return (OtherOp op', stms)
src/Futhark/IR/GPUMem.hs view
@@ -89,12 +89,7 @@ simplifyProg = simplifyProgGeneric simpleGPUMem  simplifyStms ::-  (HasScope GPUMem m, MonadFreshNames m) =>-  Stms GPUMem ->-  m-    ( Engine.SymbolTable (Engine.Wise GPUMem),-      Stms GPUMem-    )+  (HasScope GPUMem m, MonadFreshNames m) => Stms GPUMem -> m (Stms GPUMem) simplifyStms = simplifyStmsGeneric simpleGPUMem  simpleGPUMem :: Engine.SimpleOps GPUMem
src/Futhark/IR/MC/Op.hs view
@@ -119,6 +119,11 @@   removeOpWisdom (OtherOp op) =     OtherOp $ removeOpWisdom op +  addOpWisdom (ParOp par_op op) =+    ParOp (addOpWisdom <$> par_op) (addOpWisdom op)+  addOpWisdom (OtherOp op) =+    OtherOp $ addOpWisdom op+ instance (ASTRep rep, ST.IndexOp op) => ST.IndexOp (MCOp rep op) where   indexOp vtable k (ParOp _ op) is = ST.indexOp vtable k op is   indexOp vtable k (OtherOp op) is = ST.indexOp vtable k op is@@ -152,8 +157,8 @@     BodyDec rep ~ ()   ) =>   Simplify.SimplifyOp rep op ->-  MCOp rep op ->-  Engine.SimpleM rep (MCOp (Wise rep) (OpWithWisdom op), Stms (Wise rep))+  MCOp (Wise rep) op ->+  Engine.SimpleM rep (MCOp (Wise rep) op, Stms (Wise rep)) simplifyMCOp f (OtherOp op) = do   (op', stms) <- f op   return (OtherOp op', stms)
src/Futhark/IR/Mem.hs view
@@ -242,6 +242,8 @@   type OpWithWisdom (MemOp inner) = MemOp (OpWithWisdom inner)   removeOpWisdom (Alloc size space) = Alloc size space   removeOpWisdom (Inner k) = Inner $ removeOpWisdom k+  addOpWisdom (Alloc size space) = Alloc size space+  addOpWisdom (Inner k) = Inner $ addOpWisdom k  instance ST.IndexOp inner => ST.IndexOp (MemOp inner) where   indexOp vtable k (Inner op) is = ST.indexOp vtable k op is
src/Futhark/IR/Mem/Simplify.hs view
@@ -31,7 +31,7 @@ simpleGeneric ::   (SimplifyMemory rep inner) =>   (OpWithWisdom inner -> UT.UsageTable) ->-  Simplify.SimplifyOp rep inner ->+  Simplify.SimplifyOp rep (OpWithWisdom inner) ->   Simplify.SimpleOps rep simpleGeneric = simplifiable @@ -64,7 +64,7 @@   ) =>   Simplify.SimpleOps rep ->   Stms rep ->-  m (ST.SymbolTable (Wise rep), Stms rep)+  m (Stms rep) simplifyStmsGeneric ops stms = do   scope <- askScope   Simplify.simplifyStms@@ -109,7 +109,6 @@   standardRules     <> ruleBook       [ RuleBasicOp copyCopyToCopy,-        RuleBasicOp removeIdentityCopy,         RuleIf unExistentialiseMemory,         RuleOp decertifySafeAlloc       ]@@ -206,22 +205,6 @@         letExp "rearrange_v0" $ BasicOp $ Rearrange perm v2     letBind pat $ BasicOp $ Copy v0' copyCopyToCopy _ _ _ _ = Skip---- | If the destination of a copy is the same as the source, just--- remove it.-removeIdentityCopy ::-  ( BuilderOps rep,-    LetDec rep ~ (VarWisdom, MemBound u)-  ) =>-  TopDownRuleBasicOp rep-removeIdentityCopy vtable pat@(Pat [pe]) _ (Copy v)-  | (_, MemArray _ _ _ (ArrayIn dest_mem dest_ixfun)) <- patElemDec pe,-    Just (_, MemArray _ _ _ (ArrayIn src_mem src_ixfun)) <--      ST.entryLetBoundDec =<< ST.lookup v vtable,-    dest_mem == src_mem,-    dest_ixfun == src_ixfun =-    Simplify $ letBind pat $ BasicOp $ SubExp $ Var v-removeIdentityCopy _ _ _ _ = Skip  -- If an allocation is statically known to be safe, then we can remove -- the certificates on it.  This can help hoist things that would
src/Futhark/IR/Parse.hs view
@@ -52,7 +52,7 @@   lexeme . fmap nameFromString $     (:) <$> satisfy leading <*> many (satisfy constituent)   where-    leading c = isAlpha c || c == '_'+    leading c = isAlpha c || c `elem` ("_+-*/%=!<>|&^." :: String)  pVName :: Parser VName pVName = lexeme $ do@@ -876,17 +876,17 @@       mon <- pLab "monotonicity" $ brackets (pMon `sepBy` pComma)       pure $ IxFun.LMAD offset $ zipWith5 IxFun.LMADDim strides rotates shape perm mon -pPrimExpLeaf :: Parser (VName, PrimType)-pPrimExpLeaf = (,int64) <$> pVName+pPrimExpLeaf :: Parser VName+pPrimExpLeaf = pVName -pExtPrimExpLeaf :: Parser (Ext VName, PrimType)-pExtPrimExpLeaf = (,int64) <$> pExt pVName+pExtPrimExpLeaf :: Parser (Ext VName)+pExtPrimExpLeaf = pExt pVName  pIxFun :: Parser IxFun-pIxFun = pIxFunBase $ isInt64 <$> pPrimExp pPrimExpLeaf+pIxFun = pIxFunBase $ isInt64 <$> pPrimExp int64 pPrimExpLeaf  pExtIxFun :: Parser ExtIxFun-pExtIxFun = pIxFunBase $ isInt64 <$> pPrimExp pExtPrimExpLeaf+pExtIxFun = pIxFunBase $ isInt64 <$> pPrimExp int64 pExtPrimExpLeaf  pMemInfo :: Parser d -> Parser u -> Parser ret -> Parser (MemInfo d u ret) pMemInfo pd pu pret =
src/Futhark/IR/Primitive.hs view
@@ -695,10 +695,20 @@ doBinOp SRem {} = doRiskyIntBinOp doSRem doBinOp SMin {} = doIntBinOp doSMin doBinOp UMin {} = doIntBinOp doUMin-doBinOp FMin {} = doFloatBinOp min min min+doBinOp FMin {} = doFloatBinOp fmin fmin fmin+  where+    fmin x y+      | isNaN x = y+      | isNaN y = x+      | otherwise = min x y doBinOp SMax {} = doIntBinOp doSMax doBinOp UMax {} = doIntBinOp doUMax-doBinOp FMax {} = doFloatBinOp max max max+doBinOp FMax {} = doFloatBinOp fmax fmax fmax+  where+    fmax x y+      | isNaN x = y+      | isNaN y = x+      | otherwise = max x y doBinOp Shl {} = doIntBinOp doShl doBinOp LShr {} = doIntBinOp doLShr doBinOp AShr {} = doIntBinOp doAShr
src/Futhark/IR/Prop/Aliases.hs view
@@ -31,8 +31,9 @@   ) where -import Control.Arrow (first)+import Data.Bifunctor (first, second) import qualified Data.Kind+import Data.List (find) import qualified Data.Map as M import Futhark.IR.Prop (IsOp, NameInfo (..), Scope) import Futhark.IR.Prop.Names@@ -101,11 +102,25 @@         (bodyAliases tb, consumedInBody tb)         (bodyAliases fb, consumedInBody fb) expAliases (BasicOp op) = basicOpAliases op-expAliases (DoLoop merge _ loopbody) =-  map (`namesSubtract` merge_names) aliases+expAliases (DoLoop merge _ loopbody) = do+  (p, als) <-+    transitive . zip params $ zipWith mappend arg_aliases (bodyAliases loopbody)+  let als' = als `namesSubtract` param_names+  if unique $ paramDeclType p+    then pure mempty+    else pure als'   where-    aliases = bodyAliases loopbody-    merge_names = namesFromList $ map (paramName . fst) merge+    arg_aliases = map (subExpAliases . snd) merge+    params = map fst merge+    param_names = namesFromList $ map paramName params+    transitive merge_and_als =+      let merge_and_als' = map (second expand) merge_and_als+       in if merge_and_als' == merge_and_als+            then merge_and_als+            else transitive merge_and_als'+      where+        look v = maybe mempty snd $ find ((== v) . paramName . fst) merge_and_als+        expand als = als <> foldMap look (namesToList als) expAliases (Apply _ args t _) =   funcallAliases args $ map declExtTypeOf t expAliases (WithAcc inputs lam) =
src/Futhark/IR/SOACS/SOAC.hs view
@@ -607,9 +607,8 @@ instance (ASTRep rep, CanBeWise (Op rep)) => CanBeWise (SOAC rep) where   type OpWithWisdom (SOAC rep) = SOAC (Wise rep) -  removeOpWisdom = runIdentity . mapSOACM remove-    where-      remove = SOACMapper return (return . removeLambdaWisdom) return+  removeOpWisdom = runIdentity . mapSOACM (SOACMapper pure (pure . removeLambdaWisdom) pure)+  addOpWisdom = runIdentity . mapSOACM (SOACMapper pure (pure . informLambda) pure)  instance RepTypes rep => ST.IndexOp (SOAC rep) where   indexOp vtable k soac [i] = do
src/Futhark/IR/SOACS/Simplify.hs view
@@ -76,32 +76,27 @@ simplifyStms ::   (HasScope SOACS m, MonadFreshNames m) =>   Stms SOACS ->-  m (ST.SymbolTable (Wise SOACS), Stms SOACS)+  m (Stms SOACS) simplifyStms stms = do   scope <- askScope-  Simplify.simplifyStms-    simpleSOACS-    soacRules-    Engine.noExtraHoistBlockers-    scope-    stms+  Simplify.simplifyStms simpleSOACS soacRules Engine.noExtraHoistBlockers scope stms  simplifyConsts ::   MonadFreshNames m =>   Stms SOACS ->-  m (ST.SymbolTable (Wise SOACS), Stms SOACS)+  m (Stms SOACS) simplifyConsts =   Simplify.simplifyStms simpleSOACS soacRules Engine.noExtraHoistBlockers mempty  simplifySOAC ::   Simplify.SimplifiableRep rep =>-  Simplify.SimplifyOp rep (SOAC rep)+  Simplify.SimplifyOp rep (SOAC (Wise rep)) simplifySOAC (Stream outerdim arr form nes lam) = do   outerdim' <- Engine.simplify outerdim   (form', form_hoisted) <- simplifyStreamForm form   nes' <- mapM Engine.simplify nes   arr' <- mapM Engine.simplify arr-  (lam', lam_hoisted) <- Engine.simplifyLambda lam+  (lam', lam_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda lam   return     ( Stream outerdim' arr' form' nes' lam',       form_hoisted <> lam_hoisted@@ -114,7 +109,7 @@       return (Sequential, mempty) simplifySOAC (Scatter w ivs lam as) = do   w' <- Engine.simplify w-  (lam', hoisted) <- Engine.simplifyLambda lam+  (lam', hoisted) <- Engine.enterLoop $ Engine.simplifyLambda lam   ivs' <- mapM Engine.simplify ivs   as' <- mapM Engine.simplify as   return (Scatter w' ivs' lam' as', hoisted)@@ -126,10 +121,10 @@       rf' <- Engine.simplify rf       dests' <- Engine.simplify dests       nes' <- mapM Engine.simplify nes-      (op', hoisted) <- Engine.simplifyLambda op+      (op', hoisted) <- Engine.enterLoop $ Engine.simplifyLambda op       return (HistOp dests_w' rf' dests' nes' op', hoisted)   imgs' <- mapM Engine.simplify imgs-  (bfun', bfun_hoisted) <- Engine.simplifyLambda bfun+  (bfun', bfun_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda bfun   return (Hist w' imgs' ops' bfun', mconcat hoisted <> bfun_hoisted) simplifySOAC (Screma w arrs (ScremaForm scans reds map_lam)) = do   (scans', scans_hoisted) <- fmap unzip $@@ -144,7 +139,7 @@       nes' <- Engine.simplify nes       return (Reduce comm lam' nes', hoisted) -  (map_lam', map_lam_hoisted) <- Engine.simplifyLambda map_lam+  (map_lam', map_lam_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda map_lam    (,)     <$> ( Screma <$> Engine.simplify w
src/Futhark/IR/SegOp.hs view
@@ -996,6 +996,10 @@           return           return +informKernelBody :: Informing rep => KernelBody rep -> KernelBody (Wise rep)+informKernelBody (KernelBody dec stms res) =+  mkWiseKernelBody dec (informStms stms) res+ instance   (CanBeWise (Op rep), ASTRep rep, ASTConstraints lvl) =>   CanBeWise (SegOp lvl rep)@@ -1012,6 +1016,16 @@           return           return +  addOpWisdom = runIdentity . mapSegOpM add+    where+      add =+        SegOpMapper+          return+          (return . informLambda)+          (return . informKernelBody)+          return+          return+ instance ASTRep rep => ST.IndexOp (SegOp lvl rep) where   indexOp vtable k (SegMap _ space _ kbody) is = do     Returns ResultMaySimplify _ se <- maybeNth k $ kernelBodyResult kbody@@ -1124,28 +1138,28 @@ simplifyKernelBody ::   (Engine.SimplifiableRep rep, BodyDec rep ~ ()) =>   SegSpace ->-  KernelBody rep ->+  KernelBody (Wise rep) ->   Engine.SimpleM rep (KernelBody (Wise rep), Stms (Wise rep)) simplifyKernelBody space (KernelBody _ stms res) = do   par_blocker <- Engine.asksEngineEnv $ Engine.blockHoistPar . Engine.envHoistBlockers +  let blocker =+        Engine.hasFree bound_here+          `Engine.orIf` Engine.isOp+          `Engine.orIf` par_blocker+          `Engine.orIf` Engine.isConsumed+   -- Ensure we do not try to use anything that is consumed in the result.-  ((body_stms, body_res), hoisted) <-+  (body_res, body_stms, hoisted) <-     Engine.localVtable (flip (foldl' (flip ST.consume)) (foldMap consumedInResult res))       . Engine.localVtable (<> scope_vtable)       . Engine.localVtable (\vtable -> vtable {ST.simplifyMemory = True})       . Engine.enterLoop-      $ Engine.blockIf-        ( Engine.hasFree bound_here-            `Engine.orIf` Engine.isOp-            `Engine.orIf` par_blocker-            `Engine.orIf` Engine.isConsumed-        )-        $ Engine.simplifyStms stms $ do-          res' <--            Engine.localVtable (ST.hideCertified $ namesFromList $ M.keys $ scopeOf stms) $-              mapM Engine.simplify res-          return ((res', UT.usages $ freeIn res'), mempty)+      $ Engine.blockIf blocker stms $ do+        res' <-+          Engine.localVtable (ST.hideCertified $ namesFromList $ M.keys $ scopeOf stms) $+            mapM Engine.simplify res+        pure (res', UT.usages $ freeIn res')    return (mkWiseKernelBody () body_stms body_res, hoisted)   where@@ -1165,7 +1179,7 @@  simplifySegBinOp ::   Engine.SimplifiableRep rep =>-  SegBinOp rep ->+  SegBinOp (Wise rep) ->   Engine.SimpleM rep (SegBinOp (Wise rep), Stms (Wise rep)) simplifySegBinOp (SegBinOp comm lam nes shape) = do   (lam', hoisted) <-@@ -1181,7 +1195,7 @@     BodyDec rep ~ (),     Engine.Simplifiable lvl   ) =>-  SegOp lvl rep ->+  SegOp lvl (Wise rep) ->   Engine.SimpleM rep (SegOp lvl (Wise rep), Stms (Wise rep)) simplifySegOp (SegMap lvl space ts kbody) = do   (lvl', space', ts') <- Engine.simplify (lvl, space, ts)
src/Futhark/Internalise/Defunctionalise.hs view
@@ -1049,16 +1049,12 @@     mkExt _ = Nothing     rettype_st = RetType (mapMaybe mkExt (S.toList (typeDimNames ret)) ++ ret_dims) ret -    (valbind_t, valbind_ext) =-      case pats of-        [] -> (RetType [] $ retType rettype_st, retDims rettype_st)-        _ -> (rettype_st, [])     dec =       ValBind         { valBindEntryPoint = Nothing,           valBindName = fname,           valBindRetDecl = Nothing,-          valBindRetType = Info (valbind_t, valbind_ext),+          valBindRetType = Info rettype_st,           valBindTypeParams = dims',           valBindParams = pats,           valBindBody = body,@@ -1249,7 +1245,7 @@ -- boolean is true if the function is a 'DynamicFun'. defuncValBind :: ValBind -> DefM (ValBind, Env) -- Eta-expand entry points with a functional return type.-defuncValBind (ValBind entry name _ (Info (RetType _ rettype, retext)) tparams params body _ attrs loc)+defuncValBind (ValBind entry name _ (Info (RetType _ rettype)) tparams params body _ attrs loc)   | Scalar Arrow {} <- rettype = do     (body_pats, body', rettype') <- etaExpand (fromStruct rettype) body     defuncValBind $@@ -1257,14 +1253,14 @@         entry         name         Nothing-        (Info (rettype', retext))+        (Info rettype')         tparams         (params <> body_pats)         body'         Nothing         attrs         loc-defuncValBind valbind@(ValBind _ name retdecl (Info (RetType ret_dims rettype, retext)) tparams params body _ _ _) = do+defuncValBind valbind@(ValBind _ name retdecl (Info (RetType ret_dims rettype)) tparams params body _ _ _) = do   when (any isTypeParam tparams) $     error $       prettyName name ++ " has type parameters, "@@ -1279,20 +1275,17 @@         -- applications of lifted functions, we don't properly update         -- the types in the return type annotation.         combineTypeShapes rettype $ first (anyDimIfNotBound bound_sizes) $ toStruct $ typeOf body'+      ret_dims' = filter (`S.member` typeDimNames rettype') ret_dims   (missing_dims, params'') <- sizesForAll bound_sizes params' -  return+  pure     ( valbind         { valBindRetDecl = retdecl,           valBindRetType =-            Info-              ( if null params'-                  then-                    ( RetType [] $ rettype' `setUniqueness` Nonunique,-                      retext-                    )-                  else (RetType ret_dims rettype', retext)-              ),+            Info $+              if null params'+                then RetType ret_dims' $ rettype' `setUniqueness` Nonunique+                else RetType ret_dims' rettype',           valBindTypeParams =             map (`TypeParamDim` mempty) $ tparams' ++ missing_dims,           valBindParams = params'',@@ -1314,7 +1307,7 @@ defuncVals (valbind : ds) = do   (valbind', env) <- defuncValBind valbind   addValBind valbind'-  let globals = valBindName valbind' : snd (unInfo (valBindRetType valbind'))+  let globals = valBindBound valbind'   localEnv env $ areGlobal globals $ defuncVals ds  {-# NOINLINE transformProg #-}
src/Futhark/Internalise/Defunctorise.hs view
@@ -190,16 +190,14 @@     ModFun f_abs f_closure f_p f_body ->       bindingAbs (f_abs <> S.fromList (unInfo (modParamAbs f_p)))         . extendAbsTypes b_substs-        . extendScope f_closure+        . localScope (const f_closure) -- Start afresh.         . generating         $ do           outer_substs <- scopeSubsts <$> askScope           abs <- asks envAbs           let forward (k, v) = (lookupSubst k outer_substs, v)               p_substs' = M.fromList $ map forward $ M.toList p_substs-              keep k _ =-                k `M.member` p_substs'-                  || k `S.member` abs+              keep k _ = k `M.member` p_substs' || k `S.member` abs               abs_substs =                 M.filterWithKey keep $                   M.map (`lookupSubst` scopeSubsts (modScope arg_mod)) p_substs'@@ -215,7 +213,7 @@             $ do               substs <- scopeSubsts <$> askScope               x <- evalModExp f_body-              return $+              pure $                 addSubsts abs abs_substs $                   -- The next one is dubious, but is necessary to                   -- propagate substitutions from the argument (see@@ -276,14 +274,14 @@ transformExp = transformNames  transformValBind :: ValBind -> TransformM ()-transformValBind (ValBind entry name tdecl (Info (RetType dims t, retext)) tparams params e doc attrs loc) = do+transformValBind (ValBind entry name tdecl (Info (RetType dims t)) tparams params e doc attrs loc) = do   name' <- transformName name   tdecl' <- traverse transformTypeExp tdecl   t' <- transformStructType t   e' <- transformExp e   tparams' <- traverse transformNames tparams   params' <- traverse transformNames params-  emit $ ValDec $ ValBind entry name' tdecl' (Info (RetType dims t', retext)) 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@@ -306,13 +304,7 @@         (maybeAscript (srclocOf mb) (modSignature mb) $ modExp mb)         $ modParams mb   mname <- transformName $ modName mb-  abs <- asks envAbs-  -- Copy substitutions involving abstract types out, because they are-  -- always resolved at the outermost level.-  let abs_substs =-        M.filterWithKey (const . flip S.member abs) $-          scopeSubsts $ modScope mod-  return $ Scope abs_substs $ M.singleton mname mod+  return $ Scope (scopeSubsts $ modScope mod) $ M.singleton mname mod  transformDecs :: [Dec] -> TransformM Scope transformDecs ds =
src/Futhark/Internalise/Exps.hs view
@@ -39,7 +39,7 @@ internaliseFunName = nameFromString . pretty  internaliseValBind :: E.ValBind -> InternaliseM ()-internaliseValBind fb@(E.ValBind entry fname retdecl (Info (rettype, _)) tparams params body _ attrs loc) = do+internaliseValBind fb@(E.ValBind entry fname retdecl (Info rettype) tparams params body _ attrs loc) = do   localConstsScope . bindingFParams tparams params $ \shapeparams params' -> do     let shapenames = map I.paramName shapeparams @@ -94,7 +94,7 @@  generateEntryPoint :: E.EntryPoint -> E.ValBind -> InternaliseM () generateEntryPoint (E.EntryPoint e_params e_rettype) vb = localConstsScope $ do-  let (E.ValBind _ ofname _ (Info (rettype, _)) tparams params _ _ attrs loc) = vb+  let (E.ValBind _ ofname _ (Info rettype) tparams params _ _ attrs loc) = vb   bindingFParams tparams params $ \shapeparams params' -> do     entry_rettype <- internaliseEntryReturnType rettype     let entry' = entryPoint (baseName ofname) (zip e_params params') (e_rettype, entry_rettype)@@ -419,19 +419,27 @@    ctxinit <- argShapes (map I.paramName shapepat) mergepat' mergeinit_ts' -  let ctxmerge = zip shapepat ctxinit-      valmerge = zip mergepat' mergeinit'-      dropCond = case form of+  -- Ensure that the initial loop values match the shapes of the loop+  -- parameters.  XXX: Ideally they should already match (by the+  -- source language type rules), but some of our transformations+  -- (esp. defunctionalisation) strips out some size information.  For+  -- a type-correct source program, these reshapes should simplify+  -- away.+  let args = ctxinit ++ mergeinit'+  args' <-+    ensureArgShapes+      "initial loop values have right shape"+      loc+      (map I.paramName shapepat)+      (map paramType $ shapepat ++ mergepat')+      args++  let dropCond = case form of         E.While {} -> drop 1         _ -> id -  -- Ensure that the result of the loop matches the shapes of the-  -- merge parameters.  XXX: Ideally they should already match (by-  -- the source language type rules), but some of our-  -- transformations (esp. defunctionalisation) strips out some size-  -- information.  For a type-correct source program, these reshapes-  -- should simplify away.-  let merge = ctxmerge ++ valmerge+  -- As above, ensure that the result has the right shape.+  let merge = zip (shapepat ++ mergepat') args'       merge_ts = map (I.paramType . fst) merge   loopbody'' <-     localScope (scopeOfFParams $ map fst merge) . inScopeOf form' . buildBody_ $@@ -439,7 +447,7 @@         . ensureArgShapes           "shape of loop result does not match shapes in loop parameter"           loc-          (map (I.paramName . fst) ctxmerge)+          (map (I.paramName . fst) merge)           merge_ts         . map resSubExp         =<< bodyBind loopbody'@@ -448,7 +456,7 @@   map I.Var . dropCond     <$> attributing       attrs-      (letValExp desc (I.DoLoop (ctxmerge <> valmerge) form' loopbody''))+      (letValExp desc (I.DoLoop merge form' loopbody''))   where     sparams' = map (`TypeParamDim` mempty) sparams 
src/Futhark/Internalise/LiftLambdas.hs view
@@ -51,10 +51,8 @@ addValBind vb = modify $ \s ->   s     { stateValBinds = vb : stateValBinds s,-      stateGlobal = foldl' (flip S.insert) (stateGlobal s) names+      stateGlobal = foldl' (flip S.insert) (stateGlobal s) (valBindBound vb)     }-  where-    names = valBindName vb : snd (unInfo (valBindRetType vb))  replacing :: VName -> Exp -> LiftM a -> LiftM a replacing v e = local $ \env ->@@ -111,7 +109,7 @@         valBindTypeParams = tparams,         valBindParams = free_params ++ params,         valBindRetDecl = Nothing,-        valBindRetType = Info (RetType dims ret, mempty),+        valBindRetType = Info (RetType dims ret),         valBindBody = funbody,         valBindDoc = Nothing,         valBindAttrs = mempty,
src/Futhark/Internalise/Monomorphise.hs view
@@ -65,7 +65,6 @@         [TypeParam],         [Pat],         StructRetType,-        [VName],         Exp,         [AttrInfo VName],         SrcLoc@@ -300,7 +299,7 @@     -- filter those that are monomorphic versions of the current let-bound     -- function and insert them at this point, and propagate the rest.     rr <- asks envRecordReplacements-    let funbind = PolyBinding rr (fname, tparams, params, ret, [], body, mempty, loc)+    let funbind = PolyBinding rr (fname, tparams, params, ret, body, mempty, loc)     pass $ do       (e', bs) <- listen $ extendEnv fname funbind $ transformExp e       -- Do not remember this one for next time we monomorphise this@@ -625,7 +624,7 @@ -- monomorphic functions with the given expression at the bottom. unfoldLetFuns :: [ValBind] -> Exp -> Exp unfoldLetFuns [] e = e-unfoldLetFuns (ValBind _ fname _ (Info (rettype, _)) dim_params params body _ _ loc : rest) e =+unfoldLetFuns (ValBind _ fname _ (Info rettype) dim_params params body _ _ loc : rest) e =   AppExp (LetFun fname (dim_params, params, Nothing, Info rettype, body) e' loc) (Info $ AppRes e_t mempty)   where     e' = unfoldLetFuns rest e@@ -731,7 +730,7 @@   PolyBinding ->   MonoType ->   MonoM (VName, InferSizeArgs, ValBind)-monomorphiseBinding entry (PolyBinding rr (name, tparams, params, rettype, retext, body, attrs, loc)) inst_t =+monomorphiseBinding entry (PolyBinding rr (name, tparams, params, rettype, body, attrs, loc)) inst_t =   replaceRecordReplacements rr $ do     let bind_t = foldFunType (map patternStructType params) rettype     (substs, t_shape_params) <- typeSubstsM loc (noSizes bind_t) $ noNamedParams inst_t@@ -762,14 +761,14 @@               name'               (shape_params_explicit ++ shape_params_implicit)               params''-              (rettype', retext)+              rettype'               body''           else             toValBinding               name'               shape_params_implicit               (map shapeParam shape_params_explicit ++ params'')-              (rettype', retext)+              rettype'               body''       )   where@@ -879,13 +878,13 @@   PatConstr n (Info tp) ps loc -> PatConstr n (Info $ f tp) ps loc  toPolyBinding :: ValBind -> PolyBinding-toPolyBinding (ValBind _ name _ (Info (rettype, retext)) tparams params body _ attrs loc) =-  PolyBinding mempty (name, tparams, params, rettype, retext, body, attrs, loc)+toPolyBinding (ValBind _ name _ (Info rettype) tparams params body _ attrs loc) =+  PolyBinding mempty (name, tparams, params, rettype, body, attrs, loc)  -- Remove all type variables and type abbreviations from a value binding. removeTypeVariables :: Bool -> ValBind -> MonoM ValBind removeTypeVariables entry valbind = do-  let (ValBind _ _ _ (Info (RetType dims rettype, retext)) _ pats body _ _ _) = valbind+  let (ValBind _ _ _ (Info (RetType dims rettype)) _ pats body _ _ _) = valbind   subs <- asks $ M.map substFromAbbr . envTypeBindings   let mapper =         ASTMapper@@ -904,7 +903,7 @@    return     valbind-      { valBindRetType = Info (applySubst (`M.lookup` subs) $ RetType dims rettype, retext),+      { valBindRetType = Info (applySubst (`M.lookup` subs) $ RetType dims rettype),         valBindParams = map (substPat entry $ applySubst (`M.lookup` subs)) pats,         valBindBody = body'       }@@ -925,7 +924,7 @@       removeTypeVariablesInType $         foldFunType           (map patternStructType (valBindParams valbind))-          $ fst $ unInfo $ valBindRetType valbind+          $ unInfo $ valBindRetType valbind     (name, infer, valbind'') <- monomorphiseBinding True valbind' $ monoType t     tell $ Seq.singleton (name, valbind'' {valBindEntryPoint = valBindEntryPoint valbind})     addLifted (valBindName valbind) (monoType t) (name, infer)
src/Futhark/Optimise/DoubleBuffer.hs view
@@ -315,9 +315,15 @@             arg_copy <- newVName (baseString arg <> "_dbcopy")             letBind (Pat [PatElem arg_copy $ MemArray pt shape u $ ArrayIn mem' arg_ixfun]) $               BasicOp $ Copy arg-            pure (param, Var arg_copy)-          _ -> pure (param, Var arg)+            -- We need to make this parameter unique to avoid invalid+            -- hoisting (see #1533), because we are invalidating the+            -- underlying memory.+            pure (fmap mkUnique param, Var arg_copy)+          _ -> pure (fmap mkUnique param, Var arg)     maybeCopyInitial _ (param, arg) = pure (param, arg)++    mkUnique (MemArray bt shape _ ret) = MemArray bt shape Unique ret+    mkUnique x = x  optimiseLoopByCopying :: Constraints rep inner => OptimiseLoop rep optimiseLoopByCopying pat merge body = do
src/Futhark/Optimise/InPlaceLowering.hs view
@@ -59,6 +59,8 @@ --    (8) The result of the loop may not alias the merge parameter --    @r1@. --+--    (9) @y@ or its aliases may not be used after the loop.+-- -- FIXME: the implementation is not finished yet.  Specifically, not -- all of the above conditions are checked. module Futhark.Optimise.InPlaceLowering@@ -70,6 +72,7 @@  import Control.Monad.RWS import qualified Data.Map.Strict as M+import Data.Ord (comparing) import Futhark.Analysis.Alias import Futhark.Builder import Futhark.IR.Aliases@@ -78,6 +81,7 @@ import Futhark.IR.Seq (Seq) import Futhark.Optimise.InPlaceLowering.LowerIntoStm import Futhark.Pass+import Futhark.Util (nubByOrd)  -- | Apply the in-place lowering optimisation to the given program. inPlaceLoweringGPU :: Pass GPU GPU@@ -137,14 +141,19 @@   [Stm (Aliases rep)] ->   ForwardingM rep () ->   ForwardingM rep [Stm (Aliases rep)]-optimiseStms [] m = m >> return []+optimiseStms [] m = m >> pure [] optimiseStms (stm : stms) m = do   (stms', bup) <- tapBottomUp $ bindingStm stm $ optimiseStms stms m   stm' <- optimiseInStm stm-  case filter ((`elem` boundHere) . updateValue) $ forwardThese bup of+  -- XXX: unfortunate that we cannot handle duplicate update values.+  -- Would be good to improve this.  See inplacelowering6.fut.+  case nubByOrd (comparing updateValue)+    . filter (not . (`nameIn` bottomUpSeen bup) . updateSource) -- (9)+    . filter ((`elem` boundHere) . updateValue)+    $ forwardThese bup of     [] -> do       checkIfForwardableUpdate stm'-      return $ stm' : stms'+      pure $ stm' : stms'     updates -> do       lower <- asks topLowerUpdate       scope <- askScope@@ -160,13 +169,11 @@       case lower scope stm' updates of         Just lowering -> do           new_stms <- lowering-          new_stms' <--            optimiseStms new_stms $-              tell bup {forwardThese = []}-          return $ new_stms' ++ filter notUpdated stms'+          new_stms' <- optimiseStms new_stms $ tell bup {forwardThese = []}+          pure $ new_stms' ++ filter notUpdated stms'         Nothing -> do           checkIfForwardableUpdate stm'-          return $ stm' : stms'+          pure $ stm' : stms'   where     boundHere = patNames $ stmPat stm @@ -174,7 +181,8 @@       | Pat [PatElem v dec] <- pat,         BasicOp (Update Unsafe src slice (Var ve)) <- e =         maybeForward ve v dec cs src slice-    checkIfForwardableUpdate _ = return ()+    checkIfForwardableUpdate stm' =+      mapM_ seenVar $ namesToList $ freeIn $ stmExp stm'  optimiseInStm :: Constraints rep => Stm (Aliases rep) -> ForwardingM rep (Stm (Aliases rep)) optimiseInStm (Let pat dec e) =
src/Futhark/Optimise/InliningDeadFun.hs view
@@ -26,7 +26,7 @@     simplifyFun,   ) import Futhark.Optimise.CSE-import Futhark.Optimise.Simplify.Rep (addScopeWisdom)+import Futhark.Optimise.Simplify.Rep (addScopeWisdom, informStms) import Futhark.Pass import Futhark.Transform.CopyPropagate   ( copyPropagateInFun,@@ -81,9 +81,11 @@                 fdmap $ filter ((`S.member` to_inline_now) . funDefName) dont_inline_in           (vtable', consts') <-             if any (`calledByConsts` cg) to_inline_now-              then-                simplifyConsts . performCSEOnStms True-                  =<< inlineInStms inlinemap consts+              then do+                consts' <-+                  simplifyConsts . performCSEOnStms True+                    =<< inlineInStms inlinemap consts+                pure (ST.insertStms (informStms consts') mempty, consts')               else pure (vtable, consts)            let simplifyFun' fd@@ -94,7 +96,8 @@                 | otherwise =                   copyPropagateInFun simpleSOACS vtable' fd -              onFun = simplifyFun' <=< inlineInFunDef inlinemap+              onFun fd =+                simplifyFun' <=< inlineInFunDef inlinemap $ fd            to_inline_in' <- parMapM onFun to_inline_in 
src/Futhark/Optimise/Simplify.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE Strict #-}-{-# LANGUAGE TupleSections #-}  module Futhark.Optimise.Simplify   ( simplifyProg,@@ -21,7 +20,6 @@   ) where -import Data.Bifunctor (second) import qualified Futhark.Analysis.SymbolTable as ST import qualified Futhark.Analysis.UsageTable as UT import Futhark.IR@@ -43,24 +41,22 @@   PassM (Prog rep) simplifyProg simpl rules blockers (Prog consts funs) = do   (consts_vtable, consts') <--    simplifyConsts-      (UT.usages $ foldMap freeIn funs)-      (mempty, consts)+    simplifyConsts (UT.usages $ foldMap freeIn funs) (mempty, informStms consts)    -- We deepen the vtable so it will look like the constants are in an   -- "outer loop"; this communicates useful information to some   -- simplification rules (e.g. seee issue #1302).-  funs' <- parPass (simplifyFun' $ ST.deepen consts_vtable) funs+  funs' <- parPass (simplifyFun' (ST.deepen consts_vtable) . informFunDef) funs   let funs_uses = UT.usages $ foldMap freeIn funs'    (_, consts'') <- simplifyConsts funs_uses (mempty, consts') -  return $ Prog consts'' funs'+  pure $ Prog (fmap removeStmWisdom consts'') (fmap removeFunDefWisdom funs')   where     simplifyFun' consts_vtable =       simplifySomething         (Engine.localVtable (consts_vtable <>) . Engine.simplifyFun)-        removeFunDefWisdom+        id         simpl         rules         blockers@@ -69,18 +65,15 @@     simplifyConsts uses =       simplifySomething         (onConsts uses . snd)-        (second (removeStmWisdom <$>))+        id         simpl         rules         blockers         mempty      onConsts uses consts' = do-      (_, consts'') <--        Engine.simplifyStms consts' (pure ((), mempty))-      (consts''', _) <--        Engine.hoistStms rules (Engine.isFalse False) mempty uses consts''-      return (ST.insertStms consts''' mempty, consts''')+      consts'' <- Engine.simplifyStmsWithUsage uses consts'+      pure (ST.insertStms consts'' mempty, consts'')  -- | Run a simplification operation to convergence. simplifySomething ::@@ -111,7 +104,16 @@   ST.SymbolTable (Wise rep) ->   FunDef rep ->   m (FunDef rep)-simplifyFun = simplifySomething Engine.simplifyFun removeFunDefWisdom+simplifyFun simpl rules blockers vtable fd =+  removeFunDefWisdom+    <$> simplifySomething+      Engine.simplifyFun+      id+      simpl+      rules+      blockers+      vtable+      (informFunDef fd)  -- | Simplify just a single t'Lambda'. simplifyLambda ::@@ -126,14 +128,15 @@   m (Lambda rep) simplifyLambda simpl rules blockers orig_lam = do   vtable <- ST.fromScope . addScopeWisdom <$> askScope-  simplifySomething-    Engine.simplifyLambdaNoHoisting-    removeLambdaWisdom-    simpl-    rules-    blockers-    vtable-    orig_lam+  removeLambdaWisdom+    <$> simplifySomething+      Engine.simplifyLambdaNoHoisting+      id+      simpl+      rules+      blockers+      vtable+      (informLambda orig_lam)  -- | Simplify a sequence of 'Stm's. simplifyStms ::@@ -143,14 +146,14 @@   Engine.HoistBlockers rep ->   Scope rep ->   Stms rep ->-  m (ST.SymbolTable (Wise rep), Stms rep)+  m (Stms rep) simplifyStms simpl rules blockers scope =-  simplifySomething f g simpl rules blockers vtable . (mempty,)+  fmap (fmap removeStmWisdom)+    . simplifySomething f id simpl rules blockers vtable+    . informStms   where     vtable = ST.fromScope $ addScopeWisdom scope-    f (_, stms) =-      Engine.simplifyStms stms ((,mempty) <$> Engine.askVtable)-    g = second $ fmap removeStmWisdom+    f stms = Engine.simplifyStms stms  loopUntilConvergence ::   (MonadFreshNames m, Engine.SimplifiableRep rep) =>@@ -162,4 +165,4 @@   m a loopUntilConvergence env simpl f g x = do   (x', changed) <- modifyNameSource $ Engine.runSimpleM (f x) simpl env-  if changed then loopUntilConvergence env simpl f g (g x') else return $ g x'+  if changed then loopUntilConvergence env simpl f g (g x') else pure $ g x'
src/Futhark/Optimise/Simplify/Engine.hs view
@@ -50,13 +50,13 @@     -- * Building blocks     SimplifiableRep,     Simplifiable (..),-    simplifyStms,     simplifyFun,+    simplifyStms,+    simplifyStmsWithUsage,     simplifyLambda,     simplifyLambdaNoHoisting,     bindLParams,     simplifyBody,-    SimplifiedBody,     ST.SymbolTable,     hoistStms,     blockIf,@@ -69,6 +69,7 @@ import Control.Monad.State.Strict import Data.Either import Data.List (find, foldl', mapAccumL)+import qualified Data.Map as M import Data.Maybe import qualified Futhark.Analysis.SymbolTable as ST import qualified Futhark.Analysis.UsageTable as UT@@ -113,6 +114,8 @@  type Protect m = SubExp -> Pat (Rep m) -> Op (Rep m) -> Maybe (m ()) +type SimplifyOp rep op = op -> SimpleM rep (op, Stms (Wise rep))+ data SimpleOps rep = SimpleOps   { mkExpDecS ::       ST.SymbolTable (Wise rep) ->@@ -129,14 +132,12 @@     -- actually be used.     protectHoistedOpS :: Protect (Builder (Wise rep)),     opUsageS :: Op (Wise rep) -> UT.UsageTable,-    simplifyOpS :: SimplifyOp rep (Op rep)+    simplifyOpS :: SimplifyOp rep (Op (Wise rep))   } -type SimplifyOp rep op = op -> SimpleM rep (OpWithWisdom op, Stms (Wise rep))- bindableSimpleOps ::   (SimplifiableRep rep, Buildable rep) =>-  SimplifyOp rep (Op rep) ->+  SimplifyOp rep (Op (Wise rep)) ->   SimpleOps rep bindableSimpleOps =   SimpleOps mkExpDecS' mkBodyS' protectHoistedOpS' (const mempty)@@ -264,21 +265,21 @@   -- | Which side of the branch are we   -- protecting here?   Bool ->-  SimpleM rep (a, Stms (Wise rep)) ->-  SimpleM rep (a, Stms (Wise rep))+  SimpleM rep (Stms (Wise rep), a) ->+  SimpleM rep (Stms (Wise rep), a) protectIfHoisted cond side m = do-  (x, stms) <- m+  (hoisted, x) <- m   ops <- asks $ protectHoistedOpS . fst-  runBuilder $ do-    if not $ all (safeExp . stmExp) stms+  hoisted' <- runBuilder_ $ do+    if not $ all (safeExp . stmExp) hoisted       then do         cond' <-           if side             then return cond             else letSubExp "cond_neg" $ BasicOp $ UnOp Not cond-        mapM_ (protectIf ops unsafeOrCostly cond') stms-      else addStms stms-    return x+        mapM_ (protectIf ops unsafeOrCostly cond') hoisted+      else addStms hoisted+  pure (hoisted', x)   where     unsafeOrCostly e = not (safeExp e) || not (cheapExp e) @@ -289,18 +290,18 @@   SimplifiableRep rep =>   [(FParam (Wise rep), SubExp)] ->   LoopForm (Wise rep) ->-  SimpleM rep (a, Stms (Wise rep)) ->-  SimpleM rep (a, Stms (Wise rep))+  SimpleM rep (a, b, Stms (Wise rep)) ->+  SimpleM rep (a, b, Stms (Wise rep)) protectLoopHoisted merge form m = do-  (x, stms) <- m+  (x, y, stms) <- m   ops <- asks $ protectHoistedOpS . fst-  runBuilder $ do+  stms' <- runBuilder_ $ do     if not $ all (safeExp . stmExp) stms       then do         is_nonempty <- checkIfNonEmpty         mapM_ (protectIf ops (not . safeExp) is_nonempty) stms       else addStms stms-    return x+  pure (x, y, stms')   where     checkIfNonEmpty =       case form of@@ -387,67 +388,115 @@ 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 =>+  Stm (Wise rep) ->+  SimpleM rep (Stm (Wise rep))+nonrecSimplifyStm (Let pat (StmAux cs attrs (_, dec)) e) = do+  cs' <- simplify cs+  (pat', pat_cs) <- collectCerts $ simplifyPat $ removePatWisdom pat+  let aux' = StmAux (cs' <> pat_cs) attrs dec+  mkWiseLetStm pat' aux' <$> simplifyExpBase e++-- Bottom-up simplify a statement.  Recurses into sub-Bodies and Ops.+-- Does not copy-propagate into the pattern and similar, as it is+-- 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 =>+  Stm (Wise rep) ->+  UT.UsageTable ->+  SimpleM rep (Stms (Wise rep), Stm (Wise rep))+recSimplifyStm (Let pat (StmAux cs attrs (_, dec)) e) usage = do+  ((e', e_hoisted), e_cs) <- collectCerts $ simplifyExp usage pat e+  let aux' = StmAux (cs <> e_cs) attrs dec+  pure (e_hoisted, mkWiseLetStm (removePatWisdom pat) aux' e')+ hoistStms ::   SimplifiableRep rep =>   RuleBook (Wise rep) ->   BlockPred (Wise rep) ->-  ST.SymbolTable (Wise rep) ->-  UT.UsageTable ->   Stms (Wise rep) ->-  SimpleM-    rep-    ( Stms (Wise rep),-      Stms (Wise rep)-    )-hoistStms rules block vtable uses orig_stms = do-  (blocked, hoisted) <- simplifyStmsBottomUp vtable uses orig_stms+  SimpleM rep (a, UT.UsageTable) ->+  SimpleM rep (a, Stms (Wise rep), Stms (Wise rep))+hoistStms rules block orig_stms final = do+  (a, blocked, hoisted) <- simplifyStmsBottomUp orig_stms   unless (null hoisted) changed-  return (stmsFromList blocked, stmsFromList hoisted)+  pure (a, stmsFromList blocked, stmsFromList hoisted)   where-    simplifyStmsBottomUp vtable' uses' stms = do-      (_, stms') <- simplifyStmsBottomUp' vtable' uses' stms-      -- We need to do a final pass to ensure that nothing is-      -- hoisted past something that it depends on.-      let (blocked, hoisted) = partitionEithers $ blockUnhoistedDeps stms'-      return (blocked, hoisted)--    simplifyStmsBottomUp' vtable' uses' stms = do+    simplifyStmsBottomUp stms = do       opUsage <- asks $ opUsageS . fst       let usageInStm stm =             UT.usageInStm stm               <> case stmExp stm of                 Op op -> opUsage op                 _ -> mempty-      foldM (hoistable usageInStm) (uses', []) $ reverse $ zip (stmsToList stms) vtables-      where-        vtables = scanl (flip ST.insertStm) vtable' $ stmsToList stms+      (x, _, stms') <- hoistableStms usageInStm stms+      -- We need to do a final pass to ensure that nothing is+      -- hoisted past something that it depends on.+      let (blocked, hoisted) = partitionEithers $ blockUnhoistedDeps stms'+      pure (x, blocked, hoisted) -    hoistable usageInStm (uses', stms) (stm, vtable')-      | not $ any (`UT.isUsedDirectly` uses') $ provides stm =-        -- Dead statement.-        return (uses', stms)-      | otherwise = do-        res <--          localVtable (const vtable') $-            bottomUpSimplifyStm rules (vtable', uses') stm-        case res of-          Nothing -- Nothing to optimise - see if hoistable.-            | block vtable' uses' stm ->-              return-                ( expandUsage usageInStm vtable' uses' stm-                    `UT.without` provides stm,-                  Left stm : stms-                )-            | otherwise ->-              return-                ( expandUsage usageInStm vtable' uses' stm,-                  Right stm : stms-                )-          Just optimstms -> do-            changed-            (uses'', stms') <- simplifyStmsBottomUp' vtable' uses' optimstms-            return (uses'', stms' <> stms)+    descend usageInStm stms m =+      case stmsHead stms of+        Nothing -> m+        Just (stms_h, stms_t) -> localVtable (ST.insertStm stms_h) $ do+          (x, usage, stms_t') <- descend usageInStm stms_t m+          process usageInStm stms_h stms_t' usage x +    process usageInStm stm stms usage x = do+      vtable <- askVtable+      res <- bottomUpSimplifyStm rules (vtable, usage) stm+      case res of+        Nothing -- Nothing to optimise - see if hoistable.+          | block vtable usage stm ->+            -- No, not hoistable.+            pure+              ( x,+                expandUsage usageInStm vtable usage stm+                  `UT.without` provides stm,+                Left stm : stms+              )+          | otherwise ->+            -- Yes, hoistable.+            pure+              ( x,+                expandUsage usageInStm vtable usage stm,+                Right stm : stms+              )+        Just optimstms -> do+          changed+          descend usageInStm optimstms $ pure (x, usage, stms)++    hoistableStms usageInStm stms =+      case stmsHead stms of+        Nothing -> do+          (x, usage) <- final+          pure (x, usage, mempty)+        Just (stms_h, stms_t) -> do+          stms_h' <- nonrecSimplifyStm stms_h++          vtable <- askVtable+          simplified <- topDownSimplifyStm rules vtable stms_h'++          case simplified of+            Just newstms -> do+              changed+              hoistableStms usageInStm (newstms <> stms_t)+            Nothing -> do+              (x, usage, stms_t') <-+                localVtable (ST.insertStm stms_h') $+                  hoistableStms usageInStm stms_t+              if not $ any (`UT.isUsedDirectly` usage) $ provides stms_h'+                then -- Dead statement.+                  pure (x, usage, stms_t')+                else do+                  (stms_h_stms, stms_h'') <- recSimplifyStm stms_h' usage+                  descend usageInStm stms_h_stms $+                    process usageInStm stms_h'' stms_t' usage x+ blockUnhoistedDeps ::   ASTRep rep =>   [Either (Stm rep) (Stm rep)] ->@@ -522,19 +571,15 @@     addStms stms     pure res -type SimplifiedBody rep a = ((a, UT.UsageTable), Stms (Wise rep))- blockIf ::   SimplifiableRep rep =>   BlockPred (Wise rep) ->-  SimpleM rep (SimplifiedBody rep a) ->-  SimpleM rep ((Stms (Wise rep), a), Stms (Wise rep))-blockIf block m = do-  ((x, usages), stms) <- m-  vtable <- askVtable+  Stms (Wise rep) ->+  SimpleM rep (a, UT.UsageTable) ->+  SimpleM rep (a, Stms (Wise rep), Stms (Wise rep))+blockIf block stms m = do   rules <- asksEngineEnv envRules-  (blocked, hoisted) <- hoistStms rules block vtable usages stms-  return ((blocked, x), hoisted)+  hoistStms rules block stms m  hasFree :: ASTRep rep => Names -> BlockPred rep hasFree ks _ _ need = ks `namesIntersect` freeIn need@@ -579,22 +624,24 @@  hoistCommon ::   SimplifiableRep rep =>+  UT.UsageTable ->+  [UT.Usages] ->   SubExp ->   IfSort ->-  SimplifiedBody rep Result ->-  SimplifiedBody rep Result ->+  Body (Wise rep) ->+  Body (Wise rep) ->   SimpleM     rep     ( Body (Wise rep),       Body (Wise rep),       Stms (Wise rep)     )-hoistCommon cond ifsort ((res1, usages1), stms1) ((res2, usages2), stms2) = do+hoistCommon res_usage res_usages cond ifsort body1 body2 = do   is_alloc_fun <- asksEngineEnv $ isAllocation . envHoistBlockers   branch_blocker <- asksEngineEnv $ blockHoistBranch . envHoistBlockers   vtable <- askVtable   let -- We are unwilling to hoist things that are unsafe or costly,-+      -- except if they are invariant to the most enclosing loop,       -- because in that case they will also be hoisted past that       -- loop.       --@@ -616,8 +663,8 @@       -- possible.       isNotHoistableBnd _ _ (Let _ _ (BasicOp ArrayLit {})) = False       isNotHoistableBnd _ _ (Let _ _ (BasicOp SubExp {})) = False-      isNotHoistableBnd _ usages (Let pat _ _)-        | any (`UT.isSize` usages) $ patNames pat =+      isNotHoistableBnd _ usage (Let pat _ _)+        | any (`UT.isSize` usage) $ patNames pat =           False       isNotHoistableBnd _ _ stm         | is_alloc_fun stm = False@@ -631,39 +678,55 @@           `orIf` isConsuming           `orIf` isNotHoistableBnd -  rules <- asksEngineEnv envRules-  (body1_stms', safe1) <-+  (hoisted1, body1') <-     protectIfHoisted cond True $-      hoistStms rules block vtable usages1 stms1-  (body2_stms', safe2) <-+      simplifyBody block res_usage res_usages body1+  (hoisted2, body2') <-     protectIfHoisted cond False $-      hoistStms rules block vtable usages2 stms2-  let hoistable = safe1 <> safe2-  body1' <- constructBody body1_stms' res1-  body2' <- constructBody body2_stms' res2-  return (body1', body2', hoistable)+      simplifyBody block res_usage res_usages body2+  return (body1', body2', hoisted1 <> hoisted2) --- | Simplify a single body.  The @[Diet]@ only covers the value--- elements, because the context cannot be consumed.+-- | Simplify a single body. simplifyBody ::   SimplifiableRep rep =>-  [Diet] ->-  Body rep ->-  SimpleM rep (SimplifiedBody rep Result)-simplifyBody ds (Body _ stms res) =-  simplifyStms stms $ do-    res' <- simplifyResult ds res-    return (res', mempty)+  BlockPred (Wise rep) ->+  UT.UsageTable ->+  [UT.Usages] ->+  Body (Wise rep) ->+  SimpleM rep (Stms (Wise rep), Body (Wise rep))+simplifyBody blocker usage res_usages (Body _ stms res) = do+  (res', stms', hoisted) <-+    blockIf blocker stms $ do+      (res', res_usage) <- simplifyResult res_usages res+      pure (res', res_usage <> usage)+  body' <- constructBody stms' res'+  pure (hoisted, body') +-- | Simplify a single body.+simplifyBodyNoHoisting ::+  SimplifiableRep rep =>+  UT.UsageTable ->+  [UT.Usages] ->+  Body (Wise rep) ->+  SimpleM rep (Body (Wise rep))+simplifyBodyNoHoisting usage res_usages body =+  snd <$> simplifyBody (isFalse False) usage res_usages body++usageFromDiet :: Diet -> UT.Usages+usageFromDiet Consume = UT.consumedU+usageFromDiet _ = mempty+ -- | Simplify a single 'Result'.  The @[Diet]@ only covers the value -- elements, because the context cannot be consumed. simplifyResult ::-  SimplifiableRep rep => [Diet] -> Result -> SimpleM rep (Result, UT.UsageTable)-simplifyResult ds res = do+  SimplifiableRep rep => [UT.Usages] -> Result -> SimpleM rep (Result, UT.UsageTable)+simplifyResult usages res = do   res' <- mapM simplify res   vtable <- askVtable-  let consumption = consumeResult vtable $ zip ds res'-  return (res', UT.usages (freeIn res') <> consumption)+  let more_usages = mconcat $ do+        (u, Var v) <- zip usages $ map resSubExp res+        map (`UT.usage` u) $ v : namesToList (ST.lookupAliases v vtable)+  return (res', UT.usages (freeIn res') <> more_usages)  isDoLoopResult :: Result -> UT.UsageTable isDoLoopResult = mconcat . map checkForVar@@ -673,77 +736,49 @@  simplifyStms ::   SimplifiableRep rep =>-  Stms rep ->-  SimpleM rep (a, Stms (Wise rep)) ->-  SimpleM rep (a, Stms (Wise rep))-simplifyStms stms m =-  case stmsHead stms of-    Nothing -> inspectStms mempty m-    Just (Let pat (StmAux stm_cs attrs dec) e, stms') -> do-      stm_cs' <- simplify stm_cs-      ((e', e_stms), e_cs) <- collectCerts $ simplifyExp e-      (pat', pat_cs) <- collectCerts $ simplifyPat pat-      let cs = stm_cs' <> e_cs <> pat_cs-      inspectStms e_stms $-        inspectStm (mkWiseLetStm pat' (StmAux cs attrs dec) e') $-          simplifyStms stms' m--inspectStm ::-  SimplifiableRep rep =>-  Stm (Wise rep) ->-  SimpleM rep (a, Stms (Wise rep)) ->-  SimpleM rep (a, Stms (Wise rep))-inspectStm = inspectStms . oneStm+  Stms (Wise rep) ->+  SimpleM rep (Stms (Wise rep))+simplifyStms stms = do+  simplifyStmsWithUsage all_used stms+  where+    all_used =+      UT.usages (namesFromList (M.keys (scopeOf stms))) -inspectStms ::+simplifyStmsWithUsage ::   SimplifiableRep rep =>+  UT.UsageTable ->   Stms (Wise rep) ->-  SimpleM rep (a, Stms (Wise rep)) ->-  SimpleM rep (a, Stms (Wise rep))-inspectStms stms m =-  case stmsHead stms of-    Nothing -> m-    Just (stm, stms') -> do-      vtable <- askVtable-      rules <- asksEngineEnv envRules-      simplified <- topDownSimplifyStm rules vtable stm-      case simplified of-        Just newstms -> changed >> inspectStms (newstms <> stms') m-        Nothing -> do-          (x, stms'') <- localVtable (ST.insertStm stm) $ inspectStms stms' m-          return (x, oneStm stm <> stms'')+  SimpleM rep (Stms (Wise rep))+simplifyStmsWithUsage usage stms = do+  ((), stms', _) <- blockIf (isFalse False) stms $ pure ((), usage)+  pure stms' -simplifyOp :: Op rep -> SimpleM rep (Op (Wise rep), Stms (Wise rep))+simplifyOp :: Op (Wise rep) -> SimpleM rep (Op (Wise rep), Stms (Wise rep)) simplifyOp op = do   f <- asks $ simplifyOpS . fst   f op  simplifyExp ::   SimplifiableRep rep =>-  Exp rep ->+  UT.UsageTable ->+  Pat (Wise rep) ->+  Exp (Wise rep) ->   SimpleM rep (Exp (Wise rep), Stms (Wise rep))-simplifyExp (If cond tbranch fbranch (IfDec ts ifsort)) = do+simplifyExp usage (Pat pes) (If cond tbranch fbranch (IfDec ts ifsort)) = do   -- Here, we have to check whether 'cond' puts a bound on some free   -- variable, and if so, chomp it.  We should also try to do CSE   -- across branches.+  let pes_usages = map (fromMaybe mempty . (`UT.lookup` usage) . patElemName) pes   cond' <- simplify cond   ts' <- mapM simplify ts-  -- FIXME: we have to be conservative about the diet here, because we-  -- lack proper ifnormation.  Something is wrong with the order in-  -- which the simplifier does things - it should be purely bottom-up-  -- (or else, If expressions should indicate explicitly the diet of-  -- their return types).-  let ds = map (const Consume) ts-  tbranch' <- simplifyBody ds tbranch-  fbranch' <- simplifyBody ds fbranch-  (tbranch'', fbranch'', hoisted) <- hoistCommon cond' ifsort tbranch' fbranch'-  return (If cond' tbranch'' fbranch'' $ IfDec ts' ifsort, hoisted)-simplifyExp (DoLoop merge form loopbody) = do+  (tbranch', fbranch', hoisted) <-+    hoistCommon usage pes_usages cond' ifsort tbranch fbranch+  return (If cond' tbranch' fbranch' $ IfDec ts' ifsort, hoisted)+simplifyExp _ _ (DoLoop merge form loopbody) = do   let (params, args) = unzip merge   params' <- mapM (traverse simplify) params   args' <- mapM simplify args   let merge' = zip params' args'-      diets = map (diet . paramDeclType) params'   (form', boundnames, wrapbody) <- case form of     ForLoop loopvar it boundexp loopvars -> do       boundexp' <- simplify boundexp@@ -766,18 +801,22 @@           protectLoopHoisted merge' (WhileLoop cond')         )   seq_blocker <- asksEngineEnv $ blockHoistSeq . envHoistBlockers-  ((loopstms, loopres), hoisted) <-+  (loopres, loopstms, hoisted) <-     enterLoop . consumeMerge $-      bindMerge (zipWith withRes merge' (bodyResult loopbody)) $-        wrapbody $-          blockIf-            ( hasFree boundnames `orIf` isConsumed-                `orIf` seq_blocker-                `orIf` notWorthHoisting-            )-            $ do-              ((res, uses), stms) <- simplifyBody diets loopbody-              return ((res, uses <> isDoLoopResult res), stms)+      bindMerge (zipWith withRes merge' (bodyResult loopbody)) . wrapbody $+        blockIf+          ( hasFree boundnames `orIf` isConsumed+              `orIf` seq_blocker+              `orIf` notWorthHoisting+          )+          (bodyStms loopbody)+          $ do+            let params_usages =+                  map+                    (\p -> if unique (paramDeclType p) then UT.consumedU else mempty)+                    params'+            (res, uses) <- simplifyResult params_usages $ bodyResult loopbody+            pure (res, uses <> isDoLoopResult res)   loopbody' <- constructBody loopstms loopres   return (DoLoop merge' form' loopbody', hoisted)   where@@ -788,10 +827,10 @@     consumed_by_merge =       freeIn $ map snd $ filter (unique . paramDeclType . fst) merge     withRes (p, x) y = (p, x, y)-simplifyExp (Op op) = do+simplifyExp _ _ (Op op) = do   (op', stms) <- simplifyOp op   return (Op op', stms)-simplifyExp (WithAcc inputs lam) = do+simplifyExp usage _ (WithAcc inputs lam) = do   (inputs', inputs_stms) <- fmap unzip . forM inputs $ \(shape, arrs, op) -> do     (op', op_stms) <- case op of       Nothing ->@@ -801,49 +840,32 @@         nes' <- simplify nes         return (Just (op_lam', nes'), op_lam_stms)     (,op_stms) <$> ((,,op') <$> simplify shape <*> simplify arrs)-  (lam', lam_stms) <--    simplifyLambdaWithBody (isFalse True) lam $-      localVtable (ST.noteAccTokens (zip (map paramName (lambdaParams lam)) inputs')) $-        simplifyBody (map (const Observe) (lambdaReturnType lam)) $-          lambdaBody lam+  let noteAcc = ST.noteAccTokens (zip (map paramName (lambdaParams lam)) inputs')+  (lam', lam_stms) <- simplifyLambdaWith noteAcc (isFalse True) usage lam   pure (WithAcc inputs' lam', mconcat inputs_stms <> lam_stms)+simplifyExp _ _ e = do+  e' <- simplifyExpBase e+  pure (e', mempty) +-- The simple nonrecursive case that we can perform without bottom-up+-- information.+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.-simplifyExp (BasicOp (BinOp op x y))+simplifyExpBase (BasicOp (BinOp op x y))   | commutativeBinOp op = do     x' <- simplify x     y' <- simplify y-    return (BasicOp $ BinOp op (min x' y') (max x' y'), mempty)-simplifyExp e = do-  e' <- simplifyExpBase e-  return (e', mempty)--simplifyExpBase ::-  SimplifiableRep rep =>-  Exp rep ->-  SimpleM rep (Exp (Wise rep))-simplifyExpBase = mapExpM hoist+    pure $ BasicOp $ BinOp op (min x' y') (max x' y')+simplifyExpBase e = mapExpM hoist e   where     hoist =-      Mapper-        { -- Bodies are handled explicitly because we need to-          -- provide their result diet.-          mapOnBody =-            error "Unhandled body in simplification engine.",-          mapOnSubExp = simplify,-          -- Lambdas are handled explicitly because we need to-          -- bind their parameters.+      identityMapper+        { mapOnSubExp = simplify,           mapOnVName = simplify,           mapOnRetType = simplify,-          mapOnBranchType = simplify,-          mapOnFParam =-            error "Unhandled FParam in simplification engine.",-          mapOnLParam =-            error "Unhandled LParam in simplification engine.",-          mapOnOp =-            error "Unhandled Op in simplification engine."+          mapOnBranchType = simplify         }  type SimplifiableRep rep =@@ -960,51 +982,47 @@  simplifyLambda ::   SimplifiableRep rep =>-  Lambda rep ->+  Lambda (Wise rep) ->   SimpleM rep (Lambda (Wise rep), Stms (Wise rep)) simplifyLambda lam = do   par_blocker <- asksEngineEnv $ blockHoistPar . envHoistBlockers-  simplifyLambdaMaybeHoist par_blocker lam+  simplifyLambdaMaybeHoist par_blocker mempty lam  simplifyLambdaNoHoisting ::   SimplifiableRep rep =>-  Lambda rep ->+  Lambda (Wise rep) ->   SimpleM rep (Lambda (Wise rep)) simplifyLambdaNoHoisting lam =-  fst <$> simplifyLambdaMaybeHoist (isFalse False) lam+  fst <$> simplifyLambdaMaybeHoist (isFalse False) mempty lam  simplifyLambdaMaybeHoist ::   SimplifiableRep rep =>   BlockPred (Wise rep) ->-  Lambda rep ->+  UT.UsageTable ->+  Lambda (Wise rep) ->   SimpleM rep (Lambda (Wise rep), Stms (Wise rep))-simplifyLambdaMaybeHoist blocked lam =-  simplifyLambdaWithBody blocked lam $-    simplifyBody (map (const Observe) (lambdaReturnType lam)) $ lambdaBody lam+simplifyLambdaMaybeHoist = simplifyLambdaWith id -simplifyLambdaWithBody ::+simplifyLambdaWith ::   SimplifiableRep rep =>+  (ST.SymbolTable (Wise rep) -> ST.SymbolTable (Wise rep)) ->   BlockPred (Wise rep) ->-  Lambda rep ->-  SimpleM rep (SimplifiedBody rep Result) ->+  UT.UsageTable ->+  Lambda (Wise rep) ->   SimpleM rep (Lambda (Wise rep), Stms (Wise rep))-simplifyLambdaWithBody blocked lam@(Lambda params _body rettype) m = do+simplifyLambdaWith f blocked usage lam@(Lambda params body rettype) = do   params' <- mapM (traverse simplify) params   let paramnames = namesFromList $ boundByLambda lam-  ((lamstms, lamres), hoisted) <--    enterLoop . bindLParams params' $-      blockIf (blocked `orIf` hasFree paramnames `orIf` isConsumed) m-  body' <- constructBody lamstms lamres+  (hoisted, body') <-+    bindLParams params' . localVtable f $+      simplifyBody+        (blocked `orIf` hasFree paramnames `orIf` isConsumed)+        usage+        (map (const mempty) rettype)+        body   rettype' <- simplify rettype   return (Lambda params' body' rettype', hoisted) -consumeResult :: ST.SymbolTable rep -> [(Diet, SubExpRes)] -> UT.UsageTable-consumeResult vtable = mconcat . map inspect-  where-    inspect (Consume, SubExpRes _ (Var v)) =-      mconcat $ map UT.consumedUsage $ v : namesToList (ST.lookupAliases v vtable)-    inspect _ = mempty- instance Simplifiable Certs where   simplify (Certs ocs) = Certs . nubOrd . concat <$> mapM check ocs     where@@ -1015,19 +1033,13 @@           Just (Var idd', _) -> return [idd']           _ -> return [idd] -insertAllStms ::-  SimplifiableRep rep =>-  SimpleM rep (SimplifiedBody rep Result) ->-  SimpleM rep (Body (Wise rep))-insertAllStms = uncurry constructBody . fst <=< blockIf (isFalse False)- simplifyFun ::   SimplifiableRep rep =>-  FunDef rep ->+  FunDef (Wise rep) ->   SimpleM rep (FunDef (Wise rep)) simplifyFun (FunDef entry attrs fname rettype params body) = do   rettype' <- simplify rettype   params' <- mapM (traverse simplify) params-  let ds = map (diet . declExtTypeOf) rettype'-  body' <- bindFParams params $ insertAllStms $ simplifyBody ds body-  return $ FunDef entry attrs fname rettype' params' body'+  let usages = map (usageFromDiet . diet . declExtTypeOf) rettype'+  body' <- bindFParams params $ simplifyBodyNoHoisting mempty usages body+  pure $ FunDef entry attrs fname rettype' params' body'
src/Futhark/Optimise/Simplify/Rep.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-}@@ -21,6 +22,12 @@     mkWiseLetStm,     mkWiseExpDec,     CanBeWise (..),++    -- * Constructing representation+    Informing,+    informLambda,+    informFunDef,+    informStms,   ) where @@ -258,6 +265,10 @@     let Body bodyrep _ _ = mkBody (fmap removeStmWisdom stms) res      in mkWiseBody bodyrep stms res +-- | Constraints that let us transform a representation into a 'Wise'+-- representation.+type Informing rep = (ASTRep rep, CanBeWise (Op rep))+ class   ( AliasedOp (OpWithWisdom op),     IsOp (OpWithWisdom op)@@ -266,7 +277,47 @@   where   type OpWithWisdom op :: Data.Kind.Type   removeOpWisdom :: OpWithWisdom op -> op+  addOpWisdom :: op -> OpWithWisdom op  instance CanBeWise () where   type OpWithWisdom () = ()   removeOpWisdom () = ()+  addOpWisdom () = ()++informStm :: Informing rep => Stm rep -> Stm (Wise rep)+informStm (Let pat aux e) = mkWiseLetStm pat aux $ informExp e++informStms :: Informing rep => Stms rep -> Stms (Wise rep)+informStms = fmap informStm++informBody :: Informing rep => Body rep -> Body (Wise rep)+informBody (Body dec stms res) = mkWiseBody dec (informStms stms) res++informLambda :: Informing rep => Lambda rep -> Lambda (Wise rep)+informLambda (Lambda ps body ret) = Lambda ps (informBody body) ret++informExp :: Informing rep => Exp rep -> Exp (Wise rep)+informExp (If cond tbranch fbranch (IfDec ts ifsort)) =+  If cond (informBody tbranch) (informBody fbranch) (IfDec ts ifsort)+informExp (DoLoop 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+informExp e = runIdentity $ mapExpM mapper e+  where+    mapper =+      Mapper+        { mapOnBody = const $ pure . informBody,+          mapOnSubExp = pure,+          mapOnVName = pure,+          mapOnRetType = pure,+          mapOnBranchType = pure,+          mapOnFParam = pure,+          mapOnLParam = pure,+          mapOnOp = pure . addOpWisdom+        }++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/TileLoops.hs view
@@ -279,6 +279,7 @@       foldMap consumedInStm $ fst $ Alias.analyseStms mempty prestms      mustBeInlinedExp (BasicOp (Index _ slice)) = not $ null $ sliceDims slice+    mustBeInlinedExp (BasicOp Iota {}) = True     mustBeInlinedExp (BasicOp Rotate {}) = True     mustBeInlinedExp (BasicOp Rearrange {}) = True     mustBeInlinedExp (BasicOp Reshape {}) = True@@ -437,11 +438,10 @@   tilingSegMap tiling "prelude" (scalarLevel tiling) ResultPrivate $     \in_bounds slice -> do       ts <- mapM lookupType prestms_live-      fmap varsRes $-        protectOutOfBounds "pre" in_bounds ts $ do-          addPrivStms slice privstms-          addStms prestms-          pure $ varsRes prestms_live+      fmap varsRes . protectOutOfBounds "pre" in_bounds ts $ do+        addPrivStms slice privstms+        addStms prestms+        pure $ varsRes prestms_live  liveSet :: FreeIn a => Stms GPU -> a -> Names liveSet stms after =@@ -795,7 +795,7 @@       fmap varsRes $         case kind of           TilePartial ->-            letTupExp "pre"+            letTupExp "pre1d"               =<< eIf                 (toExp $ pe64 j .<. pe64 w)                 (resultBody <$> mapM (fmap Var . readTileElem) arrs)@@ -1056,7 +1056,7 @@       fmap varsRes $         case kind of           TilePartial ->-            mapM (letExp "pre" <=< readTileElemIfInBounds) arrs_and_perms+            mapM (letExp "pre2d" <=< readTileElemIfInBounds) arrs_and_perms           TileFull ->             mapM readTileElem arrs_and_perms 
src/Futhark/Pass/ExpandAllocations.hs view
@@ -485,8 +485,7 @@     sliceKernelSizes num_threads variant_sizes kspace kstms   -- Note the recursive call to expand allocations inside the newly   -- produced kernels.-  (_, slice_stms_tmp) <--    simplifyStms =<< explicitAllocationsInStms slice_stms+  slice_stms_tmp <- simplifyStms =<< explicitAllocationsInStms slice_stms   slice_stms' <- transformStms slice_stms_tmp    let variant_allocs' :: [(VName, (SubExp, SubExp, Space))]
src/Futhark/Pass/ExplicitAllocations.hs view
@@ -1095,7 +1095,7 @@     Mem rep inner   ) =>   (Engine.OpWithWisdom inner -> UT.UsageTable) ->-  (inner -> Engine.SimpleM rep (Engine.OpWithWisdom inner, Stms (Engine.Wise rep))) ->+  (Engine.OpWithWisdom inner -> Engine.SimpleM rep (Engine.OpWithWisdom inner, Stms (Engine.Wise rep))) ->   SimpleOps rep simplifiable innerUsage simplifyInnerOp =   SimpleOps mkExpDecS' mkBodyS' protectOp opUsage simplifyOp
src/Futhark/Pass/ExtractKernels.hs view
@@ -393,7 +393,7 @@     let map_lam_sequential = soacsLambdaToGPU map_lam     lvl <- segThreadCapped [w] "segscan" $ NoRecommendation SegNoVirt     addStms . fmap (certify cs)-      =<< segScan lvl res_pat w scan_ops map_lam_sequential arrs [] []+      =<< segScan lvl res_pat mempty w scan_ops map_lam_sequential arrs [] [] transformStm path (Let res_pat aux (Op (Screma w arrs form)))   | Just [Reduce comm red_fun nes] <- isReduceSOAC form,     let comm'@@ -401,7 +401,7 @@           | otherwise = comm,     Just do_irwim <- irwim res_pat w comm' red_fun $ zip nes arrs = do     types <- asksScope scopeForSOACs-    (_, stms) <- fst <$> runBuilderT (simplifyStms =<< collectStms_ (auxing aux do_irwim)) types+    stms <- fst <$> runBuilderT (simplifyStms =<< collectStms_ (auxing aux do_irwim)) types     transformStms path $ stmsToList stms transformStm path (Let pat aux@(StmAux cs _ _) (Op (Screma w arrs form)))   | Just (reds, map_lam) <- isRedomapSOAC form = do@@ -426,10 +426,8 @@           (mapstm, redstm) <-             redomapToMapAndReduce pat (w, reds, map_lam, arrs)           types <- asksScope scopeForSOACs-          transformStms path' . stmsToList <=< (`runBuilderT_` types) $ do-            (_, stms) <--              simplifyStms (stmsFromList [certify cs mapstm, certify cs redstm])-            addStms stms+          transformStms path' . stmsToList <=< (`runBuilderT_` types) $+            addStms =<< simplifyStms (stmsFromList [certify cs mapstm, certify cs redstm])          innerParallelBody path' =           renameBody
src/Futhark/Pass/ExtractKernels/BlockedKernel.hs view
@@ -51,24 +51,25 @@  prepareRedOrScan ::   (MonadBuilder m, DistRep (Rep m)) =>+  Certs ->   SubExp ->   Lambda (Rep m) ->   [VName] ->   [(VName, SubExp)] ->   [KernelInput] ->   m (SegSpace, KernelBody (Rep m))-prepareRedOrScan w map_lam arrs ispace inps = do+prepareRedOrScan cs w map_lam arrs ispace inps = do   gtid <- newVName "gtid"   space <- mkSegSpace $ ispace ++ [(gtid, w)]   kbody <- fmap (uncurry (flip (KernelBody ()))) $     runBuilder $       localScope (scopeOfSegSpace space) $ do         mapM_ readKernelInput inps-        mapM_ readKernelInput $ do+        certifying cs . mapM_ readKernelInput $ do           (p, arr) <- zip (lambdaParams map_lam) arrs           pure $ KernelInput (paramName p) (paramType p) arr [Var gtid]         res <- bodyBind (lambdaBody map_lam)-        forM res $ \(SubExpRes cs se) -> pure $ Returns ResultMaySimplify cs se+        forM res $ \(SubExpRes res_cs se) -> pure $ Returns ResultMaySimplify res_cs se    return (space, kbody) @@ -76,6 +77,7 @@   (MonadFreshNames m, DistRep rep, HasScope rep m) =>   SegOpLevel rep ->   Pat rep ->+  Certs ->   SubExp -> -- segment size   [SegBinOp rep] ->   Lambda rep ->@@ -83,8 +85,8 @@   [(VName, SubExp)] -> -- ispace = pair of (gtid, size) for the maps on "top" of this reduction   [KernelInput] -> -- inps = inputs that can be looked up by using the gtids from ispace   m (Stms rep)-segRed lvl pat w ops map_lam arrs ispace inps = runBuilder_ $ do-  (kspace, kbody) <- prepareRedOrScan w map_lam arrs ispace inps+segRed lvl pat cs w ops map_lam arrs ispace inps = runBuilder_ $ do+  (kspace, kbody) <- prepareRedOrScan cs w map_lam arrs ispace inps   letBind pat $     Op $       segOp $@@ -94,6 +96,7 @@   (MonadFreshNames m, DistRep rep, HasScope rep m) =>   SegOpLevel rep ->   Pat rep ->+  Certs ->   SubExp -> -- segment size   [SegBinOp rep] ->   Lambda rep ->@@ -101,8 +104,8 @@   [(VName, SubExp)] -> -- ispace = pair of (gtid, size) for the maps on "top" of this scan   [KernelInput] -> -- inps = inputs that can be looked up by using the gtids from ispace   m (Stms rep)-segScan lvl pat w ops map_lam arrs ispace inps = runBuilder_ $ do-  (kspace, kbody) <- prepareRedOrScan w map_lam arrs ispace inps+segScan lvl pat cs w ops map_lam arrs ispace inps = runBuilder_ $ do+  (kspace, kbody) <- prepareRedOrScan cs w map_lam arrs ispace inps   letBind pat $     Op $       segOp $@@ -119,7 +122,7 @@   [KernelInput] -> -- inps = inputs that can be looked up by using the gtids from ispace   m (Stms rep) segMap lvl pat w map_lam arrs ispace inps = runBuilder_ $ do-  (kspace, kbody) <- prepareRedOrScan w map_lam arrs ispace inps+  (kspace, kbody) <- prepareRedOrScan mempty w map_lam arrs ispace inps   letBind pat $     Op $       segOp $@@ -163,7 +166,7 @@   m (Stms rep) nonSegRed lvl pat w ops map_lam arrs = runBuilder_ $ do   (pat', ispace, read_dummy) <- dummyDim pat-  addStms =<< segRed lvl pat' w ops map_lam arrs ispace []+  addStms =<< segRed lvl pat' mempty w ops map_lam arrs ispace []   read_dummy  segHist ::
src/Futhark/Pass/ExtractKernels/DistributeNests.hs view
@@ -341,7 +341,7 @@       types <- asksScope scopeForSOACs       stream_stms <-         snd <$> runBuilderT (sequentialStreamWholeArray pat w accs lam arrs) types-      (_, stream_stms') <-+      stream_stms' <-         runReaderT (copyPropagateInStms simpleSOACS types stream_stms) types       onStms acc $ stmsToList (fmap (certify cs) stream_stms') ++ stms     onStms acc (stm : stms) =@@ -406,8 +406,7 @@             -- (which are now innermost).             stms <-               (`runReaderT` types) $-                fmap snd . simplifyStms-                  =<< interchangeLoops nest' (SeqLoop perm pat merge form body)+                simplifyStms =<< interchangeLoops nest' (SeqLoop perm pat merge form body)             onTopLevelStms stms             return acc'       _ ->@@ -430,8 +429,7 @@             let branch = Branch perm pat cond tbranch fbranch ret             stms <-               (`runReaderT` types) $-                fmap snd . simplifyStms-                  =<< interchangeBranch nest' branch+                simplifyStms =<< interchangeBranch nest' branch             onTopLevelStms stms             return acc'       _ ->@@ -453,7 +451,7 @@             let withacc = WithAccStm perm pat inputs lam             stms <-               (`runReaderT` types) $-                fmap snd . simplifyStms =<< interchangeWithAcc nest' withacc+                simplifyStms =<< interchangeWithAcc nest' withacc             onTopLevelStms stms             return acc'       _ ->@@ -524,10 +522,18 @@             nest' <- expandKernelNest pat_unused nest             map_lam' <- soacsLambda map_lam             localScope (typeEnvFromDistAcc acc') $-              segmentedScanomapKernel nest' perm w lam map_lam' nes arrs-                >>= kernelOrNot cs stm acc kernels acc'+              segmentedScanomapKernel nest' perm cs w lam map_lam' nes arrs+                >>= kernelOrNot mempty stm acc kernels acc'       _ ->         addStmToAcc stm acc+-- If the map function of the reduction contains parallelism we split+-- it, so that the parallelism can be exploited.+maybeDistributeStm (Let pat aux (Op (Screma w arrs form))) acc+  | Just (reds, map_lam) <- isRedomapSOAC form,+    lambdaContainsParallelism map_lam = do+    (mapstm, redstm) <-+      redomapToMapAndReduce pat (w, reds, map_lam, arrs)+    distributeMapBodyStms acc $ oneStm mapstm {stmAux = aux} <> oneStm redstm -- if the reduction can be distributed by itself, we will turn it into a -- segmented reduce. --@@ -551,8 +557,8 @@                   | commutativeLambda lam = Commutative                   | otherwise = comm -            regularSegmentedRedomapKernel nest' perm w comm' lam' map_lam' nes arrs-              >>= kernelOrNot cs stm acc kernels acc'+            regularSegmentedRedomapKernel nest' perm cs w comm' lam' map_lam' nes arrs+              >>= kernelOrNot mempty stm acc kernels acc'       _ ->         addStmToAcc stm acc maybeDistributeStm (Let pat (StmAux cs _ _) (Op (Screma w arrs form))) acc = do@@ -1017,13 +1023,14 @@   (MonadFreshNames m, LocalScope rep m, DistRep rep) =>   KernelNest ->   [Int] ->+  Certs ->   SubExp ->   Lambda SOACS ->   Lambda rep ->   [SubExp] ->   [VName] ->   DistNestT rep m (Maybe (Stms rep))-segmentedScanomapKernel nest perm segment_size lam map_lam nes arrs = do+segmentedScanomapKernel nest perm cs segment_size lam map_lam nes arrs = do   mk_lvl <- asks distSegLevel   onLambda <- asks distOnSOACSLambda   let onLambda' = fmap fst . runBuilder . onLambda@@ -1034,12 +1041,13 @@       let scan_op = SegBinOp Noncommutative lam'' nes'' shape       lvl <- mk_lvl (segment_size : map snd ispace) "segscan" $ NoRecommendation SegNoVirt       addStms =<< traverse renameStm-        =<< segScan lvl pat segment_size [scan_op] map_lam arrs ispace inps+        =<< segScan lvl pat cs segment_size [scan_op] map_lam arrs ispace inps  regularSegmentedRedomapKernel ::   (MonadFreshNames m, LocalScope rep m, DistRep rep) =>   KernelNest ->   [Int] ->+  Certs ->   SubExp ->   Commutativity ->   Lambda rep ->@@ -1047,14 +1055,14 @@   [SubExp] ->   [VName] ->   DistNestT rep m (Maybe (Stms rep))-regularSegmentedRedomapKernel nest perm segment_size comm lam map_lam nes arrs = do+regularSegmentedRedomapKernel nest perm cs segment_size comm lam map_lam nes arrs = do   mk_lvl <- asks distSegLevel   isSegmentedOp nest perm (freeIn lam) (freeIn map_lam) nes [] $     \pat ispace inps nes' _ -> do       let red_op = SegBinOp comm lam nes' mempty       lvl <- mk_lvl (segment_size : map snd ispace) "segred" $ NoRecommendation SegNoVirt       addStms =<< traverse renameStm-        =<< segRed lvl pat segment_size [red_op] map_lam arrs ispace inps+        =<< segRed lvl pat cs segment_size [red_op] map_lam arrs ispace inps  isSegmentedOp ::   (MonadFreshNames m, LocalScope rep m, DistRep rep) =>
src/Futhark/Pass/ExtractKernels/Distribution.hs view
@@ -32,6 +32,7 @@     innermostKernelNesting,     pushKernelNesting,     pushInnerKernelNesting,+    scopeOfKernelNest,     kernelNestLoops,     kernelNestWidths,     boundInKernelNest,@@ -81,8 +82,7 @@ ppTargets (Targets target targets) =   unlines $ map ppTarget $ targets ++ [target]   where-    ppTarget (pat, res) =-      pretty pat ++ " <- " ++ pretty res+    ppTarget (pat, res) = pretty pat ++ " <- " ++ pretty res  singleTarget :: Target -> Targets singleTarget = flip Targets []@@ -127,7 +127,7 @@   }   deriving (Show) -scopeOfLoopNesting :: DistRep rep => LoopNesting -> Scope rep+scopeOfLoopNesting :: (LParamInfo rep ~ Type) => LoopNesting -> Scope rep scopeOfLoopNesting = scopeOfLParams . map fst . loopNestingParamsAndArrs  ppLoopNesting :: LoopNesting -> String@@ -141,10 +141,7 @@  instance FreeIn LoopNesting where   freeIn' (MapNesting pat aux w params_and_arrs) =-    freeIn' pat-      <> freeIn' aux-      <> freeIn' w-      <> freeIn' params_and_arrs+    freeIn' pat <> freeIn' aux <> freeIn' w <> freeIn' params_and_arrs  data Nesting = Nesting   { nestingLetBound :: Names,@@ -164,8 +161,7 @@ ppNestings (nesting, nestings) =   unlines $ map ppNesting $ nestings ++ [nesting]   where-    ppNesting (Nesting _ loop) =-      ppLoopNesting loop+    ppNesting (Nesting _ loop) = ppLoopNesting loop  singleNesting :: Nesting -> Nestings singleNesting = (,[])@@ -234,16 +230,15 @@ kernelNestLoops :: KernelNest -> [LoopNesting] kernelNestLoops (loop, loops) = loop : loops +scopeOfKernelNest :: LParamInfo rep ~ Type => KernelNest -> Scope rep+scopeOfKernelNest = foldMap scopeOfLoopNesting . kernelNestLoops+ boundInKernelNest :: KernelNest -> Names boundInKernelNest = mconcat . boundInKernelNests  boundInKernelNests :: KernelNest -> [Names] boundInKernelNests =-  map-    ( namesFromList-        . map (paramName . fst)-        . loopNestingParamsAndArrs-    )+  map (namesFromList . map (paramName . fst) . loopNestingParamsAndArrs)     . kernelNestLoops  kernelNestWidths :: KernelNest -> [SubExp]@@ -286,10 +281,7 @@ flatKernel ::   MonadFreshNames m =>   KernelNest ->-  m-    ( [(VName, SubExp)],-      [KernelInput]-    )+  m ([(VName, SubExp)], [KernelInput]) flatKernel (MapNesting _ _ nesting_w params_and_arrs, []) = do   i <- newVName "gtid"   let inps =@@ -376,9 +368,7 @@   runMaybeT $ fmap prepare $ recurse $ zip nests targets   where     prepare (x, _, z) = (z, x)-    bound_in_nest =-      mconcat $ map boundInNesting $ inner_nest : nests-+    bound_in_nest = mconcat $ map boundInNesting $ inner_nest : nests     distributableType =       (== mempty) . namesIntersection bound_in_nest . freeIn . arrayDims @@ -418,8 +408,7 @@                 case M.lookup pname identity_map of                   Nothing -> do                     arr <--                      newIdent (baseString pname ++ "_r") $-                        arrayOfRow ptype w+                      newIdent (baseString pname ++ "_r") $ arrayOfRow ptype w                     return                       ( Param mempty pname ptype,                         arr,@@ -462,9 +451,7 @@             addTarget (free_arrs_pat, varsRes $ map paramName free_params_pat)           ) -    recurse ::-      [(Nesting, Target)] ->-      MaybeT m (KernelNest, Names, Targets)+    recurse :: [(Nesting, Target)] -> MaybeT m (KernelNest, Names, Targets)     recurse [] =       distributeAtNesting         inner_nest@@ -500,9 +487,7 @@   where     (params, arrs) = unzip params_and_arrs     (used_params, used_arrs) =-      unzip $-        filter ((`nameIn` used) . paramName . fst) $-          zip params arrs+      unzip $ filter ((`nameIn` used) . paramName . fst) $ zip params arrs  removeIdentityMappingGeneral ::   Names ->
src/Futhark/Pass/ExtractKernels/Interchange.hs view
@@ -27,14 +27,19 @@   ( KernelNest,     LoopNesting (..),     kernelNestLoops,+    scopeOfKernelNest,   ) import Futhark.Tools import Futhark.Transform.Rename+import Futhark.Util (splitFromEnd)  -- | An encoding of a sequential do-loop with no existential context, -- alongside its result pattern. data SeqLoop = SeqLoop [Int] Pat [(FParam, SubExp)] (LoopForm SOACS) Body +loopPerm :: SeqLoop -> [Int]+loopPerm (SeqLoop perm _ _ _ _) = perm+ seqLoopStm :: SeqLoop -> Stm seqLoopStm (SeqLoop _ pat merge form body) =   Let pat (defAux ()) $ DoLoop merge form body@@ -77,7 +82,7 @@         res = varsRes $ patNames loop_pat_expanded         pat' = Pat $ rearrangeShape perm $ patElems pat -    return $+    pure $       SeqLoop perm pat' merge_expanded form $         mkBody (pre_copy_stms <> oneStm map_stm) res     where@@ -91,7 +96,7 @@        expandedInit _ (Var v)         | Just arr <- isMapParameter v =-          return $ Var arr+          pure $ Var arr       expandedInit param_name se =         letSubExp (param_name <> "_expanded_init") $           BasicOp $ Replicate (Shape [w]) se@@ -99,8 +104,10 @@       expand (merge_param, merge_init) = do         expanded_param <-           newParam (param_name <> "_expanded") $-            arrayOf (paramDeclType merge_param) (Shape [w]) $-              uniqueness $ declTypeOf merge_param+            -- FIXME: Unique here is a hack to make sure the copy from+            -- makeCopyInitial is not prematurely simplified away.+            -- It'd be better to fix this somewhere else...+            arrayOf (paramDeclType merge_param) (Shape [w]) Unique         expanded_init <- expandedInit param_name merge_init         return (expanded_param, expanded_init)         where@@ -109,6 +116,39 @@       expandPatElem (PatElem name t) =         PatElem name $ arrayOfRow t w +-- We need to copy some initial arguments because otherwise the result+-- of the loop might alias the input (if the number of iterations is+-- 0), which is a problem if the result is consumed.+maybeCopyInitial ::+  (MonadBuilder m) =>+  (VName -> Bool) ->+  SeqLoop ->+  m SeqLoop+maybeCopyInitial isMapInput (SeqLoop perm loop_pat merge form body) =+  SeqLoop perm loop_pat <$> mapM f merge <*> pure form <*> pure body+  where+    f (p, Var arg)+      | isMapInput arg =+        (p,) <$> letSubExp (baseString (paramName p) <> "_inter_copy") (BasicOp $ Copy arg)+    f (p, arg) =+      pure (p, arg)++manifestMaps :: [LoopNesting] -> [VName] -> Stms SOACS -> ([VName], Stms SOACS)+manifestMaps [] res stms = (res, stms)+manifestMaps (n : ns) res stms =+  let (res', stms') = manifestMaps ns res stms+      (params, arrs) = unzip $ loopNestingParamsAndArrs n+      lam =+        Lambda+          params+          (mkBody stms' $ varsRes res')+          (map rowType $ patTypes (loopNestingPat n))+   in ( patNames $ loopNestingPat n,+        oneStm $+          Let (loopNestingPat n) (loopNestingAux n) $+            Op $ Screma (loopNestingWidth n) arrs (mapSOAC lam)+      )+ -- | Given a (parallel) map nesting and an inner sequential loop, move -- the maps inside the sequential loop.  The result is several -- statements - one of these will be the loop, which will then contain@@ -118,17 +158,29 @@   KernelNest ->   SeqLoop ->   m (Stms SOACS)-interchangeLoops nest loop = do-  (loop', stms) <--    runBuilder $-      foldM (interchangeLoop isMapParameter) loop $-        reverse $ kernelNestLoops nest-  return $ stms <> oneStm (seqLoopStm loop')+interchangeLoops full_nest = recurse (kernelNestLoops full_nest)   where-    isMapParameter v =-      fmap snd $-        find ((== v) . paramName . fst) $-          concatMap loopNestingParamsAndArrs $ kernelNestLoops nest+    recurse nest loop+      | (ns, [n]) <- splitFromEnd 1 nest = do+        let isMapParameter v =+              snd <$> find ((== v) . paramName . fst) (loopNestingParamsAndArrs n)+            isMapInput v =+              v `elem` map snd (loopNestingParamsAndArrs n)+        (loop', stms) <-+          runBuilder . localScope (scopeOfKernelNest full_nest) $+            maybeCopyInitial isMapInput+              =<< interchangeLoop isMapParameter loop n++        -- Only safe to continue interchanging if we didn't need to add+        -- any new statements; otherwise we manifest the remaining nests+        -- as Maps and hand them back to the flattener.+        if null stms+          then recurse ns loop'+          else+            let loop_stm = seqLoopStm loop'+                names = rearrangeShape (loopPerm loop') (patNames (stmPat loop_stm))+             in pure $ snd $ manifestMaps ns names $ stms <> oneStm loop_stm+      | otherwise = pure $ oneStm $ seqLoopStm loop  data Branch = Branch [Int] Pat SubExp Body Body (IfDec (BranchType SOACS)) 
src/Futhark/Pass/ExtractKernels/Intragroup.hs view
@@ -251,7 +251,7 @@         let scanfun' = soacsLambdaToGPU scanfun             mapfun' = soacsLambdaToGPU mapfun         certifying (stmAuxCerts aux) $-          addStms =<< segScan lvl' pat w [SegBinOp Noncommutative scanfun' nes mempty] mapfun' arrs [] []+          addStms =<< segScan lvl' pat mempty w [SegBinOp Noncommutative scanfun' nes mempty] mapfun' arrs [] []         parallelMin [w]     Op (Screma w arrs form)       | Just (reds, map_lam) <- isRedomapSOAC form,@@ -259,7 +259,7 @@         let red_lam' = soacsLambdaToGPU red_lam             map_lam' = soacsLambdaToGPU map_lam         certifying (stmAuxCerts aux) $-          addStms =<< segRed lvl' pat w [SegBinOp comm red_lam' nes mempty] map_lam' arrs [] []+          addStms =<< segRed lvl' pat mempty w [SegBinOp comm red_lam' nes mempty] map_lam' arrs [] []         parallelMin [w]     Op (Hist w arrs ops bucket_fun) -> do       ops' <- forM ops $ \(HistOp num_bins rf dests nes op) -> do
src/Futhark/Transform/CopyPropagate.hs view
@@ -32,7 +32,7 @@   SimpleOps rep ->   Scope rep ->   Stms rep ->-  m (ST.SymbolTable (Wise rep), Stms rep)+  m (Stms rep) copyPropagateInStms simpl = simplifyStms simpl mempty neverHoist  -- | Run copy propagation on a function.
src/Futhark/Transform/FirstOrderTransform.hs view
@@ -173,14 +173,12 @@           Nothing             | paramName p `nameIn` lam_cons -> do               p' <--                letExp (baseString (paramName p)) $-                  BasicOp $-                    Index arr $ fullSlice arr_t [DimFix $ Var i]+                letExp (baseString (paramName p)) . BasicOp $+                  Index arr $ fullSlice arr_t [DimFix $ Var i]               letBindNames [paramName p] $ BasicOp $ Copy p'             | otherwise ->               letBindNames [paramName p] $-                BasicOp $-                  Index arr $ fullSlice arr_t [DimFix $ Var i]+                BasicOp $ Index arr $ fullSlice arr_t [DimFix $ Var i]        -- Insert the statements of the lambda.  We have taken care to       -- ensure that the parameters are bound at this point.
src/Futhark/TypeCheck.hs view
@@ -1012,6 +1012,8 @@   let (mergepat, mergeexps) = unzip merge   mergeargs <- mapM checkArg mergeexps +  checkLoopArgs+   binding (scopeOf form) $ do     form_consumable <- checkForm mergeargs form @@ -1035,15 +1037,14 @@           checkBodyDec $ snd $ bodyDec loopbody            checkStms (bodyStms loopbody) $ do-            checkResult $ bodyResult loopbody+            context "In loop body result" $+              checkResult $ bodyResult loopbody              context "When matching result of body with loop parameters" $               matchLoopResult (map fst merge) $ bodyResult loopbody              let bound_here =-                  namesFromList $-                    M.keys $-                      scopeOf $ bodyStms loopbody+                  namesFromList $ M.keys $ scopeOf $ bodyStms loopbody             map (`namesSubtract` bound_here)               <$> mapM (subExpAliasesM . resSubExp) (bodyResult loopbody)   where@@ -1097,6 +1098,20 @@           paramts = map paramDeclType funparams       checkFuncall Nothing paramts mergeargs       pure mempty++    checkLoopArgs = do+      let (params, args) = unzip merge++      argtypes <- mapM subExpType args++      let expected = expectedTypes (map paramName params) params args+      unless (expected == argtypes) . bad . TypeError . pretty $+        "Loop parameters"+          </> indent 2 (ppTuple' params)+          </> "cannot accept initial values"+          </> indent 2 (ppTuple' args)+          </> "of types"+          </> indent 2 (ppTuple' argtypes) checkExp (WithAcc inputs lam) = do   unless (length (lambdaParams lam) == 2 * num_accs) $     bad . TypeError $
src/Futhark/Util.hs view
@@ -10,6 +10,7 @@ -- compatible). module Futhark.Util   ( nubOrd,+    nubByOrd,     mapAccumLM,     maxinum,     chunk,@@ -65,7 +66,7 @@ import Data.Char import Data.Either import Data.Function ((&))-import Data.List (foldl', genericDrop, genericSplitAt, sort)+import Data.List (foldl', genericDrop, genericSplitAt, sortBy) import qualified Data.List.NonEmpty as NE import qualified Data.Map as M import Data.Maybe@@ -89,7 +90,13 @@  -- | Like 'nub', but without the quadratic runtime. nubOrd :: Ord a => [a] -> [a]-nubOrd = map NE.head . NE.group . sort+nubOrd = nubByOrd compare++-- | Like 'nubBy', but without the quadratic runtime.+nubByOrd :: (a -> a -> Ordering) -> [a] -> [a]+nubByOrd cmp = map NE.head . NE.groupBy eq . sortBy cmp+  where+    eq x y = cmp x y == EQ  -- | Like 'Data.Traversable.mapAccumL', but monadic. mapAccumLM ::
src/Language/Futhark/Interpreter.hs view
@@ -751,20 +751,22 @@   Env ->   [TypeParam] ->   [Pat] ->-  StructType ->-  [VName] ->+  StructRetType ->   Exp ->   EvalM TermBinding-evalFunctionBinding env tparams ps ret retext fbody = do-  let ret' = evalType env ret+evalFunctionBinding env tparams ps ret fbody = do+  let ret' = evalType env $ retType ret       arrow (xp, xt) yt = Scalar $ Arrow () xp xt $ RetType [] yt       ftype = foldr (arrow . patternParam) ret' ps+      retext = case ps of+        [] -> retDims ret+        _ -> []    -- Distinguish polymorphic and non-polymorphic bindings here.   if null tparams     then       TermValue (Just $ T.BoundV [] ftype)-        <$> (returned env ret retext =<< evalFunction env [] ps fbody ret')+        <$> (returned env (retType ret) retext =<< evalFunction env [] ps fbody ret')     else return $       TermPoly (Just $ T.BoundV [] ftype) $ \ftype' -> do         let tparam_names = map typeParamName tparams@@ -777,7 +779,7 @@             missing_sizes =               filter (`M.notMember` envTerm env') $                 map typeParamName (filter isSizeParam tparams)-        returned env ret retext =<< evalFunction env' missing_sizes ps fbody ret'+        returned env (retType ret) retext =<< evalFunction env' missing_sizes ps fbody ret'  evalArg :: Env -> Exp -> Maybe VName -> EvalM Value evalArg env e ext = do@@ -863,8 +865,8 @@       v_s = valueShape v       env'' = env' <> i64Env (resolveExistentials (map sizeName sizes) p_t v_s)   eval env'' body-evalAppExp env (LetFun f (tparams, ps, _, Info (RetType _ ret), fbody) body _) = do-  binding <- evalFunctionBinding env tparams ps ret [] fbody+evalAppExp env (LetFun f (tparams, ps, _, Info ret, fbody) body _) = do+  binding <- evalFunctionBinding env tparams ps ret fbody   eval (env {envTerm = M.insert f binding $ envTerm env}) body evalAppExp   env@@ -1187,8 +1189,8 @@     _ -> error "Expected ModuleFun."  evalDec :: Env -> Dec -> EvalM Env-evalDec env (ValDec (ValBind _ v _ (Info (RetType _ ret, retext)) tparams ps fbody _ _ _)) = do-  binding <- evalFunctionBinding env tparams ps ret retext fbody+evalDec env (ValDec (ValBind _ v _ (Info ret) tparams ps fbody _ _ _)) = do+  binding <- evalFunctionBinding env tparams ps ret fbody   return $ env {envTerm = M.insert v binding $ envTerm env} evalDec env (OpenDec me _) = do   me' <- evalModExp env me
src/Language/Futhark/Parser/Parser.y view
@@ -646,8 +646,6 @@          QualParens (QualName qs name, loc) $2 (srcspan $1 $>) }       -- Operator sections.-     | '(' '!' ')'-        { Var (qualName "!") NoInfo (srcspan $2 $>) }      | '(' '-' ')'         { OpSection (qualName (nameFromString "-")) NoInfo (srcspan $1 $>) }      | '(' Exp2 '-' ')'
src/Language/Futhark/Pretty.hs view
@@ -469,7 +469,7 @@       fun         | isJust entry = "entry"         | otherwise = "let"-      retdecl' = case (ppr . fst <$> unAnnot rettype) `mplus` (ppr <$> retdecl) of+      retdecl' = case (ppr <$> unAnnot rettype) `mplus` (ppr <$> retdecl) of         Just rettype' -> colon <+> align rettype'         Nothing -> mempty 
src/Language/Futhark/Prop.hs view
@@ -28,6 +28,7 @@     -- * Queries on expressions     typeOf,     valBindTypeScheme,+    valBindBound,     funType,      -- * Queries on patterns and params@@ -619,8 +620,18 @@ valBindTypeScheme :: ValBindBase Info VName -> ([TypeParamBase VName], StructType) valBindTypeScheme vb =   ( valBindTypeParams vb,-    funType (valBindParams vb) (fst (unInfo (valBindRetType vb)))+    funType (valBindParams vb) (unInfo (valBindRetType vb))   )++-- | The names that are brought into scope by this value binding (not+-- including its own parameter names, but including any existential+-- sizes).+valBindBound :: ValBindBase Info VName -> [VName]+valBindBound vb =+  valBindName vb :+  case valBindParams vb of+    [] -> retDims (unInfo (valBindRetType vb))+    _ -> []  -- | The type of a function with the given parameters and return type. funType :: [PatBase Info VName] -> StructRetType -> StructType
src/Language/Futhark/Query.hs view
@@ -114,7 +114,7 @@   where     vbind_t =       foldFunType (map patternStructType (valBindParams vbind)) $-        fst $ unInfo $ valBindRetType vbind+        unInfo $ valBindRetType vbind  typeBindDefs :: TypeBind -> Defs typeBindDefs tbind =
src/Language/Futhark/Syntax.hs view
@@ -1041,7 +1041,9 @@     valBindEntryPoint :: Maybe (f EntryPoint),     valBindName :: vn,     valBindRetDecl :: Maybe (TypeExp vn),-    valBindRetType :: f (StructRetType, [VName]),+    -- | If 'valBindParams' is null, then the 'retDims' are brought+    -- into scope at this point.+    valBindRetType :: f StructRetType,     valBindTypeParams :: [TypeParamBase vn],     valBindParams :: [PatBase f vn],     valBindBody :: ExpBase f vn,
src/Language/Futhark/TypeChecker.hs view
@@ -633,7 +633,7 @@     typeError loc mempty $       withIndexLink "nested-entry" "Entry points may not be declared inside modules." -  (fname', tparams', params', maybe_tdecl', rettype@(RetType _ rettype_t), retext, body') <-+  (fname', tparams', params', maybe_tdecl', rettype@(RetType _ rettype_t), body') <-     checkFunDef (fname, maybe_tdecl, tparams, params, body, loc)    let (rettype_params, rettype') = unfoldFunType rettype_t@@ -668,7 +668,7 @@     _ -> return ()    attrs' <- mapM checkAttr attrs-  let vb = ValBind entry' fname' maybe_tdecl' (Info (rettype, retext)) tparams' params' body' doc attrs' loc+  let vb = ValBind entry' fname' maybe_tdecl' (Info rettype) tparams' params' body' doc attrs' loc   return     ( mempty         { envVtable =
src/Language/Futhark/TypeChecker/Terms.hs view
@@ -496,7 +496,7 @@         Ident (sizeName size) (Info (Scalar $ Prim $ Signed Int64)) (srclocOf size) checkExp (AppExp (LetFun name (tparams, params, maybe_retdecl, NoInfo, e) body loc) _) =   sequentially (checkBinding (name, maybe_retdecl, tparams, params, e, loc)) $-    \(tparams', params', maybe_retdecl', rettype, _, e') closure -> do+    \(tparams', params', maybe_retdecl', rettype, e') closure -> do       closure' <- lexicalClosure params' closure        bindSpaced [(Term, name)] $ do@@ -1067,7 +1067,7 @@ checkOneExp e = fmap fst . runTermTypeM $ do   e' <- checkExp e   let t = toStruct $ typeOf e'-  (tparams, _, _, _) <-+  (tparams, _, _) <-     letGeneralise (nameFromString "<exp>") (srclocOf e) [] [] t   fixOverloadedTypes $ typeVars t   e'' <- updateTypes e'@@ -1236,12 +1236,11 @@       [Pat],       Maybe (TypeExp VName),       StructRetType,-      [VName],       Exp     ) checkFunDef (fname, maybe_retdecl, tparams, params, body, loc) =   fmap fst . runTermTypeM $ do-    (tparams', params', maybe_retdecl', RetType dims rettype', retext, body') <-+    (tparams', params', maybe_retdecl', RetType dims rettype', body') <-       checkBinding (fname, maybe_retdecl, tparams, params, body, loc)      -- Since this is a top-level function, we also resolve overloaded@@ -1270,7 +1269,7 @@         typeError loc mempty . withIndexLink "may-not-be-redefined" $           "The" <+> pprName fname <+> "operator may not be redefined." -      pure (fname', tparams', params'', maybe_retdecl'', RetType dims rettype'', retext, body'')+      pure (fname', tparams', params'', maybe_retdecl'', RetType dims rettype'', body'')  -- | This is "fixing" as in "setting them", not "correcting them".  We -- only make very conservative fixing.@@ -1354,7 +1353,6 @@       [Pat],       Maybe (TypeExp VName),       StructRetType,-      [VName],       Exp     ) checkBinding (fname, maybe_retdecl, tparams, params, body, loc) =@@ -1391,12 +1389,12 @@      verifyFunctionParams (Just fname) params'' -    (tparams'', params''', rettype'', retext) <-+    (tparams'', params''', rettype'') <-       letGeneralise fname loc tparams' params'' rettype      checkGlobalAliases params'' body_t loc -    pure (tparams'', params''', maybe_retdecl'', rettype'', retext, body')+    pure (tparams'', params''', maybe_retdecl'', rettype'', body')   where     checkReturnAlias rettp params' =       foldM_ (checkReturnAlias' params') S.empty . returnAliasing rettp@@ -1584,7 +1582,7 @@   [StructType] ->   StructType ->   Constraints ->-  TermTypeM ([TypeParam], StructRetType, [VName])+  TermTypeM ([TypeParam], StructRetType) closeOverTypes defname defloc tparams paramts ret substs = do   (more_tparams, retext) <-     partitionEithers . catMaybes@@ -1597,8 +1595,7 @@       mkExt AnyDim {} = error "closeOverTypes: AnyDim"   return     ( tparams ++ more_tparams,-      injectExt (mapMaybe mkExt (nestedDims ret)) ret,-      retext+      injectExt (retext ++ mapMaybe mkExt (nestedDims ret)) ret     )   where     t = foldFunType paramts $ RetType [] ret@@ -1638,7 +1635,7 @@   [TypeParam] ->   [Pat] ->   StructType ->-  TermTypeM ([TypeParam], [Pat], StructRetType, [VName])+  TermTypeM ([TypeParam], [Pat], StructRetType) letGeneralise defname defloc tparams params rettype =   onFailure (CheckingLetGeneralise defname) $ do     now_substs <- getConstraints@@ -1663,7 +1660,7 @@     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', retext) <-+    (tparams', RetType ret_dims rettype') <-       closeOverTypes         defname         defloc@@ -1685,7 +1682,7 @@     -- let-generalisation.     modifyConstraints $ M.filterWithKey $ \k _ -> k `notElem` map typeParamName tparams' -    pure (tparams', params, RetType ret_dims rettype'', retext)+    pure (tparams', params, RetType ret_dims rettype'')  checkFunBody ::   [Pat] ->
src/Language/Futhark/TypeChecker/Terms/Monad.hs view
@@ -791,16 +791,6 @@   mustBeOneOf ts (mkUsage (srclocOf e) why) . toStruct =<< expType e   pure e -renameRetType :: StructRetType -> TermTypeM StructRetType-renameRetType (RetType dims st)-  | dims /= mempty = do-    dims' <- mapM newName dims-    let m = M.fromList $ zip dims $ map (SizeSubst . NamedDim . qualName) dims'-        st' = applySubst (`M.lookup` m) st-    pure $ RetType dims' st'-  | otherwise =-    pure $ RetType dims st- termCheckTypeExp :: TypeExp Name -> TermTypeM (TypeExp VName, [VName], StructRetType) termCheckTypeExp te = do   (te', svars, rettype, _l) <- checkTypeExp te
src/Language/Futhark/TypeChecker/Types.hs view
@@ -7,6 +7,7 @@ -- | Type checker building blocks that do not involve unification. module Language.Futhark.TypeChecker.Types   ( checkTypeExp,+    renameRetType,     unifyTypesU,     subtypeOf,     subuniqueOf,@@ -109,14 +110,27 @@ subuniqueOf Nonunique Unique = False subuniqueOf _ _ = True +-- | Ensure that the dimensions of the RetType are unique by+-- generating new names for them.  This is to avoid name capture.+renameRetType :: MonadTypeChecker m => StructRetType -> m StructRetType+renameRetType (RetType dims st)+  | dims /= mempty = do+    dims' <- mapM newName dims+    let m = M.fromList $ zip dims $ map (SizeSubst . NamedDim . qualName) dims'+        st' = applySubst (`M.lookup` m) st+    pure $ RetType dims' st'+  | otherwise =+    pure $ RetType dims st+ evalTypeExp ::   MonadTypeChecker m =>   TypeExp Name ->   m (TypeExp VName, [VName], StructRetType, Liftedness) evalTypeExp (TEVar name loc) = do   (name', ps, t, l) <- lookupType loc name+  t' <- renameRetType t   case ps of-    [] -> pure (TEVar name' loc, [], t, l)+    [] -> pure (TEVar name' loc, [], t', l)     _ ->       typeError loc mempty $         "Type constructor" <+> pquote (spread (ppr name : map ppr ps))@@ -252,7 +266,8 @@     ) evalTypeExp ote@TEApply {} = do   (tname, tname_loc, targs) <- rootAndArgs ote-  (tname', ps, RetType t_dims t, l) <- lookupType tloc tname+  (tname', ps, tname_t, l) <- lookupType tloc tname+  RetType t_dims t <- renameRetType tname_t   if length ps /= length targs     then       typeError tloc mempty $
unittests/Language/Futhark/TypeChecker/TypesTests.hs view
@@ -46,13 +46,20 @@                       TypeParamType Lifted "b_1102" mempty                     ]                     "a_1101 -> b_1102"+                ),+                ( "pair_1200",+                  TypeAbbr+                    SizeLifted+                    []+                    "?[n_1201][m_1202].([n_1201]i64, [m_1202]i64)"                 )               ]               <> envTypeTable initialEnv,           envNameMap =             M.fromList               [ ((Type, "square"), "square_1000"),-                ((Type, "fun"), "fun_1100")+                ((Type, "fun"), "fun_1100"),+                ((Type, "pair"), "pair_1200")               ]               <> envNameMap initialEnv         }@@ -114,7 +121,13 @@         ([], "bool -> ?[d_0].[d_0]i32 -> bool"),       evalTest         "bool -> fun bool ([]i32)"-        ([], "bool -> ?[d_0].bool -> [d_0]i32")+        ([], "bool -> ?[d_0].bool -> [d_0]i32"),+      evalTest+        "pair"+        ([], "?[n_0][m_1].([n_0]i64, [m_1]i64)"),+      evalTest+        "(pair,pair)"+        ([], "?[n_0][m_1][n_2][m_3].(([n_0]i64, [m_1]i64), ([n_2]i64, [m_3]i64))")     ]  substTest :: M.Map VName (Subst StructRetType) -> StructRetType -> StructRetType -> TestTree