packages feed

futhark 0.17.3 → 0.18.1

raw patch · 111 files changed

+6264/−1208 lines, 111 filesdep ~versionsPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: versions

API changes (from Hackage documentation)

- Futhark.Optimise.DoubleBuffer: doubleBuffer :: Pass KernelsMem KernelsMem
- Futhark.Optimise.DoubleBuffer: instance Control.Monad.Reader.Class.MonadReader Futhark.Optimise.DoubleBuffer.Env Futhark.Optimise.DoubleBuffer.DoubleBufferM
- Futhark.Optimise.DoubleBuffer: instance Futhark.IR.Prop.Scope.HasScope Futhark.IR.KernelsMem.KernelsMem Futhark.Optimise.DoubleBuffer.DoubleBufferM
- Futhark.Optimise.DoubleBuffer: instance Futhark.IR.Prop.Scope.LocalScope Futhark.IR.KernelsMem.KernelsMem Futhark.Optimise.DoubleBuffer.DoubleBufferM
- Futhark.Optimise.DoubleBuffer: instance Futhark.MonadFreshNames.MonadFreshNames Futhark.Optimise.DoubleBuffer.DoubleBufferM
- Futhark.Optimise.DoubleBuffer: instance GHC.Base.Applicative Futhark.Optimise.DoubleBuffer.DoubleBufferM
- Futhark.Optimise.DoubleBuffer: instance GHC.Base.Functor Futhark.Optimise.DoubleBuffer.DoubleBufferM
- Futhark.Optimise.DoubleBuffer: instance GHC.Base.Monad Futhark.Optimise.DoubleBuffer.DoubleBufferM
- Futhark.Optimise.Sink: sink :: Pass Kernels Kernels
- Futhark.Optimise.Unstream: unstream :: Pass Kernels Kernels
- Futhark.Pass.ExplicitAllocations.Kernels: instance Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.SegOp.SegOp lvl lore)
- Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl GHC.Int.Int32)
+ Futhark.Actions: compileMulticoreAction :: FutharkConfig -> CompilerMode -> FilePath -> Action MCMem
+ Futhark.Actions: multicoreImpCodeGenAction :: Action MCMem
+ Futhark.Analysis.Metrics: instance Futhark.Analysis.Metrics.OpMetrics a => Futhark.Analysis.Metrics.OpMetrics (GHC.Maybe.Maybe a)
+ Futhark.Analysis.PrimExp.Convert: le64 :: a -> TPrimExp Int64 a
+ Futhark.Analysis.PrimExp.Convert: pe64 :: SubExp -> TPrimExp Int64 VName
+ Futhark.CLI.Multicore: main :: String -> [String] -> IO ()
+ Futhark.CodeGen.Backends.GenericC: cacheMem :: ToExp a => a -> CompilerM op s (Maybe VName)
+ Futhark.CodeGen.Backends.GenericC: cproduct :: [Exp] -> Exp
+ Futhark.CodeGen.Backends.GenericC: fatMemType :: Space -> Type
+ Futhark.CodeGen.Backends.GenericC: fatMemory :: Space -> CompilerM op s Bool
+ Futhark.CodeGen.Backends.GenericC: inNewFunction :: Bool -> CompilerM op s a -> CompilerM op s a
+ Futhark.CodeGen.Backends.GenericC: intTypeToCType :: IntType -> Type
+ Futhark.CodeGen.Backends.GenericC: memToCType :: VName -> Space -> CompilerM op s Type
+ Futhark.CodeGen.Backends.GenericC: rawMemCType :: Space -> CompilerM op s Type
+ Futhark.CodeGen.Backends.MulticoreC: CParts :: String -> String -> String -> String -> CParts
+ Futhark.CodeGen.Backends.MulticoreC: [cCLI] :: CParts -> String
+ Futhark.CodeGen.Backends.MulticoreC: [cHeader] :: CParts -> String
+ Futhark.CodeGen.Backends.MulticoreC: [cLib] :: CParts -> String
+ Futhark.CodeGen.Backends.MulticoreC: [cUtils] :: CParts -> String
+ Futhark.CodeGen.Backends.MulticoreC: asExecutable :: CParts -> String
+ Futhark.CodeGen.Backends.MulticoreC: asLibrary :: CParts -> (String, String)
+ Futhark.CodeGen.Backends.MulticoreC: compileProg :: MonadFreshNames m => Prog MCMem -> m (Warnings, CParts)
+ Futhark.CodeGen.Backends.MulticoreC: data CParts
+ Futhark.CodeGen.Backends.SimpleRep: intTypeToCType :: IntType -> Type
+ Futhark.CodeGen.ImpCode: ErrorInt64 :: a -> ErrorMsgPart a
+ Futhark.CodeGen.ImpCode: declaredIn :: Code a -> Names
+ Futhark.CodeGen.ImpCode.Kernels: ErrorInt64 :: a -> ErrorMsgPart a
+ Futhark.CodeGen.ImpCode.Kernels: declaredIn :: Code a -> Names
+ Futhark.CodeGen.ImpCode.Multicore: (.&&.) :: TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: (.&.) :: TPrimExp t v -> TPrimExp t v -> TPrimExp t v
+ Futhark.CodeGen.ImpCode.Multicore: (.<.) :: TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: (.<=.) :: TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: (.==.) :: TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: (.>.) :: TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: (.>=.) :: TPrimExp t v -> TPrimExp t v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: (.^.) :: TPrimExp t v -> TPrimExp t v -> TPrimExp t v
+ Futhark.CodeGen.ImpCode.Multicore: (.|.) :: TPrimExp t v -> TPrimExp t v -> TPrimExp t v
+ Futhark.CodeGen.ImpCode.Multicore: (.||.) :: TPrimExp Bool v -> TPrimExp Bool v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: AShr :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: Abs :: IntType -> UnOp
+ Futhark.CodeGen.ImpCode.Multicore: Add :: IntType -> Overflow -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: And :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: ArrayValue :: VName -> Space -> PrimType -> Signedness -> [DimSize] -> ValueDesc
+ Futhark.CodeGen.ImpCode.Multicore: ArrayValues :: [PrimValue] -> ArrayContents
+ Futhark.CodeGen.ImpCode.Multicore: ArrayZeros :: Int -> ArrayContents
+ Futhark.CodeGen.ImpCode.Multicore: Atomic :: AtomicOp -> Multicore
+ Futhark.CodeGen.ImpCode.Multicore: AtomicAdd :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: AtomicAnd :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: AtomicCmpXchg :: PrimType -> VName -> VName -> Count Elements (TExp Int32) -> VName -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: AtomicOr :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: AtomicSub :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: AtomicXchg :: PrimType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: AtomicXor :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: BToI :: IntType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: BinOpExp :: BinOp -> PrimExp v -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: Bool :: PrimType
+ Futhark.CodeGen.ImpCode.Multicore: BoolValue :: !Bool -> PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: Cert :: PrimType
+ Futhark.CodeGen.ImpCode.Multicore: Checked :: PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: CmpEq :: PrimType -> CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: CmpLle :: CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: CmpLlt :: CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: CmpOpExp :: CmpOp -> PrimExp v -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: CmpSle :: IntType -> CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: CmpSlt :: IntType -> CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: CmpUle :: IntType -> CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: CmpUlt :: IntType -> CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: Commutative :: Commutativity
+ Futhark.CodeGen.ImpCode.Multicore: Complement :: IntType -> UnOp
+ Futhark.CodeGen.ImpCode.Multicore: Constant :: PrimValue -> SubExp
+ Futhark.CodeGen.ImpCode.Multicore: Constants :: [Param] -> Code a -> Constants a
+ Futhark.CodeGen.ImpCode.Multicore: ConvOpExp :: ConvOp -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: Count :: e -> Count u e
+ Futhark.CodeGen.ImpCode.Multicore: DefaultSpace :: Space
+ Futhark.CodeGen.ImpCode.Multicore: Definitions :: Constants a -> Functions a -> Definitions a
+ Futhark.CodeGen.ImpCode.Multicore: Dynamic :: Scheduling
+ Futhark.CodeGen.ImpCode.Multicore: ErrorInt32 :: a -> ErrorMsgPart a
+ Futhark.CodeGen.ImpCode.Multicore: ErrorInt64 :: a -> ErrorMsgPart a
+ Futhark.CodeGen.ImpCode.Multicore: ErrorMsg :: [ErrorMsgPart a] -> ErrorMsg a
+ Futhark.CodeGen.ImpCode.Multicore: ErrorString :: String -> ErrorMsgPart a
+ Futhark.CodeGen.ImpCode.Multicore: ExpArg :: Exp -> Arg
+ Futhark.CodeGen.ImpCode.Multicore: FAbs :: FloatType -> UnOp
+ Futhark.CodeGen.ImpCode.Multicore: FAdd :: FloatType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: FCmpLe :: FloatType -> CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: FCmpLt :: FloatType -> CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: FDiv :: FloatType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: FMax :: FloatType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: FMin :: FloatType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: FMod :: FloatType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: FMul :: FloatType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: FPConv :: FloatType -> FloatType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: FPToSI :: FloatType -> IntType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: FPToUI :: FloatType -> IntType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: FPow :: FloatType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: FSub :: FloatType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: Float32 :: FloatType
+ Futhark.CodeGen.ImpCode.Multicore: Float32Value :: !Float -> FloatValue
+ Futhark.CodeGen.ImpCode.Multicore: Float64 :: FloatType
+ Futhark.CodeGen.ImpCode.Multicore: Float64Value :: !Double -> FloatValue
+ Futhark.CodeGen.ImpCode.Multicore: FloatType :: FloatType -> PrimType
+ Futhark.CodeGen.ImpCode.Multicore: FloatValue :: !FloatValue -> PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: FunExp :: String -> [PrimExp v] -> PrimType -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: Function :: Bool -> [Param] -> [Param] -> Code a -> [ExternalValue] -> [ExternalValue] -> FunctionT a
+ Futhark.CodeGen.ImpCode.Multicore: Functions :: [(Name, Function a)] -> Functions a
+ Futhark.CodeGen.ImpCode.Multicore: IToB :: IntType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: Index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> ExpLeaf
+ Futhark.CodeGen.ImpCode.Multicore: Int16 :: IntType
+ Futhark.CodeGen.ImpCode.Multicore: Int16Value :: !Int16 -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: Int32 :: IntType
+ Futhark.CodeGen.ImpCode.Multicore: Int32Value :: !Int32 -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: Int64 :: IntType
+ Futhark.CodeGen.ImpCode.Multicore: Int64Value :: !Int64 -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: Int8 :: IntType
+ Futhark.CodeGen.ImpCode.Multicore: Int8Value :: !Int8 -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: IntType :: IntType -> PrimType
+ Futhark.CodeGen.ImpCode.Multicore: IntValue :: !IntValue -> PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: LShr :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: LeafExp :: v -> PrimType -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: LogAnd :: BinOp
+ Futhark.CodeGen.ImpCode.Multicore: LogOr :: BinOp
+ Futhark.CodeGen.ImpCode.Multicore: MemArg :: VName -> Arg
+ Futhark.CodeGen.ImpCode.Multicore: MemParam :: VName -> Space -> Param
+ Futhark.CodeGen.ImpCode.Multicore: Mul :: IntType -> Overflow -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: Noncommutative :: Commutativity
+ Futhark.CodeGen.ImpCode.Multicore: Nonunique :: Uniqueness
+ Futhark.CodeGen.ImpCode.Multicore: Nonvolatile :: Volatility
+ Futhark.CodeGen.ImpCode.Multicore: Not :: UnOp
+ Futhark.CodeGen.ImpCode.Multicore: OpaqueValue :: String -> [ValueDesc] -> ExternalValue
+ Futhark.CodeGen.ImpCode.Multicore: Or :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: OverflowUndef :: Overflow
+ Futhark.CodeGen.ImpCode.Multicore: OverflowWrap :: Overflow
+ Futhark.CodeGen.ImpCode.Multicore: ParLoop :: String -> VName -> Code -> Code -> Code -> [Param] -> VName -> Multicore
+ Futhark.CodeGen.ImpCode.Multicore: ParallelTask :: Code -> VName -> ParallelTask
+ Futhark.CodeGen.ImpCode.Multicore: Pow :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SDiv :: IntType -> Safety -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SDivUp :: IntType -> Safety -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SExt :: IntType -> IntType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: SIToFP :: IntType -> FloatType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: SMax :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SMin :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SMod :: IntType -> Safety -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SQuot :: IntType -> Safety -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SRem :: IntType -> Safety -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SSignum :: IntType -> UnOp
+ Futhark.CodeGen.ImpCode.Multicore: Safe :: Safety
+ Futhark.CodeGen.ImpCode.Multicore: ScalarParam :: VName -> PrimType -> Param
+ Futhark.CodeGen.ImpCode.Multicore: ScalarSpace :: [SubExp] -> PrimType -> Space
+ Futhark.CodeGen.ImpCode.Multicore: ScalarValue :: PrimType -> Signedness -> VName -> ValueDesc
+ Futhark.CodeGen.ImpCode.Multicore: ScalarVar :: VName -> ExpLeaf
+ Futhark.CodeGen.ImpCode.Multicore: SchedulerInfo :: VName -> Exp -> Scheduling -> SchedulerInfo
+ Futhark.CodeGen.ImpCode.Multicore: Segop :: String -> [Param] -> ParallelTask -> Maybe ParallelTask -> [Param] -> SchedulerInfo -> Multicore
+ Futhark.CodeGen.ImpCode.Multicore: Shl :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: SizeOf :: PrimType -> ExpLeaf
+ Futhark.CodeGen.ImpCode.Multicore: Space :: SpaceId -> Space
+ Futhark.CodeGen.ImpCode.Multicore: Static :: Scheduling
+ Futhark.CodeGen.ImpCode.Multicore: Sub :: IntType -> Overflow -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: TPrimExp :: PrimExp v -> TPrimExp t v
+ Futhark.CodeGen.ImpCode.Multicore: TransparentValue :: ValueDesc -> ExternalValue
+ Futhark.CodeGen.ImpCode.Multicore: TypeDirect :: Signedness
+ Futhark.CodeGen.ImpCode.Multicore: TypeUnsigned :: Signedness
+ Futhark.CodeGen.ImpCode.Multicore: UDiv :: IntType -> Safety -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: UDivUp :: IntType -> Safety -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: UIToFP :: IntType -> FloatType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: UMax :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: UMin :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: UMod :: IntType -> Safety -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: USignum :: IntType -> UnOp
+ Futhark.CodeGen.ImpCode.Multicore: UnOpExp :: UnOp -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: Unique :: Uniqueness
+ Futhark.CodeGen.ImpCode.Multicore: Unsafe :: Safety
+ Futhark.CodeGen.ImpCode.Multicore: VName :: !Name -> !Int -> VName
+ Futhark.CodeGen.ImpCode.Multicore: ValueExp :: PrimValue -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: Var :: VName -> SubExp
+ Futhark.CodeGen.ImpCode.Multicore: Volatile :: Volatility
+ Futhark.CodeGen.ImpCode.Multicore: Xor :: IntType -> BinOp
+ Futhark.CodeGen.ImpCode.Multicore: ZExt :: IntType -> IntType -> ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: [constsDecl] :: Constants a -> [Param]
+ Futhark.CodeGen.ImpCode.Multicore: [constsInit] :: Constants a -> Code a
+ Futhark.CodeGen.ImpCode.Multicore: [defConsts] :: Definitions a -> Constants a
+ Futhark.CodeGen.ImpCode.Multicore: [defFuns] :: Definitions a -> Functions a
+ Futhark.CodeGen.ImpCode.Multicore: [flatTid] :: ParallelTask -> VName
+ Futhark.CodeGen.ImpCode.Multicore: [iterations] :: SchedulerInfo -> Exp
+ Futhark.CodeGen.ImpCode.Multicore: [nsubtasks] :: SchedulerInfo -> VName
+ Futhark.CodeGen.ImpCode.Multicore: [scheduling] :: SchedulerInfo -> Scheduling
+ Futhark.CodeGen.ImpCode.Multicore: [task_code] :: ParallelTask -> Code
+ Futhark.CodeGen.ImpCode.Multicore: [unCount] :: Count u e -> e
+ Futhark.CodeGen.ImpCode.Multicore: [untyped] :: TPrimExp t v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: allBinOps :: [BinOp]
+ Futhark.CodeGen.ImpCode.Multicore: allCmpOps :: [CmpOp]
+ Futhark.CodeGen.ImpCode.Multicore: allConvOps :: [ConvOp]
+ Futhark.CodeGen.ImpCode.Multicore: allFloatTypes :: [FloatType]
+ Futhark.CodeGen.ImpCode.Multicore: allIntTypes :: [IntType]
+ Futhark.CodeGen.ImpCode.Multicore: allPrimTypes :: [PrimType]
+ Futhark.CodeGen.ImpCode.Multicore: allUnOps :: [UnOp]
+ Futhark.CodeGen.ImpCode.Multicore: bNot :: TPrimExp Bool v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: baseName :: VName -> Name
+ Futhark.CodeGen.ImpCode.Multicore: baseString :: VName -> String
+ Futhark.CodeGen.ImpCode.Multicore: baseTag :: VName -> Int
+ Futhark.CodeGen.ImpCode.Multicore: binOpType :: BinOp -> PrimType
+ Futhark.CodeGen.ImpCode.Multicore: blankPrimValue :: PrimType -> PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: boundByLambda :: Lambda lore -> [VName]
+ Futhark.CodeGen.ImpCode.Multicore: boundByStm :: Stm lore -> Names
+ Futhark.CodeGen.ImpCode.Multicore: boundByStms :: Stms lore -> Names
+ Futhark.CodeGen.ImpCode.Multicore: boundInBody :: Body lore -> Names
+ Futhark.CodeGen.ImpCode.Multicore: bytes :: a -> Count Bytes a
+ Futhark.CodeGen.ImpCode.Multicore: calledFuncs :: Code a -> Set Name
+ Futhark.CodeGen.ImpCode.Multicore: class NumExp t => FloatExp t
+ Futhark.CodeGen.ImpCode.Multicore: class FreeIn dec => FreeDec dec
+ Futhark.CodeGen.ImpCode.Multicore: class FreeIn a
+ Futhark.CodeGen.ImpCode.Multicore: class NumExp t => IntExp t
+ Futhark.CodeGen.ImpCode.Multicore: class Located a
+ Futhark.CodeGen.ImpCode.Multicore: class NumExp t
+ Futhark.CodeGen.ImpCode.Multicore: cmpOpType :: CmpOp -> PrimType
+ Futhark.CodeGen.ImpCode.Multicore: coerceIntPrimExp :: IntType -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: commutativeBinOp :: BinOp -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: constFoldPrimExp :: PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: convOpFun :: ConvOp -> String
+ Futhark.CodeGen.ImpCode.Multicore: convOpType :: ConvOp -> (PrimType, PrimType)
+ Futhark.CodeGen.ImpCode.Multicore: data Arg
+ Futhark.CodeGen.ImpCode.Multicore: data ArrayContents
+ Futhark.CodeGen.ImpCode.Multicore: data AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: data BinOp
+ Futhark.CodeGen.ImpCode.Multicore: data Bytes
+ Futhark.CodeGen.ImpCode.Multicore: data CmpOp
+ Futhark.CodeGen.ImpCode.Multicore: data Commutativity
+ Futhark.CodeGen.ImpCode.Multicore: data Constants a
+ Futhark.CodeGen.ImpCode.Multicore: data ConvOp
+ Futhark.CodeGen.ImpCode.Multicore: data Definitions a
+ Futhark.CodeGen.ImpCode.Multicore: data Elements
+ Futhark.CodeGen.ImpCode.Multicore: data ErrorMsgPart a
+ Futhark.CodeGen.ImpCode.Multicore: data ExpLeaf
+ Futhark.CodeGen.ImpCode.Multicore: data ExternalValue
+ Futhark.CodeGen.ImpCode.Multicore: data FV
+ Futhark.CodeGen.ImpCode.Multicore: data FloatType
+ Futhark.CodeGen.ImpCode.Multicore: data FloatValue
+ Futhark.CodeGen.ImpCode.Multicore: data FunctionT a
+ Futhark.CodeGen.ImpCode.Multicore: data Int16
+ Futhark.CodeGen.ImpCode.Multicore: data Int32
+ Futhark.CodeGen.ImpCode.Multicore: data Int64
+ Futhark.CodeGen.ImpCode.Multicore: data Int8
+ Futhark.CodeGen.ImpCode.Multicore: data IntType
+ Futhark.CodeGen.ImpCode.Multicore: data IntValue
+ Futhark.CodeGen.ImpCode.Multicore: data Loc
+ Futhark.CodeGen.ImpCode.Multicore: data Multicore
+ Futhark.CodeGen.ImpCode.Multicore: data Name
+ Futhark.CodeGen.ImpCode.Multicore: data Names
+ Futhark.CodeGen.ImpCode.Multicore: data Overflow
+ Futhark.CodeGen.ImpCode.Multicore: data ParallelTask
+ Futhark.CodeGen.ImpCode.Multicore: data Param
+ Futhark.CodeGen.ImpCode.Multicore: data PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: data PrimType
+ Futhark.CodeGen.ImpCode.Multicore: data PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: data Safety
+ Futhark.CodeGen.ImpCode.Multicore: data SchedulerInfo
+ Futhark.CodeGen.ImpCode.Multicore: data Scheduling
+ Futhark.CodeGen.ImpCode.Multicore: data Signedness
+ Futhark.CodeGen.ImpCode.Multicore: data Space
+ Futhark.CodeGen.ImpCode.Multicore: data SrcLoc
+ Futhark.CodeGen.ImpCode.Multicore: data SubExp
+ Futhark.CodeGen.ImpCode.Multicore: data UnOp
+ Futhark.CodeGen.ImpCode.Multicore: data Uniqueness
+ Futhark.CodeGen.ImpCode.Multicore: data VName
+ Futhark.CodeGen.ImpCode.Multicore: data ValueDesc
+ Futhark.CodeGen.ImpCode.Multicore: data Volatility
+ Futhark.CodeGen.ImpCode.Multicore: data Word16
+ Futhark.CodeGen.ImpCode.Multicore: data Word32
+ Futhark.CodeGen.ImpCode.Multicore: data Word64
+ Futhark.CodeGen.ImpCode.Multicore: data Word8
+ Futhark.CodeGen.ImpCode.Multicore: declaredIn :: Code a -> Names
+ Futhark.CodeGen.ImpCode.Multicore: defaultEntryPoint :: Name
+ Futhark.CodeGen.ImpCode.Multicore: doAbs :: IntValue -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doAdd :: IntValue -> IntValue -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doBinOp :: BinOp -> PrimValue -> PrimValue -> Maybe PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: doCmpEq :: PrimValue -> PrimValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: doCmpOp :: CmpOp -> PrimValue -> PrimValue -> Maybe Bool
+ Futhark.CodeGen.ImpCode.Multicore: doCmpSle :: IntValue -> IntValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: doCmpSlt :: IntValue -> IntValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: doCmpUle :: IntValue -> IntValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: doCmpUlt :: IntValue -> IntValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: doComplement :: IntValue -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doConvOp :: ConvOp -> PrimValue -> Maybe PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: doFAbs :: FloatValue -> FloatValue
+ Futhark.CodeGen.ImpCode.Multicore: doFCmpLe :: FloatValue -> FloatValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: doFCmpLt :: FloatValue -> FloatValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: doFPConv :: FloatValue -> FloatType -> FloatValue
+ Futhark.CodeGen.ImpCode.Multicore: doFPToSI :: FloatValue -> IntType -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doFPToUI :: FloatValue -> IntType -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doMul :: IntValue -> IntValue -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doPow :: IntValue -> IntValue -> Maybe IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doSDiv :: IntValue -> IntValue -> Maybe IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doSExt :: IntValue -> IntType -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doSIToFP :: IntValue -> FloatType -> FloatValue
+ Futhark.CodeGen.ImpCode.Multicore: doSMod :: IntValue -> IntValue -> Maybe IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doSSignum :: IntValue -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doUIToFP :: IntValue -> FloatType -> FloatValue
+ Futhark.CodeGen.ImpCode.Multicore: doUSignum :: IntValue -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: doUnOp :: UnOp -> PrimValue -> Maybe PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: doZExt :: IntValue -> IntType -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: elements :: a -> Count Elements a
+ Futhark.CodeGen.ImpCode.Multicore: errorMsgArgTypes :: ErrorMsg a -> [PrimType]
+ Futhark.CodeGen.ImpCode.Multicore: evalPrimExp :: (Pretty v, MonadFail m) => (v -> m PrimValue) -> PrimExp v -> m PrimValue
+ Futhark.CodeGen.ImpCode.Multicore: fMax64 :: TPrimExp Double v -> TPrimExp Double v -> TPrimExp Double v
+ Futhark.CodeGen.ImpCode.Multicore: fMin64 :: TPrimExp Double v -> TPrimExp Double v -> TPrimExp Double v
+ Futhark.CodeGen.ImpCode.Multicore: false :: TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: floatByteSize :: Num a => FloatType -> a
+ Futhark.CodeGen.ImpCode.Multicore: floatValue :: Real num => FloatType -> num -> FloatValue
+ Futhark.CodeGen.ImpCode.Multicore: floatValueType :: FloatValue -> FloatType
+ Futhark.CodeGen.ImpCode.Multicore: freeIn :: FreeIn a => a -> Names
+ Futhark.CodeGen.ImpCode.Multicore: freeIn' :: FreeIn a => a -> FV
+ Futhark.CodeGen.ImpCode.Multicore: freeInStmsAndRes :: (FreeIn (Op lore), FreeIn (LetDec lore), FreeIn (LParamInfo lore), FreeIn (FParamInfo lore), FreeDec (BodyDec lore), FreeDec (ExpDec lore)) => Stms lore -> Result -> FV
+ Futhark.CodeGen.ImpCode.Multicore: fromInteger' :: NumExp t => Integer -> TPrimExp t v
+ Futhark.CodeGen.ImpCode.Multicore: fromRational' :: FloatExp t => Rational -> TPrimExp t v
+ Futhark.CodeGen.ImpCode.Multicore: fvBind :: Names -> FV -> FV
+ Futhark.CodeGen.ImpCode.Multicore: fvName :: VName -> FV
+ Futhark.CodeGen.ImpCode.Multicore: fvNames :: Names -> FV
+ Futhark.CodeGen.ImpCode.Multicore: index :: VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp
+ Futhark.CodeGen.ImpCode.Multicore: infix 4 .>=.
+ Futhark.CodeGen.ImpCode.Multicore: infixr 2 .||.
+ Futhark.CodeGen.ImpCode.Multicore: infixr 3 .&&.
+ Futhark.CodeGen.ImpCode.Multicore: instance Futhark.IR.Prop.Names.FreeIn Futhark.CodeGen.ImpCode.Multicore.AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: instance Futhark.IR.Prop.Names.FreeIn Futhark.CodeGen.ImpCode.Multicore.Multicore
+ Futhark.CodeGen.ImpCode.Multicore: instance Futhark.IR.Prop.Names.FreeIn Futhark.CodeGen.ImpCode.Multicore.ParallelTask
+ Futhark.CodeGen.ImpCode.Multicore: instance Futhark.IR.Prop.Names.FreeIn Futhark.CodeGen.ImpCode.Multicore.SchedulerInfo
+ Futhark.CodeGen.ImpCode.Multicore: instance GHC.Show.Show Futhark.CodeGen.ImpCode.Multicore.AtomicOp
+ Futhark.CodeGen.ImpCode.Multicore: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.CodeGen.ImpCode.Multicore.Multicore
+ Futhark.CodeGen.ImpCode.Multicore: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.CodeGen.ImpCode.Multicore.ParallelTask
+ Futhark.CodeGen.ImpCode.Multicore: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.CodeGen.ImpCode.Multicore.SchedulerInfo
+ Futhark.CodeGen.ImpCode.Multicore: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.CodeGen.ImpCode.Multicore.Scheduling
+ Futhark.CodeGen.ImpCode.Multicore: intByteSize :: Num a => IntType -> a
+ Futhark.CodeGen.ImpCode.Multicore: intToInt64 :: IntValue -> Int64
+ Futhark.CodeGen.ImpCode.Multicore: intToWord64 :: IntValue -> Word64
+ Futhark.CodeGen.ImpCode.Multicore: intValue :: Integral int => IntType -> int -> IntValue
+ Futhark.CodeGen.ImpCode.Multicore: intValueType :: IntValue -> IntType
+ Futhark.CodeGen.ImpCode.Multicore: isBool :: PrimExp v -> TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: isF32 :: PrimExp v -> TPrimExp Float v
+ Futhark.CodeGen.ImpCode.Multicore: isF64 :: PrimExp v -> TPrimExp Double v
+ Futhark.CodeGen.ImpCode.Multicore: isInt16 :: PrimExp v -> TPrimExp Int16 v
+ Futhark.CodeGen.ImpCode.Multicore: isInt32 :: PrimExp v -> TPrimExp Int32 v
+ Futhark.CodeGen.ImpCode.Multicore: isInt64 :: PrimExp v -> TPrimExp Int64 v
+ Futhark.CodeGen.ImpCode.Multicore: isInt8 :: PrimExp v -> TPrimExp Int8 v
+ Futhark.CodeGen.ImpCode.Multicore: leafExpTypes :: Ord a => PrimExp a -> Set (a, PrimType)
+ Futhark.CodeGen.ImpCode.Multicore: lexicalMemoryUsage :: Function a -> Map VName Space
+ Futhark.CodeGen.ImpCode.Multicore: locOf :: Located a => a -> Loc
+ Futhark.CodeGen.ImpCode.Multicore: locOfList :: Located a => [a] -> Loc
+ Futhark.CodeGen.ImpCode.Multicore: locStr :: Located a => a -> String
+ Futhark.CodeGen.ImpCode.Multicore: locStrRel :: (Located a, Located b) => a -> b -> String
+ Futhark.CodeGen.ImpCode.Multicore: mapNames :: (VName -> VName) -> Names -> Names
+ Futhark.CodeGen.ImpCode.Multicore: nameFromString :: String -> Name
+ Futhark.CodeGen.ImpCode.Multicore: nameFromText :: Text -> Name
+ Futhark.CodeGen.ImpCode.Multicore: nameIn :: VName -> Names -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: nameToString :: Name -> String
+ Futhark.CodeGen.ImpCode.Multicore: nameToText :: Name -> Text
+ Futhark.CodeGen.ImpCode.Multicore: namesFromList :: [VName] -> Names
+ Futhark.CodeGen.ImpCode.Multicore: namesIntMap :: Names -> IntMap VName
+ Futhark.CodeGen.ImpCode.Multicore: namesIntersect :: Names -> Names -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: namesIntersection :: Names -> Names -> Names
+ Futhark.CodeGen.ImpCode.Multicore: namesSubtract :: Names -> Names -> Names
+ Futhark.CodeGen.ImpCode.Multicore: namesToList :: Names -> [VName]
+ Futhark.CodeGen.ImpCode.Multicore: negativeIsh :: PrimValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: newtype Count u e
+ Futhark.CodeGen.ImpCode.Multicore: newtype ErrorMsg a
+ Futhark.CodeGen.ImpCode.Multicore: newtype Functions a
+ Futhark.CodeGen.ImpCode.Multicore: newtype TPrimExp t v
+ Futhark.CodeGen.ImpCode.Multicore: oneIsh :: PrimValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: oneIshInt :: IntValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: oneName :: VName -> Names
+ Futhark.CodeGen.ImpCode.Multicore: paramName :: Param -> VName
+ Futhark.CodeGen.ImpCode.Multicore: pattern Skip :: () => Code a
+ Futhark.CodeGen.ImpCode.Multicore: pattern Assert :: () => Exp -> ErrorMsg Exp -> (SrcLoc, [SrcLoc]) -> Code a
+ Futhark.CodeGen.ImpCode.Multicore: pattern Comment :: () => String -> Code a -> Code a
+ Futhark.CodeGen.ImpCode.Multicore: pattern If :: () => TExp Bool -> Code a -> Code a -> Code a
+ Futhark.CodeGen.ImpCode.Multicore: pattern Write :: () => VName -> Count Elements (TExp Int64) -> PrimType -> Space -> Volatility -> Exp -> Code a
+ Futhark.CodeGen.ImpCode.Multicore: pattern Call :: () => [VName] -> Name -> [Arg] -> Code a
+ Futhark.CodeGen.ImpCode.Multicore: pattern Op :: () => a -> Code a
+ Futhark.CodeGen.ImpCode.Multicore: pquote :: Doc -> Doc
+ Futhark.CodeGen.ImpCode.Multicore: precomputed :: FreeDec dec => dec -> FV -> FV
+ Futhark.CodeGen.ImpCode.Multicore: pretty :: Pretty a => a -> String
+ Futhark.CodeGen.ImpCode.Multicore: prettySigned :: Bool -> PrimType -> String
+ Futhark.CodeGen.ImpCode.Multicore: prettyStacktrace :: Int -> [String] -> String
+ Futhark.CodeGen.ImpCode.Multicore: primBitSize :: PrimType -> Int
+ Futhark.CodeGen.ImpCode.Multicore: primByteSize :: Num a => PrimType -> a
+ Futhark.CodeGen.ImpCode.Multicore: primExpSizeAtLeast :: Int -> PrimExp v -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: primExpType :: PrimExp v -> PrimType
+ Futhark.CodeGen.ImpCode.Multicore: primFuns :: Map String ([PrimType], PrimType, [PrimValue] -> Maybe PrimValue)
+ Futhark.CodeGen.ImpCode.Multicore: primValueType :: PrimValue -> PrimType
+ Futhark.CodeGen.ImpCode.Multicore: quote :: String -> String
+ Futhark.CodeGen.ImpCode.Multicore: sExt :: IntType -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: sExt32 :: IntExp t => TPrimExp t v -> TPrimExp Int32 v
+ Futhark.CodeGen.ImpCode.Multicore: sExt64 :: IntExp t => TPrimExp t v -> TPrimExp Int64 v
+ Futhark.CodeGen.ImpCode.Multicore: sMax32 :: TPrimExp Int32 v -> TPrimExp Int32 v -> TPrimExp Int32 v
+ Futhark.CodeGen.ImpCode.Multicore: sMax64 :: TPrimExp Int64 v -> TPrimExp Int64 v -> TPrimExp Int64 v
+ Futhark.CodeGen.ImpCode.Multicore: sMin32 :: TPrimExp Int32 v -> TPrimExp Int32 v -> TPrimExp Int32 v
+ Futhark.CodeGen.ImpCode.Multicore: sMin64 :: TPrimExp Int64 v -> TPrimExp Int64 v -> TPrimExp Int64 v
+ Futhark.CodeGen.ImpCode.Multicore: srclocOf :: Located a => a -> SrcLoc
+ Futhark.CodeGen.ImpCode.Multicore: true :: TPrimExp Bool v
+ Futhark.CodeGen.ImpCode.Multicore: type Code = Code Multicore
+ Futhark.CodeGen.ImpCode.Multicore: type DimSize = SubExp
+ Futhark.CodeGen.ImpCode.Multicore: type Exp = PrimExp ExpLeaf
+ Futhark.CodeGen.ImpCode.Multicore: type Function = Function Multicore
+ Futhark.CodeGen.ImpCode.Multicore: type MemSize = SubExp
+ Futhark.CodeGen.ImpCode.Multicore: type Program = Functions Multicore
+ Futhark.CodeGen.ImpCode.Multicore: type SpaceId = String
+ Futhark.CodeGen.ImpCode.Multicore: type TExp t = TPrimExp t ExpLeaf
+ Futhark.CodeGen.ImpCode.Multicore: unOpType :: UnOp -> PrimType
+ Futhark.CodeGen.ImpCode.Multicore: valueIntegral :: Integral int => IntValue -> int
+ Futhark.CodeGen.ImpCode.Multicore: var :: VName -> PrimType -> Exp
+ Futhark.CodeGen.ImpCode.Multicore: vi32 :: VName -> TExp Int32
+ Futhark.CodeGen.ImpCode.Multicore: vi64 :: VName -> TExp Int64
+ Futhark.CodeGen.ImpCode.Multicore: withElemType :: Count Elements (TExp Int64) -> PrimType -> Count Bytes (TExp Int64)
+ Futhark.CodeGen.ImpCode.Multicore: zExt :: IntType -> PrimExp v -> PrimExp v
+ Futhark.CodeGen.ImpCode.Multicore: zExt32 :: IntExp t => TPrimExp t v -> TPrimExp Int32 v
+ Futhark.CodeGen.ImpCode.Multicore: zExt64 :: IntExp t => TPrimExp t v -> TPrimExp Int64 v
+ Futhark.CodeGen.ImpCode.Multicore: zeroIsh :: PrimValue -> Bool
+ Futhark.CodeGen.ImpCode.Multicore: zeroIshInt :: IntValue -> Bool
+ Futhark.CodeGen.ImpCode.OpenCL: ErrorInt64 :: a -> ErrorMsgPart a
+ Futhark.CodeGen.ImpCode.OpenCL: declaredIn :: Code a -> Names
+ Futhark.CodeGen.ImpCode.Sequential: ErrorInt64 :: a -> ErrorMsgPart a
+ Futhark.CodeGen.ImpCode.Sequential: declaredIn :: Code a -> Names
+ Futhark.CodeGen.ImpGen.Multicore: compileProg :: MonadFreshNames m => Prog MCMem -> m (Warnings, Definitions Multicore)
+ Futhark.CodeGen.ImpGen.Multicore: data Warnings
+ Futhark.CodeGen.ImpGen.Multicore.Base: AtomicCAS :: DoAtomicUpdate lore r -> AtomicUpdate lore r
+ Futhark.CodeGen.ImpGen.Multicore.Base: AtomicLocking :: (Locking -> DoAtomicUpdate lore r) -> AtomicUpdate lore r
+ Futhark.CodeGen.ImpGen.Multicore.Base: AtomicPrim :: DoAtomicUpdate lore r -> AtomicUpdate lore r
+ Futhark.CodeGen.ImpGen.Multicore.Base: HostEnv :: AtomicBinOp -> HostEnv
+ Futhark.CodeGen.ImpGen.Multicore.Base: Locking :: VName -> TExp Int32 -> TExp Int32 -> TExp Int32 -> ([TExp Int64] -> [TExp Int64]) -> Locking
+ Futhark.CodeGen.ImpGen.Multicore.Base: [hostAtomics] :: HostEnv -> AtomicBinOp
+ Futhark.CodeGen.ImpGen.Multicore.Base: [lockingArray] :: Locking -> VName
+ Futhark.CodeGen.ImpGen.Multicore.Base: [lockingIsUnlocked] :: Locking -> TExp Int32
+ Futhark.CodeGen.ImpGen.Multicore.Base: [lockingMapping] :: Locking -> [TExp Int64] -> [TExp Int64]
+ Futhark.CodeGen.ImpGen.Multicore.Base: [lockingToLock] :: Locking -> TExp Int32
+ Futhark.CodeGen.ImpGen.Multicore.Base: [lockingToUnlock] :: Locking -> TExp Int32
+ Futhark.CodeGen.ImpGen.Multicore.Base: atomicUpdateLocking :: AtomicBinOp -> Lambda MCMem -> AtomicUpdate MCMem ()
+ Futhark.CodeGen.ImpGen.Multicore.Base: compileKBody :: KernelBody MCMem -> ([(SubExp, [Exp])] -> ImpM MCMem () Multicore ()) -> ImpM MCMem () Multicore ()
+ Futhark.CodeGen.ImpGen.Multicore.Base: compileThreadResult :: SegSpace -> PatElem MCMem -> KernelResult -> MulticoreGen ()
+ Futhark.CodeGen.ImpGen.Multicore.Base: data AtomicUpdate lore r
+ Futhark.CodeGen.ImpGen.Multicore.Base: data Locking
+ Futhark.CodeGen.ImpGen.Multicore.Base: decideScheduling :: Code -> Scheduling
+ Futhark.CodeGen.ImpGen.Multicore.Base: decideScheduling' :: SegOp () lore -> Code -> Scheduling
+ Futhark.CodeGen.ImpGen.Multicore.Base: extractAllocations :: Code -> (Code, Code)
+ Futhark.CodeGen.ImpGen.Multicore.Base: freeParams :: Code -> [VName] -> MulticoreGen [Param]
+ Futhark.CodeGen.ImpGen.Multicore.Base: getIterationDomain :: SegOp () MCMem -> SegSpace -> MulticoreGen (TExp Int64)
+ Futhark.CodeGen.ImpGen.Multicore.Base: getReturnParams :: Pattern MCMem -> SegOp () MCMem -> MulticoreGen [Param]
+ Futhark.CodeGen.ImpGen.Multicore.Base: getSpace :: SegOp () MCMem -> SegSpace
+ Futhark.CodeGen.ImpGen.Multicore.Base: groupResultArrays :: String -> SubExp -> [SegBinOp MCMem] -> MulticoreGen [[VName]]
+ Futhark.CodeGen.ImpGen.Multicore.Base: newtype HostEnv
+ Futhark.CodeGen.ImpGen.Multicore.Base: renameHistOpLambda :: [HistOp MCMem] -> MulticoreGen [HistOp MCMem]
+ Futhark.CodeGen.ImpGen.Multicore.Base: renameSegBinOp :: [SegBinOp MCMem] -> MulticoreGen [SegBinOp MCMem]
+ Futhark.CodeGen.ImpGen.Multicore.Base: resultArrays :: String -> [SegBinOp MCMem] -> MulticoreGen [[VName]]
+ Futhark.CodeGen.ImpGen.Multicore.Base: segOpString :: SegOp () MCMem -> MulticoreGen String
+ Futhark.CodeGen.ImpGen.Multicore.Base: toParam :: VName -> TypeBase shape u -> MulticoreGen Param
+ Futhark.CodeGen.ImpGen.Multicore.Base: type AtomicBinOp = BinOp -> Maybe (VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp)
+ Futhark.CodeGen.ImpGen.Multicore.Base: type MulticoreGen = ImpM MCMem HostEnv Multicore
+ Futhark.CodeGen.ImpGen.Multicore.SegHist: compileSegHist :: Pattern MCMem -> SegSpace -> [HistOp MCMem] -> KernelBody MCMem -> TV Int32 -> MulticoreGen Code
+ Futhark.CodeGen.ImpGen.Multicore.SegMap: compileSegMap :: Pattern MCMem -> SegSpace -> KernelBody MCMem -> MulticoreGen Code
+ Futhark.CodeGen.ImpGen.Multicore.SegRed: compileSegRed :: Pattern MCMem -> SegSpace -> [SegBinOp MCMem] -> KernelBody MCMem -> TV Int32 -> MulticoreGen Code
+ Futhark.CodeGen.ImpGen.Multicore.SegRed: compileSegRed' :: Pattern MCMem -> SegSpace -> [SegBinOp MCMem] -> TV Int32 -> DoSegBody -> MulticoreGen Code
+ Futhark.CodeGen.ImpGen.Multicore.SegScan: compileSegScan :: Pattern MCMem -> SegSpace -> [SegBinOp MCMem] -> KernelBody MCMem -> TV Int32 -> MulticoreGen Code
+ Futhark.IR.MC: Disorder :: StreamOrd
+ Futhark.IR.MC: Hist :: SubExp -> [HistOp lore] -> Lambda lore -> [VName] -> SOAC lore
+ Futhark.IR.MC: InOrder :: StreamOrd
+ Futhark.IR.MC: Parallel :: StreamOrd -> Commutativity -> Lambda lore -> [SubExp] -> StreamForm lore
+ Futhark.IR.MC: Reduce :: Commutativity -> Lambda lore -> [SubExp] -> Reduce lore
+ Futhark.IR.MC: SOACMapper :: (SubExp -> m SubExp) -> (Lambda flore -> m (Lambda tlore)) -> (VName -> m VName) -> SOACMapper flore tlore m
+ Futhark.IR.MC: Scan :: Lambda lore -> [SubExp] -> Scan lore
+ Futhark.IR.MC: Scatter :: SubExp -> Lambda lore -> [VName] -> [(SubExp, Int, VName)] -> SOAC lore
+ Futhark.IR.MC: Screma :: SubExp -> ScremaForm lore -> [VName] -> SOAC lore
+ Futhark.IR.MC: ScremaForm :: [Scan lore] -> [Reduce lore] -> Lambda lore -> ScremaForm lore
+ Futhark.IR.MC: Sequential :: [SubExp] -> StreamForm lore
+ Futhark.IR.MC: Stream :: SubExp -> StreamForm lore -> Lambda lore -> [VName] -> SOAC lore
+ Futhark.IR.MC: [mapOnSOACLambda] :: SOACMapper flore tlore m -> Lambda flore -> m (Lambda tlore)
+ Futhark.IR.MC: [mapOnSOACSubExp] :: SOACMapper flore tlore m -> SubExp -> m SubExp
+ Futhark.IR.MC: [mapOnSOACVName] :: SOACMapper flore tlore m -> VName -> m VName
+ Futhark.IR.MC: [redComm] :: Reduce lore -> Commutativity
+ Futhark.IR.MC: [redLambda] :: Reduce lore -> Lambda lore
+ Futhark.IR.MC: [redNeutral] :: Reduce lore -> [SubExp]
+ Futhark.IR.MC: [scanLambda] :: Scan lore -> Lambda lore
+ Futhark.IR.MC: [scanNeutral] :: Scan lore -> [SubExp]
+ Futhark.IR.MC: data MC
+ Futhark.IR.MC: data Reduce lore
+ Futhark.IR.MC: data SOAC lore
+ Futhark.IR.MC: data SOACMapper flore tlore m
+ Futhark.IR.MC: data Scan lore
+ Futhark.IR.MC: data ScremaForm lore
+ Futhark.IR.MC: data StreamForm lore
+ Futhark.IR.MC: data StreamOrd
+ Futhark.IR.MC: getStreamAccums :: StreamForm lore -> [SubExp]
+ Futhark.IR.MC: identitySOACMapper :: Monad m => SOACMapper lore lore m
+ Futhark.IR.MC: instance Futhark.Binder.BinderOps (Futhark.Optimise.Simplify.Lore.Wise Futhark.IR.MC.MC)
+ Futhark.IR.MC: instance Futhark.Binder.BinderOps Futhark.IR.MC.MC
+ Futhark.IR.MC: instance Futhark.Binder.Class.Bindable Futhark.IR.MC.MC
+ Futhark.IR.MC: instance Futhark.IR.Decorations.Decorations Futhark.IR.MC.MC
+ Futhark.IR.MC: instance Futhark.IR.Pretty.PrettyLore Futhark.IR.MC.MC
+ Futhark.IR.MC: instance Futhark.IR.Prop.ASTLore Futhark.IR.MC.MC
+ Futhark.IR.MC: instance Futhark.IR.SegOp.HasSegOp (Futhark.Optimise.Simplify.Lore.Wise Futhark.IR.MC.MC)
+ Futhark.IR.MC: instance Futhark.IR.SegOp.HasSegOp Futhark.IR.MC.MC
+ Futhark.IR.MC: instance Futhark.TypeCheck.Checkable Futhark.IR.MC.MC
+ Futhark.IR.MC: instance Futhark.TypeCheck.CheckableOp Futhark.IR.MC.MC
+ Futhark.IR.MC: isIdentityLambda :: Lambda lore -> Bool
+ Futhark.IR.MC: isMapSOAC :: ScremaForm lore -> Maybe (Lambda lore)
+ Futhark.IR.MC: isRedomapSOAC :: ScremaForm lore -> Maybe ([Reduce lore], Lambda lore)
+ Futhark.IR.MC: isReduceSOAC :: ScremaForm lore -> Maybe [Reduce lore]
+ Futhark.IR.MC: isScanSOAC :: ScremaForm lore -> Maybe [Scan lore]
+ Futhark.IR.MC: isScanomapSOAC :: ScremaForm lore -> Maybe ([Scan lore], Lambda lore)
+ Futhark.IR.MC: mapSOAC :: Lambda lore -> ScremaForm lore
+ Futhark.IR.MC: mapSOACM :: (Applicative m, Monad m) => SOACMapper flore tlore m -> SOAC flore -> m (SOAC tlore)
+ Futhark.IR.MC: mkIdentityLambda :: (Bindable lore, MonadFreshNames m) => [Type] -> m (Lambda lore)
+ Futhark.IR.MC: nilFn :: Bindable lore => Lambda lore
+ Futhark.IR.MC: ppHist :: (PrettyLore lore, Pretty inp) => SubExp -> [HistOp lore] -> Lambda lore -> [inp] -> Doc
+ Futhark.IR.MC: ppScrema :: (PrettyLore lore, Pretty inp) => SubExp -> ScremaForm lore -> [inp] -> Doc
+ Futhark.IR.MC: redResults :: [Reduce lore] -> Int
+ Futhark.IR.MC: redomapSOAC :: [Reduce lore] -> Lambda lore -> ScremaForm lore
+ Futhark.IR.MC: reduceSOAC :: (Bindable lore, MonadFreshNames m) => [Reduce lore] -> m (ScremaForm lore)
+ Futhark.IR.MC: scanResults :: [Scan lore] -> Int
+ Futhark.IR.MC: scanSOAC :: (Bindable lore, MonadFreshNames m) => [Scan lore] -> m (ScremaForm lore)
+ Futhark.IR.MC: scanomapSOAC :: [Scan lore] -> Lambda lore -> ScremaForm lore
+ Futhark.IR.MC: scremaType :: SubExp -> ScremaForm lore -> [Type]
+ Futhark.IR.MC: simplifyProg :: Prog MC -> PassM (Prog MC)
+ Futhark.IR.MC: singleReduce :: Bindable lore => [Reduce lore] -> Reduce lore
+ Futhark.IR.MC: singleScan :: Bindable lore => [Scan lore] -> Scan lore
+ Futhark.IR.MC: soacType :: SOAC lore -> [Type]
+ Futhark.IR.MC: typeCheckSOAC :: Checkable lore => SOAC (Aliases lore) -> TypeM lore ()
+ Futhark.IR.MC.Op: OtherOp :: op -> MCOp lore op
+ Futhark.IR.MC.Op: ParOp :: Maybe (SegOp () lore) -> SegOp () lore -> MCOp lore op
+ Futhark.IR.MC.Op: data MCOp lore op
+ Futhark.IR.MC.Op: instance (Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.Decorations.Op lore), Futhark.Analysis.Metrics.OpMetrics op) => Futhark.Analysis.Metrics.OpMetrics (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Decorations.Decorations lore, GHC.Classes.Eq op) => GHC.Classes.Eq (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Decorations.Decorations lore, GHC.Classes.Ord op) => GHC.Classes.Ord (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Decorations.Decorations lore, GHC.Show.Show op) => GHC.Show.Show (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Decorations.Decorations lore, Language.SexpGrammar.Class.SexpIso op) => Language.SexpGrammar.Class.SexpIso (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Pretty.PrettyLore lore, Text.PrettyPrint.Mainland.Class.Pretty op) => Text.PrettyPrint.Mainland.Class.Pretty (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTLore lore, Futhark.Analysis.SymbolTable.IndexOp op) => Futhark.Analysis.SymbolTable.IndexOp (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTLore lore, Futhark.IR.Prop.IsOp op) => Futhark.IR.Prop.IsOp (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTLore lore, Futhark.IR.Prop.Names.FreeIn op) => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTLore lore, Futhark.Transform.Rename.Rename op) => Futhark.Transform.Rename.Rename (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.ASTLore lore, Futhark.Transform.Substitute.Substitute op) => Futhark.Transform.Substitute.Substitute (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.Aliases.Aliased lore, Futhark.IR.Prop.Aliases.AliasedOp op, Futhark.IR.Prop.ASTLore lore) => Futhark.IR.Prop.Aliases.AliasedOp (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.Decorations.Op lore), Futhark.IR.Prop.Aliases.CanBeAliased op, Futhark.IR.Prop.ASTLore lore) => Futhark.IR.Prop.Aliases.CanBeAliased (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance (Futhark.Optimise.Simplify.Lore.CanBeWise (Futhark.IR.Decorations.Op lore), Futhark.Optimise.Simplify.Lore.CanBeWise op, Futhark.IR.Prop.ASTLore lore) => Futhark.Optimise.Simplify.Lore.CanBeWise (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance Futhark.IR.Prop.TypeOf.TypedOp op => Futhark.IR.Prop.TypeOf.TypedOp (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: instance GHC.Generics.Generic (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.IR.MC.Op: simplifyMCOp :: (SimplifiableLore lore, BodyDec lore ~ ()) => SimplifyOp lore op -> MCOp lore op -> SimpleM lore (MCOp (Wise lore) (OpWithWisdom op), Stms (Wise lore))
+ Futhark.IR.MC.Op: typeCheckMCOp :: Checkable lore => (op -> TypeM lore ()) -> MCOp (Aliases lore) op -> TypeM lore ()
+ Futhark.IR.MCMem: data MCMem
+ Futhark.IR.MCMem: instance Futhark.Binder.BinderOps (Futhark.Optimise.Simplify.Lore.Wise Futhark.IR.MCMem.MCMem)
+ Futhark.IR.MCMem: instance Futhark.Binder.BinderOps Futhark.IR.MCMem.MCMem
+ Futhark.IR.MCMem: instance Futhark.IR.Decorations.Decorations Futhark.IR.MCMem.MCMem
+ Futhark.IR.MCMem: instance Futhark.IR.Mem.OpReturns Futhark.IR.MCMem.MCMem
+ Futhark.IR.MCMem: instance Futhark.IR.Pretty.PrettyLore Futhark.IR.MCMem.MCMem
+ Futhark.IR.MCMem: instance Futhark.IR.Prop.ASTLore Futhark.IR.MCMem.MCMem
+ Futhark.IR.MCMem: instance Futhark.TypeCheck.Checkable Futhark.IR.MCMem.MCMem
+ Futhark.IR.MCMem: instance Futhark.TypeCheck.CheckableOp Futhark.IR.MCMem.MCMem
+ Futhark.IR.MCMem: simplifyProg :: Prog MCMem -> PassM (Prog MCMem)
+ Futhark.IR.SOACS: ErrorInt64 :: a -> ErrorMsgPart a
+ Futhark.IR.Syntax.Core: ErrorInt64 :: a -> ErrorMsgPart a
+ Futhark.Optimise.CSE: instance (Futhark.IR.Prop.ASTLore lore, Futhark.IR.Prop.Aliases.Aliased lore, Futhark.Optimise.CSE.CSEInOp (Futhark.IR.Decorations.Op lore), Futhark.Optimise.CSE.CSEInOp op) => Futhark.Optimise.CSE.CSEInOp (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.Optimise.DoubleBuffer: doubleBufferKernels :: Pass KernelsMem KernelsMem
+ Futhark.Optimise.DoubleBuffer: doubleBufferMC :: Pass MCMem MCMem
+ Futhark.Optimise.DoubleBuffer: instance Control.Monad.Reader.Class.MonadReader (Futhark.Optimise.DoubleBuffer.Env lore) (Futhark.Optimise.DoubleBuffer.DoubleBufferM lore)
+ Futhark.Optimise.DoubleBuffer: instance Futhark.IR.Prop.ASTLore lore => Futhark.IR.Prop.Scope.HasScope lore (Futhark.Optimise.DoubleBuffer.DoubleBufferM lore)
+ Futhark.Optimise.DoubleBuffer: instance Futhark.IR.Prop.ASTLore lore => Futhark.IR.Prop.Scope.LocalScope lore (Futhark.Optimise.DoubleBuffer.DoubleBufferM lore)
+ Futhark.Optimise.DoubleBuffer: instance Futhark.MonadFreshNames.MonadFreshNames (Futhark.Optimise.DoubleBuffer.DoubleBufferM lore)
+ Futhark.Optimise.DoubleBuffer: instance GHC.Base.Applicative (Futhark.Optimise.DoubleBuffer.DoubleBufferM lore)
+ Futhark.Optimise.DoubleBuffer: instance GHC.Base.Functor (Futhark.Optimise.DoubleBuffer.DoubleBufferM lore)
+ Futhark.Optimise.DoubleBuffer: instance GHC.Base.Monad (Futhark.Optimise.DoubleBuffer.DoubleBufferM lore)
+ Futhark.Optimise.InPlaceLowering: inPlaceLoweringMC :: Pass MC MC
+ Futhark.Optimise.Sink: sinkKernels :: Pass Kernels Kernels
+ Futhark.Optimise.Sink: sinkMC :: Pass MC MC
+ Futhark.Optimise.Unstream: unstreamKernels :: Pass Kernels Kernels
+ Futhark.Optimise.Unstream: unstreamMC :: Pass MC MC
+ Futhark.Pass.ExplicitAllocations.MC: explicitAllocations :: Pass MC MCMem
+ Futhark.Pass.ExplicitAllocations.MC: instance Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.MC.Op.MCOp lore op)
+ Futhark.Pass.ExplicitAllocations.SegOp: instance Futhark.Pass.ExplicitAllocations.SizeSubst (Futhark.IR.SegOp.SegOp lvl lore)
+ Futhark.Pass.ExtractKernels.ToKernels: injectSOACS :: (Monad m, SameScope from to, ExpDec from ~ ExpDec to, BodyDec from ~ BodyDec to, RetType from ~ RetType to, BranchType from ~ BranchType to, Op from ~ SOAC from) => (SOAC to -> Op to) -> Rephraser m from to
+ Futhark.Pass.ExtractMulticore: extractMulticore :: Pass SOACS MC
+ Futhark.Pass.ExtractMulticore: instance Futhark.IR.Prop.Scope.HasScope Futhark.IR.MC.MC Futhark.Pass.ExtractMulticore.ExtractM
+ Futhark.Pass.ExtractMulticore: instance Futhark.IR.Prop.Scope.LocalScope Futhark.IR.MC.MC Futhark.Pass.ExtractMulticore.ExtractM
+ Futhark.Pass.ExtractMulticore: instance Futhark.MonadFreshNames.MonadFreshNames Futhark.Pass.ExtractMulticore.ExtractM
+ Futhark.Pass.ExtractMulticore: instance Futhark.Util.Log.MonadLogger Futhark.Pass.ExtractMulticore.ExtractM
+ Futhark.Pass.ExtractMulticore: instance GHC.Base.Applicative Futhark.Pass.ExtractMulticore.ExtractM
+ Futhark.Pass.ExtractMulticore: instance GHC.Base.Functor Futhark.Pass.ExtractMulticore.ExtractM
+ Futhark.Pass.ExtractMulticore: instance GHC.Base.Monad Futhark.Pass.ExtractMulticore.ExtractM
+ Futhark.Pass.Simplify: simplifyMC :: Pass MC MC
+ Futhark.Pass.Simplify: simplifyMCMem :: Pass MCMem MCMem
+ Futhark.Passes: mcPipeline :: Pipeline SOACS MC
+ Futhark.Passes: multicorePipeline :: Pipeline SOACS MCMem
+ Futhark.Transform.Rename: renameSomething :: (Rename a, MonadFreshNames m) => a -> m a
+ Futhark.TypeCheck: alternative :: TypeM lore a -> TypeM lore b -> TypeM lore (a, b)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl GHC.Int.Int64)
- Futhark.Analysis.PrimExp.Convert: primExpSlice :: Slice SubExp -> Slice (TPrimExp Int32 VName)
+ Futhark.Analysis.PrimExp.Convert: primExpSlice :: Slice SubExp -> Slice (TPrimExp Int64 VName)
- Futhark.Analysis.PrimExp.Convert: subExpSlice :: MonadBinder m => Slice (TPrimExp Int32 VName) -> m (Slice SubExp)
+ Futhark.Analysis.PrimExp.Convert: subExpSlice :: MonadBinder m => Slice (TPrimExp Int64 VName) -> m (Slice SubExp)
- Futhark.Analysis.SymbolTable: IndexedArray :: Certificates -> VName -> [TPrimExp Int32 VName] -> Indexed
+ Futhark.Analysis.SymbolTable: IndexedArray :: Certificates -> VName -> [TPrimExp Int64 VName] -> Indexed
- Futhark.Analysis.SymbolTable: index' :: VName -> [TPrimExp Int32 VName] -> SymbolTable lore -> Maybe Indexed
+ Futhark.Analysis.SymbolTable: index' :: VName -> [TPrimExp Int64 VName] -> SymbolTable lore -> Maybe Indexed
- Futhark.Analysis.SymbolTable: indexOp :: (IndexOp op, ASTLore lore, IndexOp (Op lore)) => SymbolTable lore -> Int -> op -> [TPrimExp Int32 VName] -> Maybe Indexed
+ Futhark.Analysis.SymbolTable: indexOp :: (IndexOp op, ASTLore lore, IndexOp (Op lore)) => SymbolTable lore -> Int -> op -> [TPrimExp Int64 VName] -> Maybe Indexed
- Futhark.CodeGen.ImpCode: withElemType :: Count Elements (TExp Int32) -> PrimType -> Count Bytes (TExp Int64)
+ Futhark.CodeGen.ImpCode: withElemType :: Count Elements (TExp Int64) -> PrimType -> Count Bytes (TExp Int64)
- Futhark.CodeGen.ImpCode.Kernels: AtomicAdd :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicAdd :: IntType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicAnd :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicAnd :: IntType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicCmpXchg :: PrimType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicCmpXchg :: PrimType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicFAdd :: FloatType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicFAdd :: FloatType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicOr :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicOr :: IntType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicSMax :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicSMax :: IntType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicSMin :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicSMin :: IntType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicUMax :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicUMax :: IntType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicUMin :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicUMin :: IntType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicXchg :: PrimType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicXchg :: PrimType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: AtomicXor :: IntType -> VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp
+ Futhark.CodeGen.ImpCode.Kernels: AtomicXor :: IntType -> VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp
- Futhark.CodeGen.ImpCode.Kernels: withElemType :: Count Elements (TExp Int32) -> PrimType -> Count Bytes (TExp Int64)
+ Futhark.CodeGen.ImpCode.Kernels: withElemType :: Count Elements (TExp Int64) -> PrimType -> Count Bytes (TExp Int64)
- Futhark.CodeGen.ImpCode.OpenCL: withElemType :: Count Elements (TExp Int32) -> PrimType -> Count Bytes (TExp Int64)
+ Futhark.CodeGen.ImpCode.OpenCL: withElemType :: Count Elements (TExp Int64) -> PrimType -> Count Bytes (TExp Int64)
- Futhark.CodeGen.ImpCode.Sequential: withElemType :: Count Elements (TExp Int32) -> PrimType -> Count Bytes (TExp Int64)
+ Futhark.CodeGen.ImpCode.Sequential: withElemType :: Count Elements (TExp Int64) -> PrimType -> Count Bytes (TExp Int64)
- Futhark.CodeGen.ImpGen: MemLocation :: VName -> [DimSize] -> IxFun (TExp Int32) -> MemLocation
+ Futhark.CodeGen.ImpGen: MemLocation :: VName -> [DimSize] -> IxFun (TExp Int64) -> MemLocation
- Futhark.CodeGen.ImpGen: [memLocationIxFun] :: MemLocation -> IxFun (TExp Int32)
+ Futhark.CodeGen.ImpGen: [memLocationIxFun] :: MemLocation -> IxFun (TExp Int64)
- Futhark.CodeGen.ImpGen: copyDWIM :: VName -> [DimIndex (TExp Int32)] -> SubExp -> [DimIndex (TExp Int32)] -> ImpM lore r op ()
+ Futhark.CodeGen.ImpGen: copyDWIM :: VName -> [DimIndex (TExp Int64)] -> SubExp -> [DimIndex (TExp Int64)] -> ImpM lore r op ()
- Futhark.CodeGen.ImpGen: copyDWIMFix :: VName -> [TExp Int32] -> SubExp -> [TExp Int32] -> ImpM lore r op ()
+ Futhark.CodeGen.ImpGen: copyDWIMFix :: VName -> [TExp Int64] -> SubExp -> [TExp Int64] -> ImpM lore r op ()
- Futhark.CodeGen.ImpGen: fullyIndexArray :: VName -> [TExp Int32] -> ImpM lore r op (VName, Space, Count Elements (TExp Int64))
+ Futhark.CodeGen.ImpGen: fullyIndexArray :: VName -> [TExp Int64] -> ImpM lore r op (VName, Space, Count Elements (TExp Int64))
- Futhark.CodeGen.ImpGen: fullyIndexArray' :: MemLocation -> [TExp Int32] -> ImpM lore r op (VName, Space, Count Elements (TExp Int64))
+ Futhark.CodeGen.ImpGen: fullyIndexArray' :: MemLocation -> [TExp Int64] -> ImpM lore r op (VName, Space, Count Elements (TExp Int64))
- Futhark.CodeGen.ImpGen: isMapTransposeCopy :: PrimType -> MemLocation -> Slice (TExp Int32) -> MemLocation -> Slice (TExp Int32) -> Maybe (TExp Int32, TExp Int32, TExp Int32, TExp Int32, TExp Int32)
+ Futhark.CodeGen.ImpGen: isMapTransposeCopy :: PrimType -> MemLocation -> Slice (TExp Int64) -> MemLocation -> Slice (TExp Int64) -> Maybe (TExp Int64, TExp Int64, TExp Int64, TExp Int64, TExp Int64)
- Futhark.CodeGen.ImpGen: sLoopNest :: Shape -> ([TExp Int32] -> ImpM lore r op ()) -> ImpM lore r op ()
+ Futhark.CodeGen.ImpGen: sLoopNest :: Shape -> ([TExp Int64] -> ImpM lore r op ()) -> ImpM lore r op ()
- Futhark.CodeGen.ImpGen: sUpdate :: VName -> Slice (TExp Int32) -> SubExp -> ImpM lore r op ()
+ Futhark.CodeGen.ImpGen: sUpdate :: VName -> Slice (TExp Int64) -> SubExp -> ImpM lore r op ()
- Futhark.CodeGen.ImpGen: sWrite :: VName -> [TExp Int32] -> Exp -> ImpM lore r op ()
+ Futhark.CodeGen.ImpGen: sWrite :: VName -> [TExp Int64] -> Exp -> ImpM lore r op ()
- Futhark.CodeGen.ImpGen: type CopyCompiler lore r op = PrimType -> MemLocation -> Slice (TExp Int32) -> MemLocation -> Slice (TExp Int32) -> ImpM lore r op ()
+ Futhark.CodeGen.ImpGen: type CopyCompiler lore r op = PrimType -> MemLocation -> Slice (TExp Int64) -> MemLocation -> Slice (TExp Int64) -> ImpM lore r op ()
- Futhark.CodeGen.ImpGen.Kernels.Base: KernelConstants :: TExp Int32 -> TExp Int32 -> TExp Int32 -> VName -> VName -> VName -> TExp Int32 -> TExp Int32 -> TExp Int32 -> TExp Int32 -> TExp Bool -> Map [SubExp] [TExp Int32] -> KernelConstants
+ Futhark.CodeGen.ImpGen.Kernels.Base: KernelConstants :: TExp Int32 -> TExp Int32 -> TExp Int32 -> VName -> VName -> VName -> TExp Int64 -> TExp Int64 -> TExp Int32 -> TExp Int32 -> TExp Bool -> Map [SubExp] [TExp Int32] -> KernelConstants
- Futhark.CodeGen.ImpGen.Kernels.Base: Locking :: VName -> TExp Int32 -> TExp Int32 -> TExp Int32 -> ([TExp Int32] -> [TExp Int32]) -> Locking
+ Futhark.CodeGen.ImpGen.Kernels.Base: Locking :: VName -> TExp Int32 -> TExp Int32 -> TExp Int32 -> ([TExp Int64] -> [TExp Int64]) -> Locking
- Futhark.CodeGen.ImpGen.Kernels.Base: [kernelGroupSize] :: KernelConstants -> TExp Int32
+ Futhark.CodeGen.ImpGen.Kernels.Base: [kernelGroupSize] :: KernelConstants -> TExp Int64
- Futhark.CodeGen.ImpGen.Kernels.Base: [kernelNumGroups] :: KernelConstants -> TExp Int32
+ Futhark.CodeGen.ImpGen.Kernels.Base: [kernelNumGroups] :: KernelConstants -> TExp Int64
- Futhark.CodeGen.ImpGen.Kernels.Base: [lockingMapping] :: Locking -> [TExp Int32] -> [TExp Int32]
+ Futhark.CodeGen.ImpGen.Kernels.Base: [lockingMapping] :: Locking -> [TExp Int64] -> [TExp Int64]
- Futhark.CodeGen.ImpGen.Kernels.Base: computeThreadChunkSize :: SplitOrdering -> TExp Int32 -> Count Elements (TExp Int32) -> Count Elements (TExp Int32) -> TV Int32 -> ImpM lore r op ()
+ Futhark.CodeGen.ImpGen.Kernels.Base: computeThreadChunkSize :: SplitOrdering -> TExp Int64 -> Count Elements (TExp Int64) -> Count Elements (TExp Int64) -> TV Int64 -> ImpM lore r op ()
- Futhark.CodeGen.ImpGen.Kernels.Base: groupCoverSpace :: [TExp Int32] -> ([TExp Int32] -> InKernelGen ()) -> InKernelGen ()
+ Futhark.CodeGen.ImpGen.Kernels.Base: groupCoverSpace :: [TExp Int64] -> ([TExp Int64] -> InKernelGen ()) -> InKernelGen ()
- Futhark.CodeGen.ImpGen.Kernels.Base: groupLoop :: TExp Int32 -> (TExp Int32 -> InKernelGen ()) -> InKernelGen ()
+ Futhark.CodeGen.ImpGen.Kernels.Base: groupLoop :: TExp Int64 -> (TExp Int64 -> InKernelGen ()) -> InKernelGen ()
- Futhark.CodeGen.ImpGen.Kernels.Base: groupScan :: Maybe (TExp Int32 -> TExp Int32 -> TExp Bool) -> TExp Int32 -> TExp Int32 -> Lambda KernelsMem -> [VName] -> InKernelGen ()
+ Futhark.CodeGen.ImpGen.Kernels.Base: groupScan :: Maybe (TExp Int32 -> TExp Int32 -> TExp Bool) -> TExp Int64 -> TExp Int64 -> Lambda KernelsMem -> [VName] -> InKernelGen ()
- Futhark.CodeGen.ImpGen.Kernels.Base: sIota :: VName -> TExp Int32 -> Exp -> Exp -> IntType -> CallKernelGen ()
+ Futhark.CodeGen.ImpGen.Kernels.Base: sIota :: VName -> TExp Int64 -> Exp -> Exp -> IntType -> CallKernelGen ()
- Futhark.CodeGen.ImpGen.Kernels.Base: sKernelGroup :: String -> Count NumGroups (TExp Int32) -> Count GroupSize (TExp Int32) -> VName -> InKernelGen () -> CallKernelGen ()
+ Futhark.CodeGen.ImpGen.Kernels.Base: sKernelGroup :: String -> Count NumGroups (TExp Int64) -> Count GroupSize (TExp Int64) -> VName -> InKernelGen () -> CallKernelGen ()
- Futhark.CodeGen.ImpGen.Kernels.Base: sKernelThread :: String -> Count NumGroups (TExp Int32) -> Count GroupSize (TExp Int32) -> VName -> InKernelGen () -> CallKernelGen ()
+ Futhark.CodeGen.ImpGen.Kernels.Base: sKernelThread :: String -> Count NumGroups (TExp Int64) -> Count GroupSize (TExp Int64) -> VName -> InKernelGen () -> CallKernelGen ()
- Futhark.CodeGen.ImpGen.Kernels.Base: type AtomicBinOp = BinOp -> Maybe (VName -> VName -> Count Elements (TExp Int32) -> Exp -> AtomicOp)
+ Futhark.CodeGen.ImpGen.Kernels.Base: type AtomicBinOp = BinOp -> Maybe (VName -> VName -> Count Elements (TExp Int64) -> Exp -> AtomicOp)
- Futhark.CodeGen.ImpGen.Kernels.Base: type DoAtomicUpdate lore r = Space -> [VName] -> [TExp Int32] -> ImpM lore r KernelOp ()
+ Futhark.CodeGen.ImpGen.Kernels.Base: type DoAtomicUpdate lore r = Space -> [VName] -> [TExp Int64] -> ImpM lore r KernelOp ()
- Futhark.CodeGen.ImpGen.Kernels.SegRed: type DoSegBody = ([(SubExp, [TExp Int32])] -> InKernelGen ()) -> InKernelGen ()
+ Futhark.CodeGen.ImpGen.Kernels.SegRed: type DoSegBody = ([(SubExp, [TExp Int64])] -> InKernelGen ()) -> InKernelGen ()
- Futhark.IR.Kernels.Sizes: SizeBespoke :: Name -> Int32 -> SizeClass
+ Futhark.IR.Kernels.Sizes: SizeBespoke :: Name -> Int64 -> SizeClass
- Futhark.IR.Kernels.Sizes: SizeThreshold :: KernelPath -> Maybe Int32 -> SizeClass
+ Futhark.IR.Kernels.Sizes: SizeThreshold :: KernelPath -> Maybe Int64 -> SizeClass
- Futhark.IR.Kernels.Sizes: sizeDefault :: SizeClass -> Maybe Int32
+ Futhark.IR.Kernels.Sizes: sizeDefault :: SizeClass -> Maybe Int64
- Futhark.IR.Mem: lookupArraySummary :: (Mem lore, HasScope lore m, Monad m) => VName -> m (VName, IxFun (TPrimExp Int32 VName))
+ Futhark.IR.Mem: lookupArraySummary :: (Mem lore, HasScope lore m, Monad m) => VName -> m (VName, IxFun (TPrimExp Int64 VName))
- Futhark.IR.Mem: type ExtIxFun = IxFun (TPrimExp Int32 (Ext VName))
+ Futhark.IR.Mem: type ExtIxFun = IxFun (TPrimExp Int64 (Ext VName))
- Futhark.IR.Mem: type IxFun = IxFun (TPrimExp Int32 VName)
+ Futhark.IR.Mem: type IxFun = IxFun (TPrimExp Int64 VName)
- Language.Futhark.Syntax: type ValueType = TypeBase Int32 ()
+ Language.Futhark.Syntax: type ValueType = TypeBase Int64 ()

Files

docs/conf.py view
@@ -262,6 +262,7 @@ man_pages = [     ('man/futhark', 'futhark', 'a parallel functional array language', [], 1),     ('man/futhark-c', 'futhark-c', 'compile Futhark to sequential C', [], 1),+    ('man/futhark-multicore', 'futhark-multicore', 'compile Futhark to multithreaded C', [], 1),     ('man/futhark-opencl', 'futhark-opencl', 'compile Futhark to OpenCL', [], 1),     ('man/futhark-cuda', 'futhark-cuda', 'compile Futhark to CUDA', [], 1),     ('man/futhark-python', 'futhark-python', 'compile Futhark to sequential Python', [], 1),
docs/index.rst view
@@ -45,6 +45,7 @@    man/futhark-autotune.rst    man/futhark-bench.rst    man/futhark-c.rst+   man/futhark-multicore.rst    man/futhark-cuda.rst    man/futhark-dataset.rst    man/futhark-doc.rst
+ docs/man/futhark-multicore.rst view
@@ -0,0 +1,109 @@+.. role:: ref(emphasis)++.. _futhark-multicore(1):++=================+futhark-multicore+=================++SYNOPSIS+========++futhark multicore [options...] <program.fut>++DESCRIPTION+===========++``futhark multicore`` translates a Futhark program to multithreaded C+code, and either compiles that C code with gcc(1) to an executable+binary program, or produces a ``.h`` and ``.c`` file that can be+linked with other code..  The standard Futhark optimisation pipeline+is used, and GCC is invoked with ``-O3 -lm -std=c11 -pthread``.++The resulting program will read the arguments to the entry point+(``main`` by default) from standard input and print its return value+on standard output.  The arguments are read and printed in Futhark+syntax.++OPTIONS+=======++-h+  Print help text to standard output and exit.++--library+  Generate a library instead of an executable.  Appends ``.c``/``.h``+  to the name indicated by the ``-o`` option to determine output+  file names.++-o outfile+  Where to write the result.  If the source program is named+  ``foo.fut``, this defaults to ``foo``.++--safe+  Ignore ``unsafe`` in program and perform safety checks unconditionally.++-v verbose+  Enable debugging output.  If compilation fails due to a compiler+  error, the result of the last successful compiler step will be+  printed to standard error.++-V+  Print version information on standard output and exit.++-W+  Do not print any warnings.++--Werror+  Treat warnings as errors.++EXECUTABLE OPTIONS+==================++The following options are accepted by executables generated by+``futhark multicore``.++-h, --help++  Print help text to standard output and exit.++-b, --binary-output++  Print the program result in the binary output format.  The default+  is human-readable text, which is very slow.++-D, --debugging++  Perform possibly expensive internal correctness checks and verbose+  logging.  Implies ``-L``.++-e, --entry-point=FUN++  The entry point to run.  Defaults to ``main``.++-L, --log++  Print various low-overhead logging information to stderr while+  running.++-r, --runs=NUM++  Perform NUM runs of the program.  With ``-t``, the runtime for each+  individual run will be printed.  Additionally, a single leading+  warmup run will be performed (not counted).  Only the final run will+  have its result written to stdout.++-t, --write-runtime-to=FILE++  Print the time taken to execute the program to the indicated file, an+  integral number of microseconds.++BUGS+====++Currently works only on Unix-like systems.++SEE ALSO+========++:ref:`futhark-c(1)`, :ref:`futhark-test(1)`
docs/usage.rst view
@@ -107,8 +107,8 @@     (:ref:`binary-data-format`).  For large outputs, this is     significantly faster and takes up less space. -Parallel Options-~~~~~~~~~~~~~~~~+GPU Options+~~~~~~~~~~~  The following options are supported by executables generated with the GPU backends (``opencl``, ``pyopencl``, and ``cuda``).
futhark.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4  name:           futhark-version:        0.17.3+version:        0.18.1 synopsis:       An optimising compiler for a functional, array-oriented language.  description:    Futhark is a small programming language designed to be compiled to@@ -79,6 +79,7 @@       Futhark.CLI.Dev       Futhark.CLI.Doc       Futhark.CLI.Misc+      Futhark.CLI.Multicore       Futhark.CLI.OpenCL       Futhark.CLI.Pkg       Futhark.CLI.PyOpenCL@@ -97,6 +98,7 @@       Futhark.CodeGen.Backends.GenericPython.AST       Futhark.CodeGen.Backends.GenericPython.Definitions       Futhark.CodeGen.Backends.GenericPython.Options+      Futhark.CodeGen.Backends.MulticoreC       Futhark.CodeGen.Backends.PyOpenCL       Futhark.CodeGen.Backends.PyOpenCL.Boilerplate       Futhark.CodeGen.Backends.SequentialC@@ -104,6 +106,7 @@       Futhark.CodeGen.Backends.SimpleRep       Futhark.CodeGen.ImpCode       Futhark.CodeGen.ImpCode.Kernels+      Futhark.CodeGen.ImpCode.Multicore       Futhark.CodeGen.ImpCode.OpenCL       Futhark.CodeGen.ImpCode.Sequential       Futhark.CodeGen.ImpGen@@ -116,6 +119,12 @@       Futhark.CodeGen.ImpGen.Kernels.SegScan       Futhark.CodeGen.ImpGen.Kernels.ToOpenCL       Futhark.CodeGen.ImpGen.Kernels.Transpose+      Futhark.CodeGen.ImpGen.Multicore+      Futhark.CodeGen.ImpGen.Multicore.Base+      Futhark.CodeGen.ImpGen.Multicore.SegHist+      Futhark.CodeGen.ImpGen.Multicore.SegMap+      Futhark.CodeGen.ImpGen.Multicore.SegRed+      Futhark.CodeGen.ImpGen.Multicore.SegScan       Futhark.CodeGen.ImpGen.OpenCL       Futhark.CodeGen.ImpGen.Sequential       Futhark.CodeGen.ImpGen.Transpose@@ -136,6 +145,9 @@       Futhark.IR.Kernels.Simplify       Futhark.IR.Kernels.Sizes       Futhark.IR.KernelsMem+      Futhark.IR.MC+      Futhark.IR.MC.Op+      Futhark.IR.MCMem       Futhark.IR.Mem       Futhark.IR.Mem.IxFun       Futhark.IR.Mem.Simplify@@ -195,6 +207,7 @@       Futhark.Pass.ExplicitAllocations.Kernels       Futhark.Pass.ExplicitAllocations.SegOp       Futhark.Pass.ExplicitAllocations.Seq+      Futhark.Pass.ExplicitAllocations.MC       Futhark.Pass.ExtractKernels       Futhark.Pass.ExtractKernels.BlockedKernel       Futhark.Pass.ExtractKernels.DistributeNests@@ -204,6 +217,7 @@       Futhark.Pass.ExtractKernels.Intragroup       Futhark.Pass.ExtractKernels.StreamKernel       Futhark.Pass.ExtractKernels.ToKernels+      Futhark.Pass.ExtractMulticore       Futhark.Pass.FirstOrderTransform       Futhark.Pass.KernelBabysitting       Futhark.Pass.Simplify
prelude/array.fut view
@@ -24,13 +24,13 @@ let init [n] 't (x: [n]t) = x[0:n-1]  -- | Take some number of elements from the head of the array.-let take [n] 't (i: i32) (x: [n]t): [i]t = x[0:i]+let take [n] 't (i: i64) (x: [n]t): [i]t = x[0:i]  -- | Remove some number of elements from the head of the array.-let drop [n] 't (i: i32) (x: [n]t) = x[i:]+let drop [n] 't (i: i64) (x: [n]t) = x[i:]  -- | Split an array at a given position.-let split [n] 't (i: i32) (xs: [n]t): ([i]t, []t) =+let split [n] 't (i: i64) (xs: [n]t): ([i]t, []t) =   (xs[:i] :> [i]t, xs[i:])  -- | Return the elements of the array in reverse order.@@ -46,28 +46,28 @@ -- | Concatenation where the result has a predetermined size.  If the -- provided size is wrong, the function will fail with a run-time -- error.-let concat_to [n] [m] 't (k: i32) (xs: [n]t) (ys: [m]t): *[k]t = xs ++ ys :> [k]t+let concat_to [n] [m] 't (k: i64) (xs: [n]t) (ys: [m]t): *[k]t = xs ++ ys :> [k]t  -- | Rotate an array some number of elements to the left.  A negative -- rotation amount is also supported. -- -- For example, if `b==rotate r a`, then `b[x+r] = a[x]`.-let rotate [n] 't (r: i32) (xs: [n]t): [n]t = intrinsics.rotate (r, xs) :> [n]t+let rotate [n] 't (r: i64) (xs: [n]t): [n]t = intrinsics.rotate (r, xs) :> [n]t  -- | Construct an array of consecutive integers of the given length, -- starting at 0.-let iota (n: i32): *[n]i32 =+let iota (n: i64): *[n]i64 =   0..1..<n  -- | Construct an array comprising valid indexes into some other -- array, starting at 0.-let indices [n] 't (_: [n]t) : *[n]i32 =+let indices [n] 't (_: [n]t) : *[n]i64 =   iota n  -- | Construct an array of the given length containing the given -- value.-let replicate 't (n: i32) (x: t): *[n]t =-  map (\_ -> x) (iota n)+let replicate 't (n: i64) (x: t): *[n]t =+  map (const x) (iota n)  -- | Copy a value.  The result will not alias anything. let copy 't (a: t): *t =@@ -79,7 +79,7 @@  -- | Like `flatten`@term, but where the final size is known.  Fails at -- runtime if the provided size is wrong.-let flatten_to [n][m] 't (l: i32) (xs: [n][m]t): [l]t =+let flatten_to [n][m] 't (l: i64) (xs: [n][m]t): [l]t =   flatten xs :> [l]t  -- | Combines the outer three dimensions of an array.@@ -91,15 +91,15 @@   flatten (flatten_3d xs)  -- | Splits the outer dimension of an array in two.-let unflatten [p] 't (n: i32) (m: i32) (xs: [p]t): [n][m]t =+let unflatten [p] 't (n: i64) (m: i64) (xs: [p]t): [n][m]t =   intrinsics.unflatten (n, m, xs) :> [n][m]t  -- | Splits the outer dimension of an array in three.-let unflatten_3d [p] 't (n: i32) (m: i32) (l: i32) (xs: [p]t): [n][m][l]t =+let unflatten_3d [p] 't (n: i64) (m: i64) (l: i64) (xs: [p]t): [n][m][l]t =   unflatten n m (unflatten (n*m) l xs)  -- | Splits the outer dimension of an array in four.-let unflatten_4d [p] 't (n: i32) (m: i32) (l: i32) (k: i32) (xs: [p]t): [n][m][l][k]t =+let unflatten_4d [p] 't (n: i64) (m: i64) (l: i64) (k: i64) (xs: [p]t): [n][m][l][k]t =   unflatten n m (unflatten_3d (n*m) l k xs)  let transpose [n] [m] 't (a: [n][m]t): [m][n]t =@@ -122,13 +122,13 @@   foldl (flip f) acc (reverse bs)  -- | Create a value for each point in a one-dimensional index space.-let tabulate 'a (n: i32) (f: i32 -> a): *[n]a =+let tabulate 'a (n: i64) (f: i64 -> a): *[n]a =   map1 f (iota n)  -- | Create a value for each point in a two-dimensional index space.-let tabulate_2d 'a (n: i32) (m: i32) (f: i32 -> i32 -> a): *[n][m]a =+let tabulate_2d 'a (n: i64) (m: i64) (f: i64 -> i64 -> a): *[n][m]a =   map1 (f >-> tabulate m) (iota n)  -- | Create a value for each point in a three-dimensional index space.-let tabulate_3d 'a (n: i32) (m: i32) (o: i32) (f: i32 -> i32 -> i32 -> a): *[n][m][o]a =+let tabulate_3d 'a (n: i64) (m: i64) (o: i64) (f: i64 -> i64 -> i64 -> a): *[n][m][o]a =   map1 (f >-> tabulate_2d m o) (iota n)
prelude/math.fut view
@@ -2,8 +2,6 @@  import "soacs" -local let const 'a 'b (x: a) (_: b): a = x- -- | Describes types of values that can be created from the primitive -- numeric types (and bool). module type from_prim = {@@ -122,8 +120,7 @@ module type real = {   include numeric -  val from_fraction: i32 -> i32 -> t-  val to_i32: t -> i32+  val from_fraction: i64 -> i64 -> t   val to_i64: t -> i64   val to_f64: t -> f64 @@ -852,8 +849,7 @@    let bool (x: bool) = if x then 1f64 else 0f64 -  let from_fraction (x: i32) (y: i32) = i32 x / i32 y-  let to_i32 (x: f64) = intrinsics.fptosi_f64_i32 x+  let from_fraction (x: i64) (y: i64) = i64 x / i64 y   let to_i64 (x: f64) = intrinsics.fptosi_f64_i64 x   let to_f64 (x: f64) = x @@ -960,8 +956,7 @@    let bool (x: bool) = if x then 1f32 else 0f32 -  let from_fraction (x: i32) (y: i32) = i32 x / i32 y-  let to_i32 (x: f32) = intrinsics.fptosi_f32_i32 x+  let from_fraction (x: i64) (y: i64) = i64 x / i64 y   let to_i64 (x: f32) = intrinsics.fptosi_f32_i64 x   let to_f64 (x: f32) = intrinsics.fpconv_f32_f64 x 
prelude/soacs.fut view
@@ -118,7 +118,7 @@ -- -- In practice, the *O(n)* behaviour only occurs if *m* is also very -- large.-let reduce_by_index 'a [m] [n] (dest : *[m]a) (f : a -> a -> a) (ne : a) (is : [n]i32) (as : [n]a) : *[m]a =+let reduce_by_index 'a [m] [n] (dest : *[m]a) (f : a -> a -> a) (ne : a) (is : [n]i64) (as : [n]a) : *[m]a =   intrinsics.hist (1, dest, f, ne, is, as) :> *[m]a  -- | Inclusive prefix scan.  Has the same caveats with respect to@@ -163,7 +163,7 @@  -- | `reduce_stream op f as` splits `as` into chunks, applies `f` to each -- of these in parallel, and uses `op` (which must be associative) to--- combine the per-chunk results into a final result.  The `i32`+-- combine the per-chunk results into a final result.  The `i64` -- passed to `f` is the size of the chunk.  This SOAC is useful when -- `f` can be given a particularly work-efficient sequential -- implementation.  Operationally, we can imagine that `as` is divided@@ -176,7 +176,7 @@ -- **Work:** *O(n)* -- -- **Span:** *O(log(n))*-let reduce_stream [n] 'a 'b (op: b -> b -> b) (f: (k: i32) -> [k]a -> b) (as: [n]a): b =+let reduce_stream [n] 'a 'b (op: b -> b -> b) (f: (k: i64) -> [k]a -> b) (as: [n]a): b =   intrinsics.reduce_stream (op, f, as)  -- | As `reduce_stream`@term, but the chunks do not necessarily@@ -186,7 +186,7 @@ -- **Work:** *O(n)* -- -- **Span:** *O(log(n))*-let reduce_stream_per [n] 'a 'b (op: b -> b -> b) (f: (k: i32) -> [k]a -> b) (as: [n]a): b =+let reduce_stream_per [n] 'a 'b (op: b -> b -> b) (f: (k: i64) -> [k]a -> b) (as: [n]a): b =   intrinsics.reduce_stream_per (op, f, as)  -- | Similar to `reduce_stream`@term, except that each chunk must produce@@ -196,7 +196,7 @@ -- **Work:** *O(n)* -- -- **Span:** *O(1)*-let map_stream [n] 'a 'b (f: (k: i32) -> [k]a -> [k]b) (as: [n]a): *[n]b =+let map_stream [n] 'a 'b (f: (k: i64) -> [k]a -> [k]b) (as: [n]a): *[n]b =   intrinsics.map_stream (f, as) :> *[n]b  -- | Similar to `map_stream`@term, but the chunks do not necessarily@@ -206,7 +206,7 @@ -- **Work:** *O(n)* -- -- **Span:** *O(1)*-let map_stream_per [n] 'a 'b (f: (k: i32) -> [k]a -> [k]b) (as: [n]a): *[n]b =+let map_stream_per [n] 'a 'b (f: (k: i64) -> [k]a -> [k]b) (as: [n]a): *[n]b =   intrinsics.map_stream_per (f, as) :> *[n]b  -- | Return `true` if the given function returns `true` for all@@ -252,5 +252,5 @@ -- **Work:** *O(n)* -- -- **Span:** *O(1)*-let scatter 't [m] [n] (dest: *[m]t) (is: [n]i32) (vs: [n]t): *[m]t =+let scatter 't [m] [n] (dest: *[m]t) (is: [n]i64) (vs: [n]t): *[m]t =   intrinsics.scatter (dest, is, vs) :> *[m]t
+ rts/c/chaselev.h view
@@ -0,0 +1,180 @@+// Start of chaselev.h++#ifndef _CHASELEV_H_+#define _CHASELEV_H_++/* Implementation of Chase-lev's concurrent lock-free deque+   from ``Dynamic Circular Work-Stealing Deque`` (2005)+   This implementation was ported from+   https://github.com/deepsea-inria/heartbeat++   !!!+   This implementation leaks memory,+   if the circular array is grown+   as we don't maintain a list of the old buffers.+   However, we can't safely free it either as a stealing thread might+   be reading from it.+   !!!+ */++#if defined(MCCHASELEV)+#include <stdlib.h>+#include <assert.h>+#include <string.h>+++static struct subtask* const STEAL_RES_EMPTY = (struct subtask*) 0;+static struct subtask* const STEAL_RES_ABORT = (struct subtask*) 1;++static const int strong = 0;+static const int backoff_nb_cycles = 1l << 10;+++static inline struct subtask* cb_get(struct subtask **buf, int64_t capacity, int64_t i)  {+  return (struct subtask*)__atomic_load_n(&buf[i % capacity], __ATOMIC_RELAXED);+}++static inline void cb_put (struct subtask **buf, int64_t capacity, int64_t i, struct subtask* x) {+  __atomic_store_n(&buf[i % capacity], x, __ATOMIC_RELAXED);+}++struct deque_buffer* grow(struct subtask **old_array,+                          int64_t old_capacity,+                          int64_t new_capacity,+                          int64_t b,+                          int64_t t)+{+  struct deque_buffer* new_deque_buffer = malloc(sizeof(struct deque_buffer));+  new_deque_buffer->size = new_capacity;+  new_deque_buffer->array = calloc(new_capacity,  sizeof(struct subtask*));++  for (int64_t i = t; i < b; i++) {+    cb_put(new_deque_buffer->array, new_capacity, i, cb_get(old_array, old_capacity, i));+  }+  return new_deque_buffer;+}++static inline int deque_init(struct deque *q, int64_t capacity) {+  assert(q != NULL);+  memset(q, 0, sizeof(struct deque));++  q->buffer = malloc(sizeof(struct deque_buffer));+  q->buffer->array = calloc(capacity, sizeof(struct subtask*));+  q->buffer->size = capacity;++  q->dead = 0;++  if (q->buffer->array == NULL) {+    return -1;+  }++  if (q->buffer == NULL) {+    return -1;+  }+  return 0;+}++static inline void deque_destroy(struct deque* q)+{+  q->dead = 1;+  free(q->buffer->array);+  free(q->buffer);+}++static inline int cas_top (struct deque *q, int64_t old_val, int64_t new_val) {+  int64_t ov = old_val;+  if(__atomic_compare_exchange_n(&q->top, &ov, new_val, strong,+                                 __ATOMIC_SEQ_CST, __ATOMIC_RELAXED)) {+    return 1;+  }+  spin_for(backoff_nb_cycles);+  return 0;+}+++void push_back(struct deque *q, struct subtask*subtask)+{+  assert(subtask != NULL);+  assert(q != NULL);++  int64_t b = __atomic_load_n(&q->bottom, __ATOMIC_RELAXED); // load atomically+  int64_t t = __atomic_load_n(&q->top, __ATOMIC_ACQUIRE);    // load atomically+  struct deque_buffer *buffer = __atomic_load_n(&q->buffer, __ATOMIC_RELAXED);+  if (b-t >= (buffer->size - 1)) {+    // grow_queue+    struct subtask **old_array = buffer->array;+    int64_t old_capacity = __atomic_load_n(&buffer->size, __ATOMIC_RELAXED);+    int64_t new_capacity = old_capacity * 2;+    struct deque_buffer *new_buffer = grow(old_array, old_capacity, new_capacity, b, t);+    __atomic_store_n(&q->buffer, new_buffer, __ATOMIC_RELEASE);+    buffer = __atomic_load_n(&q->buffer, __ATOMIC_RELAXED);+    memset(old_array, 0, sizeof(struct subtask*) * old_capacity);+    // free(old_array);  Not safe!!+  }++  cb_put(buffer->array, buffer->size, b, subtask);+  __atomic_thread_fence(__ATOMIC_RELEASE);+  __atomic_store_n(&q->bottom, b+1, __ATOMIC_RELAXED);+  return;+}+++struct subtask * pop_back(struct deque *q)+{+  int64_t b = __atomic_load_n(&q->bottom, __ATOMIC_RELAXED) - 1; // load atomically+  struct deque_buffer *buffer = __atomic_load_n(&q->buffer, __ATOMIC_RELAXED);+  __atomic_store_n(&q->bottom, b, __ATOMIC_RELAXED);+	__atomic_thread_fence(__ATOMIC_SEQ_CST);+  int64_t t = __atomic_load_n(&q->top, __ATOMIC_RELAXED);+  if (b < t) {+    __atomic_store_n(&q->bottom, t, __ATOMIC_RELAXED);+    return NULL;+  }+  struct subtask* item = cb_get(buffer->array, buffer->size, b);+  if (b > t) {+    return item;+  }++  // else there's only one item left+  // Did we win the race?+  if (!cas_top(q, t, t + 1)) {+    item = NULL;+  }+  __atomic_store_n(&q->bottom, t+1, __ATOMIC_RELAXED);+  return item;+}++struct subtask* steal(struct deque *q)+{+  assert(q != NULL);++  int64_t t = __atomic_load_n(&q->top, __ATOMIC_ACQUIRE);    // load atomically+  __atomic_thread_fence(__ATOMIC_SEQ_CST);+  int64_t b = __atomic_load_n(&q->bottom, __ATOMIC_ACQUIRE); // load atomically+  if (t >= b) {+    return STEAL_RES_EMPTY;+  }++  struct deque_buffer *buffer = __atomic_load_n(&q->buffer, __ATOMIC_CONSUME);+  struct subtask* item = cb_get(buffer->array, buffer->size, t);+  if (!cas_top(q, t, t + 1)) {+    return STEAL_RES_ABORT;+  }++  return item;+}+++static inline size_t nb_subtasks(struct deque *q)+{+  return (size_t)__atomic_load_n(&q->bottom, __ATOMIC_RELAXED) - __atomic_load_n(&q->top, __ATOMIC_RELAXED);+}++static inline int empty(struct deque *q)+{+  return nb_subtasks(q) < 1;+}++#endif+#endif+// end of chaselev.h
+ rts/c/multicore_defs.h view
@@ -0,0 +1,108 @@+// start of multicore_defs.h++#ifndef MULTICORE_DEFS+#define MULTICORE_DEFS++#include <signal.h>++/* #define MCPROFILE */++// Which queue implementation to use+#define MCJOBQUEUE+// NOTE! MCCHASELEV has been removed from multicore branch+// Switch to multicore_deque branch to use chase-lev deque+/* #define MCCHASELEV */+++#if defined(_WIN32)+#include <windows.h>+#elif defined(__APPLE__)+#include <sys/sysctl.h>+// For getting cpu usage of threads+#include <mach/mach.h>+#include <sys/resource.h>+#elif defined(__linux__)+#include <sys/sysinfo.h>+#include <sys/resource.h>+#include <signal.h>+#endif+++// Forward declarations+// Scheduler definitions+struct scheduler;+struct scheduler_info;+struct scheduler_subtask;+struct scheduler_task;+++struct subtask_queue {+  int capacity;             // Size of the buffer.+  int first;                // Index of the start of the ring buffer.+  int num_used;             // Number of used elements in the buffer.+  struct subtask **buffer;++  pthread_mutex_t mutex;    // Mutex used for synchronisation.+  pthread_cond_t cond;      // Condition variable used for synchronisation.+  int dead;++#if defined(MCPROFILE)+  /* Profiling fields */+  uint64_t time_enqueue;+  uint64_t time_dequeue;+  uint64_t n_dequeues;+  uint64_t n_enqueues;+#endif+};++++// Function definitions+typedef int (*segop_fn)(void* args, int64_t iterations, int tid, struct scheduler_info info);+typedef int (*parloop_fn)(void* args, int64_t start, int64_t end, int subtask_id, int tid);+++/* A subtask that can be executed by a worker */+struct subtask {+  /* The parloop function */+  parloop_fn fn;+  /* Execution parameters */+  void* args;+  int64_t start, end;+  int id;++  /* Dynamic scheduling parameters */+  int chunkable;+  int64_t chunk_size;++  /* Shared variables across subtasks */+  volatile int *counter; // Counter for ongoing subtasks+  // Shared task timers and iterators+  int64_t *task_time;+  int64_t *task_iter;++  /* For debugging */+  const char *name;+};+++struct worker {+  pthread_t thread;+  struct scheduler *scheduler;  /* Reference to the scheduler struct the worker belongs to*/+  struct subtask_queue q;+  int dead;+  int tid;                      /* Just a thread id */++  /* "thread local" time fields used for online algorithm */+  uint64_t timer;+  uint64_t total;+  int nested; /* How nested the current computation is */++  // Profiling fields+  int output_usage;            /* Whether to dump thread usage */+  uint64_t time_spent_working; /* Time spent in parloop functions */+};++#endif++// end of multicore_defs.h
+ rts/c/multicore_util.h view
@@ -0,0 +1,103 @@+// start of multicore_util.h++/* Multicore Utility functions */++#ifndef _MULTICORE_UTIL_H_+#define _MULTICORE_UTIL_H_++/* A wrapper for getting rusage on Linux and MacOS */+/* TODO maybe figure out this for windows */+static inline int getrusage_thread(struct rusage *rusage)+{+  int err = -1;+#if  defined(__APPLE__)+    thread_basic_info_data_t info = { 0 };+    mach_msg_type_number_t info_count = THREAD_BASIC_INFO_COUNT;+    kern_return_t kern_err;++    kern_err = thread_info(mach_thread_self(),+                           THREAD_BASIC_INFO,+                           (thread_info_t)&info,+                           &info_count);+    if (kern_err == KERN_SUCCESS) {+        memset(rusage, 0, sizeof(struct rusage));+        rusage->ru_utime.tv_sec = info.user_time.seconds;+        rusage->ru_utime.tv_usec = info.user_time.microseconds;+        rusage->ru_stime.tv_sec = info.system_time.seconds;+        rusage->ru_stime.tv_usec = info.system_time.microseconds;+        err = 0;+    } else {+        errno = EINVAL;+    }+#elif defined(__linux__)+    err = getrusage(RUSAGE_THREAD, rusage);+#endif+    return err;+}++/* returns the number of logical cores */+static int num_processors()+{+#if  defined(_WIN32)+/* https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info */+    SYSTEM_INFO sysinfo;+    GetSystemInfo(&sysinfo);+    int ncores = sysinfo.dwNumberOfProcessors;+    fprintf(stderr, "Found %d cores on your Windows machine\n Is that correct?\n", ncores);+    return ncores;+#elif defined(__APPLE__)+    int ncores;+    size_t ncores_size = sizeof(ncores);+    CHECK_ERRNO(sysctlbyname("hw.logicalcpu", &ncores, &ncores_size, NULL, 0),+                "sysctlbyname (hw.logicalcpu)");+    return ncores;+#elif defined(__linux__)+  return get_nprocs();+#else+  fprintf(stderr, "operating system not recognised\n");+  return -1;+#endif+}++static inline void output_thread_usage(struct worker *worker)+{+  struct rusage usage;+  CHECK_ERRNO(getrusage_thread(&usage), "getrusage_thread");+  struct timeval user_cpu_time = usage.ru_utime;+  struct timeval sys_cpu_time = usage.ru_stime;+  fprintf(stderr, "tid: %2d - work time %10llu us - user time: %10llu us - sys: %10llu us\n",+          worker->tid,+          (long long unsigned)worker->time_spent_working / 1000,+          (long long unsigned)(user_cpu_time.tv_sec * 1000000 + user_cpu_time.tv_usec),+          (long long unsigned)(sys_cpu_time.tv_sec * 1000000 + sys_cpu_time.tv_usec));+}+++static unsigned int g_seed;++// Used to seed the generator.+static inline void fast_srand(unsigned int seed) {+    g_seed = seed;+}++// Compute a pseudorandom integer.+// Output value in range [0, 32767]+static inline unsigned int fast_rand(void) {+    g_seed = (214013*g_seed+2531011);+    return (g_seed>>16)&0x7FFF;+}+++int64_t min_int64(int64_t x, int64_t y)+{+  return x < y ? x : y;+}++int64_t max_int64(int64_t x, int64_t y)+{+  return x > y ? x : y;+}+++#endif+// end of multicore_util.h
+ rts/c/scheduler.h view
@@ -0,0 +1,278 @@+// start of scheduler.h+#ifndef _SCHEDULER_H_+#define _SCHEDULER_H_+++static int dummy_counter = 0;+static int64_t dummy_timer = 0;+static int64_t dummy_iter = 0;++static int dummy_fn(void *args, int64_t start, int64_t end, int subtask_id, int tid) {+  (void)args;+  (void)start;+  (void)end;+  (void)subtask_id;+  (void)tid;+  return 0;+}++// Wake up threads, who are blocking by pushing a dummy task+// onto their queue+static inline void wake_up_threads(struct scheduler *scheduler, int start_tid, int end_tid) {++#if defined(MCDEBUG)+  assert(start_tid >= 1);+  assert(end_tid <= scheduler->num_threads);+#endif+  for (int i = start_tid; i < end_tid; i++) {+    struct subtask *subtask = create_subtask(dummy_fn, NULL, "dummy_fn",+                                            &dummy_counter,+                                            &dummy_timer, &dummy_iter,+                                            0, 0,+                                            0, 0,+                                            0);+    CHECK_ERR(subtask_queue_enqueue(&scheduler->workers[i], subtask), "subtask_queue_enqueue");+  }+}++static inline int is_finished(struct worker *worker) {+  return worker->dead && subtask_queue_is_empty(&worker->q);+}++// Try to steal from a random queue+static inline int steal_from_random_worker(struct worker* worker)+{+  int my_id = worker->tid;+  struct scheduler* scheduler = worker->scheduler;+  int k = random_other_worker(scheduler, my_id);+  struct worker *worker_k = &scheduler->workers[k];+  struct subtask* subtask =  NULL;+  int retval = subtask_queue_steal(worker_k, &subtask);+  if (retval == 0) {+    subtask_queue_enqueue(worker, subtask);+    return 1;+  }+  return 0;+}+++static inline void *scheduler_worker(void* args)+{+  struct worker *worker = (struct worker*) args;+  worker_local = worker;+  struct subtask * subtask = NULL;+  while(!is_finished(worker)) {+    if (!subtask_queue_is_empty(&worker->q)) {+      int retval = subtask_queue_dequeue(worker, &subtask, 0);+      if (retval == 0) {+        assert(subtask != NULL);+        CHECK_ERR(run_subtask(worker, subtask), "run_subtask");+      } // else someone stole our work++    } else if (active_work) { /* steal */+      while (!is_finished(worker) && active_work) {+        if (steal_from_random_worker(worker)) {+          break;+        }+      }+    } else { /* go back to sleep and wait for work */+      int retval = subtask_queue_dequeue(worker, &subtask, 1);+      if (retval == 0) {+        assert(subtask != NULL);+        CHECK_ERR(run_subtask(worker, subtask), "run_subtask");+      }+    }+  }++  assert(subtask_queue_is_empty(&worker->q));+  __atomic_fetch_sub(&num_workers, 1, __ATOMIC_RELAXED);+#if defined(MCPROFILE)+  if (worker->output_usage)+    output_thread_usage(worker);+#endif+  return NULL;+}+++static inline int scheduler_execute_parloop(struct scheduler *scheduler,+                                            struct scheduler_parloop *task,+                                            int64_t *timer)+{++  struct worker * worker = worker_local;++  struct scheduler_info info = task->info;+  int64_t iter_pr_subtask = info.iter_pr_subtask;+  int64_t remainder = info.remainder;+  int nsubtasks = info.nsubtasks;+  volatile int join_counter = nsubtasks;++  // Shared timer used to sum up all+  // sequential work from each subtask+  int64_t task_timer = 0;+  int64_t task_iter = 0;++  enum scheduling sched = info.sched;+  /* If each subtasks should be processed in chunks */+  int chunkable = sched == STATIC ? 0 : 1;+  int64_t chunk_size = 1; // The initial chunk size when no info is avaliable+++  if (info.wake_up_threads || sched == DYNAMIC)+    __atomic_add_fetch(&active_work, nsubtasks, __ATOMIC_RELAXED);++  int64_t start = 0;+  int64_t end = iter_pr_subtask + (int64_t)(remainder != 0);+  for (int subtask_id = 0; subtask_id < nsubtasks; subtask_id++) {+    struct subtask *subtask = create_subtask(task->fn, task->args, task->name,+                                              &join_counter,+                                              &task_timer, &task_iter,+                                              start, end,+                                              chunkable, chunk_size,+                                              subtask_id);+    assert(subtask != NULL);+    if (worker->nested){+      CHECK_ERR(subtask_queue_enqueue(&scheduler->workers[worker->tid], subtask),+                "subtask_queue_enqueue");+    } else {+      CHECK_ERR(subtask_queue_enqueue(&scheduler->workers[subtask_id], subtask),+                "subtask_queue_enqueue");+    }+    // Update range params+    start = end;+    end += iter_pr_subtask + ((subtask_id + 1) < remainder);+  }++  if (info.wake_up_threads) {+    wake_up_threads(scheduler, nsubtasks, scheduler->num_threads);+  }++  // Join (wait for subtasks to finish)+  while(join_counter != 0) {+    if (!subtask_queue_is_empty(&worker->q)) {+      struct subtask *subtask = NULL;+      int err = subtask_queue_dequeue(worker, &subtask, 0);+      if (err == 0 ) {+        CHECK_ERR(run_subtask(worker, subtask), "run_subtask");+      }+    } else {+      if (steal_from_random_worker(worker)) {+        struct subtask *subtask = NULL;+        int err = subtask_queue_dequeue(worker, &subtask, 0);+        if (err == 0) {+          CHECK_ERR(run_subtask(worker, subtask), "run_subtask");+        }+      }+    }+  }+++  if (info.wake_up_threads || sched == DYNAMIC) {+    __atomic_sub_fetch(&active_work, nsubtasks, __ATOMIC_RELAXED);+  }++  // Write back timing results of all sequential work+  (*timer) += task_timer;+  return scheduler_error;+}+++static inline int scheduler_execute_task(struct scheduler *scheduler,+                                         struct scheduler_parloop *task)+{++  struct worker *worker = worker_local;++  int err = 0;+  if (task->iterations == 0) {+    return err;+  }++  // How much sequential work was performed by the task+  int64_t task_timer = 0;++  /* Execute task sequential or parallel based on decision made earlier */+  if (task->info.nsubtasks == 1) {+    int64_t start = get_wall_time_ns();+    err = task->fn(task->args, 0, task->iterations, 0, worker->tid);+    int64_t end = get_wall_time_ns();+    task_timer = end - start;+    worker->time_spent_working += task_timer;+    // Report time measurements+    // TODO the update of both of these should really be a single atomic!!+    __atomic_fetch_add(task->info.task_time, task_timer, __ATOMIC_RELAXED);+    __atomic_fetch_add(task->info.task_iter, task->iterations, __ATOMIC_RELAXED);+  } else {+    // Add "before" time if we already are inside a task+    int64_t time_before = 0;+    if (worker->nested > 0) {+      time_before = total_now(worker->total, worker->timer);+    }++    err = scheduler_execute_parloop(scheduler, task, &task_timer);++    // Report time measurements+    // TODO the update of both of these should really be a single atomic!!+    __atomic_fetch_add(task->info.task_time, task_timer, __ATOMIC_RELAXED);+    __atomic_fetch_add(task->info.task_iter, task->iterations, __ATOMIC_RELAXED);++    // Update timers to account for new timings+    worker->total = time_before + task_timer;+    worker->timer = get_wall_time_ns();+  }+++  return err;+}++/* Decide on how schedule the incoming task i.e. how many subtasks and+   to run sequential or (potentially nested) parallel code body */+static inline int scheduler_prepare_task(struct scheduler* scheduler,+                                         struct scheduler_segop *task)+{+  assert(task != NULL);++  struct worker *worker = worker_local;+  struct scheduler_info info;+  info.task_time = task->task_time;+  info.task_iter = task->task_iter;++  int nsubtasks;+  // Decide if task should be scheduled sequentially+  if (is_small(task, scheduler->num_threads, &nsubtasks)) {+    info.iter_pr_subtask = task->iterations;+    info.remainder = 0;+    info.nsubtasks = nsubtasks;+    return task->top_level_fn(task->args, task->iterations, worker->tid, info);+  } else {+    info.iter_pr_subtask = task->iterations / nsubtasks;+    info.remainder = task->iterations % nsubtasks;+    info.sched = task->sched;+    switch (task->sched) {+    case STATIC:+      info.nsubtasks = info.iter_pr_subtask == 0 ? info.remainder : ((task->iterations - info.remainder) / info.iter_pr_subtask);+      break;+    case DYNAMIC:+      // As any thread can take any subtasks, we are being safe with using+      // an upper bound on the number of tasks such that the task allocate enough memory+      info.nsubtasks = info.iter_pr_subtask == 0 ? info.remainder : nsubtasks;+      break;+    default:+      assert(!"Got unknown scheduling");+    }+  }++  info.wake_up_threads = 0;+  // We only use the nested parallel segop function if we can't exchaust all cores+  // using the outer most level+  if (task->nested_fn != NULL && info.nsubtasks < scheduler->num_threads && info.nsubtasks == task->iterations) {+    if (worker->nested == 0)+      info.wake_up_threads = 1;+    return task->nested_fn(task->args, task->iterations, worker->tid, info);+  }++  return task->top_level_fn(task->args, task->iterations, worker->tid, info);+}++#endif+// End of scheduler.h
+ rts/c/scheduler_common.h view
@@ -0,0 +1,244 @@+// start of scheduler_common.h++#ifndef _SCHEDULER_COMMON_H_+#define _SCHEDULER_COMMON_H_++#include <float.h>++/* Scheduler definitions */+enum scheduling {+  DYNAMIC,+  STATIC+};++/* How a given task should be executed */+/* Filled out by the scheduler+   and passed to the segop function+*/+struct scheduler_info {+  int64_t iter_pr_subtask;+  int64_t remainder;+  int nsubtasks;+  enum scheduling sched;+  int wake_up_threads;++  int64_t *task_time;+  int64_t *task_iter;+};++struct scheduler {+  struct worker *workers;+  int num_threads;+};++/* A parallel parloop task  */+struct scheduler_parloop {+  const char* name;+  parloop_fn fn;+  void* args;+  int64_t iterations;+  struct scheduler_info info;+};+++/* A task for the scheduler to execute */+struct scheduler_segop {+  void *args;+  segop_fn top_level_fn;+  segop_fn nested_fn;+  int64_t iterations;+  enum scheduling sched;++  // Pointers to timer and iter associated with the task+  int64_t *task_time;+  int64_t *task_iter;++  // For debugging+  const char* name;+};++// If there is work to steal => active_work > 0+static volatile int active_work = 0;+// Number of alive workers+static volatile sig_atomic_t num_workers;++// Thread local variable worker struct+// Note that, accesses to tls variables are expensive+// Minimize direct references to this variable+__thread struct worker* worker_local = NULL;++/* Only one error can be returned at the time now+   Maybe we can provide a stack like structure for pushing errors onto+   if we wish to backpropagte multiple errors */+static volatile sig_atomic_t scheduler_error = 0;++// kappa time unit in nanoseconds+static double kappa = 5.1f * 1000;++int64_t total_now(int64_t total, int64_t time) {+  return total + (get_wall_time_ns() - time);+}++int random_other_worker(struct scheduler *scheduler, int my_id) {+  (void)scheduler;+  int my_num_workers = __atomic_load_n(&num_workers, __ATOMIC_RELAXED);+  assert(my_num_workers != 1);+  int i = fast_rand() % (my_num_workers - 1);+  if (i >= my_id) {+    i++;+  }+#ifdef MCDEBUG+  assert(i >= 0);+  assert(i < my_num_workers);+  assert(i != my_id);+#endif++  return i;+}+++static inline int64_t compute_chunk_size(struct subtask* subtask)+{+  double C = (double)*subtask->task_time / (double)*subtask->task_iter;+  if (C == 0.0F) C += DBL_EPSILON;+  return max_int64((int64_t)(kappa / C), 1);+}++/* Takes a chunk from subtask and enqueues the remaining iterations onto the worker's queue */+/* A no-op if the subtask is not chunkable */+static inline struct subtask* chunk_subtask(struct worker* worker, struct subtask *subtask)+{+  if (subtask->chunkable) {+    // Do we have information from previous runs avaliable+    if (*subtask->task_iter > 0) {+      subtask->chunk_size = compute_chunk_size(subtask);+      assert(subtask->chunk_size > 0);+    }+    int64_t remaining_iter = subtask->end - subtask->start;+    assert(remaining_iter > 0);+    if (remaining_iter > subtask->chunk_size) {+      struct subtask *new_subtask = malloc(sizeof(struct subtask));+      *new_subtask = *subtask;+      // increment the subtask join counter to account for new subtask+      __atomic_fetch_add(subtask->counter, 1, __ATOMIC_RELAXED);+      // Update range parameters+      subtask->end = subtask->start + subtask->chunk_size;+      new_subtask->start = subtask->end;+      subtask_queue_enqueue(worker, new_subtask);+    }+  }+  return subtask;+}++static inline int run_subtask(struct worker* worker, struct subtask* subtask)+{+  assert(subtask != NULL);+  assert(worker != NULL);++  subtask = chunk_subtask(worker, subtask);+  worker->total = 0;+  worker->timer = get_wall_time_ns();+#if defined(MCPROFILE)+  int64_t start = worker->timer;+#endif+  worker->nested++;+  int err = subtask->fn(subtask->args, subtask->start, subtask->end,+                        subtask->chunkable ? worker->tid : subtask->id,+                        worker->tid);+  worker->nested--;+  // Some error occured during some other subtask+  // so we just clean-up and return+  if (scheduler_error != 0) {+    // Even a failed task counts as finished.+    __atomic_fetch_sub(subtask->counter, 1, __ATOMIC_RELAXED);+    free(subtask);+    return 0;+  }+  if (err != 0) {+    __atomic_store_n(&scheduler_error, err, __ATOMIC_RELAXED);+  }+  // Total sequential time spent+  int64_t time_elapsed = total_now(worker->total, worker->timer);+#if defined(MCPROFILE)+  worker->time_spent_working += get_wall_time_ns() - start;+#endif+  int64_t iter = subtask->end - subtask->start;+  // report measurements+  // These updates should really be done using a single atomic CAS operation+  __atomic_fetch_add(subtask->task_time, time_elapsed, __ATOMIC_RELAXED);+  __atomic_fetch_add(subtask->task_iter, iter, __ATOMIC_RELAXED);+  // We need a fence here, since if the counter is decremented before either+  // of the two above are updated bad things can happen, e.g. if they are stack-allocated+  __atomic_thread_fence(__ATOMIC_SEQ_CST);+  __atomic_fetch_sub(subtask->counter, 1, __ATOMIC_RELAXED);+  free(subtask);+  return 0;+}+++static inline int is_small(struct scheduler_segop *task, int nthreads, int *nsubtasks)+{+  int64_t time = *task->task_time;+  int64_t iter = *task->task_iter;++  if (task->sched == DYNAMIC || iter == 0) {+    *nsubtasks = nthreads;+    return 0;+  }++  // Estimate the constant C+  double C = (double)time / (double)iter;+  double cur_task_iter = (double) task->iterations;++  // Returns true if the task is small i.e.+  // if the number of iterations times C is smaller+  // than the overhead of subtask creation+  if (C == 0.0F || C * cur_task_iter < kappa) {+    *nsubtasks = 1;+    return 1;+  }++  // Else compute how many subtasks this tasks should create+  int64_t min_iter_pr_subtask = max_int64((int64_t)(kappa / C), 1);+  *nsubtasks = (int)min_int64(max_int64(task->iterations / min_iter_pr_subtask, 1), nthreads);++  return 0;+}++// TODO make this prettier+static inline struct subtask* create_subtask(parloop_fn fn,+                                             void* args,+                                             const char* name,+                                             volatile int* counter,+                                             int64_t *timer,+                                             int64_t *iter,+                                             int64_t start, int64_t end,+                                             int chunkable,+                                             int64_t chunk_size,+                                             int id)+{+  struct subtask* subtask = malloc(sizeof(struct subtask));+  if (subtask == NULL) {+    assert(!"malloc failed in create_subtask");+    return NULL;+  }+  subtask->fn         = fn;+  subtask->args       = args;++  subtask->counter    = counter;+  subtask->task_time  = timer;+  subtask->task_iter  = iter;++  subtask->start      = start;+  subtask->end        = end;+  subtask->id         = id;+  subtask->chunkable  = chunkable;+  subtask->chunk_size = chunk_size;++  subtask->name       = name;+  return subtask;+}+++#endif+// end of scheduler_common.h
+ rts/c/scheduler_tune.h view
@@ -0,0 +1,127 @@+/* The self-tuning program to estimate $\kappa$ */++struct futhark_mc_segred_stage_1_struct {+  struct futhark_context *ctx;+  int32_t *free_tuning_res;+  int32_t *array;+};++/* Reduction function over an integer array */+int futhark_mc_tuning_segred_stage_1(void *args, int64_t start, int64_t end,+                                     int flat_tid, int tid) {+  (void)flat_tid;+  (void)tid;++  int err = 0;+  struct futhark_mc_segred_stage_1_struct *futhark_mc_segred_stage_1_struct = (struct futhark_mc_segred_stage_1_struct *) args;+  struct futhark_context *ctx = futhark_mc_segred_stage_1_struct->ctx;+  int32_t *array = futhark_mc_segred_stage_1_struct->array;+  int32_t *tuning_res = futhark_mc_segred_stage_1_struct->free_tuning_res;++  int32_t sum = 0;+  for (int i = start; i < end; i++) {+    int32_t y = array[i];+    sum = add32(sum, y);+  }+  *tuning_res = sum;+  return err;+}++/* The main entry point for the tuning process */+/* Sets the global variable ``kappa`` */+int futhark_segred_tuning_program(struct futhark_context *ctx)+{+  int err = 0;++  int64_t iterations = 100000000;+  int64_t tuning_time = 0;+  int64_t tuning_iter = 0;++  int32_t *array = malloc(sizeof(int32_t) * iterations);+  for (int64_t i = 0; i < iterations; i++) {+    array[i] = fast_rand();+  }++  int64_t start_tuning = get_wall_time_ns();+  /* **************************** */+  /* Run sequential reduce first' */+  /* **************************** */+  int64_t tuning_sequentiual_start = get_wall_time_ns();+  struct futhark_mc_segred_stage_1_struct futhark_mc_segred_stage_1_struct;+  int32_t tuning_res;+  futhark_mc_segred_stage_1_struct.ctx = ctx;+  futhark_mc_segred_stage_1_struct.free_tuning_res = &tuning_res;+  futhark_mc_segred_stage_1_struct.array = array;++  err = futhark_mc_tuning_segred_stage_1(&futhark_mc_segred_stage_1_struct, 0, iterations, 0, 0);+  int64_t tuning_sequentiual_end = get_wall_time_ns();+  int64_t sequential_elapsed = tuning_sequentiual_end - tuning_sequentiual_start;++  double C = (double)sequential_elapsed / (double)iterations;+  fprintf(stderr, " Time for sequential run is %lld - Found C %f\n", (long long)sequential_elapsed, C);++  /* ********************** */+  /* Now run tuning process */+  /* ********************** */+  // Setup a scheduler with a single worker+  int num_threads = ctx->scheduler.num_threads;+  ctx->scheduler.num_threads = 1;+  ctx->scheduler.workers = malloc(sizeof(struct worker));+  worker_local = &ctx->scheduler.workers[0];+  worker_local->tid = 0;+  CHECK_ERR(subtask_queue_init(&ctx->scheduler.workers[0].q, 1024), "failed to init queue for worker %d\n", 0);++  // Start tuning for kappa+  double kappa_tune = 1000; // Initial kappa is 1 us+  double ratio;+  int64_t time_elapsed;+  while(1) {+    int64_t min_iter_pr_subtask = (int64_t) (kappa_tune / C) == 0 ? 1 : (kappa_tune / C);+    int nsubtasks = iterations / min_iter_pr_subtask;+    struct scheduler_info info;+    info.iter_pr_subtask = min_iter_pr_subtask;++    info.nsubtasks = iterations / min_iter_pr_subtask;+    info.remainder = iterations % min_iter_pr_subtask;+    info.task_time = &tuning_time;+    info.task_iter = &tuning_iter;+    info.sched = STATIC;++    struct scheduler_parloop futhark_segred_tuning_scheduler_parloop;+    futhark_segred_tuning_scheduler_parloop.name = "futhark_mc_tuning_segred_stage_1";+    futhark_segred_tuning_scheduler_parloop.fn = futhark_mc_tuning_segred_stage_1;+    futhark_segred_tuning_scheduler_parloop.args = &futhark_mc_segred_stage_1_struct;+    futhark_segred_tuning_scheduler_parloop.iterations = iterations;+    futhark_segred_tuning_scheduler_parloop.info = info;++    int64_t tuning_chunked_start = get_wall_time_ns();+    int futhark_segred_tuning_program_err =+      scheduler_execute_task(&ctx->scheduler,+                             &futhark_segred_tuning_scheduler_parloop);+    assert(futhark_segred_tuning_program_err == 0);+    int64_t tuning_chunked_end = get_wall_time_ns();+    time_elapsed =  tuning_chunked_end - tuning_chunked_start;++    ratio = (double)time_elapsed / (double)sequential_elapsed;+    if (ratio < 1.055) {+      break;+    }+    kappa_tune += 100; // Increase by 100 ns at the time+    fprintf(stderr, "nsubtask %d - kappa %f - ratio %f\n", nsubtasks, kappa_tune, ratio);+  }++  int64_t end_tuning = get_wall_time_ns();+  fprintf(stderr, "tuning took %lld ns and found kappa %f - time %lld - ratio %f\n",+          (long long)end_tuning - start_tuning,+          kappa_tune,+          (long long)time_elapsed,+          ratio);+  kappa = kappa_tune;++  // Clean-up+  CHECK_ERR(subtask_queue_destroy(&ctx->scheduler.workers[0].q), "failed to destroy queue");+  free(array);+  free(ctx->scheduler.workers);+  ctx->scheduler.num_threads = num_threads;+  return err;+}
+ rts/c/subtask_queue.h view
@@ -0,0 +1,247 @@+// start of subtask_queue.h++#ifndef SUBTASK_QUEUE_H+#define SUBTASK_QUEUE_H++/* Doubles the size of the queue */+static inline int subtask_queue_grow_queue(struct subtask_queue *subtask_queue) {++  int new_capacity = 2 * subtask_queue->capacity;+#ifdef MCDEBUG+  fprintf(stderr, "Growing queue to %d\n", subtask_queue->capacity * 2);+#endif++  struct subtask **new_buffer = calloc(new_capacity, sizeof(struct subtask*));+  for (int i = 0; i < subtask_queue->num_used; i++) {+    new_buffer[i] = subtask_queue->buffer[(subtask_queue->first + i) % subtask_queue->capacity];+  }++  free(subtask_queue->buffer);+  subtask_queue->buffer = new_buffer;+  subtask_queue->capacity = new_capacity;+  subtask_queue->first = 0;++  return 0;+}++// Initialise a job queue with the given capacity.  The queue starts out+// empty.  Returns non-zero on error.+static inline int subtask_queue_init(struct subtask_queue *subtask_queue, int capacity)+{+  assert(subtask_queue != NULL);+  memset(subtask_queue, 0, sizeof(struct subtask_queue));++  subtask_queue->capacity = capacity;+  subtask_queue->buffer = calloc(capacity, sizeof(struct subtask*));+  if (subtask_queue->buffer == NULL) {+    return -1;+  }++  CHECK_ERRNO(pthread_mutex_init(&subtask_queue->mutex, NULL), "pthread_mutex_init");+  CHECK_ERRNO(pthread_cond_init(&subtask_queue->cond, NULL), "pthread_cond_init");++  return 0;+}++// Destroy the job queue.  Blocks until the queue is empty before it+// is destroyed.+static inline int subtask_queue_destroy(struct subtask_queue *subtask_queue)+{+  assert(subtask_queue != NULL);++  CHECK_ERR(pthread_mutex_lock(&subtask_queue->mutex), "pthread_mutex_lock");++  while (subtask_queue->num_used != 0) {+    CHECK_ERR(pthread_cond_wait(&subtask_queue->cond, &subtask_queue->mutex), "pthread_cond_wait");+  }++  // Queue is now empty.  Let's kill it!+  subtask_queue->dead = 1;+  free(subtask_queue->buffer);+  CHECK_ERR(pthread_cond_broadcast(&subtask_queue->cond), "pthread_cond_broadcast");+  CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");++  return 0;+}++static inline void dump_queue(struct worker *worker)+{+  struct subtask_queue *subtask_queue = &worker->q;+  CHECK_ERR(pthread_mutex_lock(&subtask_queue->mutex), "pthread_mutex_lock");+  for (int i = 0; i < subtask_queue->num_used; i++) {+    struct subtask * subtask = subtask_queue->buffer[(subtask_queue->first + i) % subtask_queue->capacity];+    printf("queue tid %d with %d task %s\n", worker->tid, i, subtask->name);+  }+  CHECK_ERR(pthread_cond_broadcast(&subtask_queue->cond), "pthread_cond_broadcast");+  CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");+}++// Push an element onto the end of the job queue.  Blocks if the+// subtask_queue is full (its size is equal to its capacity).  Returns+// non-zero on error.  It is an error to push a job onto a queue that+// has been destroyed.+static inline int subtask_queue_enqueue(struct worker *worker, struct subtask *subtask )+{+  assert(worker != NULL);+  struct subtask_queue *subtask_queue = &worker->q;++#ifdef MCPROFILE+  uint64_t start = get_wall_time();+#endif++  CHECK_ERR(pthread_mutex_lock(&subtask_queue->mutex), "pthread_mutex_lock");+  // Wait until there is room in the subtask_queue.+  while (subtask_queue->num_used == subtask_queue->capacity && !subtask_queue->dead) {+    if (subtask_queue->num_used == subtask_queue->capacity) {+      CHECK_ERR(subtask_queue_grow_queue(subtask_queue), "subtask_queue_grow_queue");+      continue;+    }+    CHECK_ERR(pthread_cond_wait(&subtask_queue->cond, &subtask_queue->mutex), "pthread_cond_wait");+  }++  if (subtask_queue->dead) {+    CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");+    return -1;+  }++  // If we made it past the loop, there is room in the subtask_queue.+  subtask_queue->buffer[(subtask_queue->first + subtask_queue->num_used) % subtask_queue->capacity] = subtask;+  subtask_queue->num_used++;++#ifdef MCPROFILE+  uint64_t end = get_wall_time();+  subtask_queue->time_enqueue += (end - start);+  subtask_queue->n_enqueues++;+#endif+  // Broadcast a reader (if any) that there is now an element.+  CHECK_ERR(pthread_cond_broadcast(&subtask_queue->cond), "pthread_cond_broadcast");+  CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");++  return 0;+}+++/* Like subtask_queue_dequeue, but with two differences:+   1) the subtask is stolen from the __front__ of the queue+   2) returns immediately if there is no subtasks queued,+      as we dont' want to block on another workers queue and+*/+static inline int subtask_queue_steal(struct worker *worker,+                                      struct subtask **subtask)+{+  struct subtask_queue *subtask_queue = &worker->q;+  assert(subtask_queue != NULL);++#ifdef MCPROFILE+  uint64_t start = get_wall_time();+#endif+  CHECK_ERR(pthread_mutex_lock(&subtask_queue->mutex), "pthread_mutex_lock");++  if (subtask_queue->num_used == 0) {+    CHECK_ERR(pthread_cond_broadcast(&subtask_queue->cond), "pthread_cond_broadcast");+    CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");+    return 1;+  }++  if (subtask_queue->dead) {+    CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");+    return -1;+  }++  // Tasks gets stolen from the "front"+  struct subtask *cur_back = subtask_queue->buffer[subtask_queue->first];+  struct subtask *new_subtask = NULL;+  int remaining_iter = cur_back->end - cur_back->start;+  // If subtask is chunkable, we steal half of the iterations+  if (cur_back->chunkable && remaining_iter > 1) {+      int64_t half = remaining_iter / 2;+      new_subtask = malloc(sizeof(struct subtask));+      *new_subtask = *cur_back;+      new_subtask->start = cur_back->end - half;+      cur_back->end = new_subtask->start;+      __atomic_fetch_add(cur_back->counter, 1, __ATOMIC_RELAXED);+  } else {+    new_subtask = cur_back;+    subtask_queue->num_used--;+    subtask_queue->first = (subtask_queue->first + 1) % subtask_queue->capacity;+  }+  *subtask = new_subtask;++  if (*subtask == NULL) {+    CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthred_mutex_unlock");+    return 1;+  }++#ifdef MCPROFILE+  uint64_t end = get_wall_time();+  subtask_queue->time_dequeue += (end - start);+  subtask_queue->n_dequeues++;+#endif++  // Broadcast a writer (if any) that there is now room for more.+  CHECK_ERR(pthread_cond_broadcast(&subtask_queue->cond), "pthread_cond_broadcast");+  CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");++  return 0;+}+++// Pop an element from the back of the job queue.+// Optional argument can be provided to block or not+static inline int subtask_queue_dequeue(struct worker *worker,+                                        struct subtask **subtask, int blocking)+{+  assert(worker != NULL);+  struct subtask_queue *subtask_queue = &worker->q;++#ifdef MCPROFILE+  uint64_t start = get_wall_time();+#endif++  CHECK_ERR(pthread_mutex_lock(&subtask_queue->mutex), "pthread_mutex_lock");+  if (subtask_queue->num_used == 0 && !blocking) {+    CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");+    return 1;+  }+  // Try to steal some work while the subtask_queue is empty+  while (subtask_queue->num_used == 0 && !subtask_queue->dead) {+    pthread_cond_wait(&subtask_queue->cond, &subtask_queue->mutex);+  }++  if (subtask_queue->dead) {+    CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");+    return -1;+  }++  // dequeue pops from the back+  *subtask = subtask_queue->buffer[(subtask_queue->first + subtask_queue->num_used - 1) % subtask_queue->capacity];+  subtask_queue->num_used--;++  if (*subtask == NULL) {+    assert(!"got NULL ptr");+    CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthred_mutex_unlock");+    return -1;+  }++#ifdef MCPROFILE+  uint64_t end = get_wall_time();+  subtask_queue->time_dequeue += (end - start);+  subtask_queue->n_dequeues++;+#endif++  // Broadcast a writer (if any) that there is now room for more.+  CHECK_ERR(pthread_cond_broadcast(&subtask_queue->cond), "pthread_cond_broadcast");+  CHECK_ERR(pthread_mutex_unlock(&subtask_queue->mutex), "pthread_mutex_unlock");++  return 0;+}++static inline int subtask_queue_is_empty(struct subtask_queue *subtask_queue)+{+  return subtask_queue->num_used == 0;+}+++#endif++// End of subtask_queue.h
rts/c/timing.h view
@@ -26,6 +26,30 @@   return time.tv_sec * 1000000 + time.tv_usec; } +static int64_t get_wall_time_ns(void) {+  struct timespec time;+  assert(clock_gettime(CLOCK_REALTIME, &time) == 0);+  return time.tv_sec * 1000000000 + time.tv_nsec;+}+++static inline uint64_t rdtsc() {+  unsigned int hi, lo;+  __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));+  return  ((uint64_t) lo) | (((uint64_t) hi) << 32);+}++static inline void rdtsc_wait(uint64_t n) {+  const uint64_t start = rdtsc();+  while (rdtsc() < (start + n)) {+    __asm__("PAUSE");+  }+}+static inline void spin_for(uint64_t nb_cycles) {+  rdtsc_wait(nb_cycles);+}++ #endif  // End of timing.h.
rts/c/util.h view
@@ -2,6 +2,9 @@ // // Various helper functions that are useful in all generated C code. +#include <errno.h>+#include <string.h>+ static const char *fut_progname = "(embedded Futhark)";  static void futhark_panic(int eval, const char *fmt, ...) {@@ -24,6 +27,24 @@   vsnprintf(buffer, needed, s, vl);   return buffer; }+++static inline void check_err(int errval, int sets_errno, const char *fun, int line,+                            const char *msg, ...)+{+  if (errval) {+    char str[256];+    char errnum[10];+    sprintf(errnum, "%d", errval);+    sprintf(str, "ERROR: %s in %s() at line %d with error code %s\n", msg, fun, line,+            sets_errno ? strerror(errno) : errnum);+    fprintf(stderr, "%s", str);+    exit(errval);+  }+}++#define CHECK_ERR(err, msg...) check_err(err, 0, __func__, __LINE__, msg)+#define CHECK_ERRNO(err, msg...) check_err(err, 1, __func__, __LINE__, msg)  // Read a file into a NUL-terminated string; returns NULL on error. static void* slurp_file(const char *filename, size_t *size) {
rts/python/opencl.py view
@@ -122,7 +122,7 @@      self.global_failure = self.pool.allocate(np.int32().itemsize)     cl.enqueue_fill_buffer(self.queue, self.global_failure, np.int32(-1), 0, np.int32().itemsize)-    self.global_failure_args = self.pool.allocate(np.int32().itemsize *+    self.global_failure_args = self.pool.allocate(np.int64().itemsize *                                                   (self.global_failure_args_max+1))     self.failure_is_an_option = np.int32(0) @@ -225,7 +225,7 @@         cl.enqueue_fill_buffer(self.queue, self.global_failure, np.int32(-1), 0, np.int32().itemsize)          # Read failure args.-        failure_args = np.empty(self.global_failure_args_max+1, dtype=np.int32)+        failure_args = np.empty(self.global_failure_args_max+1, dtype=np.int64)         cl.enqueue_copy(self.queue, failure_args, self.global_failure_args, is_blocking=True)          raise Exception(self.failure_msgs[failure[0]].format(*failure_args))
src/Futhark/Actions.hs view
@@ -6,10 +6,12 @@   ( printAction,     impCodeGenAction,     kernelImpCodeGenAction,+    multicoreImpCodeGenAction,     metricsAction,     compileCAction,     compileOpenCLAction,     compileCUDAAction,+    compileMulticoreAction,     sexpAction,   ) where@@ -21,12 +23,15 @@ import Futhark.Analysis.Metrics import qualified Futhark.CodeGen.Backends.CCUDA as CCUDA import qualified Futhark.CodeGen.Backends.COpenCL as COpenCL+import qualified Futhark.CodeGen.Backends.MulticoreC as MulticoreC import qualified Futhark.CodeGen.Backends.SequentialC as SequentialC import qualified Futhark.CodeGen.ImpGen.Kernels as ImpGenKernels+import qualified Futhark.CodeGen.ImpGen.Multicore as ImpGenMulticore import qualified Futhark.CodeGen.ImpGen.Sequential as ImpGenSequential import Futhark.Compiler.CLI import Futhark.IR import Futhark.IR.KernelsMem (KernelsMem)+import Futhark.IR.MCMem (MCMem) import Futhark.IR.Prop.Aliases import Futhark.IR.SeqMem (SeqMem) import Futhark.Util (runProgramWithExitCode)@@ -71,6 +76,14 @@       actionProcedure = liftIO . putStrLn . pretty . snd <=< ImpGenKernels.compileProgOpenCL     } +multicoreImpCodeGenAction :: Action MCMem+multicoreImpCodeGenAction =+  Action+    { actionName = "Compile to imperative multicore",+      actionDescription = "Translate program into imperative multicore IL and write it on standard output.",+      actionProcedure = liftIO . putStrLn . pretty . snd <=< ImpGenMulticore.compileProg+    }+ -- | Print metrics about AST node counts to stdout. sexpAction :: ASTLore lore => Action lore sexpAction =@@ -207,6 +220,46 @@                 [cpath, "-O", "-std=c99", "-lm", "-o", outpath]                   ++ extra_options           ret <- liftIO $ runProgramWithExitCode "gcc" args mempty+          case ret of+            Left err ->+              externalErrorS $ "Failed to run gcc: " ++ show err+            Right (ExitFailure code, _, gccerr) ->+              externalErrorS $+                "gcc failed with code "+                  ++ show code+                  ++ ":\n"+                  ++ gccerr+            Right (ExitSuccess, _, _) ->+              return ()++-- | The @futhark multicore@ action.+compileMulticoreAction :: FutharkConfig -> CompilerMode -> FilePath -> Action MCMem+compileMulticoreAction fcfg mode outpath =+  Action+    { actionName = "Compile to multicore",+      actionDescription = "Compile to multicore",+      actionProcedure = helper+    }+  where+    helper prog = do+      cprog <- handleWarnings fcfg $ MulticoreC.compileProg prog+      let cpath = outpath `addExtension` "c"+          hpath = outpath `addExtension` "h"++      case mode of+        ToLibrary -> do+          let (header, impl) = MulticoreC.asLibrary cprog+          liftIO $ writeFile hpath header+          liftIO $ writeFile cpath impl+        ToExecutable -> do+          liftIO $ writeFile cpath $ MulticoreC.asExecutable cprog+          -- let debug_flags = ["-g", "-fno-omit-frame-pointer", "-fsanitize=address", "-fsanitize=integer", "-fsanitize=undefined", "-fno-sanitize-recover=null"]+          ret <-+            liftIO $+              runProgramWithExitCode+                "gcc"+                [cpath, "-O3", "-pthread", "-std=c11", "-lm", "-o", outpath]+                mempty           case ret of             Left err ->               externalErrorS $ "Failed to run gcc: " ++ show err
src/Futhark/Analysis/HORep/SOAC.hs view
@@ -526,7 +526,7 @@   SOAC lore ->   m (SOAC lore, [Ident]) soacToStream soac = do-  chunk_param <- newParam "chunk" $ Prim int32+  chunk_param <- newParam "chunk" $ Prim int64   let chvar = Futhark.Var $ paramName chunk_param       (lam, inps) = (lambda soac, inputs soac)       w = width soac@@ -579,7 +579,7 @@         lastel_tmp_ids <- mapM (newIdent "lstel_tmp") accrtps         empty_arr <- newIdent "empty_arr" $ Prim Bool         inpacc_ids <- mapM (newParam "inpacc") accrtps-        outszm1id <- newIdent "szm1" $ Prim int32+        outszm1id <- newIdent "szm1" $ Prim int64         -- 1. let (scan0_ids,map_resids)  = scanomap(scan_lam,nes,map_lam,a_ch)         let insbnd =               mkLet [] (scan0_ids ++ map_resids) $@@ -591,17 +591,17 @@               mkLet [] [outszm1id] $                 BasicOp $                   BinOp-                    (Sub Int32 OverflowUndef)+                    (Sub Int64 OverflowUndef)                     (Futhark.Var $ paramName chunk_param)-                    (constant (1 :: Int32))+                    (constant (1 :: Int64))             -- 3. let lasteel_ids = ...             empty_arr_bnd =               mkLet [] [empty_arr] $                 BasicOp $                   CmpOp-                    (CmpSlt Int32)+                    (CmpSlt Int64)                     (Futhark.Var $ identName outszm1id)-                    (constant (0 :: Int32))+                    (constant (0 :: Int64))             leltmpbnds =               zipWith                 ( \lid arrid ->
src/Futhark/Analysis/Metrics.hs view
@@ -48,6 +48,10 @@ class OpMetrics op where   opMetrics :: op -> MetricsM () +instance OpMetrics a => OpMetrics (Maybe a) where+  opMetrics Nothing = return ()+  opMetrics (Just x) = opMetrics x+ instance OpMetrics () where   opMetrics () = return () 
src/Futhark/Analysis/PrimExp/Convert.hs view
@@ -7,6 +7,8 @@     primExpFromSubExp,     pe32,     le32,+    pe64,+    le64,     primExpFromSubExpM,     replaceInPrimExp,     replaceInPrimExpM,@@ -92,6 +94,14 @@ le32 :: a -> TPrimExp Int32 a le32 = isInt32 . flip LeafExp int32 +-- | Shorthand for constructing a 'TPrimExp' of type 'Int64'.+pe64 :: SubExp -> TPrimExp Int64 VName+pe64 = isInt64 . primExpFromSubExp int64++-- | Shorthand for constructing a 'TPrimExp' of type 'Int64', from a leaf.+le64 :: a -> TPrimExp Int64 a+le64 = isInt64 . flip LeafExp int64+ -- | Applying a monadic transformation to the leaves in a 'PrimExp'. replaceInPrimExpM ::   Monad m =>@@ -133,9 +143,9 @@   fromMaybe (LeafExp v t) $ M.lookup v tab  -- | Convert a 'SubExp' slice to a 'PrimExp' slice.-primExpSlice :: Slice SubExp -> Slice (TPrimExp Int32 VName)-primExpSlice = map $ fmap $ isInt32 . primExpFromSubExp int32+primExpSlice :: Slice SubExp -> Slice (TPrimExp Int64 VName)+primExpSlice = map $ fmap pe64  -- | Convert a 'PrimExp' slice to a 'SubExp' slice.-subExpSlice :: MonadBinder m => Slice (TPrimExp Int32 VName) -> m (Slice SubExp)+subExpSlice :: MonadBinder m => Slice (TPrimExp Int64 VName) -> m (Slice SubExp) subExpSlice = mapM $ traverse $ toSubExp "slice"
src/Futhark/Analysis/SymbolTable.hs view
@@ -111,7 +111,7 @@     Indexed Certificates (PrimExp VName)   | -- | The indexing corresponds to another (perhaps more     -- advantageous) array.-    IndexedArray Certificates VName [TPrimExp Int32 VName]+    IndexedArray Certificates VName [TPrimExp Int64 VName]  indexedAddCerts :: Certificates -> Indexed -> Indexed indexedAddCerts cs1 (Indexed cs2 v) = Indexed (cs1 <> cs2) v@@ -122,7 +122,7 @@   freeIn' (IndexedArray cs arr v) = freeIn' cs <> freeIn' arr <> freeIn' v  -- | Indexing a delayed array if possible.-type IndexArray = [TPrimExp Int32 VName] -> Maybe Indexed+type IndexArray = [TPrimExp Int64 VName] -> Maybe Indexed  data Entry lore = Entry   { -- | True if consumed.@@ -265,7 +265,7 @@  index' ::   VName ->-  [TPrimExp Int32 VName] ->+  [TPrimExp Int64 VName] ->   SymbolTable lore ->   Maybe Indexed index' name is vtable = do@@ -288,7 +288,7 @@     SymbolTable lore ->     Int ->     op ->-    [TPrimExp Int32 VName] ->+    [TPrimExp Int64 VName] ->     Maybe Indexed   indexOp _ _ _ _ = Nothing @@ -322,18 +322,18 @@   | Just oldshape <- arrayDims <$> lookupType v table =     let is' =           reshapeIndex-            (map pe32 oldshape)-            (map pe32 $ newDims newshape)+            (map pe64 oldshape)+            (map pe64 $ newDims newshape)             is      in index' v is' table indexExp table (BasicOp (Index v slice)) _ is =   index' v (adjust slice is) table   where     adjust (DimFix j : js') is' =-      pe32 j : adjust js' is'+      pe64 j : adjust js' is'     adjust (DimSlice j _ s : js') (i : is') =-      let i_t_s = i * pe32 s-          j_p_i_t_s = pe32 j + i_t_s+      let i_t_s = i * pe64 s+          j_p_i_t_s = pe64 j + i_t_s        in j_p_i_t_s : adjust js' is'     adjust _ _ = [] indexExp _ _ _ _ = Nothing
src/Futhark/CLI/Dev.hs view
@@ -18,6 +18,8 @@ import Futhark.IR (ASTLore, Op, Prog, pretty) import qualified Futhark.IR.Kernels as Kernels import qualified Futhark.IR.KernelsMem as KernelsMem+import qualified Futhark.IR.MC as MC+import qualified Futhark.IR.MCMem as MCMem import Futhark.IR.Prop.Aliases (CanBeAliased) import qualified Futhark.IR.SOACS as SOACS import qualified Futhark.IR.Seq as Seq@@ -38,6 +40,7 @@ import qualified Futhark.Pass.ExplicitAllocations.Kernels as Kernels import qualified Futhark.Pass.ExplicitAllocations.Seq as Seq import Futhark.Pass.ExtractKernels+import Futhark.Pass.ExtractMulticore import Futhark.Pass.FirstOrderTransform import Futhark.Pass.KernelBabysitting import Futhark.Pass.Simplify@@ -91,8 +94,10 @@ data UntypedPassState   = SOACS (Prog SOACS.SOACS)   | Kernels (Prog Kernels.Kernels)+  | MC (Prog MC.MC)   | Seq (Prog Seq.Seq)   | KernelsMem (Prog KernelsMem.KernelsMem)+  | MCMem (Prog MCMem.MCMem)   | SeqMem (Prog SeqMem.SeqMem)  getSOACSProg :: UntypedPassState -> Maybe (Prog SOACS.SOACS)@@ -107,15 +112,19 @@ instance Representation UntypedPassState where   representation (SOACS _) = "SOACS"   representation (Kernels _) = "Kernels"+  representation (MC _) = "MC"   representation (Seq _) = "Seq"   representation (KernelsMem _) = "KernelsMem"+  representation (MCMem _) = "MCMem"   representation (SeqMem _) = "SeqMEm"  instance PP.Pretty UntypedPassState where   ppr (SOACS prog) = PP.ppr prog   ppr (Kernels prog) = PP.ppr prog+  ppr (MC prog) = PP.ppr prog   ppr (Seq prog) = PP.ppr prog   ppr (SeqMem prog) = PP.ppr prog+  ppr (MCMem prog) = PP.ppr prog   ppr (KernelsMem prog) = PP.ppr prog  newtype UntypedPass@@ -129,6 +138,7 @@   = SOACSAction (Action SOACS.SOACS)   | KernelsAction (Action Kernels.Kernels)   | KernelsMemAction (FilePath -> Action KernelsMem.KernelsMem)+  | MCMemAction (FilePath -> Action MCMem.MCMem)   | SeqMemAction (FilePath -> Action SeqMem.SeqMem)   | PolyAction       ( forall lore.@@ -144,12 +154,14 @@ untypedActionName (KernelsAction a) = actionName a untypedActionName (SeqMemAction a) = actionName $ a "" untypedActionName (KernelsMemAction a) = actionName $ a ""+untypedActionName (MCMemAction a) = actionName $ a "" untypedActionName (PolyAction a) = actionName (a :: Action SOACS.SOACS)  instance Representation UntypedAction where   representation (SOACSAction _) = "SOACS"   representation (KernelsAction _) = "Kernels"   representation (KernelsMemAction _) = "KernelsMem"+  representation (MCMemAction _) = "MCMem"   representation (SeqMemAction _) = "SeqMem"   representation PolyAction {} = "<any>" @@ -247,12 +259,16 @@       SOACS <$> runPipeline (onePass simplifySOACS) config prog     perform (Kernels prog) config =       Kernels <$> runPipeline (onePass simplifyKernels) config prog+    perform (MC prog) config =+      MC <$> runPipeline (onePass simplifyMC) config prog     perform (Seq prog) config =       Seq <$> runPipeline (onePass simplifySeq) config prog     perform (SeqMem prog) config =       SeqMem <$> runPipeline (onePass simplifySeqMem) config prog     perform (KernelsMem prog) config =       KernelsMem <$> runPipeline (onePass simplifyKernelsMem) config prog+    perform (MCMem prog) config =+      MCMem <$> runPipeline (onePass simplifyMCMem) config prog      long = [passLongOption pass]     pass = simplifySOACS@@ -299,12 +315,16 @@       SOACS <$> runPipeline (onePass $ performCSE True) config prog     perform (Kernels prog) config =       Kernels <$> runPipeline (onePass $ performCSE True) config prog+    perform (MC prog) config =+      MC <$> runPipeline (onePass $ performCSE True) config prog     perform (Seq prog) config =       Seq <$> runPipeline (onePass $ performCSE True) config prog     perform (SeqMem prog) config =       SeqMem <$> runPipeline (onePass $ performCSE False) config prog     perform (KernelsMem prog) config =       KernelsMem <$> runPipeline (onePass $ performCSE False) config prog+    perform (MCMem prog) config =+      MCMem <$> runPipeline (onePass $ performCSE False) config prog      long = [passLongOption pass]     pass = performCSE True :: Pass SOACS.SOACS SOACS.SOACS@@ -384,6 +404,14 @@       "Translate program into the imperative IL with kernels and write it on standard output.",     Option       []+      ["compile-imperative-multicore"]+      ( NoArg $+          Right $ \opts ->+            opts {futharkAction = MCMemAction $ const multicoreImpCodeGenAction}+      )+      "Translate program into the imperative IL with kernels and write it on standard output.",+    Option+      []       ["compile-opencl"]       ( NoArg $           Right $ \opts ->@@ -443,12 +471,13 @@     soacsPassOption inlineFunctions [],     kernelsPassOption babysitKernels [],     kernelsPassOption tileLoops [],-    kernelsPassOption unstream [],-    kernelsPassOption sink [],+    kernelsPassOption unstreamKernels [],+    kernelsPassOption sinkKernels [],     typedPassOption soacsProg Kernels extractKernels [],+    typedPassOption soacsProg MC extractMulticore [],     iplOption [],     allocateOption "a",-    kernelsMemPassOption doubleBuffer [],+    kernelsMemPassOption doubleBufferKernels [],     kernelsMemPassOption expandAllocations [],     cseOption [],     simplifyOption "e",@@ -480,7 +509,15 @@       "Run the sequential CPU compilation pipeline"       sequentialCpuPipeline       []-      ["cpu"]+      ["cpu"],+    pipelineOption+      getSOACSProg+      "MCMem"+      MCMem+      "Run the multicore compilation pipeline"+      multicorePipeline+      []+      ["multicore"]   ]  incVerbosity :: Maybe FilePath -> FutharkConfig -> FutharkConfig@@ -593,15 +630,21 @@       actionProcedure (action base) prog     (KernelsMem prog, KernelsMemAction action) ->       actionProcedure (action base) prog+    (MCMem prog, MCMemAction action) ->+      actionProcedure (action base) prog     (SOACS soacs_prog, PolyAction acs) ->       actionProcedure acs soacs_prog     (Kernels kernels_prog, PolyAction acs) ->       actionProcedure acs kernels_prog+    (MC mc_prog, PolyAction acs) ->+      actionProcedure acs mc_prog     (Seq seq_prog, PolyAction acs) ->       actionProcedure acs seq_prog     (KernelsMem mem_prog, PolyAction acs) ->       actionProcedure acs mem_prog     (SeqMem mem_prog, PolyAction acs) ->+      actionProcedure acs mem_prog+    (MCMem mem_prog, PolyAction acs) ->       actionProcedure acs mem_prog     (_, action) ->       externalErrorS $
+ src/Futhark/CLI/Multicore.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE FlexibleContexts #-}++module Futhark.CLI.Multicore (main) where++import Futhark.Actions (compileMulticoreAction)+import Futhark.Compiler.CLI+import Futhark.Passes (multicorePipeline)++main :: String -> [String] -> IO ()+main = compilerMain+  ()+  []+  "Compile to multicore C"+  "Generate multicore C code from optimised Futhark program."+  multicorePipeline+  $ \fcfg () mode outpath prog ->+    actionProcedure (compileMulticoreAction fcfg mode outpath) prog
src/Futhark/CLI/Test.hs view
@@ -579,7 +579,7 @@           { configBackend = "c",             configFuthark = Nothing,             configRunner = "",-            configExtraOptions = [],+            configExtraOptions = ["-b"],             configExtraCompilerOptions = [],             configTuning = Just "tuning"           },
src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs view
@@ -392,7 +392,7 @@                  CUDA_SUCCEED(cuMemAlloc(&ctx->global_failure, sizeof(no_error)));                  CUDA_SUCCEED(cuMemcpyHtoD(ctx->global_failure, &no_error, sizeof(no_error)));                  // The +1 is to avoid zero-byte allocations.-                 CUDA_SUCCEED(cuMemAlloc(&ctx->global_failure_args, sizeof(int32_t)*($int:max_failure_args+1)));+                 CUDA_SUCCEED(cuMemAlloc(&ctx->global_failure_args, sizeof(int64_t)*($int:max_failure_args+1)));                   $stms:init_kernel_fields @@ -442,7 +442,7 @@                                     &no_failure,                                     sizeof(int32_t))); -                     typename int32_t args[$int:max_failure_args+1];+                     typename int64_t args[$int:max_failure_args+1];                      CUDA_SUCCEED(                        cuMemcpyDtoH(&args,                                     ctx->global_failure_args,
src/Futhark/CodeGen/Backends/COpenCL/Boilerplate.hs view
@@ -41,7 +41,8 @@             escapeChar c = [c]          in concatMap escapeChar       onPart (ErrorString s) = printfEscape s-      onPart ErrorInt32 {} = "%d"+      onPart ErrorInt32 {} = "%lld"+      onPart ErrorInt64 {} = "%lld"       onFailure i (FailureMsg emsg@(ErrorMsg parts) backtrace) =         let msg = concatMap onPart parts ++ "\n" ++ printfEscape backtrace             msgargs = [[C.cexp|args[$int:j]|] | j <- [0 .. errorMsgNumArgs emsg -1]]@@ -375,7 +376,7 @@                      ctx->global_failure_args =                        clCreateBuffer(ctx->opencl.ctx,                                       CL_MEM_READ_WRITE,-                                      sizeof(cl_int)*($int:max_failure_args+1), NULL, &error);+                                      sizeof(int64_t)*($int:max_failure_args+1), NULL, &error);                      OPENCL_SUCCEED_OR_RETURN(error);                       // Load all the kernels.@@ -472,7 +473,7 @@                                          0, sizeof(cl_int), &no_failure,                                          0, NULL, NULL)); -                   typename cl_int args[$int:max_failure_args+1];+                   typename int64_t args[$int:max_failure_args+1];                    OPENCL_SUCCEED_OR_RETURN(                      clEnqueueReadBuffer(ctx->opencl.queue,                                          ctx->global_failure_args,
src/Futhark/CodeGen/Backends/GenericC.hs view
@@ -33,12 +33,13 @@      -- * Monadic compiler interface     CompilerM,-    CompilerState (compUserState),+    CompilerState (compUserState, compNameSrc),     getUserState,     modifyUserState,     contextContents,     contextFinalInits,     runCompilerM,+    inNewFunction,     cachingMemory,     blockScope,     compileFun,@@ -64,9 +65,16 @@     publicName,     contextType,     contextField,+    memToCType,+    cacheMem,+    fatMemory,+    rawMemCType,+    cproduct,+    fatMemType,      -- * Building Blocks     primTypeToCType,+    intTypeToCType,     copyMemoryDefaultSpace,   ) where@@ -209,6 +217,7 @@   free_all_mem <- collect $ mapM_ (uncurry unRefMem) =<< gets compDeclaredMem   let onPart (ErrorString s) = return ("%s", [C.cexp|$string:s|])       onPart (ErrorInt32 x) = ("%d",) <$> compileExp x+      onPart (ErrorInt64 x) = ("%lld",) <$> compileExp x   (formatstrs, formatargs) <- unzip <$> mapM onPart parts   let formatstr = "Error: " ++ concat formatstrs ++ "\n\nBacktrace:\n%s"   items@@ -403,6 +412,22 @@       const w {accItems = mempty}     ) +-- | Used when we, inside an existing 'CompilerM' action, want to+-- generate code for a new function.  Use this so that the compiler+-- understands that previously declared memory doesn't need to be+-- freed inside this action.+inNewFunction :: Bool -> CompilerM op s a -> CompilerM op s a+inNewFunction keep_cached m = do+  old_mem <- gets compDeclaredMem+  modify $ \s -> s {compDeclaredMem = mempty}+  x <- local noCached m+  modify $ \s -> s {compDeclaredMem = old_mem}+  return x+  where+    noCached env+      | keep_cached = env+      | otherwise = env {envCachedMem = mempty}+ item :: C.BlockItem -> CompilerM op s () item x = tell $ mempty {accItems = DL.singleton x} @@ -675,7 +700,9 @@   let setdef =         [C.cedecl|static int $id:(fatMemSet space) ($ty:ctx_ty *ctx, $ty:mty *lhs, $ty:mty *rhs, const char *lhs_desc) {   int ret = $id:(fatMemUnRef space)(ctx, lhs, lhs_desc);-  (*(rhs->references))++;+  if (rhs->references != NULL) {+    (*(rhs->references))++;+  }   *lhs = *rhs;   return ret; }@@ -1617,6 +1644,11 @@   let headerdefs =         [C.cunit| $esc:("// Headers\n")+/* We need to define _GNU_SOURCE before+   _any_ headers files are imported to get+   the usage statistics of a thread (i.e. have RUSAGE_THREAD) on GNU/Linux+   https://manpages.courier-mta.org/htmlman2/getrusage.2.html */+$esc:("#define _GNU_SOURCE") $esc:("#include <stdint.h>") $esc:("#include <stddef.h>") $esc:("#include <stdbool.h>")@@ -2097,7 +2129,7 @@       iexp' <- compileExp $ untyped iexp       return [C.cexp|$id:src[$exp:iexp']|]     compileLeaf (SizeOf t) =-      return [C.cexp|(typename int64_t)sizeof($ty:t')|]+      return [C.cexp|(typename int32_t)sizeof($ty:t')|]       where         t' = primTypeToCType t 
src/Futhark/CodeGen/Backends/GenericPython.hs view
@@ -1132,6 +1132,7 @@   e' <- compileExp e   let onPart (Imp.ErrorString s) = return ("%s", String s)       onPart (Imp.ErrorInt32 x) = ("%d",) <$> compileExp x+      onPart (Imp.ErrorInt64 x) = ("%d",) <$> compileExp x   (formatstrs, formatargs) <- unzip <$> mapM onPart parts   stm $     Assert
+ src/Futhark/CodeGen/Backends/MulticoreC.hs view
@@ -0,0 +1,703 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++-- | C code generator.  This module can convert a correct ImpCode+-- program to an equivalent C program.+module Futhark.CodeGen.Backends.MulticoreC+  ( compileProg,+    GC.CParts (..),+    GC.asLibrary,+    GC.asExecutable,+  )+where++import Control.Monad+import Data.FileEmbed+import qualified Data.Map as M+import Data.Maybe+import qualified Futhark.CodeGen.Backends.GenericC as GC+import Futhark.CodeGen.Backends.GenericC.Options+import Futhark.CodeGen.Backends.SimpleRep+import Futhark.CodeGen.ImpCode.Multicore+import qualified Futhark.CodeGen.ImpGen.Multicore as ImpGen+import Futhark.IR.MCMem (MCMem, Prog)+import Futhark.MonadFreshNames+import qualified Language.C.Quote.OpenCL as C+import qualified Language.C.Syntax as C++compileProg ::+  MonadFreshNames m =>+  Prog MCMem ->+  m (ImpGen.Warnings, GC.CParts)+compileProg =+  traverse+    ( GC.compileProg+        "multicore"+        operations+        generateContext+        ""+        [DefaultSpace]+        cliOptions+    )+    <=< ImpGen.compileProg+  where+    generateContext = do+      let multicore_defs_h = $(embedStringFile "rts/c/multicore_defs.h")+          multicore_util_h = $(embedStringFile "rts/c/multicore_util.h")+          subtask_queue_h = $(embedStringFile "rts/c/subtask_queue.h")+          scheduler_common_h = $(embedStringFile "rts/c/scheduler_common.h")+          scheduler_h = $(embedStringFile "rts/c/scheduler.h")+          scheduler_tune_h = $(embedStringFile "rts/c/scheduler_tune.h")++      mapM_+        GC.earlyDecl+        [C.cunit|+                              $esc:multicore_defs_h+                              $esc:multicore_util_h+                              $esc:subtask_queue_h+                              $esc:scheduler_common_h+                              $esc:scheduler_h+                             |]++      mapM_ GC.earlyDecl [C.cunit|int futhark_segred_tuning_program(struct futhark_context *ctx);|]+      mapM_ GC.libDecl [C.cunit|$esc:scheduler_tune_h|]++      cfg <- GC.publicDef "context_config" GC.InitDecl $ \s ->+        ( [C.cedecl|struct $id:s;|],+          [C.cedecl|struct $id:s { int debugging; int profiling; };|]+        )++      GC.publicDef_ "context_config_new" GC.InitDecl $ \s ->+        ( [C.cedecl|struct $id:cfg* $id:s(void);|],+          [C.cedecl|struct $id:cfg* $id:s(void) {+                                 struct $id:cfg *cfg = (struct $id:cfg*) malloc(sizeof(struct $id:cfg));+                                 if (cfg == NULL) {+                                   return NULL;+                                 }+                                 cfg->debugging = 0;+                                 cfg->profiling = 0;+                                 return cfg;+                               }|]+        )++      GC.publicDef_ "context_config_free" GC.InitDecl $ \s ->+        ( [C.cedecl|void $id:s(struct $id:cfg* cfg);|],+          [C.cedecl|void $id:s(struct $id:cfg* cfg) {+                                 free(cfg);+                               }|]+        )++      GC.publicDef_ "context_config_set_debugging" GC.InitDecl $ \s ->+        ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],+          [C.cedecl|void $id:s(struct $id:cfg* cfg, int detail) {+                          cfg->debugging = detail;+                        }|]+        )++      GC.publicDef_ "context_config_set_profiling" GC.InitDecl $ \s ->+        ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],+          [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag) {+                          cfg->profiling = flag;+                        }|]+        )++      GC.publicDef_ "context_config_set_logging" GC.InitDecl $ \s ->+        ( [C.cedecl|void $id:s(struct $id:cfg* cfg, int flag);|],+          [C.cedecl|void $id:s(struct $id:cfg* cfg, int detail) {+                                 /* Does nothing for this backend. */+                                 (void)cfg; (void)detail;+                               }|]+        )++      (fields, init_fields) <- GC.contextContents++      ctx <- GC.publicDef "context" GC.InitDecl $ \s ->+        ( [C.cedecl|struct $id:s;|],+          [C.cedecl|struct $id:s {+                          struct scheduler scheduler;+                          int detail_memory;+                          int debugging;+                          int profiling;+                          int profiling_paused;+                          typename lock_t lock;+                          char *error;+                          int total_runs;+                          long int total_runtime;+                          $sdecls:fields++                          // Tuning parameters+                          typename int64_t tuning_timing;+                          typename int64_t tuning_iter;+                        };|]+        )++      GC.publicDef_ "context_new" GC.InitDecl $ \s ->+        ( [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg);|],+          [C.cedecl|struct $id:ctx* $id:s(struct $id:cfg* cfg) {+                 struct $id:ctx* ctx = (struct $id:ctx*) malloc(sizeof(struct $id:ctx));+                 if (ctx == NULL) {+                   return NULL;+                 }++                 // Initialize rand()+                 fast_srand(time(0));+                 ctx->detail_memory = cfg->debugging;+                 ctx->debugging = cfg->debugging;+                 ctx->profiling = cfg->profiling;+                 ctx->profiling_paused = 0;+                 ctx->error = NULL;+                 create_lock(&ctx->lock);+                 ctx->scheduler.num_threads = num_processors();+                 if (ctx->scheduler.num_threads < 1) return NULL;++                 $stms:init_fields++                 // futhark_segred_tuning_program(ctx);++                 ctx->scheduler.workers = calloc(ctx->scheduler.num_threads, sizeof(struct worker));+                 if (ctx->scheduler.workers == NULL) return NULL;+                 num_workers = ctx->scheduler.num_threads;++                 worker_local = &ctx->scheduler.workers[0];+                 worker_local->tid = 0;+                 worker_local->scheduler = &ctx->scheduler;+                 CHECK_ERR(subtask_queue_init(&worker_local->q, 1024), "failed to init queue for worker %d\n", 0);+++                 for (int i = 1; i < ctx->scheduler.num_threads; i++) {+                   struct worker *cur_worker = &ctx->scheduler.workers[i];+                   memset(cur_worker, 0, sizeof(struct worker));+                   cur_worker->tid = i;+                   cur_worker->output_usage = 0;+                   cur_worker->scheduler = &ctx->scheduler;+                   CHECK_ERR(subtask_queue_init(&cur_worker->q, 1024), "failed to init queue for worker %d\n", i);++                   CHECK_ERR(pthread_create(&cur_worker->thread, NULL, &scheduler_worker,+                                            cur_worker),+                             "Failed to create worker %d\n", i);+                 }++                 init_constants(ctx);+++                 return ctx;+              }|]+        )++      GC.publicDef_ "context_free" GC.InitDecl $ \s ->+        ( [C.cedecl|void $id:s(struct $id:ctx* ctx);|],+          [C.cedecl|void $id:s(struct $id:ctx* ctx) {+                 free_constants(ctx);++                 // output_thread_usage(worker_local);+                 for (int i = 1; i < ctx->scheduler.num_threads; i++)+                 {+                   struct worker *cur_worker = &ctx->scheduler.workers[i];+                   cur_worker->dead = 1;+                   subtask_queue_destroy(&cur_worker->q);+                   CHECK_ERR(pthread_join(ctx->scheduler.workers[i].thread, NULL), "pthread_join");+                 }+++                 free(ctx->scheduler.workers);+                 free_lock(&ctx->lock);+                 free(ctx);+               }|]+        )++      GC.publicDef_ "context_sync" GC.InitDecl $ \s ->+        ( [C.cedecl|int $id:s(struct $id:ctx* ctx);|],+          [C.cedecl|int $id:s(struct $id:ctx* ctx) {+                                 (void)ctx;+                                 return 0;+                               }|]+        )++cliOptions :: [Option]+cliOptions =+  [ Option+      { optionLongName = "profile",+        optionShortName = Just 'P',+        optionArgument = NoArgument,+        optionAction = [C.cstm|futhark_context_config_set_profiling(cfg, 1);|],+        optionDescription = "Gather profiling information."+      }+  ]++operations :: GC.Operations Multicore ()+operations =+  GC.defaultOperations+    { GC.opsCompiler = compileOp,+      GC.opsCopy = copyMulticoreMemory,+      GC.opsCritical =+        -- The thread entering an API function is always considered+        -- the "first worker" - note that this might differ from the+        -- thread that created the context!  This likely only matters+        -- for entry points, since they are the only API functions+        -- that contain parallel operations.+        ( [C.citems|worker_local = &ctx->scheduler.workers[0];|],+          []+        )+    }++copyMulticoreMemory :: GC.Copy Multicore ()+copyMulticoreMemory destmem destidx DefaultSpace srcmem srcidx DefaultSpace nbytes =+  GC.copyMemoryDefaultSpace destmem destidx srcmem srcidx nbytes+copyMulticoreMemory _ _ destspace _ _ srcspace _ =+  error $ "Cannot copy to " ++ show destspace ++ " from " ++ show srcspace++closureFreeStructField :: VName -> Name+closureFreeStructField v =+  nameFromString "free_" <> nameFromString (pretty v)++closureRetvalStructField :: VName -> Name+closureRetvalStructField v =+  nameFromString "retval_" <> nameFromString (pretty v)++data ValueType = Prim | MemBlock | RawMem++compileFreeStructFields :: [VName] -> [(C.Type, ValueType)] -> [C.FieldGroup]+compileFreeStructFields = zipWith field+  where+    field name (ty, Prim) =+      [C.csdecl|$ty:ty $id:(closureFreeStructField name);|]+    field name (_, _) =+      [C.csdecl|$ty:defaultMemBlockType $id:(closureFreeStructField name);|]++compileRetvalStructFields :: [VName] -> [(C.Type, ValueType)] -> [C.FieldGroup]+compileRetvalStructFields = zipWith field+  where+    field name (ty, Prim) =+      [C.csdecl|$ty:ty *$id:(closureRetvalStructField name);|]+    field name (_, _) =+      [C.csdecl|$ty:defaultMemBlockType $id:(closureRetvalStructField name);|]++compileSetStructValues ::+  C.ToIdent a =>+  a ->+  [VName] ->+  [(C.Type, ValueType)] ->+  [C.Stm]+compileSetStructValues struct = zipWith field+  where+    field name (_, Prim) =+      [C.cstm|$id:struct.$id:(closureFreeStructField name)=$id:name;|]+    field name (_, MemBlock) =+      [C.cstm|$id:struct.$id:(closureFreeStructField name)=$id:name.mem;|]+    field name (_, RawMem) =+      [C.cstm|$id:struct.$id:(closureFreeStructField name)=$id:name;|]++compileSetRetvalStructValues ::+  C.ToIdent a =>+  a ->+  [VName] ->+  [(C.Type, ValueType)] ->+  [C.Stm]+compileSetRetvalStructValues struct = zipWith field+  where+    field name (_, Prim) =+      [C.cstm|$id:struct.$id:(closureRetvalStructField name)=&$id:name;|]+    field name (_, MemBlock) =+      [C.cstm|$id:struct.$id:(closureRetvalStructField name)=$id:name.mem;|]+    field name (_, RawMem) =+      [C.cstm|$id:struct.$id:(closureRetvalStructField name)=$id:name;|]++compileGetRetvalStructVals :: C.ToIdent a => a -> [VName] -> [(C.Type, ValueType)] -> [C.InitGroup]+compileGetRetvalStructVals struct = zipWith field+  where+    field name (ty, Prim) =+      [C.cdecl|$ty:ty $id:name = *$id:struct->$id:(closureRetvalStructField name);|]+    field name (ty, _) =+      [C.cdecl|$ty:ty $id:name =+                 {.desc = $string:(pretty name),+                 .mem = $id:struct->$id:(closureRetvalStructField name),+                 .size = 0, .references = NULL};|]++compileGetStructVals ::+  C.ToIdent a =>+  a ->+  [VName] ->+  [(C.Type, ValueType)] ->+  [C.InitGroup]+compileGetStructVals struct = zipWith field+  where+    field name (ty, Prim) =+      [C.cdecl|$ty:ty $id:name = $id:struct->$id:(closureFreeStructField name);|]+    field name (ty, _) =+      [C.cdecl|$ty:ty $id:name =+                 {.desc = $string:(pretty name),+                  .mem = $id:struct->$id:(closureFreeStructField name),+                  .size = 0, .references = NULL};|]++compileWriteBackResVals :: C.ToIdent a => a -> [VName] -> [(C.Type, ValueType)] -> [C.Stm]+compileWriteBackResVals struct = zipWith field+  where+    field name (_, Prim) =+      [C.cstm|*$id:struct->$id:(closureRetvalStructField name) = $id:name;|]+    field name (_, _) =+      [C.cstm|$id:struct->$id:(closureRetvalStructField name) = $id:name.mem;|]++paramToCType :: Param -> GC.CompilerM op s (C.Type, ValueType)+paramToCType (ScalarParam _ pt) = do+  let t = GC.primTypeToCType pt+  return (t, Prim)+paramToCType (MemParam name space') = mcMemToCType name space'++mcMemToCType :: VName -> Space -> GC.CompilerM op s (C.Type, ValueType)+mcMemToCType v space = do+  refcount <- GC.fatMemory space+  cached <- isJust <$> GC.cacheMem v+  return+    ( GC.fatMemType space,+      if refcount && not cached+        then MemBlock+        else RawMem+    )++functionRuntime :: Name -> C.Id+functionRuntime = (`C.toIdent` mempty) . (<> "_total_runtime")++functionRuns :: Name -> C.Id+functionRuns = (`C.toIdent` mempty) . (<> "_runs")++functionIter :: Name -> C.Id+functionIter = (`C.toIdent` mempty) . (<> "_iter")++multiCoreReport :: [(Name, Bool)] -> [C.BlockItem]+multiCoreReport names = report_kernels+  where+    report_kernels = concatMap reportKernel names+    max_name_len_pad = 40+    format_string name True =+      let name_s = nameToString name+          padding = replicate (max_name_len_pad - length name_s) ' '+       in unwords ["tid %2d -", name_s ++ padding, "ran %10d times; avg: %10ldus; total: %10ldus; time pr. iter %9.6f; iters %9ld; avg %ld\n"]+    format_string name False =+      let name_s = nameToString name+          padding = replicate (max_name_len_pad - length name_s) ' '+       in unwords ["        ", name_s ++ padding, "ran %10d times; avg: %10ldus; total: %10ldus; time pr. iter %9.6f; iters %9ld; avg %ld\n"]+    reportKernel (name, is_array) =+      let runs = functionRuns name+          total_runtime = functionRuntime name+          iters = functionIter name+       in if is_array+            then+              [ [C.citem|+                     for (int i = 0; i < ctx->scheduler.num_threads; i++) {+                       fprintf(stderr,+                         $string:(format_string name is_array),+                         i,+                         ctx->$id:runs[i],+                         (long int) ctx->$id:total_runtime[i] / (ctx->$id:runs[i] != 0 ? ctx->$id:runs[i] : 1),+                         (long int) ctx->$id:total_runtime[i],+                         (double) ctx->$id:total_runtime[i] /  (ctx->$id:iters[i] == 0 ? 1 : (double)ctx->$id:iters[i]),+                         (long int) (ctx->$id:iters[i]),+                         (long int) (ctx->$id:iters[i]) / (ctx->$id:runs[i] != 0 ? ctx->$id:runs[i] : 1)+                         );+                     }+                   |]+              ]+            else+              [ [C.citem|+                    fprintf(stderr,+                       $string:(format_string name is_array),+                       ctx->$id:runs,+                       (long int) ctx->$id:total_runtime / (ctx->$id:runs != 0 ? ctx->$id:runs : 1),+                       (long int) ctx->$id:total_runtime,+                       (double) ctx->$id:total_runtime /  (ctx->$id:iters == 0 ? 1 : (double)ctx->$id:iters),+                       (long int) (ctx->$id:iters),+                       (long int) (ctx->$id:iters) / (ctx->$id:runs != 0 ? ctx->$id:runs : 1));+                   |],+                [C.citem|ctx->total_runtime += ctx->$id:total_runtime;|],+                [C.citem|ctx->total_runs += ctx->$id:runs;|]+              ]++addBenchmarkFields :: Name -> Maybe VName -> GC.CompilerM op s ()+addBenchmarkFields name (Just _) = do+  GC.contextField (functionRuntime name) [C.cty|typename int64_t*|] $ Just [C.cexp|calloc(sizeof(typename int64_t), ctx->scheduler.num_threads)|]+  GC.contextField (functionRuns name) [C.cty|int*|] $ Just [C.cexp|calloc(sizeof(int), ctx->scheduler.num_threads)|]+  GC.contextField (functionIter name) [C.cty|typename int64_t*|] $ Just [C.cexp|calloc(sizeof(sizeof(typename int64_t)), ctx->scheduler.num_threads)|]+addBenchmarkFields name Nothing = do+  GC.contextField (functionRuntime name) [C.cty|typename int64_t|] $ Just [C.cexp|0|]+  GC.contextField (functionRuns name) [C.cty|int|] $ Just [C.cexp|0|]+  GC.contextField (functionIter name) [C.cty|typename int64_t|] $ Just [C.cexp|0|]++benchmarkCode :: Name -> Maybe VName -> [C.BlockItem] -> GC.CompilerM op s [C.BlockItem]+benchmarkCode name tid code = do+  addBenchmarkFields name tid+  return+    [C.citems|+     typename uint64_t $id:start;+     if (ctx->profiling && !ctx->profiling_paused) {+       $id:start = get_wall_time();+     }+     $items:code+     if (ctx->profiling && !ctx->profiling_paused) {+       typename uint64_t $id:end = get_wall_time();+       typename uint64_t elapsed = $id:end - $id:start;+       $items:(updateFields tid)+     }+     |]+  where+    start = name <> "_start"+    end = name <> "_end"+    updateFields Nothing =+      [C.citems|__atomic_fetch_add(&ctx->$id:(functionRuns name), 1, __ATOMIC_RELAXED);+                                            __atomic_fetch_add(&ctx->$id:(functionRuntime name), elapsed, __ATOMIC_RELAXED);+                                            __atomic_fetch_add(&ctx->$id:(functionIter name), iterations, __ATOMIC_RELAXED);|]+    updateFields (Just _tid') =+      [C.citems|ctx->$id:(functionRuns name)[tid]++;+                                            ctx->$id:(functionRuntime name)[tid] += elapsed;+                                            ctx->$id:(functionIter name)[tid] += iterations;|]++functionTiming :: Name -> C.Id+functionTiming = (`C.toIdent` mempty) . (<> "_total_time")++functionIterations :: Name -> C.Id+functionIterations = (`C.toIdent` mempty) . (<> "_total_iter")++addTimingFields :: Name -> GC.CompilerM op s ()+addTimingFields name = do+  GC.contextField (functionTiming name) [C.cty|typename int64_t|] $ Just [C.cexp|0|]+  GC.contextField (functionIterations name) [C.cty|typename int64_t|] $ Just [C.cexp|0|]++multicoreName :: String -> GC.CompilerM op s Name+multicoreName s = do+  s' <- newVName ("futhark_mc_" ++ s)+  return $ nameFromString $ baseString s' ++ "_" ++ show (baseTag s')++multicoreDef :: String -> (Name -> GC.CompilerM op s C.Definition) -> GC.CompilerM op s Name+multicoreDef s f = do+  s' <- multicoreName s+  GC.libDecl =<< f s'+  return s'++generateFunction ::+  C.ToIdent a =>+  M.Map VName Space ->+  String ->+  Code ->+  a ->+  [(VName, (C.Type, ValueType))] ->+  [(VName, (C.Type, ValueType))] ->+  VName ->+  VName ->+  GC.CompilerM Multicore s Name+generateFunction lexical basename code fstruct free retval tid ntasks = do+  let (fargs, fctypes) = unzip free+  let (retval_args, retval_ctypes) = unzip retval+  multicoreDef basename $ \s -> do+    fbody <- benchmarkCode s (Just tid) <=< GC.inNewFunction False $+      GC.cachingMemory lexical $+        \decl_cached free_cached -> GC.blockScope $ do+          mapM_ GC.item [C.citems|$decls:(compileGetStructVals fstruct fargs fctypes)|]+          mapM_ GC.item [C.citems|$decls:(compileGetRetvalStructVals fstruct retval_args retval_ctypes)|]+          mapM_ GC.item decl_cached+          code' <- GC.blockScope $ GC.compileCode code+          mapM_ GC.item [C.citems|$items:code'|]+          mapM_ GC.stm free_cached+    return+      [C.cedecl|int $id:s(void *args, typename int64_t iterations, int tid, struct scheduler_info info) {+                           int err = 0;+                           int $id:tid = tid;+                           int $id:ntasks = info.nsubtasks;+                           struct $id:fstruct *$id:fstruct = (struct $id:fstruct*) args;+                           struct futhark_context *ctx = $id:fstruct->ctx;+                           $items:fbody+                           $stms:(compileWriteBackResVals fstruct retval_args retval_ctypes)+                           cleanup: {}+                           return err;+                      }|]++prepareTaskStruct ::+  String ->+  [VName] ->+  [(C.Type, ValueType)] ->+  [VName] ->+  [(C.Type, ValueType)] ->+  GC.CompilerM Multicore s Name+prepareTaskStruct name free_args free_ctypes retval_args retval_ctypes = do+  fstruct <- multicoreDef name $ \s ->+    return+      [C.cedecl|struct $id:s {+                       struct futhark_context *ctx;+                       $sdecls:(compileFreeStructFields free_args free_ctypes)+                       $sdecls:(compileRetvalStructFields retval_args retval_ctypes)+                     };|]+  GC.decl [C.cdecl|struct $id:fstruct $id:fstruct;|]+  GC.stm [C.cstm|$id:fstruct.ctx = ctx;|]+  GC.stms [C.cstms|$stms:(compileSetStructValues fstruct free_args free_ctypes)|]+  GC.stms [C.cstms|$stms:(compileSetRetvalStructValues fstruct retval_args retval_ctypes)|]+  return fstruct++-- Generate a segop function for top_level and potentially nested SegOp code+compileOp :: GC.OpCompiler Multicore ()+compileOp (Segop name params seq_task par_task retvals (SchedulerInfo nsubtask e sched)) = do+  let (ParallelTask seq_code tid) = seq_task+  free_ctypes <- mapM paramToCType params+  retval_ctypes <- mapM paramToCType retvals+  let free_args = map paramName params+      retval_args = map paramName retvals+      free = zip free_args free_ctypes+      retval = zip retval_args retval_ctypes++  e' <- GC.compileExp e++  let lexical = lexicalMemoryUsage $ Function False [] params seq_code [] []++  fstruct <-+    prepareTaskStruct "task" free_args free_ctypes retval_args retval_ctypes++  fpar_task <- generateFunction lexical (name ++ "_task") seq_code fstruct free retval tid nsubtask+  addTimingFields fpar_task++  let ftask_name = fstruct <> "_task"+  GC.decl [C.cdecl|struct scheduler_segop $id:ftask_name;|]+  GC.stm [C.cstm|$id:ftask_name.args = &$id:fstruct;|]+  GC.stm [C.cstm|$id:ftask_name.top_level_fn = $id:fpar_task;|]+  GC.stm [C.cstm|$id:ftask_name.name = $string:(nameToString fpar_task);|]+  GC.stm [C.cstm|$id:ftask_name.iterations = $exp:e';|]+  -- Create the timing fields for the task+  GC.stm [C.cstm|$id:ftask_name.task_time = &ctx->$id:(functionTiming fpar_task);|]+  GC.stm [C.cstm|$id:ftask_name.task_iter = &ctx->$id:(functionIterations fpar_task);|]++  case sched of+    Dynamic -> GC.stm [C.cstm|$id:ftask_name.sched = DYNAMIC;|]+    Static -> GC.stm [C.cstm|$id:ftask_name.sched = STATIC;|]++  -- Generate the nested segop function if available+  fnpar_task <- case par_task of+    Just (ParallelTask nested_code nested_tid) -> do+      let lexical_nested = lexicalMemoryUsage $ Function False [] params nested_code [] []+      fnpar_task <- generateFunction lexical_nested (name ++ "_nested_task") nested_code fstruct free retval nested_tid nsubtask+      GC.stm [C.cstm|$id:ftask_name.nested_fn = $id:fnpar_task;|]+      return $ zip [fnpar_task] [True]+    Nothing -> do+      GC.stm [C.cstm|$id:ftask_name.nested_fn=NULL;|]+      return mempty++  let ftask_err = fpar_task <> "_err"+  let code =+        [C.citems|int $id:ftask_err = scheduler_prepare_task(&ctx->scheduler, &$id:ftask_name);+                  if ($id:ftask_err != 0) {+                    err = 1; goto cleanup;+                  }|]++  mapM_ GC.item code++  -- Add profile fields for -P option+  mapM_ GC.profileReport $ multiCoreReport $ (fpar_task, True) : fnpar_task+compileOp (ParLoop s' i prebody body postbody free tid) = do+  free_ctypes <- mapM paramToCType free+  let free_args = map paramName free++  let lexical =+        lexicalMemoryUsage $+          Function False [] free (prebody <> body) [] []++  fstruct <-+    prepareTaskStruct (s' ++ "_parloop_struct") free_args free_ctypes mempty mempty++  ftask <- multicoreDef (s' ++ "_parloop") $ \s -> do+    fbody <- benchmarkCode s (Just tid)+      <=< GC.inNewFunction False+      $ GC.cachingMemory lexical $+        \decl_cached free_cached -> GC.blockScope $ do+          mapM_+            GC.item+            [C.citems|$decls:(compileGetStructVals fstruct free_args free_ctypes)|]++          mapM_ GC.item decl_cached++          GC.decl [C.cdecl|typename int64_t iterations = end - start;|]+          GC.decl [C.cdecl|typename int64_t $id:i = start;|]+          GC.compileCode prebody+          body' <- GC.blockScope $ GC.compileCode body+          GC.stm+            [C.cstm|for (; $id:i < end; $id:i++) {+                       $items:body'+                     }|]+          GC.compileCode postbody+          GC.stm [C.cstm|cleanup: {}|]+          mapM_ GC.stm free_cached++    return+      [C.cedecl|int $id:s(void *args, typename int64_t start, typename int64_t end, int $id:tid, int tid) {+                       int err = 0;+                       struct $id:fstruct *$id:fstruct = (struct $id:fstruct*) args;+                       struct futhark_context *ctx = $id:fstruct->ctx;+                       $items:fbody+                       return err;+                     }|]++  let ftask_name = ftask <> "_task"+  GC.decl [C.cdecl|struct scheduler_parloop $id:ftask_name;|]+  GC.stm [C.cstm|$id:ftask_name.name = $string:(nameToString ftask);|]+  GC.stm [C.cstm|$id:ftask_name.fn = $id:ftask;|]+  GC.stm [C.cstm|$id:ftask_name.args = &$id:fstruct;|]+  GC.stm [C.cstm|$id:ftask_name.iterations = iterations;|]+  GC.stm [C.cstm|$id:ftask_name.info = info;|]++  let ftask_err = ftask <> "_err"+      ftask_total = ftask <> "_total"+  code' <-+    benchmarkCode+      ftask_total+      Nothing+      [C.citems|int $id:ftask_err = scheduler_execute_task(&ctx->scheduler, &$id:ftask_name);+               if ($id:ftask_err != 0) {+                 err = 1;+                 goto cleanup;+               }|]++  mapM_ GC.item code'+  mapM_ GC.profileReport $ multiCoreReport $ zip [ftask, ftask_total] [True, False]+compileOp (Atomic aop) =+  atomicOps aop++doAtomic ::+  (C.ToIdent a1, C.ToIdent a2) =>+  a1 ->+  a2 ->+  Count u (TExp Int32) ->+  Exp ->+  String ->+  C.Type ->+  GC.CompilerM op s ()+doAtomic old arr ind val op ty = do+  ind' <- GC.compileExp $ untyped $ unCount ind+  val' <- GC.compileExp val+  GC.stm [C.cstm|$id:old = $id:op(&(($ty:ty*)$id:arr.mem)[$exp:ind'], ($ty:ty) $exp:val', __ATOMIC_RELAXED);|]++atomicOps :: AtomicOp -> GC.CompilerM op s ()+atomicOps (AtomicCmpXchg t old arr ind res val) = do+  ind' <- GC.compileExp $ untyped $ unCount ind+  new_val' <- GC.compileExp val+  let cast = [C.cty|$ty:(GC.primTypeToCType t)*|]+  GC.stm+    [C.cstm|$id:res = $id:op(&(($ty:cast)$id:arr.mem)[$exp:ind'],+                ($ty:cast)&$id:old,+                 $exp:new_val',+                 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);|]+  where+    op :: String+    op = "__atomic_compare_exchange_n"+atomicOps (AtomicXchg t old arr ind val) = do+  ind' <- GC.compileExp $ untyped $ unCount ind+  val' <- GC.compileExp val+  let cast = [C.cty|$ty:(GC.primTypeToCType t)*|]+  GC.stm [C.cstm|$id:old = $id:op(&(($ty:cast)$id:arr.mem)[$exp:ind'], $exp:val', __ATOMIC_SEQ_CST);|]+  where+    op :: String+    op = "__atomic_exchange_n"+atomicOps (AtomicAdd t old arr ind val) =+  doAtomic old arr ind val "__atomic_fetch_add" [C.cty|$ty:(GC.intTypeToCType t)|]+atomicOps (AtomicSub t old arr ind val) =+  doAtomic old arr ind val "__atomic_fetch_sub" [C.cty|$ty:(GC.intTypeToCType t)|]+atomicOps (AtomicAnd t old arr ind val) =+  doAtomic old arr ind val "__atomic_fetch_and" [C.cty|$ty:(GC.intTypeToCType t)|]+atomicOps (AtomicOr t old arr ind val) =+  doAtomic old arr ind val "__atomic_fetch_or" [C.cty|$ty:(GC.intTypeToCType t)|]+atomicOps (AtomicXor t old arr ind val) =+  doAtomic old arr ind val "__atomic_fetch_xor" [C.cty|$ty:(GC.intTypeToCType t)|]
src/Futhark/CodeGen/Backends/PyOpenCL/Boilerplate.hs view
@@ -82,6 +82,7 @@      onPart (ErrorString s) = formatEscape s     onPart ErrorInt32 {} = "{}"+    onPart ErrorInt64 {} = "{}"  sizeClassesToPython :: M.Map Name SizeClass -> PyExp sizeClassesToPython = Dict . map f . M.toList
src/Futhark/CodeGen/Backends/SimpleRep.hs view
@@ -6,6 +6,7 @@   ( tupleField,     funName,     defaultMemBlockType,+    intTypeToCType,     primTypeToCType,     signedPrimTypeToCType, 
src/Futhark/CodeGen/ImpCode.hs view
@@ -41,6 +41,7 @@     ErrorMsgPart (..),     errorMsgArgTypes,     ArrayContents (..),+    declaredIn,     lexicalMemoryUsage,     calledFuncs, @@ -302,7 +303,8 @@     go f (Comment _ x) = f x     go _ _ = mempty -    declared (DeclareMem mem space) = M.singleton mem space+    declared (DeclareMem mem space) =+      M.singleton mem space     declared x = go declared x      set (SetMem x y _) = namesFromList [x, y]@@ -364,7 +366,7 @@  -- | Convert a count of elements into a count of bytes, given the -- per-element size.-withElemType :: Count Elements (TExp Int32) -> PrimType -> Count Bytes (TExp Int64)+withElemType :: Count Elements (TExp Int64) -> PrimType -> Count Bytes (TExp Int64) withElemType (Count e) t =   bytes $ sExt64 e * isInt64 (LeafExp (SizeOf t) (IntType Int64)) 
src/Futhark/CodeGen/ImpCode/Kernels.hs view
@@ -165,17 +165,17 @@ -- This old value is stored in the first 'VName'.  The second 'VName' -- is the memory block to update.  The 'Exp' is the new value. data AtomicOp-  = AtomicAdd IntType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicFAdd FloatType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicSMax IntType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicSMin IntType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicUMax IntType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicUMin IntType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicAnd IntType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicOr IntType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicXor IntType VName VName (Count Elements (Imp.TExp Int32)) Exp-  | AtomicCmpXchg PrimType VName VName (Count Elements (Imp.TExp Int32)) Exp Exp-  | AtomicXchg PrimType VName VName (Count Elements (Imp.TExp Int32)) Exp+  = AtomicAdd IntType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicFAdd FloatType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicSMax IntType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicSMin IntType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicUMax IntType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicUMin IntType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicAnd IntType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicOr IntType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicXor IntType VName VName (Count Elements (Imp.TExp Int64)) Exp+  | AtomicCmpXchg PrimType VName VName (Count Elements (Imp.TExp Int64)) Exp Exp+  | AtomicXchg PrimType VName VName (Count Elements (Imp.TExp Int64)) Exp   deriving (Show)  instance FreeIn AtomicOp where
+ src/Futhark/CodeGen/ImpCode/Multicore.hs view
@@ -0,0 +1,126 @@+-- | Multicore imperative code.+module Futhark.CodeGen.ImpCode.Multicore+  ( Program,+    Function,+    FunctionT (Function),+    Code,+    Multicore (..),+    Scheduling (..),+    SchedulerInfo (..),+    AtomicOp (..),+    ParallelTask (..),+    module Futhark.CodeGen.ImpCode,+  )+where++import Futhark.CodeGen.ImpCode hiding (Code, Function)+import qualified Futhark.CodeGen.ImpCode as Imp+import Futhark.Util.Pretty++-- | An imperative program.+type Program = Imp.Functions Multicore++-- | An imperative function.+type Function = Imp.Function Multicore++-- | A piece of imperative code, with multicore operations inside.+type Code = Imp.Code Multicore++-- | A multicore operation.+data Multicore+  = Segop String [Param] ParallelTask (Maybe ParallelTask) [Param] SchedulerInfo+  | ParLoop String VName Code Code Code [Param] VName+  | Atomic AtomicOp++-- | Atomic operations return the value stored before the update.+-- This old value is stored in the first 'VName'.  The second 'VName'+-- is the memory block to update.  The 'Exp' is the new value.+data AtomicOp+  = AtomicAdd IntType VName VName (Count Elements (Imp.TExp Int32)) Exp+  | AtomicSub IntType VName VName (Count Elements (Imp.TExp Int32)) Exp+  | AtomicAnd IntType VName VName (Count Elements (Imp.TExp Int32)) Exp+  | AtomicOr IntType VName VName (Count Elements (Imp.TExp Int32)) Exp+  | AtomicXor IntType VName VName (Count Elements (Imp.TExp Int32)) Exp+  | AtomicXchg PrimType VName VName (Count Elements (Imp.TExp Int32)) Exp+  | AtomicCmpXchg PrimType VName VName (Count Elements (Imp.TExp Int32)) VName Exp+  deriving (Show)++instance FreeIn AtomicOp where+  freeIn' (AtomicAdd _ _ arr i x) = freeIn' arr <> freeIn' i <> freeIn' x+  freeIn' (AtomicSub _ _ arr i x) = freeIn' arr <> freeIn' i <> freeIn' x+  freeIn' (AtomicAnd _ _ arr i x) = freeIn' arr <> freeIn' i <> freeIn' x+  freeIn' (AtomicOr _ _ arr i x) = freeIn' arr <> freeIn' i <> freeIn' x+  freeIn' (AtomicXor _ _ arr i x) = freeIn' arr <> freeIn' i <> freeIn' x+  freeIn' (AtomicCmpXchg _ _ arr i retval x) = freeIn' arr <> freeIn' i <> freeIn' x <> freeIn' retval+  freeIn' (AtomicXchg _ _ arr i x) = freeIn' arr <> freeIn' i <> freeIn' x++data SchedulerInfo = SchedulerInfo+  { nsubtasks :: VName, -- The variable that describes how many subtasks the scheduler created+    iterations :: Imp.Exp, -- The number of total iterations for a task+    scheduling :: Scheduling -- The type scheduling for the task+  }++data ParallelTask = ParallelTask+  { task_code :: Code,+    flatTid :: VName -- The variable for the thread id execution the code+  }++-- | Whether the Scheduler should schedule the tasks as Dynamic+-- or it is restainted to Static+data Scheduling+  = Dynamic+  | Static++instance Pretty Scheduling where+  ppr Dynamic = text "Dynamic"+  ppr Static = text "Static"++-- TODO fix all of this!+instance Pretty SchedulerInfo where+  ppr (SchedulerInfo nsubtask i sched) =+    text "SchedulingInfo"+      <+> text "number of subtasks"+      <+> ppr nsubtask+      <+> text "scheduling"+      <+> ppr sched+      <+> text "iter"+      <+> ppr i++instance Pretty ParallelTask where+  ppr (ParallelTask code _) =+    ppr code++instance Pretty Multicore where+  ppr (Segop s free _par_code seq_code retval scheduler) =+    text "parfor"+      <+> ppr scheduler+      <+> ppr free+      <+> text s+      <+> text "seq_code"+      <+> nestedBlock "{" "}" (ppr seq_code)+      <+> text "retvals"+      <+> ppr retval+  ppr (ParLoop s i prebody body postbody params info) =+    text "parloop" <+> ppr s <+> ppr i+      <+> ppr prebody+      <+> ppr params+      <+> ppr info+      <+> langle+      <+> nestedBlock "{" "}" (ppr body)+      <+> ppr postbody+  ppr (Atomic _) = text "AtomicOp"++instance FreeIn SchedulerInfo where+  freeIn' (SchedulerInfo nsubtask iter _) =+    freeIn' iter <> freeIn' nsubtask++instance FreeIn ParallelTask where+  freeIn' (ParallelTask code _) =+    freeIn' code++instance FreeIn Multicore where+  freeIn' (Segop _ _ par_code seq_code _ info) =+    freeIn' par_code <> freeIn' seq_code <> freeIn' info+  freeIn' (ParLoop _ _ prebody body postbody _ _) =+    freeIn' prebody <> fvBind (Imp.declaredIn prebody) (freeIn' $ body <> postbody)+  freeIn' (Atomic aop) = freeIn' aop
src/Futhark/CodeGen/ImpGen.hs view
@@ -156,9 +156,9 @@ type CopyCompiler lore r op =   PrimType ->   MemLocation ->-  Slice (Imp.TExp Int32) ->+  Slice (Imp.TExp Int64) ->   MemLocation ->-  Slice (Imp.TExp Int32) ->+  Slice (Imp.TExp Int64) ->   ImpM lore r op ()  -- | An alternate way of compiling an allocation.@@ -191,7 +191,7 @@ data MemLocation = MemLocation   { memLocationName :: VName,     memLocationShape :: [Imp.DimSize],-    memLocationIxFun :: IxFun.IxFun (Imp.TExp Int32)+    memLocationIxFun :: IxFun.IxFun (Imp.TExp Int64)   }   deriving (Eq, Show) @@ -621,7 +621,7 @@         Nothing -> do           out <- imp $ newVName "out_arrsize"           tell-            ( [Imp.ScalarParam out int32],+            ( [Imp.ScalarParam out int64],               M.singleton x $ ScalarDestination out             )           put (memseen, M.insert x out arrseen)@@ -773,7 +773,7 @@     ForLoop i _ bound loopvars -> do       let setLoopParam (p, a)             | Prim _ <- paramType p =-              copyDWIM (paramName p) [] (Var a) [DimFix $ Imp.vi32 i]+              copyDWIM (paramName p) [] (Var a) [DimFix $ Imp.vi64 i]             | otherwise =               return () @@ -828,22 +828,22 @@     uncurry warn loc "Safety check required at run-time." defCompileBasicOp (Pattern _ [pe]) (Index src slice)   | Just idxs <- sliceIndices slice =-    copyDWIM (patElemName pe) [] (Var src) $ map (DimFix . toInt32Exp) idxs+    copyDWIM (patElemName pe) [] (Var src) $ map (DimFix . toInt64Exp) idxs defCompileBasicOp _ Index {} =   return () defCompileBasicOp (Pattern _ [pe]) (Update _ slice se) =-  sUpdate (patElemName pe) (map (fmap toInt32Exp) slice) se+  sUpdate (patElemName pe) (map (fmap toInt64Exp) slice) se defCompileBasicOp (Pattern _ [pe]) (Replicate (Shape ds) se) = do   ds' <- mapM toExp ds   is <- replicateM (length ds) (newVName "i")-  copy_elem <- collect $ copyDWIM (patElemName pe) (map (DimFix . Imp.vi32) is) se []+  copy_elem <- collect $ copyDWIM (patElemName pe) (map (DimFix . Imp.vi64) is) se []   emit $ foldl (.) id (zipWith Imp.For is ds') copy_elem defCompileBasicOp _ Scratch {} =   return () defCompileBasicOp (Pattern [] [pe]) (Iota n e s it) = do   e' <- toExp e   s' <- toExp s-  sFor "i" (toInt32Exp n) $ \i -> do+  sFor "i" (toInt64Exp n) $ \i -> do     let i' = sExt it $ untyped i     x <-       dPrimV "x" $@@ -856,16 +856,16 @@ defCompileBasicOp (Pattern _ [pe]) (Manifest _ src) =   copyDWIM (patElemName pe) [] (Var src) [] defCompileBasicOp (Pattern _ [pe]) (Concat i x ys _) = do-  offs_glb <- dPrimV "tmp_offs" (0 :: Imp.TExp Int32)+  offs_glb <- dPrimV "tmp_offs" 0    forM_ (x : ys) $ \y -> do     y_dims <- arrayDims <$> lookupType y     let rows = case drop i y_dims of           [] -> error $ "defCompileBasicOp Concat: empty array shape for " ++ pretty y-          r : _ -> toInt32Exp r+          r : _ -> toInt64Exp r         skip_dims = take i y_dims         sliceAllDim d = DimSlice 0 d 1-        skip_slices = map (sliceAllDim . toInt32Exp) skip_dims+        skip_slices = map (sliceAllDim . toInt64Exp) skip_dims         destslice = skip_slices ++ [DimSlice (tvExp offs_glb) rows 1]     copyDWIM (patElemName pe) destslice (Var y) []     offs_glb <-- tvExp offs_glb + rows@@ -877,7 +877,7 @@     static_array <- newVNameForFun "static_array"     emit $ Imp.DeclareArray static_array dest_space t $ Imp.ArrayValues vs     let static_src =-          MemLocation static_array [intConst Int32 $ fromIntegral $ length es] $+          MemLocation static_array [intConst Int64 $ fromIntegral $ length es] $             IxFun.iota [fromIntegral $ length es]         entry = MemVar Nothing $ MemEntry dest_space     addVar static_array entry@@ -1216,7 +1216,7 @@  fullyIndexArray ::   VName ->-  [Imp.TExp Int32] ->+  [Imp.TExp Int64] ->   ImpM lore r op (VName, Imp.Space, Count Elements (Imp.TExp Int64)) fullyIndexArray name indices = do   arr <- lookupArray name@@ -1224,7 +1224,7 @@  fullyIndexArray' ::   MemLocation ->-  [Imp.TExp Int32] ->+  [Imp.TExp Int64] ->   ImpM lore r op (VName, Imp.Space, Count Elements (Imp.TExp Int64)) fullyIndexArray' (MemLocation mem _ ixfun) indices = do   space <- entryMemSpace <$> lookupMemory mem@@ -1233,13 +1233,10 @@           let (zero_is, is) = splitFromEnd (length ds) indices            in map (const 0) zero_is ++ is         _ -> indices--      ixfun64 = fmap sExt64 ixfun-      indices64 = fmap sExt64 indices'   return     ( mem,       space,-      elements $ IxFun.index ixfun64 indices64+      elements $ IxFun.index ixfun indices'     )  -- More complicated read/write operations that use index functions.@@ -1253,15 +1250,15 @@ isMapTransposeCopy ::   PrimType ->   MemLocation ->-  Slice (Imp.TExp Int32) ->+  Slice (Imp.TExp Int64) ->   MemLocation ->-  Slice (Imp.TExp Int32) ->+  Slice (Imp.TExp Int64) ->   Maybe-    ( Imp.TExp Int32,-      Imp.TExp Int32,-      Imp.TExp Int32,-      Imp.TExp Int32,-      Imp.TExp Int32+    ( Imp.TExp Int64,+      Imp.TExp Int64,+      Imp.TExp Int64,+      Imp.TExp Int64,+      Imp.TExp Int64     ) isMapTransposeCopy   bt@@ -1334,16 +1331,16 @@         $ transposeArgs           pt           destmem-          (bytes $ sExt64 destoffset)+          (bytes destoffset)           srcmem-          (bytes $ sExt64 srcoffset)-          (sExt64 num_arrays)-          (sExt64 size_x)-          (sExt64 size_y)+          (bytes srcoffset)+          num_arrays+          size_x+          size_y   | Just destoffset <--      IxFun.linearWithOffset (IxFun.slice dest_ixfun64 destslice64) pt_size,+      IxFun.linearWithOffset (IxFun.slice dest_ixfun destslice) pt_size,     Just srcoffset <--      IxFun.linearWithOffset (IxFun.slice src_ixfun64 srcslice64) pt_size = do+      IxFun.linearWithOffset (IxFun.slice src_ixfun srcslice) pt_size = do     srcspace <- entryMemSpace <$> lookupMemory srcmem     destspace <- entryMemSpace <$> lookupMemory destmem     if isScalarSpace srcspace || isScalarSpace destspace@@ -1367,11 +1364,6 @@     MemLocation destmem _ dest_ixfun = dest     MemLocation srcmem _ src_ixfun = src -    dest_ixfun64 = fmap sExt64 dest_ixfun-    destslice64 = map (fmap sExt64) destslice-    src_ixfun64 = fmap sExt64 src_ixfun-    srcslice64 = map (fmap sExt64) srcslice-     isScalarSpace ScalarSpace {} = True     isScalarSpace _ = False @@ -1379,7 +1371,7 @@ copyElementWise bt dest destslice src srcslice = do   let bounds = sliceDims srcslice   is <- replicateM (length bounds) (newVName "i")-  let ivars = map Imp.vi32 is+  let ivars = map Imp.vi64 is   (destmem, destspace, destidx) <-     fullyIndexArray' dest $ fixSlice destslice ivars   (srcmem, srcspace, srcidx) <-@@ -1395,9 +1387,9 @@ copyArrayDWIM ::   PrimType ->   MemLocation ->-  [DimIndex (Imp.TExp Int32)] ->+  [DimIndex (Imp.TExp Int64)] ->   MemLocation ->-  [DimIndex (Imp.TExp Int32)] ->+  [DimIndex (Imp.TExp Int64)] ->   ImpM lore r op (Imp.Code op) copyArrayDWIM   bt@@ -1419,9 +1411,9 @@           Imp.index srcmem srcoffset bt srcspace vol     | otherwise = do       let destslice' =-            fullSliceNum (map toInt32Exp destshape) destslice+            fullSliceNum (map toInt64Exp destshape) destslice           srcslice' =-            fullSliceNum (map toInt32Exp srcshape) srcslice+            fullSliceNum (map toInt64Exp srcshape) srcslice           destrank = length $ sliceDims destslice'           srcrank = length $ sliceDims srcslice'       if destrank /= srcrank@@ -1445,9 +1437,9 @@ -- instead of a variable name. copyDWIMDest ::   ValueDestination ->-  [DimIndex (Imp.TExp Int32)] ->+  [DimIndex (Imp.TExp Int64)] ->   SubExp ->-  [DimIndex (Imp.TExp Int32)] ->+  [DimIndex (Imp.TExp Int64)] ->   ImpM lore r op () copyDWIMDest _ _ (Constant v) (_ : _) =   error $@@ -1539,9 +1531,9 @@ -- Thing.  Both destination and source must be in scope. copyDWIM ::   VName ->-  [DimIndex (Imp.TExp Int32)] ->+  [DimIndex (Imp.TExp Int64)] ->   SubExp ->-  [DimIndex (Imp.TExp Int32)] ->+  [DimIndex (Imp.TExp Int64)] ->   ImpM lore r op () copyDWIM dest dest_slice src src_slice = do   dest_entry <- lookupVar dest@@ -1558,9 +1550,9 @@ -- | As 'copyDWIM', but implicitly 'DimFix'es the indexes. copyDWIMFix ::   VName ->-  [Imp.TExp Int32] ->+  [Imp.TExp Int64] ->   SubExp ->-  [Imp.TExp Int32] ->+  [Imp.TExp Int64] ->   ImpM lore r op () copyDWIMFix dest dest_is src src_is =   copyDWIM dest (map DimFix dest_is) src (map DimFix src_is)@@ -1589,7 +1581,7 @@ typeSize t =   Imp.bytes $     isInt64 (Imp.LeafExp (Imp.SizeOf $ elemType t) int64)-      * product (map (sExt64 . toInt32Exp) (arrayDims t))+      * product (map toInt64Exp (arrayDims t))  --- Building blocks for constructing code. @@ -1664,14 +1656,14 @@ sArrayInMem name pt shape mem =   sArray name pt shape $     ArrayIn mem $-      IxFun.iota $ map (isInt32 . primExpFromSubExp int32) $ shapeDims shape+      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 lore r op VName sAllocArrayPerm name pt shape space perm = do   let permuted_dims = rearrangeShape perm $ shapeDims shape   mem <- sAlloc (name ++ "_mem") (typeSize (Array pt shape NoUniqueness)) space-  let iota_ixfun = IxFun.iota $ map (isInt32 . primExpFromSubExp int32) permuted_dims+  let iota_ixfun = IxFun.iota $ map (isInt64 . primExpFromSubExp int64) permuted_dims   sArray name pt shape $     ArrayIn mem $ IxFun.permute iota_ixfun $ rearrangeInverse perm @@ -1686,30 +1678,30 @@   let num_elems = case vs of         Imp.ArrayValues vs' -> length vs'         Imp.ArrayZeros n -> fromIntegral n-      shape = Shape [intConst Int32 $ toInteger num_elems]+      shape = Shape [intConst Int64 $ toInteger num_elems]   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] -sWrite :: VName -> [Imp.TExp Int32] -> Imp.Exp -> ImpM lore r op ()+sWrite :: VName -> [Imp.TExp Int64] -> Imp.Exp -> ImpM lore r op () sWrite arr is v = do   (mem, space, offset) <- fullyIndexArray arr is   vol <- asks envVolatility   emit $ Imp.Write mem offset (primExpType v) space vol v -sUpdate :: VName -> Slice (Imp.TExp Int32) -> SubExp -> ImpM lore r op ()+sUpdate :: VName -> Slice (Imp.TExp Int64) -> SubExp -> ImpM lore r op () sUpdate arr slice v = copyDWIM arr slice v []  sLoopNest ::   Shape ->-  ([Imp.TExp Int32] -> ImpM lore r op ()) ->+  ([Imp.TExp Int64] -> ImpM lore r op ()) ->   ImpM lore r op () sLoopNest = sLoopNest' [] . shapeDims   where     sLoopNest' is [] f = f $ reverse is     sLoopNest' is (d : ds) f =-      sFor "nest_i" (toInt32Exp d) $ \i -> sLoopNest' (i : is) ds f+      sFor "nest_i" (toInt64Exp d) $ \i -> sLoopNest' (i : is) ds f  -- | Untyped assignment. (<~~) :: VName -> Imp.Exp -> ImpM lore r op ()
src/Futhark/CodeGen/ImpGen/Kernels.hs view
@@ -188,7 +188,7 @@   x' <- toExp x   s' <- toExp s -  sIota (patElemName pe) (toInt32Exp n) x' s' et+  sIota (patElemName pe) (toInt64Exp n) x' s' et expCompiler (Pattern _ [pe]) (BasicOp (Replicate _ se)) =   sReplicate (patElemName pe) se -- Allocation in the "local" space is just a placeholder.@@ -243,7 +243,7 @@         IxFun.linearWithOffset (IxFun.slice destIxFun destslice) bt_size,       Just srcoffset <-         IxFun.linearWithOffset (IxFun.slice srcIxFun srcslice) bt_size = do-      let num_elems = Imp.elements $ product $ map toInt32Exp srcshape+      let num_elems = Imp.elements $ product $ map toInt64Exp srcshape       srcspace <- entryMemSpace <$> lookupMemory srcmem       destspace <- entryMemSpace <$> lookupMemory destmem       emit $
src/Futhark/CodeGen/ImpGen/Kernels/Base.hs view
@@ -68,8 +68,8 @@     kernelGlobalThreadIdVar :: VName,     kernelLocalThreadIdVar :: VName,     kernelGroupIdVar :: VName,-    kernelNumGroups :: Imp.TExp Int32,-    kernelGroupSize :: Imp.TExp Int32,+    kernelNumGroups :: Imp.TExp Int64,+    kernelGroupSize :: Imp.TExp Int64,     kernelNumThreads :: Imp.TExp Int32,     kernelWaveSize :: Imp.TExp Int32,     kernelThreadActive :: Imp.TExp Bool,@@ -102,7 +102,7 @@   localEnv f m   where     mkMap ltid dims = do-      let dims' = map toInt32Exp dims+      let dims' = map (sExt32 . toInt64Exp) dims       ids' <- mapM (dPrimVE "ltid_pre") $ unflattenIndex dims' ltid       return (dims, ids') @@ -140,16 +140,16 @@   ImpM lore r op () splitSpace (Pattern [] [size]) o w i elems_per_thread = do   num_elements <- Imp.elements . TPrimExp <$> toExp w-  let i' = toInt32Exp i+  let i' = toInt64Exp i   elems_per_thread' <- Imp.elements . TPrimExp <$> toExp elems_per_thread-  computeThreadChunkSize o i' elems_per_thread' num_elements (mkTV (patElemName size) int32)+  computeThreadChunkSize o i' elems_per_thread' num_elements (mkTV (patElemName size) int64) splitSpace pat _ _ _ _ =   error $ "Invalid target for splitSpace: " ++ pretty pat  compileThreadExp :: ExpCompiler KernelsMem KernelEnv Imp.KernelOp compileThreadExp (Pattern _ [dest]) (BasicOp (ArrayLit es _)) =   forM_ (zip [0 ..] es) $ \(i, e) ->-    copyDWIMFix (patElemName dest) [fromIntegral (i :: Int32)] e []+    copyDWIMFix (patElemName dest) [fromIntegral (i :: Int64)] e [] compileThreadExp dest e =   defCompileExp dest e @@ -179,13 +179,13 @@ -- passed-in function is invoked with the (symbolic) iteration.  For -- multidimensional loops, use 'groupCoverSpace'. groupLoop ::-  Imp.TExp Int32 ->-  (Imp.TExp Int32 -> InKernelGen ()) ->+  Imp.TExp Int64 ->+  (Imp.TExp Int64 -> InKernelGen ()) ->   InKernelGen () groupLoop n f = do   constants <- kernelConstants <$> askEnv   kernelLoop-    (kernelLocalThreadId constants)+    (sExt64 $ kernelLocalThreadId constants)     (kernelGroupSize constants)     n     f@@ -194,8 +194,8 @@ -- all threads in the group participate.  The passed-in function is -- invoked with a (symbolic) point in the index space. groupCoverSpace ::-  [Imp.TExp Int32] ->-  ([Imp.TExp Int32] -> InKernelGen ()) ->+  [Imp.TExp Int64] ->+  ([Imp.TExp Int64] -> InKernelGen ()) ->   InKernelGen () groupCoverSpace ds f =   groupLoop (product ds) $ f . unflattenIndex ds@@ -204,9 +204,9 @@ -- The static arrays stuff does not work inside kernels. compileGroupExp (Pattern _ [dest]) (BasicOp (ArrayLit es _)) =   forM_ (zip [0 ..] es) $ \(i, e) ->-    copyDWIMFix (patElemName dest) [fromIntegral (i :: Int32)] e []+    copyDWIMFix (patElemName dest) [fromIntegral (i :: Int64)] e [] compileGroupExp (Pattern _ [dest]) (BasicOp (Replicate ds se)) = do-  let ds' = map toInt32Exp $ shapeDims ds+  let ds' = map toInt64Exp $ shapeDims ds   groupCoverSpace ds' $ \is ->     copyDWIMFix (patElemName dest) is se (drop (shapeRank ds) is)   sOp $ Imp.Barrier Imp.FenceLocal@@ -232,7 +232,7 @@     sOp $ Imp.Barrier Imp.FenceLocal     ltid <- kernelLocalThreadId . kernelConstants <$> askEnv     sWhen (ltid .==. 0) $-      copyDWIM (patElemName pe) (map (fmap toInt32Exp) slice) se []+      copyDWIM (patElemName pe) (map (fmap toInt64Exp) slice) se []     sOp $ Imp.Barrier Imp.FenceLocal compileGroupExp dest e =   defCompileExp dest e@@ -242,11 +242,11 @@ sanityCheckLevel SegGroup {} =   error "compileGroupOp: unexpected group-level SegOp." -localThreadIDs :: [SubExp] -> InKernelGen [Imp.TExp Int32]+localThreadIDs :: [SubExp] -> InKernelGen [Imp.TExp Int64] localThreadIDs dims = do-  ltid <- kernelLocalThreadId . kernelConstants <$> askEnv-  let dims' = map toInt32Exp dims-  fromMaybe (unflattenIndex dims' ltid)+  ltid <- sExt64 . kernelLocalThreadId . kernelConstants <$> askEnv+  let dims' = map toInt64Exp dims+  maybe (unflattenIndex dims' ltid) (map sExt64)     . M.lookup dims     . kernelLocalIdMap     . kernelConstants@@ -264,7 +264,7 @@ prepareIntraGroupSegHist ::   Count GroupSize SubExp ->   [HistOp KernelsMem] ->-  InKernelGen [[Imp.TExp Int32] -> InKernelGen ()]+  InKernelGen [[Imp.TExp Int64] -> InKernelGen ()] prepareIntraGroupSegHist group_size =   fmap snd . mapAccumLM onOp Nothing   where@@ -281,8 +281,8 @@         (Nothing, AtomicLocking f) -> do           locks <- newVName "locks" -          let num_locks = toInt32Exp $ unCount group_size-              dims = map toInt32Exp $ shapeDims (histShape op) ++ [histWidth op]+          let num_locks = toInt64Exp $ unCount group_size+              dims = map toInt64Exp $ shapeDims (histShape op) ++ [histWidth op]               l' = Locking locks 0 1 0 (pure . (`rem` num_locks) . flattenIndex dims)               locks_t = Array int32 (Shape [unCount group_size]) NoUniqueness @@ -290,7 +290,7 @@           dArray locks int32 (arrayShape locks_t) $             ArrayIn locks_mem $               IxFun.iota $-                map pe32 $ arrayDims locks_t+                map pe64 $ arrayDims locks_t            sComment "All locks start out unlocked" $             groupCoverSpace [kernelGroupSize constants] $ \is ->@@ -321,21 +321,22 @@ compileGroupOp pat (Inner (SegOp (SegScan lvl space scans _ body))) = do   compileGroupSpace lvl space   let (ltids, dims) = unzip $ unSegSpace space-      dims' = map toInt32Exp dims+      dims' = map toInt64Exp dims    whenActive lvl space $     compileStms mempty (kernelBodyStms body) $       forM_ (zip (patternNames pat) $ kernelBodyResult body) $ \(dest, res) ->         copyDWIMFix           dest-          (map Imp.vi32 ltids)+          (map Imp.vi64 ltids)           (kernelResultSubExp res)           []    sOp $ Imp.ErrorSync Imp.FenceLocal    let segment_size = last dims'-      crossesSegment from to = (to - from) .>. (to `rem` segment_size)+      crossesSegment from to =+        (sExt64 to - sExt64 from) .>. (sExt64 to `rem` segment_size)    -- groupScan needs to treat the scan output as a one-dimensional   -- array of scan elements, so we invent some new flattened arrays@@ -351,7 +352,7 @@           (baseString (patElemName pe) ++ "_flat")           (elemType pe_t)           (Shape arr_dims)-          $ ArrayIn mem $ IxFun.iota $ map pe32 arr_dims+          $ ArrayIn mem $ IxFun.iota $ map pe64 arr_dims        num_scan_results = sum $ map (length . segBinOpNeutral) scans @@ -367,7 +368,7 @@       (red_pes, map_pes) =         splitAt (segBinOpResults ops) $ patternElements pat -      dims' = map toInt32Exp dims+      dims' = map toInt64Exp dims        mkTempArr t =         sAllocArray "red_arr" (elemType t) (Shape dims <> arrayShape t) $ Space "local"@@ -380,7 +381,7 @@       let (red_res, map_res) =             splitAt (segBinOpResults ops) $ kernelBodyResult body       forM_ (zip tmp_arrs red_res) $ \(dest, res) ->-        copyDWIMFix dest (map Imp.vi32 ltids) (kernelResultSubExp res) []+        copyDWIMFix dest (map Imp.vi64 ltids) (kernelResultSubExp res) []       zipWithM_ (compileThreadResult space) map_pes map_res    sOp $ Imp.ErrorSync Imp.FenceLocal@@ -390,7 +391,7 @@     -- handle directly with a group-level reduction.     [dim'] -> do       forM_ (zip ops tmps_for_ops) $ \(op, tmps) ->-        groupReduce dim' (segBinOpLambda op) tmps+        groupReduce (sExt32 dim') (segBinOpLambda op) tmps        sOp $ Imp.ErrorSync Imp.FenceLocal @@ -413,10 +414,11 @@                     drop (length ltids) (memLocationShape arr_loc)             sArray "red_arr_flat" pt flat_shape $               ArrayIn (memLocationName arr_loc) $-                IxFun.iota $ map pe32 $ shapeDims flat_shape+                IxFun.iota $ map pe64 $ shapeDims flat_shape        let segment_size = last dims'-          crossesSegment from to = (to - from) .>. (to `rem` segment_size)+          crossesSegment from to =+            (sExt64 to - sExt64 from) .>. (sExt64 to `rem` sExt64 segment_size)        forM_ (zip ops tmps_for_ops) $ \(op, tmps) -> do         tmps_flat <- mapM flatten tmps@@ -463,10 +465,10 @@        forM_ (zip4 red_is vs_per_op ops' ops) $         \(bin, op_vs, do_op, HistOp dest_w _ _ _ shape lam) -> do-          let bin' = toInt32Exp bin-              dest_w' = toInt32Exp dest_w+          let bin' = toInt64Exp bin+              dest_w' = toInt64Exp dest_w               bin_in_bounds = 0 .<=. bin' .&&. bin' .<. dest_w'-              bin_is = map Imp.vi32 (init ltids) ++ [bin']+              bin_is = map Imp.vi64 (init ltids) ++ [bin']               vs_params = takeLast (length op_vs) $ lambdaParams lam            sComment "perform atomic updates" $@@ -502,13 +504,13 @@     -- | A transformation from the logical lock index to the     -- physical position in the array.  This can also be used     -- to make the lock array smaller.-    lockingMapping :: [Imp.TExp Int32] -> [Imp.TExp Int32]+    lockingMapping :: [Imp.TExp Int64] -> [Imp.TExp Int64]   }  -- | A function for generating code for an atomic update.  Assumes -- that the bucket is in-bounds. type DoAtomicUpdate lore r =-  Space -> [VName] -> [Imp.TExp Int32] -> ImpM lore r Imp.KernelOp ()+  Space -> [VName] -> [Imp.TExp Int64] -> ImpM lore r Imp.KernelOp ()  -- | The mechanism that will be used for performing the atomic update. -- Approximates how efficient it will be.  Ordered from most to least@@ -524,7 +526,7 @@ -- | Is there an atomic t'BinOp' corresponding to this t'BinOp'? type AtomicBinOp =   BinOp ->-  Maybe (VName -> VName -> Count Imp.Elements (Imp.TExp Int32) -> Imp.Exp -> Imp.AtomicOp)+  Maybe (VName -> VName -> Count Imp.Elements (Imp.TExp Int64) -> Imp.Exp -> Imp.AtomicOp)  -- | Do an atomic update corresponding to a binary operator lambda. atomicUpdateLocking ::@@ -546,7 +548,7 @@          (arr', _a_space, bucket_offset) <- fullyIndexArray a bucket -        case opHasAtomicSupport space (tvVar old) arr' (sExt32 <$> bucket_offset) op of+        case opHasAtomicSupport space (tvVar old) arr' bucket_offset op of           Just f -> sOp $ f $ Imp.var y t           Nothing ->             atomicUpdateCAS space t a (tvVar old) bucket x $@@ -588,7 +590,7 @@               int32               (tvVar old)               locks'-              (sExt32 <$> locks_offset)+              locks_offset               (untyped $ lockingIsUnlocked locking)               (untyped $ lockingToLock locking)       lock_acquired = tvExp old .==. lockingIsUnlocked locking@@ -601,7 +603,7 @@               int32               (tvVar old)               locks'-              (sExt32 <$> locks_offset)+              locks_offset               (untyped $ lockingToLock locking)               (untyped $ lockingToUnlock locking)       break_loop = continue <-- false@@ -656,7 +658,7 @@   PrimType ->   VName ->   VName ->-  [Imp.TExp Int32] ->+  [Imp.TExp Int64] ->   VName ->   InKernelGen () ->   InKernelGen ()@@ -698,7 +700,7 @@           int32           (tvVar old_bits)           arr'-          (sExt32 <$> bucket_offset)+          bucket_offset           (toBits (Imp.var assumed t))           (toBits (Imp.var x t))     old <~~ fromBits (untyped $ tvExp old_bits)@@ -773,16 +775,16 @@  computeThreadChunkSize ::   SplitOrdering ->-  Imp.TExp Int32 ->-  Imp.Count Imp.Elements (Imp.TExp Int32) ->-  Imp.Count Imp.Elements (Imp.TExp Int32) ->-  TV Int32 ->+  Imp.TExp Int64 ->+  Imp.Count Imp.Elements (Imp.TExp Int64) ->+  Imp.Count Imp.Elements (Imp.TExp Int64) ->+  TV Int64 ->   ImpM lore r op () computeThreadChunkSize (SplitStrided stride) thread_index elements_per_thread num_elements chunk_var =   chunk_var-    <-- sMin32+    <-- sMin64       (Imp.unCount elements_per_thread)-      ((Imp.unCount num_elements - thread_index) `divUp` toInt32Exp stride)+      ((Imp.unCount num_elements - thread_index) `divUp` toInt64Exp stride) computeThreadChunkSize SplitContiguous thread_index elements_per_thread num_elements chunk_var = do   starting_point <-     dPrimV "starting_point" $@@ -796,7 +798,7 @@    sIf     (no_remaining_elements .||. beyond_bounds)-    (chunk_var <-- (0 :: Imp.TExp Int32))+    (chunk_var <-- 0)     ( sIf         is_last_thread         (chunk_var <-- Imp.unCount last_thread_elements)@@ -810,8 +812,8 @@         .<. (thread_index + 1) * Imp.unCount elements_per_thread  kernelInitialisationSimple ::-  Count NumGroups (Imp.TExp Int32) ->-  Count GroupSize (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->+  Count GroupSize (Imp.TExp Int64) ->   CallKernelGen (KernelConstants, InKernelGen ()) kernelInitialisationSimple (Count num_groups) (Count group_size) = do   global_tid <- newVName "global_tid"@@ -829,7 +831,7 @@           group_id           num_groups           group_size-          (group_size * num_groups)+          (sExt32 (group_size * num_groups))           (Imp.vi32 wave_size)           true           mempty@@ -837,7 +839,7 @@   let set_constants = do         dPrim_ global_tid int32         dPrim_ local_tid int32-        dPrim_ inner_group_size int32+        dPrim_ inner_group_size int64         dPrim_ wave_size int32         dPrim_ group_id int32 @@ -855,8 +857,8 @@   x : xs -> foldl (.&&.) x xs   where     (is, ws) = unzip limit-    actives = zipWith active is $ map toInt32Exp ws-    active i = (Imp.vi32 i .<.)+    actives = zipWith active is $ map toInt64Exp ws+    active i = (Imp.vi64 i .<.)  -- | Change every memory block to be in the global address space, -- except those who are in the local memory space.  This only affects@@ -901,20 +903,20 @@       readReduceArgument param arr         | Prim _ <- paramType param = do           let i = local_tid + tvExp offset-          copyDWIMFix (paramName param) [] (Var arr) [i]+          copyDWIMFix (paramName param) [] (Var arr) [sExt64 i]         | otherwise = do           let i = global_tid + tvExp offset-          copyDWIMFix (paramName param) [] (Var arr) [i]+          copyDWIMFix (paramName param) [] (Var arr) [sExt64 i]        writeReduceOpResult param arr         | Prim _ <- paramType param =-          copyDWIMFix arr [local_tid] (Var $ paramName param) []+          copyDWIMFix arr [sExt64 local_tid] (Var $ paramName param) []         | otherwise =           return ()    let (reduce_acc_params, reduce_arr_params) = splitAt (length arrs) $ lambdaParams lam -  skip_waves <- dPrim "skip_waves" int32+  skip_waves <- dPrimV "skip_waves" (1 :: Imp.TExp Int32)   dLParams $ lambdaParams lam    offset <-- (0 :: Imp.TExp Int32)@@ -936,7 +938,7 @@       group_size = kernelGroupSize constants       wave_id = local_tid `quot` wave_size       in_wave_id = local_tid - wave_id * wave_size-      num_waves = (group_size + wave_size - 1) `quot` wave_size+      num_waves = (sExt32 group_size + wave_size - 1) `quot` wave_size       arg_in_bounds = local_tid + tvExp offset .<. w        doing_in_wave_reductions =@@ -959,8 +961,7 @@         (wave_id .&. (2 * tvExp skip_waves - 1)) .==. 0       apply_in_cross_wave_iteration =         arg_in_bounds .&&. is_first_thread_in_wave .&&. wave_not_skipped-      cross_wave_reductions = do-        skip_waves <-- (1 :: Imp.TExp Int32)+      cross_wave_reductions =         sWhile doing_cross_wave_reductions $ do           barrier           offset <-- tvExp skip_waves * wave_size@@ -974,8 +975,8 @@  groupScan ::   Maybe (Imp.TExp Int32 -> Imp.TExp Int32 -> Imp.TExp Bool) ->-  Imp.TExp Int32 ->-  Imp.TExp Int32 ->+  Imp.TExp Int64 ->+  Imp.TExp Int64 ->   Lambda KernelsMem ->   [VName] ->   InKernelGen ()@@ -983,11 +984,14 @@   constants <- kernelConstants <$> askEnv   renamed_lam <- renameLambda lam -  let ltid = kernelLocalThreadId constants+  let ltid32 = kernelLocalThreadId constants+      ltid = sExt64 ltid32       (x_params, y_params) = splitAt (length arrs) $ lambdaParams lam    dLParams (lambdaParams lam ++ lambdaParams renamed_lam) +  ltid_in_bounds <- dPrimVE "ltid_in_bounds" $ ltid .<. w+   -- 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@@ -1000,8 +1004,8 @@   -- it were a runtime parameter.  Some day.   let block_size = 32       simd_width = kernelWaveSize constants-      block_id = ltid `quot` block_size-      in_block_id = ltid - block_id * block_size+      block_id = ltid32 `quot` block_size+      in_block_id = ltid32 - block_id * block_size       doInBlockScan seg_flag' active =         inBlockScan           constants@@ -1012,7 +1016,6 @@           active           arrs           barrier-      ltid_in_bounds = ltid .<. w       array_scan = not $ all primType $ lambdaReturnType lam       barrier         | array_scan =@@ -1020,19 +1023,19 @@         | otherwise =           sOp $ Imp.Barrier Imp.FenceLocal -      group_offset = kernelGroupId constants * kernelGroupSize constants+      group_offset = sExt64 (kernelGroupId constants) * kernelGroupSize constants        writeBlockResult p arr         | primType $ paramType p =-          copyDWIM arr [DimFix block_id] (Var $ paramName p) []+          copyDWIM arr [DimFix $ sExt64 block_id] (Var $ paramName p) []         | otherwise =-          copyDWIM arr [DimFix $ group_offset + block_id] (Var $ paramName p) []+          copyDWIM arr [DimFix $ group_offset + sExt64 block_id] (Var $ paramName p) []        readPrevBlockResult p arr         | primType $ paramType p =-          copyDWIM (paramName p) [] (Var arr) [DimFix $ block_id - 1]+          copyDWIM (paramName p) [] (Var arr) [DimFix $ sExt64 block_id - 1]         | otherwise =-          copyDWIM (paramName p) [] (Var arr) [DimFix $ group_offset + block_id - 1]+          copyDWIM (paramName p) [] (Var arr) [DimFix $ group_offset + sExt64 block_id - 1]    doInBlockScan seg_flag ltid_in_bounds lam   barrier@@ -1043,7 +1046,7 @@       sWhen is_first_block $         forM_ (zip x_params arrs) $ \(x, arr) ->           unless (primType $ paramType x) $-            copyDWIM arr [DimFix $ arrs_full_size + group_offset + block_size + ltid] (Var $ paramName x) []+            copyDWIM arr [DimFix $ arrs_full_size + group_offset + sExt64 block_size + ltid] (Var $ paramName x) []      barrier @@ -1074,7 +1077,7 @@               arr               [DimFix $ arrs_full_size + group_offset + ltid]               (Var arr)-              [DimFix $ arrs_full_size + group_offset + block_size + ltid]+              [DimFix $ arrs_full_size + group_offset + sExt64 block_size + ltid]      barrier @@ -1092,7 +1095,7 @@           compileBody' x_params $ lambdaBody lam         | Just flag_true <- seg_flag = do           inactive <--            dPrimVE "inactive" $ flag_true (block_id * block_size -1) ltid+            dPrimVE "inactive" $ flag_true (block_id * block_size -1) ltid32           sWhen inactive y_to_x           when array_scan barrier           sUnless inactive $ compileBody' x_params $ lambdaBody lam@@ -1122,7 +1125,7 @@ inBlockScan ::   KernelConstants ->   Maybe (Imp.TExp Int32 -> Imp.TExp Int32 -> Imp.TExp Bool) ->-  Imp.TExp Int32 ->+  Imp.TExp Int64 ->   Imp.TExp Int32 ->   Imp.TExp Int32 ->   Imp.TExp Bool ->@@ -1158,7 +1161,7 @@         | Just flag_true <- seg_flag = do           inactive <-             dPrimVE "inactive" $-              flag_true (ltid - tvExp skip_threads) ltid+              flag_true (ltid32 - tvExp skip_threads) ltid32           sWhen inactive y_to_x           when array_scan barrier           sUnless inactive $ compileBody' x_params $ lambdaBody scan_lam@@ -1169,11 +1172,11 @@           barrier    sComment "in-block scan (hopefully no barriers needed)" $ do-    skip_threads <-- (1 :: Imp.TExp Int32)+    skip_threads <-- 1     sWhile (tvExp skip_threads .<. block_size) $ do       sWhen (in_block_thread_active .&&. active) $ do         sComment "read operands" $-          zipWithM_ (readParam (tvExp skip_threads)) x_params arrs+          zipWithM_ (readParam (sExt64 $ tvExp skip_threads)) x_params arrs         sComment "perform operation" op_to_x        maybeBarrier@@ -1186,10 +1189,11 @@        skip_threads <-- tvExp skip_threads * 2   where-    block_id = ltid `quot` block_size-    in_block_id = ltid - block_id * block_size-    ltid = kernelLocalThreadId constants-    gtid = kernelGlobalThreadId constants+    block_id = ltid32 `quot` block_size+    in_block_id = ltid32 - block_id * block_size+    ltid32 = kernelLocalThreadId constants+    ltid = sExt64 ltid32+    gtid = sExt64 $ kernelGlobalThreadId constants     array_scan = not $ all primType $ lambdaReturnType scan_lam      readInitial p arr@@ -1211,13 +1215,13 @@       | otherwise =         copyDWIM (paramName y) [] (Var $ paramName x) [] -computeMapKernelGroups :: Imp.TExp Int64 -> CallKernelGen (Imp.TExp Int64, Imp.TExp Int32)+computeMapKernelGroups :: Imp.TExp Int64 -> CallKernelGen (Imp.TExp Int64, Imp.TExp Int64) computeMapKernelGroups kernel_size = do-  group_size <- dPrim "group_size" int32+  group_size <- dPrim "group_size" int64   fname <- askFunction   let group_size_key = keyWithEntryPoint fname $ nameFromString $ pretty $ tvVar group_size   sOp $ Imp.GetSize (tvVar group_size) group_size_key Imp.SizeGroup-  num_groups <- dPrimV "num_groups" $ kernel_size `divUp` sExt64 (tvExp group_size)+  num_groups <- dPrimV "num_groups" $ kernel_size `divUp` tvExp group_size   return (tvExp num_groups, tvExp group_size)  simpleKernelConstants ::@@ -1245,9 +1249,9 @@         thread_gtid         thread_ltid         group_id-        (sExt32 num_groups)+        num_groups         group_size-        (group_size * sExt32 num_groups)+        (sExt32 (group_size * num_groups))         0         (Imp.vi64 thread_gtid .<. kernel_size)         mempty,@@ -1272,13 +1276,13 @@   sOp $ Imp.GetGroupId (tvVar phys_group_id) 0   let iterations =         (required_groups - tvExp phys_group_id)-          `divUp` kernelNumGroups constants+          `divUp` sExt32 (kernelNumGroups constants)    sFor "i" iterations $ \i -> do     m . tvExp       =<< dPrimV         "virt_group_id"-        (tvExp phys_group_id + i * kernelNumGroups constants)+        (tvExp phys_group_id + i * sExt32 (kernelNumGroups constants))     -- Make sure the virtual group is actually done before we let     -- another virtual group have its way with it.     sOp $ Imp.Barrier Imp.FenceGlobal@@ -1288,8 +1292,8 @@  sKernelThread ::   String ->-  Count NumGroups (Imp.TExp Int32) ->-  Count GroupSize (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->+  Count GroupSize (Imp.TExp Int64) ->   VName ->   InKernelGen () ->   CallKernelGen ()@@ -1297,8 +1301,8 @@  sKernelGroup ::   String ->-  Count NumGroups (Imp.TExp Int32) ->-  Count GroupSize (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->+  Count GroupSize (Imp.TExp Int64) ->   VName ->   InKernelGen () ->   CallKernelGen ()@@ -1331,8 +1335,8 @@   Operations KernelsMem KernelEnv Imp.KernelOp ->   (KernelConstants -> Imp.TExp Int32) ->   String ->-  Count NumGroups (Imp.TExp Int32) ->-  Count GroupSize (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->+  Count GroupSize (Imp.TExp Int64) ->   VName ->   InKernelGen () ->   CallKernelGen ()@@ -1392,7 +1396,7 @@   t <- subExpType se   ds <- dropLast (arrayRank t) . arrayDims <$> lookupType arr -  let dims = map toInt32Exp $ ds ++ arrayDims t+  let dims = map toInt64Exp $ ds ++ arrayDims t   (constants, set_constants) <-     simpleKernelConstants (product $ map sExt64 dims) "replicate" @@ -1401,7 +1405,7 @@         keyWithEntryPoint fname $           nameFromString $             "replicate_" ++ show (baseTag $ kernelGlobalThreadIdVar constants)-      is' = unflattenIndex dims $ kernelGlobalThreadId constants+      is' = unflattenIndex dims $ sExt64 $ kernelGlobalThreadId constants    sKernelFailureTolerant True threadOperations constants name $ do     set_constants@@ -1432,7 +1436,7 @@         sArray "arr" bt shape $           ArrayIn mem $             IxFun.iota $-              map pe32 $ shapeDims shape+              map pe64 $ shapeDims shape       sReplicateKernel arr $ Var val    return fname@@ -1451,7 +1455,7 @@               []               fname               [ Imp.MemArg arr_mem,-                Imp.ExpArg $ untyped $ product $ map toInt32Exp arr_shape,+                Imp.ExpArg $ untyped $ product $ map toInt64Exp arr_shape,                 Imp.ExpArg $ toExp' v_t' v               ]     _ -> return Nothing@@ -1488,7 +1492,7 @@    sKernelFailureTolerant True threadOperations constants name $ do     set_constants-    let gtid = kernelGlobalThreadId constants+    let gtid = sExt64 $ kernelGlobalThreadId constants     sWhen (kernelThreadActive constants) $ do       (destmem, destspace, destidx) <- fullyIndexArray' destloc [gtid] @@ -1520,7 +1524,7 @@             Imp.ScalarParam s $ IntType bt           ]         shape = Shape [Var n]-        n' = Imp.vi32 n+        n' = Imp.vi64 n         x' = Imp.var x $ IntType bt         s' = Imp.var s $ IntType bt @@ -1529,7 +1533,7 @@         sArray "arr" (IntType bt) shape $           ArrayIn mem $             IxFun.iota $-              map pe32 $ shapeDims shape+              map pe64 $ shapeDims shape       sIotaKernel arr (sExt64 n') x' s' bt    return fname@@ -1537,7 +1541,7 @@ -- | Perform an Iota with a kernel. sIota ::   VName ->-  Imp.TExp Int32 ->+  Imp.TExp Int64 ->   Imp.Exp ->   Imp.Exp ->   IntType ->@@ -1552,7 +1556,7 @@           []           fname           [Imp.MemArg arr_mem, Imp.ExpArg $ untyped n, Imp.ExpArg x, Imp.ExpArg s]-    else sIotaKernel arr (sExt64 n) x s et+    else sIotaKernel arr n x s et  sCopy :: CopyCompiler KernelsMem HostEnv Imp.HostOp sCopy@@ -1565,7 +1569,7 @@       -- Note that the shape of the destination and the source are       -- necessarily the same.       let shape = sliceDims srcslice-          kernel_size = product $ map sExt64 shape+          kernel_size = product shape        (constants, set_constants) <- simpleKernelConstants kernel_size "copy" @@ -1578,7 +1582,7 @@       sKernelFailureTolerant True threadOperations constants name $ do         set_constants -        let gtid = kernelGlobalThreadId constants+        let gtid = sExt64 $ kernelGlobalThreadId constants             dest_is = unflattenIndex shape gtid             src_is = dest_is @@ -1587,7 +1591,7 @@         (_, srcspace, srcidx) <-           fullyIndexArray' srcloc $ fixSlice srcslice src_is -        sWhen (gtid .<. sExt32 kernel_size) $+        sWhen (gtid .<. kernel_size) $           emit $             Imp.Write destmem destidx bt destspace Imp.Nonvolatile $               Imp.index srcmem srcidx bt srcspace Imp.Nonvolatile@@ -1598,26 +1602,29 @@   KernelResult ->   InKernelGen () compileGroupResult _ pe (TileReturns [(w, per_group_elems)] what) = do-  n <- toInt32Exp . arraySize 0 <$> lookupType what+  n <- toInt64Exp . arraySize 0 <$> lookupType what    constants <- kernelConstants <$> askEnv-  let ltid = kernelLocalThreadId constants-      offset = toInt32Exp per_group_elems * kernelGroupId constants+  let ltid = sExt64 $ kernelLocalThreadId constants+      offset =+        toInt64Exp per_group_elems+          * sExt64 (kernelGroupId constants)    -- Avoid loop for the common case where each thread is statically   -- known to write at most one element.   localOps threadOperations $-    if toInt32Exp per_group_elems == kernelGroupSize constants+    if toInt64Exp per_group_elems == kernelGroupSize constants       then-        sWhen (offset + ltid .<. toInt32Exp w) $+        sWhen (ltid + offset .<. toInt64Exp w) $           copyDWIMFix (patElemName pe) [ltid + offset] (Var what) [ltid]       else sFor "i" (n `divUp` kernelGroupSize constants) $ \i -> do         j <- dPrimVE "j" $ kernelGroupSize constants * i + ltid-        sWhen (j .<. n) $ copyDWIMFix (patElemName pe) [j + offset] (Var what) [j]+        sWhen (j + offset .<. toInt64Exp w) $+          copyDWIMFix (patElemName pe) [j + offset] (Var what) [j] compileGroupResult space pe (TileReturns dims what) = do   let gids = map fst $ unSegSpace space-      out_tile_sizes = map (toInt32Exp . snd) dims-      group_is = zipWith (*) (map Imp.vi32 gids) out_tile_sizes+      out_tile_sizes = map (toInt64Exp . snd) dims+      group_is = zipWith (*) (map Imp.vi64 gids) out_tile_sizes   local_is <- localThreadIDs $ map snd dims   is_for_thread <-     mapM (dPrimV "thread_out_index") $@@ -1629,7 +1636,7 @@ compileGroupResult space pe (Returns _ what) = do   constants <- kernelConstants <$> askEnv   in_local_memory <- arrayInLocalMemory what-  let gids = map (Imp.vi32 . fst) $ unSegSpace space+  let gids = map (Imp.vi64 . fst) $ unSegSpace space    if not in_local_memory     then@@ -1652,22 +1659,24 @@   KernelResult ->   InKernelGen () compileThreadResult space pe (Returns _ what) = do-  let is = map (Imp.vi32 . fst) $ unSegSpace space+  let is = map (Imp.vi64 . fst) $ unSegSpace space   copyDWIMFix (patElemName pe) is what [] compileThreadResult _ pe (ConcatReturns SplitContiguous _ per_thread_elems what) = do   constants <- kernelConstants <$> askEnv-  let offset = toInt32Exp per_thread_elems * kernelGlobalThreadId constants-  n <- toInt32Exp . arraySize 0 <$> lookupType what+  let offset =+        toInt64Exp per_thread_elems+          * sExt64 (kernelGlobalThreadId constants)+  n <- toInt64Exp . arraySize 0 <$> lookupType what   copyDWIM (patElemName pe) [DimSlice offset n 1] (Var what) [] compileThreadResult _ pe (ConcatReturns (SplitStrided stride) _ _ what) = do-  offset <- kernelGlobalThreadId . kernelConstants <$> askEnv-  n <- toInt32Exp . arraySize 0 <$> lookupType what-  copyDWIM (patElemName pe) [DimSlice offset n $ toInt32Exp stride] (Var what) []+  offset <- sExt64 . kernelGlobalThreadId . kernelConstants <$> askEnv+  n <- toInt64Exp . arraySize 0 <$> lookupType what+  copyDWIM (patElemName pe) [DimSlice offset n $ toInt64Exp stride] (Var what) [] compileThreadResult _ pe (WriteReturns rws _arr dests) = do   constants <- kernelConstants <$> askEnv-  let rws' = map toInt32Exp rws+  let rws' = map toInt64Exp rws   forM_ dests $ \(slice, e) -> do-    let slice' = map (fmap toInt32Exp) slice+    let slice' = map (fmap toInt64Exp) slice         condInBounds (DimFix i) rw =           0 .<=. i .&&. i .<. rw         condInBounds (DimSlice i n s) rw =
src/Futhark/CodeGen/ImpGen/Kernels/SegHist.hs view
@@ -62,23 +62,22 @@  data SegHistSlug = SegHistSlug   { slugOp :: HistOp KernelsMem,-    slugNumSubhistos :: TV Int32,+    slugNumSubhistos :: TV Int64,     slugSubhistos :: [SubhistosInfo],     slugAtomicUpdate :: AtomicUpdate KernelsMem KernelEnv   }  histoSpaceUsage ::   HistOp KernelsMem ->-  Imp.Count Imp.Bytes (Imp.TExp Int32)+  Imp.Count Imp.Bytes (Imp.TExp Int64) histoSpaceUsage op =-  fmap sExt32 $-    sum $-      map-        ( typeSize-            . (`arrayOfRow` histWidth op)-            . (`arrayOfShape` histShape op)-        )-        $ lambdaReturnType $ histOp op+  sum $+    map+      ( typeSize+          . (`arrayOfRow` histWidth op)+          . (`arrayOfShape` histShape op)+      )+      $ lambdaReturnType $ histOp op  -- | Figure out how much memory is needed per histogram, both -- segmented and unsegmented,, and compute some other auxiliary@@ -87,8 +86,8 @@   SegSpace ->   HistOp KernelsMem ->   CallKernelGen-    ( Imp.Count Imp.Bytes (Imp.TExp Int32),-      Imp.Count Imp.Bytes (Imp.TExp Int32),+    ( Imp.Count Imp.Bytes (Imp.TExp Int64),+      Imp.Count Imp.Bytes (Imp.TExp Int64),       SegHistSlug     ) computeHistoUsage space op = do@@ -111,7 +110,7 @@         subhistos_membind =           ArrayIn subhistos_mem $             IxFun.iota $-              map pe32 $ shapeDims subhistos_shape+              map pe64 $ shapeDims subhistos_shape     subhistos <-       sArray         (baseString dest ++ "_subhistos")@@ -128,8 +127,8 @@              multiHistoCase = do               let num_elems =-                    foldl' (*) (tvExp num_subhistos) $-                      map toInt32Exp $ arrayDims dest_t+                    foldl' (*) (sExt64 $ tvExp num_subhistos) $+                      map toInt64Exp $ arrayDims dest_t                let subhistos_mem_size =                     Imp.bytes $@@ -139,15 +138,15 @@               sReplicate subhistos ne               subhistos_t <- lookupType subhistos               let slice =-                    fullSliceNum (map toInt32Exp $ arrayDims subhistos_t) $-                      map (unitSlice 0 . toInt32Exp . snd) segment_dims+                    fullSliceNum (map toInt64Exp $ arrayDims subhistos_t) $+                      map (unitSlice 0 . toInt64Exp . snd) segment_dims                         ++ [DimFix 0]               sUpdate subhistos slice $ Var dest          sIf (tvExp num_subhistos .==. 1) unitHistoCase multiHistoCase    let h = histoSpaceUsage op-      segmented_h = h * product (map (Imp.bytes . toInt32Exp) $ init $ segSpaceDims space)+      segmented_h = h * product (map (Imp.bytes . toInt64Exp) $ init $ segSpaceDims space)    atomics <- hostAtomics <$> askEnv @@ -164,7 +163,7 @@   SegHistSlug ->   CallKernelGen     ( Maybe Locking,-      [Imp.TExp Int32] -> InKernelGen ()+      [Imp.TExp Int64] -> InKernelGen ()     ) prepareAtomicUpdateGlobal l dests slug =   -- We need a separate lock array if the operators are not all of a@@ -183,7 +182,7 @@       -- algorithm to ensure good distribution of locks.       let num_locks = 100151           dims =-            map toInt32Exp $+            map toInt64Exp $               shapeDims (histShape (slugOp slug))                 ++ [ tvSize (slugNumSubhistos slug),                      histWidth (slugOp slug)@@ -208,11 +207,11 @@ prepareIntermediateArraysGlobal ::   Passage ->   Imp.TExp Int32 ->-  Imp.TExp Int32 ->+  Imp.TExp Int64 ->   [SegHistSlug] ->   CallKernelGen     ( Imp.TExp Int32,-      [[Imp.TExp Int32] -> InKernelGen ()]+      [[Imp.TExp Int64] -> InKernelGen ()]     ) prepareIntermediateArraysGlobal passage hist_T hist_N slugs = do   -- The paper formulae assume there is only one histogram, but in our@@ -223,11 +222,11 @@   -- paper.    -- The sum of all Hs.-  hist_H <- dPrimVE "hist_H" $ sum $ map (toInt32Exp . histWidth . slugOp) slugs+  hist_H <- dPrimVE "hist_H" $ sum $ map (toInt64Exp . histWidth . slugOp) slugs    hist_RF <-     dPrimVE "hist_RF" $-      sum (map (r64 . toInt32Exp . histRaceFactor . slugOp) slugs)+      sum (map (r64 . toInt64Exp . histRaceFactor . slugOp) slugs)         / genericLength slugs    hist_el_size <- dPrimVE "hist_el_size" $ sum $ map slugElAvgSize slugs@@ -238,7 +237,7 @@    hist_M_min <-     dPrimVE "hist_M_min" $-      sMax32 1 $ t64 $ r64 hist_T / hist_C_max+      sMax32 1 $ sExt32 $ t64 $ r64 hist_T / hist_C_max    -- Querying L2 cache size is not reliable.  Instead we provide a   -- tunable knob with a hopefully sane default.@@ -268,8 +267,9 @@     $ hist_S       <-- case passage of         MayBeMultiPass ->-          (hist_M_min * hist_H * hist_el_size)-            `divUp` t64 (hist_F_L2 * r64 (tvExp hist_L2) * hist_RACE_exp)+          sExt32 $+            (sExt64 hist_M_min * hist_H * sExt64 hist_el_size)+              `divUp` t64 (hist_F_L2 * r64 (tvExp hist_L2) * hist_RACE_exp)         MustBeSinglePass ->           1 @@ -289,7 +289,7 @@     hist_k_RF = 0.75 -- Chosen experimentally     hist_F_L2 = 0.4 -- Chosen experimentally     r64 = isF64 . ConvOpExp (SIToFP Int32 Float64) . untyped-    t64 = isInt32 . ConvOpExp (FPToSI Float64 Int32) . untyped+    t64 = isInt64 . ConvOpExp (FPToSI Float64 Int64) . untyped      -- "Average element size" as computed by a formula that also takes     -- locking into account.@@ -319,9 +319,9 @@      onOp hist_L2 hist_M_min hist_S hist_RACE_exp l slug = do       let SegHistSlug op num_subhistos subhisto_info do_op = slug-          hist_H = toInt32Exp $ histWidth op+          hist_H = toInt64Exp $ histWidth op -      hist_H_chk <- dPrimVE "hist_H_chk" $ hist_H `divUp` hist_S+      hist_H_chk <- dPrimVE "hist_H_chk" $ hist_H `divUp` sExt64 hist_S        emit $ Imp.DebugPrint "Chunk size (H_chk)" $ Just $ untyped hist_H_chk @@ -345,14 +345,14 @@       hist_M <- dPrimVE "hist_M" $         case slugAtomicUpdate slug of           AtomicPrim {} -> 1-          _ -> sMax32 hist_M_min $ t64 $ r64 hist_T / hist_C+          _ -> sMax32 hist_M_min $ sExt32 $ t64 $ r64 hist_T / hist_C        emit $ Imp.DebugPrint "Elements/thread in L2 cache (k_max)" $ Just $ untyped hist_k_max       emit $ Imp.DebugPrint "Multiplication degree (M)" $ Just $ untyped hist_M       emit $ Imp.DebugPrint "Cooperation level (C)" $ Just $ untyped hist_C        -- num_subhistos is the variable we use to communicate back.-      num_subhistos <-- hist_M+      num_subhistos <-- sExt64 hist_M        -- Initialise sub-histograms.       --@@ -384,22 +384,22 @@  histKernelGlobalPass ::   [PatElem KernelsMem] ->-  Count NumGroups (Imp.TExp Int32) ->-  Count GroupSize (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->+  Count GroupSize (Imp.TExp Int64) ->   SegSpace ->   [SegHistSlug] ->   KernelBody KernelsMem ->-  [[Imp.TExp Int32] -> InKernelGen ()] ->+  [[Imp.TExp Int64] -> InKernelGen ()] ->   Imp.TExp Int32 ->   Imp.TExp Int32 ->   CallKernelGen () histKernelGlobalPass map_pes num_groups group_size space slugs kbody histograms hist_S chk_i = do   let (space_is, space_sizes) = unzip $ unSegSpace space-      space_sizes_64 = map (sExt64 . toInt32Exp) space_sizes+      space_sizes_64 = map (sExt64 . toInt64Exp) space_sizes       total_w_64 = product space_sizes_64    hist_H_chks <- forM (map (histWidth . slugOp) slugs) $ \w ->-    dPrimVE "hist_H_chk" $ toInt32Exp w `divUp` hist_S+    dPrimVE "hist_H_chk" $ toInt64Exp w `divUp` sExt64 hist_S    sKernelThread "seghist_global" num_groups group_size (segFlat space) $ do     constants <- kernelConstants <$> askEnv@@ -408,7 +408,9 @@     subhisto_inds <- forM slugs $ \slug ->       dPrimVE "subhisto_ind" $         kernelGlobalThreadId constants-          `quot` (kernelNumThreads constants `divUp` tvExp (slugNumSubhistos slug))+          `quot` ( kernelNumThreads constants+                     `divUp` sExt32 (tvExp (slugNumSubhistos slug))+                 )      -- Loop over flat offsets into the input and output.  The     -- calculation is done with 64-bit integers to avoid overflow,@@ -434,7 +436,7 @@             forM_ (zip map_pes map_res) $ \(pe, res) ->               copyDWIMFix                 (patElemName pe)-                (map (Imp.vi32 . fst) $ unSegSpace space)+                (map (Imp.vi64 . fst) $ unSegSpace space)                 (kernelResultSubExp res)                 [] @@ -450,9 +452,9 @@                  subhisto_ind,                  hist_H_chk                  ) -> do-                  let chk_beg = chk_i * hist_H_chk-                      bucket' = toInt32Exp $ kernelResultSubExp bucket-                      dest_w' = toInt32Exp dest_w+                  let chk_beg = sExt64 chk_i * hist_H_chk+                      bucket' = toInt64Exp $ kernelResultSubExp bucket+                      dest_w' = toInt64Exp dest_w                       bucket_in_bounds =                         chk_beg .<=. bucket'                           .&&. bucket' .<. (chk_beg + hist_H_chk)@@ -461,8 +463,8 @@                    sWhen bucket_in_bounds $ do                     let bucket_is =-                          map Imp.vi32 (init space_is)-                            ++ [subhisto_ind, bucket']+                          map Imp.vi64 (init space_is)+                            ++ [sExt64 subhisto_ind, bucket']                     dLParams $ lambdaParams lam                     sLoopNest shape $ \is -> do                       forM_ (zip vs_params vs') $ \(p, res) ->@@ -478,10 +480,10 @@   KernelBody KernelsMem ->   CallKernelGen () histKernelGlobal map_pes num_groups group_size space slugs kbody = do-  let num_groups' = fmap toInt32Exp num_groups-      group_size' = fmap toInt32Exp group_size+  let num_groups' = fmap toInt64Exp num_groups+      group_size' = fmap toInt64Exp group_size   let (_space_is, space_sizes) = unzip $ unSegSpace space-      num_threads = unCount num_groups' * unCount group_size'+      num_threads = sExt32 $ unCount num_groups' * unCount group_size'    emit $ Imp.DebugPrint "## Using global memory" Nothing @@ -489,7 +491,7 @@     prepareIntermediateArraysGlobal       (bodyPassage kbody)       num_threads-      (toInt32Exp $ last space_sizes)+      (toInt64Exp $ last space_sizes)       slugs    sFor "chk_i" hist_S $ \chk_i ->@@ -509,25 +511,25 @@       SubExp ->       InKernelGen         ( [VName],-          [Imp.TExp Int32] -> InKernelGen ()+          [Imp.TExp Int64] -> InKernelGen ()         )     )   ]  prepareIntermediateArraysLocal ::   TV Int32 ->-  Count NumGroups (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->   SegSpace ->   [SegHistSlug] ->   CallKernelGen InitLocalHistograms prepareIntermediateArraysLocal num_subhistos_per_group groups_per_segment space slugs = do   num_segments <-     dPrimVE "num_segments" $-      product $ map (toInt32Exp . snd) $ init $ unSegSpace space+      product $ map (toInt64Exp . snd) $ init $ unSegSpace space   mapM (onOp num_segments) slugs   where     onOp num_segments (SegHistSlug op num_subhistos subhisto_info do_op) = do-      num_subhistos <-- unCount groups_per_segment * num_segments+      num_subhistos <-- sExt64 (unCount groups_per_segment) * num_segments        emit $         Imp.DebugPrint "Number of subhistograms in global memory" $@@ -544,7 +546,7 @@                     shapeDims (histShape op)                       ++ [hist_H_chk] -            let dims = map toInt32Exp $ shapeDims lock_shape+            let dims = map toInt64Exp $ shapeDims lock_shape              locks <- sAllocArray "locks" int32 lock_shape $ Space "local" @@ -581,10 +583,10 @@  histKernelLocalPass ::   TV Int32 ->-  Count NumGroups (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->   [PatElem KernelsMem] ->-  Count NumGroups (Imp.TExp Int32) ->-  Count GroupSize (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->+  Count GroupSize (Imp.TExp Int64) ->   SegSpace ->   [SegHistSlug] ->   KernelBody KernelsMem ->@@ -609,33 +611,46 @@         segment_dims = init space_sizes         (i_in_segment, segment_size) = last $ unSegSpace space         num_subhistos_per_group = tvExp num_subhistos_per_group_var-        segment_size' = toInt32Exp segment_size+        segment_size' = toInt64Exp segment_size      num_segments <-       dPrimVE "num_segments" $-        product $ map toInt32Exp segment_dims+        product $ map toInt64Exp segment_dims      hist_H_chks <- forM (map (histWidth . slugOp) slugs) $ \w ->-      dPrimV "hist_H_chk" $ toInt32Exp w `divUp` hist_S+      dPrimV "hist_H_chk" $ toInt64Exp w `divUp` sExt64 hist_S +    histo_sizes <- forM (zip slugs hist_H_chks) $ \(slug, hist_H_chk) -> do+      let histo_dims =+            tvExp hist_H_chk :+            map toInt64Exp (shapeDims (histShape (slugOp slug)))+      histo_size <-+        dPrimVE "histo_size" $ product histo_dims+      let group_hists_size =+            sExt64 num_subhistos_per_group * histo_size+      init_per_thread <-+        dPrimVE "init_per_thread" $ sExt32 $ group_hists_size `divUp` unCount group_size+      return (histo_dims, histo_size, init_per_thread)+     sKernelThread "seghist_local" num_groups group_size (segFlat space) $-      virtualiseGroups SegVirt (unCount groups_per_segment * num_segments) $ \group_id -> do+      virtualiseGroups SegVirt (sExt32 $ unCount groups_per_segment * num_segments) $ \group_id -> do         constants <- kernelConstants <$> askEnv -        flat_segment_id <- dPrimVE "flat_segment_id" $ group_id `quot` unCount groups_per_segment-        gid_in_segment <- dPrimVE "gid_in_segment" $ group_id `rem` unCount groups_per_segment+        flat_segment_id <- dPrimVE "flat_segment_id" $ group_id `quot` sExt32 (unCount groups_per_segment)+        gid_in_segment <- dPrimVE "gid_in_segment" $ group_id `rem` sExt32 (unCount groups_per_segment)         -- This pgtid is kind of a "virtualised physical" gtid - not the         -- same thing as the gtid used for the SegHist itself.         pgtid_in_segment <-           dPrimVE "pgtid_in_segment" $-            gid_in_segment * kernelGroupSize constants + kernelLocalThreadId constants+            gid_in_segment * sExt32 (kernelGroupSize constants)+              + kernelLocalThreadId constants         threads_per_segment <-           dPrimVE "threads_per_segment" $-            unCount groups_per_segment * kernelGroupSize constants+            sExt32 $ unCount groups_per_segment * kernelGroupSize constants          -- Set segment indices.         zipWithM_ dPrimV_ segment_is $-          unflattenIndex (map toInt32Exp segment_dims) flat_segment_id+          unflattenIndex (map toInt64Exp segment_dims) $ sExt64 flat_segment_id          histograms <- forM (zip init_histograms hist_H_chks) $           \((glob_subhistos, init_local_subhistos), hist_H_chk) -> do@@ -649,38 +664,32 @@           dPrimVE "thread_local_subhisto_i" $             kernelLocalThreadId constants `rem` num_subhistos_per_group -        let onSlugs f = forM_ (zip slugs histograms) $ \(slug, (dests, hist_H_chk, _)) -> do-              let histo_dims =-                    tvExp hist_H_chk :-                    map toInt32Exp (shapeDims (histShape (slugOp slug)))-              histo_size <- dPrimVE "histo_size" $ product histo_dims-              f slug dests (tvExp hist_H_chk) histo_dims histo_size+        let onSlugs f =+              forM_ (zip3 slugs histograms histo_sizes) $+                \(slug, (dests, hist_H_chk, _), (histo_dims, histo_size, init_per_thread)) ->+                  f slug dests (tvExp hist_H_chk) histo_dims histo_size init_per_thread          let onAllHistograms f =-              onSlugs $ \slug dests hist_H_chk histo_dims histo_size -> do-                let group_hists_size = num_subhistos_per_group * histo_size-                init_per_thread <--                  dPrimVE "init_per_thread" $-                    group_hists_size-                      `divUp` kernelGroupSize constants+              onSlugs $ \slug dests hist_H_chk histo_dims histo_size init_per_thread -> do+                let group_hists_size = num_subhistos_per_group * sExt32 histo_size                  forM_ (zip dests (histNeutral $ slugOp slug)) $                   \((dest_global, dest_local), ne) ->                     sFor "local_i" init_per_thread $ \i -> do                       j <-                         dPrimVE "j" $-                          i * kernelGroupSize constants+                          i * sExt32 (kernelGroupSize constants)                             + kernelLocalThreadId constants                       j_offset <-                         dPrimVE "j_offset" $-                          num_subhistos_per_group * histo_size * gid_in_segment + j+                          num_subhistos_per_group * sExt32 histo_size * gid_in_segment + j -                      local_subhisto_i <- dPrimVE "local_subhisto_i" $ j `quot` histo_size-                      let local_bucket_is = unflattenIndex histo_dims $ j `rem` histo_size+                      local_subhisto_i <- dPrimVE "local_subhisto_i" $ j `quot` sExt32 histo_size+                      let local_bucket_is = unflattenIndex histo_dims $ sExt64 $ j `rem` sExt32 histo_size                           global_bucket_is =-                            head local_bucket_is + chk_i * hist_H_chk :+                            head local_bucket_is + sExt64 chk_i * hist_H_chk :                             tail local_bucket_is-                      global_subhisto_i <- dPrimVE "global_subhisto_i" $ j_offset `quot` histo_size+                      global_subhisto_i <- dPrimVE "global_subhisto_i" $ j_offset `quot` sExt32 histo_size                        sWhen (j .<. group_hists_size) $                         f@@ -696,8 +705,8 @@         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.vi32 segment_is ++ [0] ++ global_bucket_is-                  local_is = local_subhisto_i : local_bucket_is+              let global_is = map Imp.vi64 segment_is ++ [0] ++ global_bucket_is+                  local_is = sExt64 local_subhisto_i : local_bucket_is               sIf                 (global_subhisto_i .==. 0)                 (copyDWIMFix dest_local local_is (Var dest_global) global_is)@@ -707,7 +716,7 @@          sOp $ Imp.Barrier Imp.FenceLocal -        kernelLoop pgtid_in_segment threads_per_segment segment_size' $ \ie -> do+        kernelLoop pgtid_in_segment threads_per_segment (sExt32 segment_size') $ \ie -> do           dPrimV_ i_in_segment ie            -- We execute the bucket function once and update each histogram@@ -726,7 +735,7 @@                 forM_ (zip map_pes map_res) $ \(pe, se) ->                   copyDWIMFix                     (patElemName pe)-                    (map Imp.vi32 space_is)+                    (map Imp.vi64 space_is)                     se                     [] @@ -736,14 +745,14 @@                  bucket,                  vs'                  ) -> do-                  let chk_beg = chk_i * tvExp hist_H_chk-                      bucket' = toInt32Exp bucket-                      dest_w' = toInt32Exp dest_w+                  let chk_beg = sExt64 chk_i * tvExp hist_H_chk+                      bucket' = toInt64Exp bucket+                      dest_w' = toInt64Exp dest_w                       bucket_in_bounds =                         bucket' .<. dest_w'                           .&&. chk_beg .<=. bucket'                           .&&. bucket' .<. (chk_beg + tvExp hist_H_chk)-                      bucket_is = [thread_local_subhisto_i, bucket' - chk_beg]+                      bucket_is = [sExt64 thread_local_subhisto_i, bucket' - chk_beg]                       vs_params = takeLast (length vs') $ lambdaParams lam                    sComment "perform atomic updates" $@@ -757,30 +766,28 @@         sOp $ Imp.ErrorSync Imp.FenceGlobal          sComment "Compact the multiple local memory subhistograms to result in global memory" $-          onSlugs $ \slug dests hist_H_chk histo_dims histo_size -> do-            bins_per_thread <--              dPrimVE "init_per_thread" $-                histo_size `divUp` kernelGroupSize constants-+          onSlugs $ \slug dests hist_H_chk histo_dims _histo_size bins_per_thread -> do             trunc_H <-               dPrimV "trunc_H" $-                sMin32 hist_H_chk $-                  toInt32Exp (histWidth (slugOp slug)) - chk_i * head histo_dims+                sMin64 hist_H_chk $+                  toInt64Exp (histWidth (slugOp slug))+                    - sExt64 chk_i * head histo_dims             let trunc_histo_dims =                   tvExp trunc_H :-                  map toInt32Exp (shapeDims (histShape (slugOp slug)))-            trunc_histo_size <- dPrimVE "histo_size" $ product trunc_histo_dims+                  map toInt64Exp (shapeDims (histShape (slugOp slug)))+            trunc_histo_size <- dPrimVE "histo_size" $ sExt32 $ product trunc_histo_dims              sFor "local_i" bins_per_thread $ \i -> do               j <-                 dPrimVE "j" $-                  i * kernelGroupSize constants + kernelLocalThreadId constants+                  i * sExt32 (kernelGroupSize constants)+                    + kernelLocalThreadId constants               sWhen (j .<. trunc_histo_size) $ do                 -- We are responsible for compacting the flat bin 'j', which                 -- we immediately unflatten.-                let local_bucket_is = unflattenIndex histo_dims j+                let local_bucket_is = unflattenIndex histo_dims $ sExt64 j                     global_bucket_is =-                      head local_bucket_is + chk_i * hist_H_chk :+                      head local_bucket_is + sExt64 chk_i * hist_H_chk :                       tail local_bucket_is                 dLParams $ lambdaParams $ histOp $ slugOp slug                 let (global_dests, local_dests) = unzip dests@@ -803,20 +810,20 @@                         (paramName yp)                         []                         (Var subhisto)-                        (subhisto_id + 1 : local_bucket_is)+                        (sExt64 subhisto_id + 1 : local_bucket_is)                     compileBody' xparams $ lambdaBody $ histOp $ slugOp slug                  sComment "Put final bucket value in global memory." $ do                   let global_is =-                        map Imp.vi32 segment_is-                          ++ [group_id `rem` unCount groups_per_segment]+                        map Imp.vi64 segment_is+                          ++ [sExt64 group_id `rem` unCount groups_per_segment]                           ++ global_bucket_is                   forM_ (zip xparams global_dests) $ \(xp, global_dest) ->                     copyDWIMFix global_dest global_is (Var $ paramName xp) []  histKernelLocal ::   TV Int32 ->-  Count NumGroups (Imp.TExp Int32) ->+  Count NumGroups (Imp.TExp Int64) ->   [PatElem KernelsMem] ->   Count NumGroups SubExp ->   Count GroupSize SubExp ->@@ -826,8 +833,8 @@   KernelBody KernelsMem ->   CallKernelGen () histKernelLocal num_subhistos_per_group_var groups_per_segment map_pes num_groups group_size space hist_S slugs kbody = do-  let num_groups' = fmap toInt32Exp num_groups-      group_size' = fmap toInt32Exp group_size+  let num_groups' = fmap toInt64Exp num_groups+      group_size' = fmap toInt64Exp group_size       num_subhistos_per_group = tvExp num_subhistos_per_group_var    emit $@@ -864,9 +871,9 @@   [PatElem KernelsMem] ->   Imp.TExp Int32 ->   SegSpace ->-  Imp.TExp Int32 ->-  Imp.TExp Int32 ->-  Imp.TExp Int32 ->+  Imp.TExp Int64 ->+  Imp.TExp Int64 ->+  Imp.TExp Int64 ->   Imp.TExp Int32 ->   [SegHistSlug] ->   KernelBody KernelsMem ->@@ -885,20 +892,20 @@   num_groups <-     fmap (Imp.Count . tvSize) $       dPrimV "num_groups" $-        hist_T `divUp` toInt32Exp (unCount group_size)-  let num_groups' = toInt32Exp <$> num_groups-      group_size' = toInt32Exp <$> group_size+        sExt64 hist_T `divUp` toInt64Exp (unCount group_size)+  let num_groups' = toInt64Exp <$> num_groups+      group_size' = toInt64Exp <$> group_size -  let r64 = isF64 . ConvOpExp (SIToFP Int32 Float64) . untyped-      t64 = isInt32 . ConvOpExp (FPToSI Float64 Int32) . untyped+  let r64 = isF64 . ConvOpExp (SIToFP Int64 Float64) . untyped+      t64 = isInt64 . ConvOpExp (FPToSI Float64 Int64) . untyped    -- M approximation.   hist_m' <-     dPrimVE "hist_m_prime" $       r64-        ( sMin32-            (tvExp hist_L `quot` hist_el_size)-            (hist_N `divUp` unCount num_groups')+        ( sMin64+            (sExt64 (tvExp hist_L `quot` hist_el_size))+            (hist_N `divUp` sExt64 (unCount num_groups'))         )         / r64 hist_H @@ -907,15 +914,15 @@   -- M in the paper, but not adjusted for asymptotic efficiency.   hist_M0 <-     dPrimVE "hist_M0" $-      sMax32 1 $ sMin32 (t64 hist_m') hist_B+      sMax64 1 $ sMin64 (t64 hist_m') hist_B    -- Minimal sequential chunking factor.   let q_small = 2    -- The number of segments/histograms produced..-  hist_Nout <- dPrimVE "hist_Nout" $ product $ map toInt32Exp segment_dims+  hist_Nout <- dPrimVE "hist_Nout" $ product $ map toInt64Exp segment_dims -  hist_Nin <- dPrimVE "hist_Nin" $ toInt32Exp $ last space_sizes+  hist_Nin <- dPrimVE "hist_Nin" $ toInt64Exp $ last space_sizes    -- Maximum M for work efficiency.   work_asymp_M_max <-@@ -928,9 +935,9 @@                 `divUp` sExt64 hist_Nout          -- Number of groups, rounded up.-        let r = hist_T_hist_min `divUp` hist_B+        let r = hist_T_hist_min `divUp` sExt32 hist_B -        dPrimVE "work_asymp_M_max" $ hist_Nin `quot` (r * hist_H)+        dPrimVE "work_asymp_M_max" $ hist_Nin `quot` (sExt64 r * hist_H)       else         dPrimVE "work_asymp_M_max" $           (hist_Nout * hist_N)@@ -939,7 +946,7 @@                    )    -- Number of subhistograms per result histogram.-  hist_M <- dPrimV "hist_M" $ sMin32 hist_M0 work_asymp_M_max+  hist_M <- dPrimV "hist_M" $ sExt32 $ sMin64 hist_M0 work_asymp_M_max    -- hist_M may be zero (which we'll check for below), but we need it   -- for some divisions first, so crudely make a nonzero form.@@ -949,7 +956,7 @@   -- working on the same (sub)histogram.   hist_C <-     dPrimVE "hist_C" $-      hist_B `divUp` hist_M_nonzero+      hist_B `divUp` sExt64 hist_M_nonzero    emit $ Imp.DebugPrint "local hist_M0" $ Just $ untyped hist_M0   emit $ Imp.DebugPrint "local work asymp M max" $ Just $ untyped work_asymp_M_max@@ -958,18 +965,30 @@   emit $ Imp.DebugPrint "local M" $ Just $ untyped $ tvExp hist_M   emit $     Imp.DebugPrint "local memory needed" $-      Just $ untyped $ hist_H * hist_el_size * tvExp hist_M+      Just $ untyped $ hist_H * hist_el_size * sExt64 (tvExp hist_M)    -- local_mem_needed is what we need to keep a single bucket in local   -- memory - this is an absolute minimum.  We can fit anything else   -- by doing multiple passes, although more than a few is   -- (heuristically) not efficient.-  local_mem_needed <- dPrimVE "local_mem_needed" $ hist_el_size * tvExp hist_M-  hist_S <- dPrimVE "hist_S" $ (hist_H * local_mem_needed) `divUp` tvExp hist_L+  local_mem_needed <-+    dPrimVE "local_mem_needed" $+      hist_el_size * sExt64 (tvExp hist_M)+  hist_S <-+    dPrimVE "hist_S" $+      sExt32 $+        (hist_H * local_mem_needed) `divUp` tvExp hist_L   let max_S = case bodyPassage kbody of         MustBeSinglePass -> 1         MayBeMultiPass -> fromIntegral $ maxinum $ map slugMaxLocalMemPasses slugs +  groups_per_segment <-+    if segmented+      then+        fmap Count $+          dPrimVE "groups_per_segment" $ unCount num_groups' `divUp` hist_Nout+      else pure num_groups'+   -- We only use local memory if the number of updates per histogram   -- at least matches the histogram size, as otherwise it is not   -- asymptotically efficient.  This mostly matters for the segmented@@ -981,10 +1000,6 @@           .&&. hist_C .<=. hist_B           .&&. tvExp hist_M .>. 0 -      groups_per_segment-        | segmented = num_groups' `divUp` Imp.Count hist_Nout-        | otherwise = num_groups'-       run = do         emit $ Imp.DebugPrint "## Using local memory" Nothing         emit $ Imp.DebugPrint "Histogram size (H)" $ Just $ untyped hist_H@@ -1020,9 +1035,9 @@   -- rather figuring out whether to use a local or global memory   -- strategy, as well as collapsing the subhistograms produced (which   -- are always in global memory, but their number may vary).-  let num_groups' = fmap toInt32Exp num_groups-      group_size' = fmap toInt32Exp group_size-      dims = map toInt32Exp $ segSpaceDims space+  let num_groups' = fmap toInt64Exp num_groups+      group_size' = fmap toInt64Exp group_size+      dims = map toInt64Exp $ segSpaceDims space        num_red_res = length ops + sum (map (length . histNeutral) ops)       (all_red_pes, map_pes) = splitAt num_red_res pes@@ -1038,7 +1053,7 @@     let hist_B = unCount group_size'      -- Size of a histogram.-    hist_H <- dPrimVE "hist_H" $ sum $ map (toInt32Exp . histWidth) ops+    hist_H <- dPrimVE "hist_H" $ sum $ map (toInt64Exp . histWidth) ops      -- Size of a single histogram element.  Actually the weighted     -- average of histogram elements in cases where we have more than@@ -1060,7 +1075,7 @@         sum (map (toInt32Exp . histRaceFactor . slugOp) slugs)           `quot` genericLength slugs -    let hist_T = unCount num_groups' * unCount group_size'+    let hist_T = sExt32 $ unCount num_groups' * unCount group_size'     emit $ Imp.DebugPrint "\n# SegHist" Nothing     emit $ Imp.DebugPrint "Number of threads (T)" $ Just $ untyped hist_T     emit $ Imp.DebugPrint "Desired group size (B)" $ Just $ untyped hist_B@@ -1068,7 +1083,7 @@     emit $ Imp.DebugPrint "Input elements per histogram (N)" $ Just $ untyped hist_N     emit $       Imp.DebugPrint "Number of segments" $-        Just $ untyped $ product $ map (toInt32Exp . snd) segment_dims+        Just $ untyped $ product $ map (toInt64Exp . snd) segment_dims     emit $ Imp.DebugPrint "Histogram element size (el_size)" $ Just $ untyped hist_el_size     emit $ Imp.DebugPrint "Race factor (RF)" $ Just $ untyped hist_RF     emit $ Imp.DebugPrint "Memory per set of subhistograms per segment" $ Just $ untyped h@@ -1126,7 +1141,7 @@           red_cont $             flip map subhistos $ \subhisto ->               ( Var subhisto,-                map Imp.vi32 $+                map Imp.vi64 $                   map fst segment_dims ++ [subhistogram_id, bucket_id] ++ vector_ids               )   where
src/Futhark/CodeGen/ImpGen/Kernels/SegMap.hs view
@@ -24,14 +24,15 @@   CallKernelGen () compileSegMap pat lvl space kbody = do   let (is, dims) = unzip $ unSegSpace space-      dims' = map toInt32Exp dims-      num_groups' = toInt32Exp <$> segNumGroups lvl-      group_size' = toInt32Exp <$> segGroupSize lvl+      dims' = map toInt64Exp dims+      num_groups' = toInt64Exp <$> segNumGroups lvl+      group_size' = toInt64Exp <$> segGroupSize lvl    case lvl of     SegThread {} -> do       emit $ Imp.DebugPrint "\n# SegMap" Nothing-      let virt_num_groups = product dims' `divUp` unCount group_size'+      let virt_num_groups =+            sExt32 $ product dims' `divUp` unCount group_size'       sKernelThread "segmap" num_groups' group_size' (segFlat space) $         virtualiseGroups (segVirt lvl) virt_num_groups $ \group_id -> do           local_tid <- kernelLocalThreadId . kernelConstants <$> askEnv@@ -40,7 +41,7 @@                   + sExt64 local_tid            zipWithM_ dPrimV_ is $-            map sExt32 $ unflattenIndex (map sExt64 dims') global_tid+            map sExt64 $ unflattenIndex (map sExt64 dims') global_tid            sWhen (isActive $ unSegSpace space) $             compileStms mempty (kernelBodyStms kbody) $@@ -48,10 +49,10 @@                 kernelBodyResult kbody     SegGroup {} ->       sKernelGroup "segmap_intragroup" num_groups' group_size' (segFlat space) $ do-        let virt_num_groups = product dims'+        let virt_num_groups = sExt32 $ product dims'         precomputeSegOpIDs (kernelBodyStms kbody) $           virtualiseGroups (segVirt lvl) virt_num_groups $ \group_id -> do-            zipWithM_ dPrimV_ is $ unflattenIndex dims' group_id+            zipWithM_ dPrimV_ is $ unflattenIndex dims' $ sExt64 group_id              compileStms mempty (kernelBodyStms kbody) $               zipWithM_ (compileGroupResult space) (patternElements pat) $
src/Futhark/CodeGen/ImpGen/Kernels/SegRed.hs view
@@ -72,7 +72,7 @@ -- for saving the results of the body.  The results should be -- represented as a pairing of a t'SubExp' along with a list of -- indexes into that 'SubExp' for reading the result.-type DoSegBody = ([(SubExp, [Imp.TExp Int32])] -> InKernelGen ()) -> InKernelGen ()+type DoSegBody = ([(SubExp, [Imp.TExp Int64])] -> InKernelGen ()) -> InKernelGen ()  -- | Compile 'SegRed' instance to host-level code with calls to -- various kernels.@@ -106,11 +106,11 @@   | genericLength reds > maxNumOps =     compilerLimitationS $       "compileSegRed': at most " ++ show maxNumOps ++ " reduction operators are supported."-  | [(_, Constant (IntValue (Int32Value 1))), _] <- unSegSpace space =+  | [(_, Constant (IntValue (Int64Value 1))), _] <- unSegSpace space =     nonsegmentedReduction pat num_groups group_size space reds body   | otherwise = do-    let group_size' = toInt32Exp $ unCount group_size-        segment_size = toInt32Exp $ last $ segSpaceDims space+    let group_size' = toInt64Exp $ unCount group_size+        segment_size = toInt64Exp $ last $ segSpaceDims space         use_small_segments = segment_size * 2 .<. group_size'     sIf       use_small_segments@@ -139,7 +139,7 @@       MemArray pt shape _ (ArrayIn mem _) -> do         let shape' = Shape [num_threads] <> shape         sArray "red_arr" pt shape' $-          ArrayIn mem $ IxFun.iota $ map pe32 $ shapeDims shape'+          ArrayIn mem $ IxFun.iota $ map pe64 $ shapeDims shape'       _ -> do         let pt = elemType $ paramType p             shape = Shape [group_size]@@ -176,9 +176,9 @@   CallKernelGen () nonsegmentedReduction segred_pat num_groups group_size space reds body = do   let (gtids, dims) = unzip $ unSegSpace space-      dims' = map toInt32Exp dims-      num_groups' = fmap toInt32Exp num_groups-      group_size' = fmap toInt32Exp group_size+      dims' = map toInt64Exp dims+      num_groups' = fmap toInt64Exp num_groups+      group_size' = fmap toInt64Exp group_size       global_tid = Imp.vi32 $ segFlat space       w = last dims' @@ -201,10 +201,12 @@      -- Since this is the nonsegmented case, all outer segment IDs must     -- necessarily be 0.-    forM_ gtids $ \v -> dPrimV_ v (0 :: Imp.TExp Int32)+    forM_ gtids $ \v -> dPrimV_ v (0 :: Imp.TExp Int64)      let num_elements = Imp.elements w-    let elems_per_thread = num_elements `divUp` Imp.elements (kernelNumThreads constants)+        elems_per_thread =+          num_elements+            `divUp` Imp.elements (sExt64 (kernelNumThreads constants))      slugs <-       mapM@@ -253,7 +255,7 @@             0             [0]             0-            (kernelNumGroups constants)+            (sExt64 $ kernelNumGroups constants)             slug             red_x_params             red_y_params@@ -276,19 +278,19 @@   CallKernelGen () smallSegmentsReduction (Pattern _ segred_pes) num_groups group_size space reds body = do   let (gtids, dims) = unzip $ unSegSpace space-      dims' = map toInt32Exp dims+      dims' = map toInt64Exp dims       segment_size = last dims'    -- Careful to avoid division by zero now.   segment_size_nonzero <--    dPrimVE "segment_size_nonzero" $ sMax32 1 segment_size+    dPrimVE "segment_size_nonzero" $ sMax64 1 segment_size -  let num_groups' = fmap toInt32Exp num_groups-      group_size' = fmap toInt32Exp group_size+  let num_groups' = fmap toInt64Exp num_groups+      group_size' = fmap toInt64Exp group_size   num_threads <- dPrimV "num_threads" $ unCount num_groups' * unCount group_size'   let num_segments = product $ init dims'       segments_per_group = unCount group_size' `quot` segment_size_nonzero-      required_groups = num_segments `divUp` segments_per_group+      required_groups = sExt32 $ num_segments `divUp` segments_per_group    emit $ Imp.DebugPrint "\n# SegRed-small" Nothing   emit $ Imp.DebugPrint "num_segments" $ Just $ untyped num_segments@@ -307,8 +309,10 @@       -- Compute the 'n' input indices.  The outer 'n-1' correspond to       -- the segment ID, and are computed from the group id.  The inner       -- is computed from the local thread id, and may be out-of-bounds.-      let ltid = kernelLocalThreadId constants-          segment_index = (ltid `quot` segment_size_nonzero) + (group_id' * segments_per_group)+      let ltid = sExt64 $ kernelLocalThreadId constants+          segment_index =+            (ltid `quot` segment_size_nonzero)+              + (sExt64 group_id' * sExt64 segments_per_group)           index_within_segment = ltid `rem` segment_size        zipWithM_ dPrimV_ (init gtids) $ unflattenIndex (init dims') segment_index@@ -336,13 +340,14 @@           out_of_bounds        sOp $ Imp.ErrorSync Imp.FenceLocal -- Also implicitly barrier.-      let crossesSegment from to = (to - from) .>. (to `rem` segment_size)+      let crossesSegment from to =+            (sExt64 to - sExt64 from) .>. (sExt64 to `rem` segment_size)       sWhen (segment_size .>. 0) $         sComment "perform segmented scan to imitate reduction" $           forM_ (zip reds reds_arrs) $ \(SegBinOp _ red_op _ _, red_arrs) ->             groupScan               (Just crossesSegment)-              (tvExp num_threads)+              (sExt64 $ tvExp num_threads)               (segment_size * segments_per_group)               red_op               red_arrs@@ -351,13 +356,15 @@        sComment "save final values of segments" $         sWhen-          ( group_id' * segments_per_group + ltid .<. num_segments+          ( sExt64 group_id' * segments_per_group + sExt64 ltid .<. num_segments               .&&. ltid .<. segments_per_group           )           $ forM_ (zip segred_pes (concat reds_arrs)) $ \(pe, arr) -> do             -- Figure out which segment result this thread should write...-            let flat_segment_index = group_id' * segments_per_group + ltid-                gtids' = unflattenIndex (init dims') flat_segment_index+            let flat_segment_index =+                  sExt64 group_id' * segments_per_group + sExt64 ltid+                gtids' =+                  unflattenIndex (init dims') flat_segment_index             copyDWIMFix               (patElemName pe)               gtids'@@ -378,11 +385,11 @@   CallKernelGen () largeSegmentsReduction segred_pat num_groups group_size space reds body = do   let (gtids, dims) = unzip $ unSegSpace space-      dims' = map toInt32Exp dims+      dims' = map toInt64Exp dims       num_segments = product $ init dims'       segment_size = last dims'-      num_groups' = fmap toInt32Exp num_groups-      group_size' = fmap toInt32Exp group_size+      num_groups' = fmap toInt64Exp num_groups+      group_size' = fmap toInt64Exp group_size    (groups_per_segment, elems_per_thread) <-     groupsPerSegmentAndElementsPerThread@@ -436,26 +443,26 @@     -- We probably do not have enough actual workgroups to cover the     -- entire iteration space.  Some groups thus have to perform double     -- duty; we put an outer loop to accomplish this.-    virtualiseGroups SegVirt (tvExp virt_num_groups) $ \group_id -> do+    virtualiseGroups SegVirt (sExt32 (tvExp virt_num_groups)) $ \group_id -> do       let segment_gtids = init gtids           w = last dims           local_tid = kernelLocalThreadId constants        flat_segment_id <-         dPrimVE "flat_segment_id" $-          group_id `quot` groups_per_segment+          group_id `quot` sExt32 groups_per_segment        global_tid <-         dPrimVE "global_tid" $-          (group_id * unCount group_size' + local_tid)-            `rem` (unCount group_size' * groups_per_segment)+          (sExt64 group_id * sExt64 (unCount group_size') + sExt64 local_tid)+            `rem` (sExt64 (unCount group_size') * groups_per_segment) -      let first_group_for_segment = flat_segment_id * groups_per_segment+      let first_group_for_segment = sExt64 flat_segment_id * groups_per_segment        zipWithM_ dPrimV_ segment_gtids $-        unflattenIndex (init dims') flat_segment_id-      dPrim_ (last gtids) int32-      let num_elements = Imp.elements $ toInt32Exp w+        unflattenIndex (init dims') $ sExt64 flat_segment_id+      dPrim_ (last gtids) int64+      let num_elements = Imp.elements $ toInt64Exp w        slugs <-         mapM (segBinOpSlug local_tid group_id) $@@ -465,7 +472,7 @@           constants           (zip gtids dims')           num_elements-          global_tid+          (sExt32 global_tid)           elems_per_thread           (tvVar threads_per_segment)           slugs@@ -501,8 +508,8 @@                     pes                     group_id                     flat_segment_id-                    (map Imp.vi32 segment_gtids)-                    first_group_for_segment+                    (map Imp.vi64 segment_gtids)+                    (sExt64 first_group_for_segment)                     groups_per_segment                     slug                     red_x_params@@ -521,25 +528,25 @@               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.vi32 segment_gtids) (Var acc) acc_is+                    copyDWIMFix (patElemName v) (map Imp.vi64 segment_gtids) (Var acc) acc_is        sIf (groups_per_segment .==. 1) one_group_per_segment multiple_groups_per_segment  -- Careful to avoid division by zero here.  We have at least one group -- per segment. groupsPerSegmentAndElementsPerThread ::-  Imp.TExp Int32 ->-  Imp.TExp Int32 ->-  Count NumGroups (Imp.TExp Int32) ->-  Count GroupSize (Imp.TExp Int32) ->+  Imp.TExp Int64 ->+  Imp.TExp Int64 ->+  Count NumGroups (Imp.TExp Int64) ->+  Count GroupSize (Imp.TExp Int64) ->   CallKernelGen-    ( Imp.TExp Int32,-      Imp.Count Imp.Elements (Imp.TExp Int32)+    ( Imp.TExp Int64,+      Imp.Count Imp.Elements (Imp.TExp Int64)     ) groupsPerSegmentAndElementsPerThread segment_size num_segments num_groups_hint group_size = do   groups_per_segment <-     dPrimVE "groups_per_segment" $-      unCount num_groups_hint `divUp` sMax32 1 num_segments+      unCount num_groups_hint `divUp` sMax64 1 num_segments   elements_per_thread <-     dPrimVE "elements_per_thread" $       segment_size `divUp` (unCount group_size * groups_per_segment)@@ -552,7 +559,7 @@     -- (either local or global memory).     slugArrs :: [VName],     -- | Places to store accumulator in stage 1 reduction.-    slugAccs :: [(VName, [Imp.TExp Int32])]+    slugAccs :: [(VName, [Imp.TExp Int64])]   }  slugBody :: SegBinOpSlug -> Body KernelsMem@@ -585,29 +592,29 @@         acc <- dPrim (baseString (paramName p) <> "_acc") t         return (tvVar acc, [])       | otherwise =-        return (param_arr, [local_tid, group_id])+        return (param_arr, [sExt64 local_tid, sExt64 group_id])  reductionStageZero ::   KernelConstants ->-  [(VName, Imp.TExp Int32)] ->-  Imp.Count Imp.Elements (Imp.TExp Int32) ->+  [(VName, Imp.TExp Int64)] ->+  Imp.Count Imp.Elements (Imp.TExp Int64) ->   Imp.TExp Int32 ->-  Imp.Count Imp.Elements (Imp.TExp Int32) ->+  Imp.Count Imp.Elements (Imp.TExp Int64) ->   VName ->   [SegBinOpSlug] ->   DoSegBody ->   InKernelGen ([Lambda KernelsMem], InKernelGen ()) reductionStageZero constants ispace num_elements global_tid elems_per_thread threads_per_segment slugs body = do   let (gtids, _dims) = unzip ispace-      gtid = mkTV (last gtids) int32-      local_tid = kernelLocalThreadId constants+      gtid = mkTV (last gtids) int64+      local_tid = sExt64 $ kernelLocalThreadId constants    -- Figure out how many elements this thread should process.-  chunk_size <- dPrim "chunk_size" int32+  chunk_size <- dPrim "chunk_size" int64   let ordering = case slugsComm slugs of         Commutative -> SplitStrided $ Var threads_per_segment         Noncommutative -> SplitContiguous-  computeThreadChunkSize ordering global_tid elems_per_thread num_elements chunk_size+  computeThreadChunkSize ordering (sExt64 global_tid) elems_per_thread num_elements chunk_size    dScope Nothing $ scopeOfLParams $ concatMap slugParams slugs @@ -631,7 +638,7 @@                   copyDWIMFix arr [local_tid] (Var $ paramName p) []              sOp $ Imp.ErrorSync Imp.FenceLocal -- Also implicitly barrier.-            groupReduce (kernelGroupSize constants) slug_op_renamed (slugArrs slug)+            groupReduce (sExt32 (kernelGroupSize constants)) slug_op_renamed (slugArrs slug)              sOp $ Imp.Barrier Imp.FenceLocal @@ -656,13 +663,13 @@     gtid       <-- case comm of         Commutative ->-          global_tid-            + Imp.vi32 threads_per_segment * i+          sExt64 global_tid+            + Imp.vi64 threads_per_segment * i         Noncommutative ->-          let index_in_segment = global_tid `quot` kernelGroupSize constants-           in local_tid-                + (index_in_segment * Imp.unCount elems_per_thread + i)-                * kernelGroupSize constants+          let index_in_segment = global_tid `quot` sExt32 (kernelGroupSize constants)+           in sExt64 local_tid+                + (sExt64 index_in_segment * Imp.unCount elems_per_thread + i)+                * sExt64 (kernelGroupSize constants)      check_bounds $       sComment "apply map function" $@@ -704,10 +711,10 @@  reductionStageOne ::   KernelConstants ->-  [(VName, Imp.TExp Int32)] ->-  Imp.Count Imp.Elements (Imp.TExp Int32) ->+  [(VName, Imp.TExp Int64)] ->+  Imp.Count Imp.Elements (Imp.TExp Int64) ->   Imp.TExp Int32 ->-  Imp.Count Imp.Elements (Imp.TExp Int32) ->+  Imp.Count Imp.Elements (Imp.TExp Int64) ->   VName ->   [SegBinOpSlug] ->   DoSegBody ->@@ -730,9 +737,9 @@   [PatElem KernelsMem] ->   Imp.TExp Int32 ->   Imp.TExp Int32 ->-  [Imp.TExp Int32] ->-  Imp.TExp Int32 ->-  Imp.TExp Int32 ->+  [Imp.TExp Int64] ->+  Imp.TExp Int64 ->+  Imp.TExp Int64 ->   SegBinOpSlug ->   [LParam KernelsMem] ->   [LParam KernelsMem] ->@@ -770,13 +777,14 @@     (counter_mem, _, counter_offset) <-       fullyIndexArray         counter-        [ counter_i * num_counters-            + flat_segment_id `rem` num_counters+        [ sExt64 $+            counter_i * num_counters+              + flat_segment_id `rem` num_counters         ]     comment "first thread in group saves group result to global memory" $       sWhen (local_tid .==. 0) $ do         forM_ (take (length nes) $ zip group_res_arrs (slugAccs slug)) $ \(v, (acc, acc_is)) ->-          copyDWIMFix v [0, group_id] (Var acc) acc_is+          copyDWIMFix v [0, sExt64 group_id] (Var acc) acc_is         sOp $ Imp.MemFence Imp.FenceGlobal         -- Increment the counter, thus stating that our result is         -- available.@@ -786,7 +794,7 @@               Int32               (tvVar old_counter)               counter_mem-              (sExt32 <$> counter_offset)+              counter_offset               $ untyped (1 :: Imp.TExp Int32)         -- Now check if we were the last group to write our result.  If         -- so, it is our responsibility to produce the final result.@@ -806,7 +814,7 @@       sWhen (local_tid .==. 0) $         sOp $           Imp.Atomic DefaultSpace $-            Imp.AtomicAdd Int32 (tvVar old_counter) counter_mem (sExt32 <$> counter_offset) $+            Imp.AtomicAdd Int32 (tvVar old_counter) counter_mem counter_offset $               untyped $ negate groups_per_segment        sLoopNest (slugShape slug) $ \vec_is -> do@@ -818,7 +826,7 @@         comment "read in the per-group-results" $ do           read_per_thread <-             dPrimVE "read_per_thread" $-              groups_per_segment `divUp` group_size+              groups_per_segment `divUp` sExt64 group_size            forM_ (zip red_x_params nes) $ \(p, ne) ->             copyDWIMFix (paramName p) [] ne []@@ -826,7 +834,7 @@           sFor "i" read_per_thread $ \i -> do             group_res_id <-               dPrimVE "group_res_id" $-                local_tid * read_per_thread + i+                sExt64 local_tid * read_per_thread + i             index_of_group_res <-               dPrimVE "index_of_group_res" $                 first_group_for_segment + group_res_id@@ -846,12 +854,12 @@          forM_ (zip red_x_params red_arrs) $ \(p, arr) ->           when (primType $ paramType p) $-            copyDWIMFix arr [local_tid] (Var $ paramName p) []+            copyDWIMFix arr [sExt64 local_tid] (Var $ paramName p) []          sOp $ Imp.Barrier Imp.FenceLocal          sComment "reduce the per-group results" $ do-          groupReduce group_size red_op_renamed red_arrs+          groupReduce (sExt32 group_size) red_op_renamed red_arrs            sComment "and back to memory with the final result" $             sWhen (local_tid .==. 0) $
src/Futhark/CodeGen/ImpGen/Kernels/SegScan.hs view
@@ -44,7 +44,7 @@               arr <-                 lift $                   sArray "scan_arr" pt shape' $-                    ArrayIn mem $ IxFun.iota $ map pe32 $ shapeDims shape'+                    ArrayIn mem $ IxFun.iota $ map pe64 $ shapeDims shape'               return (arr, [])             _ -> do               let pt = elemType $ paramType p@@ -69,13 +69,13 @@           mem <- lift $ sDeclareMem "scan_arr_mem" $ Space "local"           return ([size], mem) -type CrossesSegment = Maybe (Imp.TExp Int32 -> Imp.TExp Int32 -> Imp.TExp Bool)+type CrossesSegment = Maybe (Imp.TExp Int64 -> Imp.TExp Int64 -> Imp.TExp Bool) -localArrayIndex :: KernelConstants -> Type -> Imp.TExp Int32+localArrayIndex :: KernelConstants -> Type -> Imp.TExp Int64 localArrayIndex constants t =   if primType t-    then kernelLocalThreadId constants-    else kernelGlobalThreadId constants+    then sExt64 (kernelLocalThreadId constants)+    else sExt64 (kernelGlobalThreadId constants)  barrierFor :: Lambda KernelsMem -> (Bool, Imp.Fence, InKernelGen ()) barrierFor scan_op = (array_scan, fence, sOp $ Imp.Barrier fence)@@ -100,7 +100,7 @@     forM_ (zip pes scan_res) $ \(pe, res) ->       copyDWIMFix         (patElemName pe)-        (map Imp.vi32 gtids)+        (map Imp.vi64 gtids)         (kernelResultSubExp res)         []   | otherwise =@@ -108,7 +108,7 @@       copyDWIMFix (paramName p) [] (kernelResultSubExp res) []  readToScanValues ::-  [Imp.TExp Int32] ->+  [Imp.TExp Int64] ->   [PatElem KernelsMem] ->   SegBinOp KernelsMem ->   InKernelGen ()@@ -120,9 +120,9 @@     return ()  readCarries ::-  Imp.TExp Int32 ->-  [Imp.TExp Int32] ->-  [Imp.TExp Int32] ->+  Imp.TExp Int64 ->+  [Imp.TExp Int64] ->+  [Imp.TExp Int64] ->   [PatElem KernelsMem] ->   SegBinOp KernelsMem ->   InKernelGen ()@@ -152,16 +152,16 @@   SegSpace ->   [SegBinOp KernelsMem] ->   KernelBody KernelsMem ->-  CallKernelGen (TV Int32, Imp.TExp Int32, CrossesSegment)+  CallKernelGen (TV Int32, Imp.TExp Int64, CrossesSegment) scanStage1 (Pattern _ all_pes) num_groups group_size space scans kbody = do-  let num_groups' = fmap toInt32Exp num_groups-      group_size' = fmap toInt32Exp group_size-  num_threads <- dPrimV "num_threads" $ unCount num_groups' * unCount group_size'+  let num_groups' = fmap toInt64Exp num_groups+      group_size' = fmap toInt64Exp group_size+  num_threads <- dPrimV "num_threads" $ sExt32 $ unCount num_groups' * unCount group_size'    let (gtids, dims) = unzip $ unSegSpace space-      dims' = map toInt32Exp dims+      dims' = map toInt64Exp dims   let num_elements = product dims'-      elems_per_thread = num_elements `divUp` tvExp num_threads+      elems_per_thread = num_elements `divUp` sExt64 (tvExp num_threads)       elems_per_group = unCount group_size' * elems_per_thread    let crossesSegment =@@ -184,18 +184,18 @@     sFor "j" elems_per_thread $ \j -> do       chunk_offset <-         dPrimV "chunk_offset" $-          kernelGroupSize constants * j-            + kernelGroupId constants * elems_per_group+          sExt64 (kernelGroupSize constants) * j+            + sExt64 (kernelGroupId constants) * elems_per_group       flat_idx <-         dPrimV "flat_idx" $-          tvExp chunk_offset + kernelLocalThreadId constants+          tvExp chunk_offset + sExt64 (kernelLocalThreadId constants)       -- Construct segment indices.       zipWithM_ dPrimV_ gtids $ unflattenIndex dims' $ tvExp flat_idx        let per_scan_pes = segBinOpChunks scans all_pes            in_bounds =-            foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi32 gtids) dims'+            foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi64 gtids) dims'            when_in_bounds = compileStms mempty (kernelBodyStms kbody) $ do             let (all_scan_res, map_res) =@@ -211,7 +211,7 @@               forM_ (zip (takeLast (length map_res) all_pes) map_res) $ \(pe, se) ->                 copyDWIMFix                   (patElemName pe)-                  (map Imp.vi32 gtids)+                  (map Imp.vi64 gtids)                   (kernelResultSubExp se)                   [] @@ -232,7 +232,7 @@                 sIf                   in_bounds                   ( do-                      readToScanValues (map Imp.vi32 gtids ++ vec_is) pes scan+                      readToScanValues (map Imp.vi64 gtids ++ vec_is) pes scan                       readCarries (tvExp chunk_offset) dims' vec_is pes scan                   )                   ( forM_ (zip (yParams scan) (segBinOpNeutral scan)) $ \(p, ne) ->@@ -242,13 +242,14 @@               sComment "combine with carry and write to local memory" $                 compileStms mempty (bodyStms $ lambdaBody scan_op) $                   forM_ (zip3 rets local_arrs (bodyResult $ lambdaBody scan_op)) $-                    \(t, arr, se) -> copyDWIMFix arr [localArrayIndex constants t] se []+                    \(t, arr, se) ->+                      copyDWIMFix arr [localArrayIndex constants t] se []                let crossesSegment' = do                     f <- crossesSegment                     Just $ \from to ->-                      let from' = from + tvExp chunk_offset-                          to' = to + tvExp chunk_offset+                      let from' = sExt64 from + tvExp chunk_offset+                          to' = sExt64 to + tvExp chunk_offset                        in f from' to'                sOp $ Imp.ErrorSync fence@@ -257,8 +258,8 @@               scan_op_renamed <- renameLambda scan_op               groupScan                 crossesSegment'-                (tvExp num_threads)-                (kernelGroupSize constants)+                (sExt64 $ tvExp num_threads)+                (sExt64 $ kernelGroupSize constants)                 scan_op_renamed                 local_arrs @@ -267,7 +268,7 @@                   forM_ (zip3 rets pes local_arrs) $ \(t, pe, arr) ->                     copyDWIMFix                       (patElemName pe)-                      (map Imp.vi32 gtids ++ vec_is)+                      (map Imp.vi64 gtids ++ vec_is)                       (Var arr)                       [localArrayIndex constants t] @@ -280,8 +281,10 @@                         []                         (Var arr)                         [ if primType $ paramType p-                            then kernelGroupSize constants - 1-                            else (kernelGroupId constants + 1) * kernelGroupSize constants - 1+                            then sExt64 (kernelGroupSize constants) - 1+                            else+                              (sExt64 (kernelGroupId constants) + 1)+                                * sExt64 (kernelGroupSize constants) - 1                         ]                   load_neutral =                     forM_ (zip nes scan_x_params) $ \(ne, p) ->@@ -294,10 +297,10 @@                     Just f ->                       f                         ( tvExp chunk_offset-                            + kernelGroupSize constants -1+                            + sExt64 (kernelGroupSize constants) -1                         )                         ( tvExp chunk_offset-                            + kernelGroupSize constants+                            + sExt64 (kernelGroupSize constants)                         )                 should_load_carry <-                   dPrimVE "should_load_carry" $@@ -313,7 +316,7 @@ scanStage2 ::   Pattern KernelsMem ->   TV Int32 ->-  Imp.TExp Int32 ->+  Imp.TExp Int64 ->   Count NumGroups SubExp ->   CrossesSegment ->   SegSpace ->@@ -321,16 +324,18 @@   CallKernelGen () scanStage2 (Pattern _ all_pes) stage1_num_threads elems_per_group num_groups crossesSegment space scans = do   let (gtids, dims) = unzip $ unSegSpace space-      dims' = map toInt32Exp dims+      dims' = map toInt64Exp dims    -- Our group size is the number of groups for the stage 1 kernel.   let group_size = Count $ unCount num_groups-      group_size' = fmap toInt32Exp group_size+      group_size' = fmap toInt64Exp group_size    let crossesSegment' = do         f <- crossesSegment         Just $ \from to ->-          f ((from + 1) * elems_per_group - 1) ((to + 1) * elems_per_group - 1)+          f+            ((sExt64 from + 1) * elems_per_group - 1)+            ((sExt64 to + 1) * elems_per_group - 1)    sKernelThread "scan_stage2" 1 group_size' (segFlat space) $ do     constants <- kernelConstants <$> askEnv@@ -340,17 +345,17 @@      flat_idx <-       dPrimV "flat_idx" $-        (kernelLocalThreadId constants + 1) * elems_per_group - 1+        (sExt64 (kernelLocalThreadId constants) + 1) * elems_per_group - 1     -- Construct segment indices.     zipWithM_ dPrimV_ gtids $ unflattenIndex dims' $ tvExp flat_idx      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.vi32 gtids ++ vec_is+          let glob_is = map Imp.vi64 gtids ++ vec_is                in_bounds =-                foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi32 gtids) dims'+                foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi64 gtids) dims'                when_in_bounds = forM_ (zip3 rets local_arrs pes) $ \(t, arr, pe) ->                 copyDWIMFix@@ -371,8 +376,8 @@            groupScan             crossesSegment'-            (tvExp stage1_num_threads)-            (kernelGroupSize constants)+            (sExt64 $ tvExp stage1_num_threads)+            (sExt64 $ kernelGroupSize constants)             scan_op             local_arrs @@ -389,19 +394,19 @@   Pattern KernelsMem ->   Count NumGroups SubExp ->   Count GroupSize SubExp ->-  Imp.TExp Int32 ->+  Imp.TExp Int64 ->   CrossesSegment ->   SegSpace ->   [SegBinOp KernelsMem] ->   CallKernelGen () scanStage3 (Pattern _ all_pes) num_groups group_size elems_per_group crossesSegment space scans = do-  let num_groups' = fmap toInt32Exp num_groups-      group_size' = fmap toInt32Exp group_size+  let num_groups' = fmap toInt64Exp num_groups+      group_size' = fmap toInt64Exp group_size       (gtids, dims) = unzip $ unSegSpace space-      dims' = map toInt32Exp dims+      dims' = map toInt64Exp dims   required_groups <-     dPrimVE "required_groups" $-      product dims' `divUp` unCount group_size'+      sExt32 $ product dims' `divUp` sExt64 (unCount group_size')    sKernelThread "scan_stage3" num_groups' group_size' (segFlat space) $     virtualiseGroups SegVirt required_groups $ \virt_group_id -> do@@ -410,8 +415,8 @@       -- Compute our logical index.       flat_idx <-         dPrimVE "flat_idx" $-          virt_group_id * unCount group_size'-            + kernelLocalThreadId constants+          sExt64 virt_group_id * sExt64 (unCount group_size')+            + sExt64 (kernelLocalThreadId constants)       zipWithM_ dPrimV_ gtids $ unflattenIndex dims' flat_idx        -- Figure out which group this element was originally in.@@ -428,7 +433,7 @@       -- then the carry was updated in stage 2), and we are not crossing       -- a segment boundary.       let in_bounds =-            foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi32 gtids) dims'+            foldl1 (.&&.) $ zipWith (.<.) (map Imp.vi64 gtids) dims'           crosses_segment =             fromMaybe false $               crossesSegment@@ -459,14 +464,14 @@                     (paramName p)                     []                     (Var $ patElemName pe)-                    (map Imp.vi32 gtids ++ vec_is)+                    (map Imp.vi64 gtids ++ vec_is)                  compileBody' scan_x_params $ lambdaBody scan_op                  forM_ (zip scan_x_params pes) $ \(p, pe) ->                   copyDWIMFix                     (patElemName pe)-                    (map Imp.vi32 gtids ++ vec_is)+                    (map Imp.vi64 gtids ++ vec_is)                     (Var $ paramName p)                     [] @@ -485,14 +490,14 @@   -- Since stage 2 involves a group size equal to the number of groups   -- used for stage 1, we have to cap this number to the maximum group   -- size.-  stage1_max_num_groups <- dPrim "stage1_max_num_groups" int32+  stage1_max_num_groups <- dPrim "stage1_max_num_groups" int64   sOp $ Imp.GetSizeMax (tvVar stage1_max_num_groups) SizeGroup    stage1_num_groups <-     fmap (Imp.Count . tvSize) $       dPrimV "stage1_num_groups" $-        sMin32 (tvExp stage1_max_num_groups) $-          toInt32Exp $ Imp.unCount $ segNumGroups lvl+        sMin64 (tvExp stage1_max_num_groups) $+          toInt64Exp $ Imp.unCount $ segNumGroups lvl    (stage1_num_threads, elems_per_group, crossesSegment) <-     scanStage1 pat stage1_num_groups (segGroupSize lvl) space scans kbody@@ -502,4 +507,4 @@   scanStage2 pat stage1_num_threads elems_per_group stage1_num_groups crossesSegment space scans   scanStage3 pat (segNumGroups lvl) (segGroupSize lvl) elems_per_group crossesSegment space scans   where-    n = product $ map toInt32Exp $ segSpaceDims space+    n = product $ map toInt64Exp $ segSpaceDims space
src/Futhark/CodeGen/ImpGen/Kernels/ToOpenCL.hs view
@@ -180,7 +180,7 @@    let params =         [ [C.cparam|__global int *global_failure|],-          [C.cparam|__global int *global_failure_args|]+          [C.cparam|__global typename int64_t *global_failure_args|]         ]       (func, cstate) =         genGPUCode FunMode (functionBody device_func) failures $@@ -312,7 +312,7 @@       failure_params =         [ [C.cparam|__global int *global_failure|],           [C.cparam|int failure_is_an_option|],-          [C.cparam|__global int *global_failure_args|]+          [C.cparam|__global typename int64_t *global_failure_args|]         ]        params =@@ -780,6 +780,10 @@       let setArgs _ [] = return []           setArgs i (ErrorString {} : parts') = setArgs i parts'           setArgs i (ErrorInt32 x : parts') = do+            x' <- GC.compileExp x+            stms <- setArgs (i + 1) parts'+            return $ [C.cstm|global_failure_args[$int:i] = (typename int64_t)$exp:x';|] : stms+          setArgs i (ErrorInt64 x : parts') = do             x' <- GC.compileExp x             stms <- setArgs (i + 1) parts'             return $ [C.cstm|global_failure_args[$int:i] = $exp:x';|] : stms
+ src/Futhark/CodeGen/ImpGen/Multicore.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}++module Futhark.CodeGen.ImpGen.Multicore+  ( Futhark.CodeGen.ImpGen.Multicore.compileProg,+    Warnings,+  )+where++import qualified Futhark.CodeGen.ImpCode.Multicore as Imp+import Futhark.CodeGen.ImpGen+import Futhark.CodeGen.ImpGen.Multicore.Base+import Futhark.CodeGen.ImpGen.Multicore.SegHist+import Futhark.CodeGen.ImpGen.Multicore.SegMap+import Futhark.CodeGen.ImpGen.Multicore.SegRed+import Futhark.CodeGen.ImpGen.Multicore.SegScan+import Futhark.IR.MCMem+import Futhark.MonadFreshNames+import Prelude hiding (quot, rem)++-- GCC supported primitve atomic Operations+-- TODO: Add support for 1, 2, and 16 bytes too+gccAtomics :: AtomicBinOp+gccAtomics = flip lookup cpu+  where+    cpu =+      [ (Add Int32 OverflowUndef, Imp.AtomicAdd Int32),+        (Sub Int32 OverflowUndef, Imp.AtomicSub Int32),+        (And Int32, Imp.AtomicAnd Int32),+        (Xor Int32, Imp.AtomicXor Int32),+        (Or Int32, Imp.AtomicOr Int32),+        (Add Int64 OverflowUndef, Imp.AtomicAdd Int64),+        (Sub Int64 OverflowUndef, Imp.AtomicSub Int64),+        (And Int64, Imp.AtomicAnd Int64),+        (Xor Int64, Imp.AtomicXor Int64),+        (Or Int64, Imp.AtomicOr Int64)+      ]++compileProg ::+  MonadFreshNames m =>+  Prog MCMem ->+  m (Warnings, Imp.Definitions Imp.Multicore)+compileProg = Futhark.CodeGen.ImpGen.compileProg (HostEnv gccAtomics) ops Imp.DefaultSpace+  where+    ops = defaultOperations opCompiler+    opCompiler dest (Alloc e space) = compileAlloc dest e space+    opCompiler dest (Inner op) = compileMCOp dest op++compileMCOp ::+  Pattern MCMem ->+  MCOp MCMem () ->+  ImpM MCMem HostEnv Imp.Multicore ()+compileMCOp _ (OtherOp ()) = pure ()+compileMCOp pat (ParOp par_op op) = do+  let space = getSpace op+  dPrimV_ (segFlat space) (0 :: Imp.TExp Int32)+  iterations <- getIterationDomain op space+  nsubtasks <- dPrim "num_tasks" $ IntType Int32+  seq_code <- compileSegOp pat op nsubtasks+  retvals <- getReturnParams pat op++  let scheduling_info = Imp.SchedulerInfo (tvVar nsubtasks) (untyped iterations)++  par_code <- case par_op of+    Just nested_op -> do+      let space' = getSpace nested_op+      dPrimV_ (segFlat space') (0 :: Imp.TExp Int32)+      compileSegOp pat nested_op nsubtasks+    Nothing -> return mempty++  let par_task = case par_op of+        Just nested_op -> Just $ Imp.ParallelTask par_code $ segFlat $ getSpace nested_op+        Nothing -> Nothing++  let non_free =+        ( [segFlat space, tvVar nsubtasks]+            ++ map Imp.paramName retvals+        )+          ++ case par_op of+            Just nested_op ->+              [segFlat $ getSpace nested_op]+            Nothing -> []++  s <- segOpString op+  free_params <- freeParams (par_code <> seq_code) non_free+  let seq_task = Imp.ParallelTask seq_code (segFlat space)+  emit $ Imp.Op $ Imp.Segop s free_params seq_task par_task retvals $ scheduling_info (decideScheduling' op seq_code)++compileSegOp ::+  Pattern MCMem ->+  SegOp () MCMem ->+  TV Int32 ->+  ImpM MCMem HostEnv Imp.Multicore Imp.Code+compileSegOp pat (SegHist _ space histops _ kbody) ntasks =+  compileSegHist pat space histops kbody ntasks+compileSegOp pat (SegScan _ space scans _ kbody) ntasks =+  compileSegScan pat space scans kbody ntasks+compileSegOp pat (SegRed _ space reds _ kbody) ntasks =+  compileSegRed pat space reds kbody ntasks+compileSegOp pat (SegMap _ space _ kbody) _ =+  compileSegMap pat space kbody
+ src/Futhark/CodeGen/ImpGen/Multicore/Base.hs view
@@ -0,0 +1,458 @@+module Futhark.CodeGen.ImpGen.Multicore.Base+  ( toParam,+    compileKBody,+    extractAllocations,+    compileThreadResult,+    HostEnv (..),+    AtomicBinOp,+    MulticoreGen,+    decideScheduling,+    decideScheduling',+    groupResultArrays,+    renameSegBinOp,+    resultArrays,+    freeParams,+    renameHistOpLambda,+    atomicUpdateLocking,+    AtomicUpdate (..),+    Locking (..),+    getSpace,+    getIterationDomain,+    getReturnParams,+    segOpString,+  )+where++import Control.Monad+import Data.Bifunctor+import Data.List (elemIndex, find)+import Data.Maybe+import qualified Futhark.CodeGen.ImpCode.Multicore as Imp+import Futhark.CodeGen.ImpGen+import Futhark.Error+import Futhark.IR.MCMem+import Futhark.Transform.Rename+import Futhark.Util (maybeNth)+import Prelude hiding (quot, rem)++-- | Is there an atomic t'BinOp' corresponding to this t'BinOp'?+type AtomicBinOp =+  BinOp ->+  Maybe (VName -> VName -> Imp.Count Imp.Elements (Imp.TExp Int32) -> Imp.Exp -> Imp.AtomicOp)++newtype HostEnv = HostEnv+  {hostAtomics :: AtomicBinOp}++type MulticoreGen = ImpM MCMem HostEnv Imp.Multicore++segOpString :: SegOp () MCMem -> MulticoreGen String+segOpString SegMap {} = return "segmap"+segOpString SegRed {} = return "segred"+segOpString SegScan {} = return "segscan"+segOpString SegHist {} = return "seghist"++toParam :: VName -> TypeBase shape u -> MulticoreGen Imp.Param+toParam name (Prim pt) = return $ Imp.ScalarParam name pt+toParam name (Mem space) = return $ Imp.MemParam name space+toParam name Array {} = do+  name_entry <- lookupVar name+  case name_entry of+    ArrayVar _ (ArrayEntry (MemLocation mem _ _) _) ->+      return $ Imp.MemParam mem DefaultSpace+    _ -> error $ "[toParam] Could not handle array for " ++ show name++getSpace :: SegOp () MCMem -> SegSpace+getSpace (SegHist _ space _ _ _) = space+getSpace (SegRed _ space _ _ _) = space+getSpace (SegScan _ space _ _ _) = space+getSpace (SegMap _ space _ _) = space++getIterationDomain :: SegOp () MCMem -> SegSpace -> MulticoreGen (Imp.TExp Int64)+getIterationDomain SegMap {} space = do+  let ns = map snd $ unSegSpace space+      ns_64 = map (sExt64 . toInt32Exp) ns+  return $ product ns_64+getIterationDomain _ space = do+  let ns = map snd $ unSegSpace space+      ns_64 = map (sExt64 . toInt32Exp) ns+  case unSegSpace space of+    [_] -> return $ product ns_64+    -- A segmented SegOp is over the segments+    -- so we drop the last dimension, which is+    -- executed sequentially+    _ -> return $ product $ init ns_64++-- When the SegRed's return value is a scalar+-- we perform a call by value-result in the segop function+getReturnParams :: Pattern MCMem -> SegOp () MCMem -> MulticoreGen [Imp.Param]+getReturnParams pat SegRed {} = do+  let retvals = map patElemName $ patternElements pat+  retvals_ts <- mapM lookupType retvals+  zipWithM toParam retvals retvals_ts+getReturnParams _ _ = return mempty++renameSegBinOp :: [SegBinOp MCMem] -> MulticoreGen [SegBinOp MCMem]+renameSegBinOp segbinops =+  forM segbinops $ \(SegBinOp comm lam ne shape) -> do+    lam' <- renameLambda lam+    return $ SegBinOp comm lam' ne shape++compileKBody ::+  KernelBody MCMem ->+  ([(SubExp, [Imp.Exp])] -> ImpM MCMem () Imp.Multicore ()) ->+  ImpM MCMem () Imp.Multicore ()+compileKBody kbody red_cont =+  compileStms (freeIn $ kernelBodyResult kbody) (kernelBodyStms kbody) $ do+    let red_res = kernelBodyResult kbody+    red_cont $ zip (map kernelResultSubExp red_res) $ repeat []++compileThreadResult ::+  SegSpace ->+  PatElem MCMem ->+  KernelResult ->+  MulticoreGen ()+compileThreadResult space pe (Returns _ what) = do+  let is = map (Imp.vi64 . fst) $ unSegSpace space+  copyDWIMFix (patElemName pe) is what []+compileThreadResult _ _ ConcatReturns {} =+  compilerBugS "compileThreadResult: ConcatReturn unhandled."+compileThreadResult _ _ WriteReturns {} =+  compilerBugS "compileThreadResult: WriteReturns unhandled."+compileThreadResult _ _ TileReturns {} =+  compilerBugS "compileThreadResult: TileReturns unhandled."++freeVariables :: Imp.Code -> [VName] -> [VName]+freeVariables code names =+  namesToList $ freeIn code `namesSubtract` namesFromList names++freeParams :: Imp.Code -> [VName] -> MulticoreGen [Imp.Param]+freeParams code names = do+  let freeVars = freeVariables code names+  ts <- mapM lookupType freeVars+  zipWithM toParam freeVars ts++-- | Arrays for storing group results.+resultArrays :: String -> [SegBinOp MCMem] -> MulticoreGen [[VName]]+resultArrays s segops =+  forM segops $ \(SegBinOp _ lam _ shape) ->+    forM (lambdaReturnType lam) $ \t -> do+      let pt = elemType t+          full_shape = shape <> arrayShape t+      sAllocArray s pt full_shape DefaultSpace++-- | Arrays for storing group results shared between threads+groupResultArrays ::+  String ->+  SubExp ->+  [SegBinOp MCMem] ->+  MulticoreGen [[VName]]+groupResultArrays s num_threads reds =+  forM reds $ \(SegBinOp _ lam _ shape) ->+    forM (lambdaReturnType lam) $ \t -> do+      let pt = elemType t+          full_shape = Shape [num_threads] <> shape <> arrayShape t+      sAllocArray s pt full_shape DefaultSpace++isLoadBalanced :: Imp.Code -> Bool+isLoadBalanced (a Imp.:>>: b) = isLoadBalanced a && isLoadBalanced b+isLoadBalanced (Imp.For _ _ a) = isLoadBalanced a+isLoadBalanced (Imp.If _ a b) = isLoadBalanced a && isLoadBalanced b+isLoadBalanced (Imp.Comment _ a) = isLoadBalanced a+isLoadBalanced Imp.While {} = False+isLoadBalanced (Imp.Op (Imp.ParLoop _ _ _ code _ _ _)) = isLoadBalanced code+isLoadBalanced _ = True++segBinOpComm' :: [SegBinOp lore] -> Commutativity+segBinOpComm' = mconcat . map segBinOpComm++decideScheduling' :: SegOp () lore -> Imp.Code -> Imp.Scheduling+decideScheduling' SegHist {} _ = Imp.Static+decideScheduling' SegScan {} _ = Imp.Static+decideScheduling' (SegRed _ _ reds _ _) code =+  case segBinOpComm' reds of+    Commutative -> decideScheduling code+    Noncommutative -> Imp.Static+decideScheduling' SegMap {} code = decideScheduling code++decideScheduling :: Imp.Code -> Imp.Scheduling+decideScheduling code =+  if isLoadBalanced code+    then Imp.Static+    else Imp.Dynamic++-- | Try to extract invariant allocations.  If we assume that the+-- given 'Code' is the body of a 'SegOp', then it is always safe to+-- move the immediate allocations to the prebody.+extractAllocations :: Imp.Code -> (Imp.Code, Imp.Code)+extractAllocations segop_code = f segop_code+  where+    declared = Imp.declaredIn segop_code+    f (Imp.DeclareMem name space) =+      -- Hoisting declarations out is always safe.+      (Imp.DeclareMem name space, mempty)+    f (Imp.Allocate name size space)+      | not $ freeIn size `namesIntersect` declared =+        (Imp.Allocate name size space, mempty)+    f (x Imp.:>>: y) = f x <> f y+    f (Imp.While cond body) =+      (mempty, Imp.While cond body)+    f (Imp.For i bound body) =+      (mempty, Imp.For i bound body)+    f (Imp.Comment s code) =+      second (Imp.Comment s) (f code)+    f Imp.Free {} =+      mempty+    f (Imp.If cond tcode fcode) =+      let (ta, tcode') = f tcode+          (fa, fcode') = f fcode+       in (ta <> fa, Imp.If cond tcode' fcode')+    f (Imp.Op (Imp.ParLoop s i prebody body postbody free info)) =+      let (body_allocs, body') = extractAllocations body+          (free_allocs, here_allocs) = f body_allocs+          free' =+            filter+              ( not+                  . (`nameIn` Imp.declaredIn body_allocs)+                  . Imp.paramName+              )+              free+       in ( free_allocs,+            here_allocs+              <> Imp.Op (Imp.ParLoop s i prebody body' postbody free' info)+          )+    f code =+      (mempty, code)++-------------------------------+------- SegHist helpers -------+-------------------------------+renameHistOpLambda :: [HistOp MCMem] -> MulticoreGen [HistOp MCMem]+renameHistOpLambda hist_ops =+  forM hist_ops $ \(HistOp w rf dest neutral shape lam) -> do+    lam' <- renameLambda lam+    return $ HistOp w rf dest neutral shape lam'++-- | Locking strategy used for an atomic update.+data Locking = Locking+  { -- | Array containing the lock.+    lockingArray :: VName,+    -- | Value for us to consider the lock free.+    lockingIsUnlocked :: Imp.TExp Int32,+    -- | What to write when we lock it.+    lockingToLock :: Imp.TExp Int32,+    -- | What to write when we unlock it.+    lockingToUnlock :: Imp.TExp Int32,+    -- | A transformation from the logical lock index to the+    -- physical position in the array.  This can also be used+    -- to make the lock array smaller.+    lockingMapping :: [Imp.TExp Int64] -> [Imp.TExp Int64]+  }++-- | A function for generating code for an atomic update.  Assumes+-- that the bucket is in-bounds.+type DoAtomicUpdate lore r =+  [VName] -> [Imp.TExp Int64] -> MulticoreGen ()++-- | The mechanism that will be used for performing the atomic update.+-- Approximates how efficient it will be.  Ordered from most to least+-- efficient.+data AtomicUpdate lore r+  = AtomicPrim (DoAtomicUpdate lore r)+  | -- | Can be done by efficient swaps.+    AtomicCAS (DoAtomicUpdate lore r)+  | -- | Requires explicit locking.+    AtomicLocking (Locking -> DoAtomicUpdate lore r)++atomicUpdateLocking ::+  AtomicBinOp ->+  Lambda MCMem ->+  AtomicUpdate MCMem ()+atomicUpdateLocking atomicBinOp lam+  | Just ops_and_ts <- splitOp lam,+    all (\(_, t, _, _) -> supportedPrims $ primBitSize t) ops_and_ts =+    primOrCas ops_and_ts $ \arrs bucket ->+      -- If the operator is a vectorised binary operator on 32-bit values,+      -- we can use a particularly efficient implementation. If the+      -- operator has an atomic implementation we use that, otherwise it+      -- is still a binary operator which can be implemented by atomic+      -- compare-and-swap if 32 bits.+      forM_ (zip arrs ops_and_ts) $ \(a, (op, t, x, y)) -> do+        -- Common variables.+        old <- dPrim "old" t++        (arr', _a_space, bucket_offset) <- fullyIndexArray a bucket++        case opHasAtomicSupport (tvVar old) arr' (sExt32 <$> bucket_offset) op of+          Just f -> sOp $ f $ Imp.var y t+          Nothing ->+            atomicUpdateCAS t a (tvVar old) bucket x $+              x <~~ Imp.BinOpExp op (Imp.var x t) (Imp.var y t)+  where+    opHasAtomicSupport old arr' bucket' bop = do+      let atomic f = Imp.Atomic . f old arr' bucket'+      atomic <$> atomicBinOp bop++    primOrCas ops+      | all isPrim ops = AtomicPrim+      | otherwise = AtomicCAS++    isPrim (op, _, _, _) = isJust $ atomicBinOp op+atomicUpdateLocking _ op+  | [Prim t] <- lambdaReturnType op,+    [xp, _] <- lambdaParams op,+    supportedPrims (primBitSize t) = AtomicCAS $ \[arr] bucket -> do+    old <- dPrim "old" t+    atomicUpdateCAS t arr (tvVar old) bucket (paramName xp) $+      compileBody' [xp] $ lambdaBody op+atomicUpdateLocking _ op = AtomicLocking $ \locking arrs bucket -> do+  old <- dPrim "old" int32+  continue <- dPrimVol "continue" int32 (0 :: Imp.TExp Int32)++  -- Correctly index into locks.+  (locks', _locks_space, locks_offset) <-+    fullyIndexArray (lockingArray locking) $ lockingMapping locking bucket++  -- Critical section+  let try_acquire_lock = do+        old <-- (0 :: Imp.TExp Int32)+        sOp $+          Imp.Atomic $+            Imp.AtomicCmpXchg+              int32+              (tvVar old)+              locks'+              (sExt32 <$> locks_offset)+              (tvVar continue)+              (untyped (lockingToLock locking))+      lock_acquired = tvExp continue+      -- Even the releasing is done with an atomic rather than a+      -- simple write, for memory coherency reasons.+      release_lock = do+        old <-- lockingToLock locking+        sOp $+          Imp.Atomic $+            Imp.AtomicCmpXchg+              int32+              (tvVar old)+              locks'+              (sExt32 <$> locks_offset)+              (tvVar continue)+              (untyped (lockingToUnlock locking))++  -- Preparing parameters. It is assumed that the caller has already+  -- filled the arr_params. We copy the current value to the+  -- accumulator parameters.+  let (acc_params, _arr_params) = splitAt (length arrs) $ lambdaParams op+      bind_acc_params =+        everythingVolatile $+          sComment "bind lhs" $+            forM_ (zip acc_params arrs) $ \(acc_p, arr) ->+              copyDWIMFix (paramName acc_p) [] (Var arr) bucket++  let op_body =+        sComment "execute operation" $+          compileBody' acc_params $ lambdaBody op++      do_hist =+        everythingVolatile $+          sComment "update global result" $+            zipWithM_ (writeArray bucket) arrs $ map (Var . paramName) acc_params++  -- While-loop: Try to insert your value+  sWhile (tvExp continue .==. 0) $ do+    try_acquire_lock+    sUnless (lock_acquired .==. 0) $ do+      dLParams acc_params+      bind_acc_params+      op_body+      do_hist+      release_lock+  where+    writeArray bucket arr val = copyDWIMFix arr bucket val []++atomicUpdateCAS ::+  PrimType ->+  VName ->+  VName ->+  [Imp.TExp Int64] ->+  VName ->+  MulticoreGen () ->+  MulticoreGen ()+atomicUpdateCAS t arr old bucket x do_op = do+  -- Code generation target:+  --+  -- old = d_his[idx];+  -- do {+  --   assumed = old;+  --   x = do_op(assumed, y);+  --   old = atomicCAS(&d_his[idx], assumed, tmp);+  -- } while(assumed != old);+  run_loop <- dPrimV "run_loop" (0 :: Imp.TExp Int32)+  everythingVolatile $ copyDWIMFix old [] (Var arr) bucket+  (arr', _a_space, bucket_offset) <- fullyIndexArray arr bucket++  bytes <- toIntegral $ primBitSize t+  (to, from) <- getBitConvertFunc $ primBitSize t+  -- While-loop: Try to insert your value+  let (toBits, _fromBits) =+        case t of+          FloatType _ ->+            ( \v -> Imp.FunExp to [v] bytes,+              \v -> Imp.FunExp from [v] t+            )+          _ -> (id, id)++  sWhile (tvExp run_loop .==. 0) $ do+    x <~~ Imp.var old t+    do_op -- Writes result into x+    sOp $+      Imp.Atomic $+        Imp.AtomicCmpXchg+          bytes+          old+          arr'+          (sExt32 <$> bucket_offset)+          (tvVar run_loop)+          (toBits (Imp.var x t))++-- | Horizontally fission a lambda that models a binary operator.+splitOp :: ASTLore lore => Lambda lore -> Maybe [(BinOp, PrimType, VName, VName)]+splitOp lam = mapM splitStm $ bodyResult $ lambdaBody lam+  where+    n = length $ lambdaReturnType lam+    splitStm (Var res) = do+      Let (Pattern [] [pe]) _ (BasicOp (BinOp op (Var x) (Var y))) <-+        find (([res] ==) . patternNames . stmPattern) $+          stmsToList $ bodyStms $ lambdaBody lam+      i <- Var res `elemIndex` bodyResult (lambdaBody lam)+      xp <- maybeNth i $ lambdaParams lam+      yp <- maybeNth (n + i) $ lambdaParams lam+      guard $ paramName xp == x+      guard $ paramName yp == y+      Prim t <- Just $ patElemType pe+      return (op, t, paramName xp, paramName yp)+    splitStm _ = Nothing++-- TODO for supporting 8 and 16 bits (and 128)+-- we need a functions for converting to and from bits+getBitConvertFunc :: Int -> MulticoreGen (String, String)+-- getBitConvertFunc 8 = return $ ("to_bits8, from_bits8")+-- getBitConvertFunc 16 = return $ ("to_bits8, from_bits8")+getBitConvertFunc 32 = return ("to_bits32", "from_bits32")+getBitConvertFunc 64 = return ("to_bits64", "from_bits64")+getBitConvertFunc b = error $ "number of bytes is not supported " ++ pretty b++supportedPrims :: Int -> Bool+supportedPrims 8 = True+supportedPrims 16 = True+supportedPrims 32 = True+supportedPrims 64 = True+supportedPrims _ = False++-- Supported bytes lengths by GCC (and clang) compiler+toIntegral :: Int -> MulticoreGen PrimType+toIntegral 8 = return int8+toIntegral 16 = return int16+toIntegral 32 = return int32+toIntegral 64 = return int64+toIntegral b = error $ "number of bytes is not supported for CAS - " ++ pretty b
+ src/Futhark/CodeGen/ImpGen/Multicore/SegHist.hs view
@@ -0,0 +1,359 @@+module Futhark.CodeGen.ImpGen.Multicore.SegHist+  ( compileSegHist,+  )+where++import Control.Monad+import Data.List (zip4, zip5)+import qualified Futhark.CodeGen.ImpCode.Multicore as Imp+import Futhark.CodeGen.ImpGen+import Futhark.CodeGen.ImpGen.Multicore.Base+import Futhark.CodeGen.ImpGen.Multicore.SegRed (compileSegRed')+import Futhark.IR.MCMem+import Futhark.MonadFreshNames+import Futhark.Util (chunks, splitFromEnd, takeLast)+import Futhark.Util.IntegralExp (rem)+import Prelude hiding (quot, rem)++compileSegHist ::+  Pattern MCMem ->+  SegSpace ->+  [HistOp MCMem] ->+  KernelBody MCMem ->+  TV Int32 ->+  MulticoreGen Imp.Code+compileSegHist pat space histops kbody nsubtasks+  | [_] <- unSegSpace space =+    nonsegmentedHist pat space histops kbody nsubtasks+  | otherwise =+    segmentedHist pat space histops kbody++-- | Split some list into chunks equal to the number of values+-- returned by each 'SegBinOp'+segHistOpChunks :: [HistOp lore] -> [a] -> [[a]]+segHistOpChunks = chunks . map (length . histNeutral)++nonsegmentedHist ::+  Pattern MCMem ->+  SegSpace ->+  [HistOp MCMem] ->+  KernelBody MCMem ->+  TV Int32 ->+  MulticoreGen Imp.Code+nonsegmentedHist pat space histops kbody num_histos = do+  let ns = map snd $ unSegSpace space+      ns_64 = map toInt64Exp ns+      num_histos' = tvExp num_histos+      hist_width = toInt64Exp $ histWidth $ head histops+      use_subhistogram = sExt64 num_histos' * hist_width .<=. product ns_64++  histops' <- renameHistOpLambda histops++  collect $ do+    flat_idx <- dPrim "iter" int64+    sIf+      use_subhistogram+      (subHistogram pat flat_idx space histops num_histos kbody)+      (atomicHistogram pat flat_idx space histops' kbody)++-- |+-- Atomic Histogram approach+-- The implementation has three sub-strategies depending on the+-- type of the operator+-- 1. If values are integral scalars, a direct-supported atomic update is used.+-- 2. If values are on one memory location, e.g. a float, then a+-- CAS operation is used to perform the update, where the float is+-- casted to an integral scalar.+-- 1. and 2. currently only works for 32-bit and 64-bit types,+-- but GCC has support for 8-, 16- and 128- bit types as well.+-- 3. Otherwise a locking based approach is used+onOpAtomic :: HistOp MCMem -> MulticoreGen ([VName] -> [Imp.TExp Int64] -> MulticoreGen ())+onOpAtomic op = do+  atomics <- hostAtomics <$> askEnv+  let lambda = histOp op+      do_op = atomicUpdateLocking atomics lambda+  case do_op of+    AtomicPrim f -> return f+    AtomicCAS f -> return f+    AtomicLocking f -> do+      -- Allocate a static array of locks+      -- as in the GPU backend+      let num_locks = 100151 -- This number is taken from the GPU backend+          dims =+            map toInt64Exp $+              shapeDims (histShape op) ++ [histWidth op]+      locks <-+        sStaticArray "hist_locks" DefaultSpace int32 $+          Imp.ArrayZeros num_locks+      let l' = Locking locks 0 1 0 (pure . (`rem` fromIntegral num_locks) . flattenIndex dims)+      return $ f l'++atomicHistogram ::+  Pattern MCMem ->+  TV Int64 ->+  SegSpace ->+  [HistOp MCMem] ->+  KernelBody MCMem ->+  MulticoreGen ()+atomicHistogram pat flat_idx space histops kbody = do+  let (is, ns) = unzip $ unSegSpace space+      ns_64 = map toInt64Exp ns+  let num_red_res = length histops + sum (map (length . histNeutral) histops)+      (all_red_pes, map_pes) = splitAt num_red_res $ patternValueElements pat++  atomicOps <- mapM onOpAtomic histops++  body <- collect $ do+    zipWithM_ dPrimV_ is $ unflattenIndex ns_64 $ tvExp flat_idx+    compileStms mempty (kernelBodyStms kbody) $ do+      let (red_res, map_res) = splitFromEnd (length map_pes) $ kernelBodyResult kbody+          perOp = chunks $ map (length . histDest) histops+          (buckets, vs) = splitAt (length histops) red_res++      let pes_per_op = chunks (map (length . histDest) histops) all_red_pes+      forM_ (zip5 histops (perOp vs) buckets atomicOps pes_per_op) $+        \(HistOp dest_w _ _ _ shape lam, vs', bucket, do_op, dest_res) -> do+          let (_is_params, vs_params) = splitAt (length vs') $ lambdaParams lam+              dest_w' = toInt64Exp dest_w+              bucket' = toInt64Exp $ kernelResultSubExp bucket+              bucket_in_bounds = bucket' .<. dest_w' .&&. 0 .<=. bucket'++          sComment "save map-out results" $+            forM_ (zip map_pes map_res) $ \(pe, res) ->+              copyDWIMFix (patElemName pe) (map Imp.vi64 is) (kernelResultSubExp res) []++          sComment "perform updates" $+            sWhen bucket_in_bounds $ do+              let bucket_is = map Imp.vi64 (init is) ++ [bucket']+              dLParams $ lambdaParams lam+              sLoopNest shape $ \is' -> do+                forM_ (zip vs_params vs') $ \(p, res) ->+                  copyDWIMFix (paramName p) [] (kernelResultSubExp res) is'+                do_op (map patElemName dest_res) (bucket_is ++ is')++  free_params <- freeParams body (segFlat space : [tvVar flat_idx])+  emit $ Imp.Op $ Imp.ParLoop "atomic_seg_hist" (tvVar flat_idx) mempty body mempty free_params $ segFlat space++updateHisto :: HistOp MCMem -> [VName] -> [Imp.TExp Int64] -> MulticoreGen ()+updateHisto op arrs bucket = do+  let acc_params = take (length arrs) $ lambdaParams $ histOp op+      bind_acc_params =+        forM_ (zip acc_params arrs) $ \(acc_p, arr) ->+          copyDWIMFix (paramName acc_p) [] (Var arr) bucket+      op_body = compileBody' [] $ lambdaBody $ histOp op+      writeArray arr val = copyDWIMFix arr bucket val []+      do_hist = zipWithM_ writeArray arrs $ bodyResult $ lambdaBody $ histOp op++  sComment "Start of body" $ do+    dLParams acc_params+    bind_acc_params+    op_body+    do_hist++-- Generates num_histos sub-histograms of the size+-- of the destination histogram+-- Then for each chunk of the input each subhistogram+-- is computed and finally combined through a segmented reduction+-- across the histogram indicies.+-- This is expected to be fast if len(histDest) is small+subHistogram ::+  Pattern MCMem ->+  TV Int64 ->+  SegSpace ->+  [HistOp MCMem] ->+  TV Int32 ->+  KernelBody MCMem ->+  MulticoreGen ()+subHistogram pat flat_idx space histops num_histos kbody = do+  emit $ Imp.DebugPrint "subHistogram segHist" Nothing++  let (is, ns) = unzip $ unSegSpace space+      ns_64 = map toInt64Exp ns++  let pes = patternElements pat+      num_red_res = length histops + sum (map (length . histNeutral) histops)+      map_pes = drop num_red_res pes+      per_red_pes = segHistOpChunks histops $ patternValueElements pat++  -- Allocate array of subhistograms in the calling thread.  Each+  -- tasks will work in its own private allocations (to avoid false+  -- sharing), but this is where they will ultimately copy their+  -- results.+  global_subhistograms <- forM histops $ \histop ->+    forM (histType histop) $ \t -> do+      let shape = Shape [tvSize num_histos] <> arrayShape t+      sAllocArray "subhistogram" (elemType t) shape DefaultSpace++  let tid' = Imp.vi64 $ segFlat space+      flat_idx' = tvExp flat_idx++  (local_subhistograms, prebody) <- collect' $ do+    zipWithM_ dPrimV_ is $ unflattenIndex ns_64 $ sExt64 flat_idx'++    forM (zip per_red_pes histops) $ \(pes', histop) -> do+      op_local_subhistograms <- forM (histType histop) $ \t ->+        sAllocArray "subhistogram" (elemType t) (arrayShape t) DefaultSpace++      forM_ (zip3 pes' op_local_subhistograms (histNeutral histop)) $ \(pe, hist, ne) ->+        -- First thread initializes histogram with dest vals. Others+        -- initialize with neutral element+        sIf+          (tid' .==. 0)+          (copyDWIMFix hist [] (Var $ patElemName pe) [])+          ( sFor "i" (toInt64Exp $ histWidth histop) $ \i ->+              sLoopNest (histShape histop) $ \vec_is ->+                copyDWIMFix hist (i : vec_is) ne []+          )++      return op_local_subhistograms++  -- Generate loop body of parallel function+  body <- collect $ do+    zipWithM_ dPrimV_ is $ unflattenIndex ns_64 $ sExt64 flat_idx'+    compileStms mempty (kernelBodyStms kbody) $ do+      let (red_res, map_res) = splitFromEnd (length map_pes) $ kernelBodyResult kbody+          (buckets, vs) = splitAt (length histops) red_res+          perOp = chunks $ map (length . histDest) histops++      sComment "save map-out results" $+        forM_ (zip map_pes map_res) $ \(pe, res) ->+          copyDWIMFix+            (patElemName pe)+            (map Imp.vi64 is)+            (kernelResultSubExp res)+            []++      forM_ (zip4 histops local_subhistograms buckets (perOp vs)) $+        \( histop@(HistOp dest_w _ _ _ shape lam),+           histop_subhistograms,+           bucket,+           vs'+           ) -> do+            let bucket' = toInt64Exp $ kernelResultSubExp bucket+                dest_w' = toInt64Exp dest_w+                bucket_in_bounds = bucket' .<. dest_w' .&&. 0 .<=. bucket'+                vs_params = takeLast (length vs') $ lambdaParams lam+                bucket_is = [bucket']++            sComment "perform updates" $+              sWhen bucket_in_bounds $ do+                dLParams $ lambdaParams lam+                sLoopNest shape $ \is' -> do+                  forM_ (zip vs_params vs') $ \(p, res) ->+                    copyDWIMFix (paramName p) [] (kernelResultSubExp res) is'+                  updateHisto histop histop_subhistograms (bucket_is ++ is')++  -- Copy the task-local subhistograms to the global subhistograms,+  -- where they will be combined.+  postbody <- collect $+    forM_ (zip (concat global_subhistograms) (concat local_subhistograms)) $+      \(global, local) -> copyDWIMFix global [tid'] (Var local) []++  free_params <- freeParams (prebody <> body <> postbody) (segFlat space : [tvVar flat_idx])+  let (body_allocs, body') = extractAllocations body+  emit $ Imp.Op $ Imp.ParLoop "seghist_stage_1" (tvVar flat_idx) (body_allocs <> prebody) body' postbody free_params $ segFlat space++  -- Perform a segmented reduction over the subhistograms+  forM_ (zip3 per_red_pes global_subhistograms histops) $ \(red_pes, hists, op) -> do+    bucket_id <- newVName "bucket_id"+    subhistogram_id <- newVName "subhistogram_id"++    let num_buckets = histWidth op+        segred_space =+          SegSpace (segFlat space) $+            segment_dims+              ++ [(bucket_id, num_buckets)]+              ++ [(subhistogram_id, tvSize num_histos)]++        segred_op = SegBinOp Noncommutative (histOp op) (histNeutral op) (histShape op)++    nsubtasks_red <- dPrim "num_tasks" $ IntType Int32+    red_code <- compileSegRed' (Pattern [] red_pes) segred_space [segred_op] nsubtasks_red $ \red_cont ->+      red_cont $+        flip map hists $ \subhisto ->+          ( Var subhisto,+            map Imp.vi64 $+              map fst segment_dims ++ [subhistogram_id, bucket_id]+          )++    let ns_red = map (toInt64Exp . snd) $ unSegSpace segred_space+        iterations = product $ init ns_red -- The segmented reduction is sequential over the inner most dimension+        scheduler_info = Imp.SchedulerInfo (tvVar nsubtasks_red) (untyped iterations) Imp.Static+        red_task = Imp.ParallelTask red_code $ segFlat space+    free_params_red <- freeParams red_code [segFlat space, tvVar nsubtasks_red]+    emit $ Imp.Op $ Imp.Segop "seghist_red" free_params_red red_task Nothing mempty scheduler_info+  where+    segment_dims = init $ unSegSpace space++-- This implementation for a Segmented Hist only+-- parallelize over the segments,+-- where each segment is updated sequentially.+segmentedHist ::+  Pattern MCMem ->+  SegSpace ->+  [HistOp MCMem] ->+  KernelBody MCMem ->+  MulticoreGen Imp.Code+segmentedHist pat space histops kbody = do+  emit $ Imp.DebugPrint "Segmented segHist" Nothing+  -- Iteration variable over the segments+  segments_i <- dPrim "segment_iter" $ IntType Int64+  collect $ do+    par_body <- compileSegHistBody (tvExp segments_i) pat space histops kbody+    free_params <- freeParams par_body [segFlat space, tvVar segments_i]+    let (body_allocs, body') = extractAllocations par_body+    emit $ Imp.Op $ Imp.ParLoop "segmented_hist" (tvVar segments_i) body_allocs body' mempty free_params $ segFlat space++compileSegHistBody ::+  Imp.TExp Int64 ->+  Pattern MCMem ->+  SegSpace ->+  [HistOp MCMem] ->+  KernelBody MCMem ->+  MulticoreGen Imp.Code+compileSegHistBody idx pat space histops kbody = do+  let (is, ns) = unzip $ unSegSpace space+      ns_64 = map toInt64Exp ns++  let num_red_res = length histops + sum (map (length . histNeutral) histops)+      map_pes = drop num_red_res $ patternValueElements pat+      per_red_pes = segHistOpChunks histops $ patternValueElements pat++  collect $ do+    let inner_bound = last ns_64+    sFor "i" inner_bound $ \i -> do+      zipWithM_ dPrimV_ (init is) $ unflattenIndex (init ns_64) idx+      dPrimV_ (last is) i++      compileStms mempty (kernelBodyStms kbody) $ do+        let (red_res, map_res) =+              splitFromEnd (length map_pes) $+                map kernelResultSubExp $ kernelBodyResult kbody+            (buckets, vs) = splitAt (length histops) red_res+            perOp = chunks $ map (length . histDest) histops++        forM_ (zip4 per_red_pes histops (perOp vs) buckets) $+          \(red_pes, HistOp dest_w _ _ _ shape lam, vs', bucket) -> do+            let (is_params, vs_params) = splitAt (length vs') $ lambdaParams lam+                bucket' = toInt64Exp bucket+                dest_w' = toInt64Exp dest_w+                bucket_in_bounds = bucket' .<. dest_w' .&&. 0 .<=. bucket'++            sComment "save map-out results" $+              forM_ (zip map_pes map_res) $ \(pe, res) ->+                copyDWIMFix (patElemName pe) (map Imp.vi64 is) res []++            sComment "perform updates" $+              sWhen bucket_in_bounds $ do+                dLParams $ lambdaParams lam+                sLoopNest shape $ \vec_is -> do+                  -- 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)+                  -- 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 $ bodyResult $ lambdaBody lam) $+                      \(pe, se) -> copyDWIMFix (patElemName pe) (map Imp.vi64 (init is) ++ [buck] ++ vec_is) se []
+ src/Futhark/CodeGen/ImpGen/Multicore/SegMap.hs view
@@ -0,0 +1,62 @@+module Futhark.CodeGen.ImpGen.Multicore.SegMap+  ( compileSegMap,+  )+where++import Control.Monad+import qualified Futhark.CodeGen.ImpCode.Multicore as Imp+import Futhark.CodeGen.ImpGen+import Futhark.CodeGen.ImpGen.Multicore.Base+import Futhark.IR.MCMem+import Futhark.Transform.Rename++writeResult ::+  [VName] ->+  PatElemT dec ->+  KernelResult ->+  MulticoreGen ()+writeResult is pe (Returns _ se) =+  copyDWIMFix (patElemName pe) (map Imp.vi64 is) se []+writeResult _ pe (WriteReturns rws _ idx_vals) = do+  let (iss, vs) = unzip idx_vals+      rws' = map toInt64Exp rws+  forM_ (zip iss vs) $ \(slice, v) -> do+    let slice' = map (fmap toInt64Exp) slice+        condInBounds (DimFix i) rw =+          0 .<=. i .&&. i .<. rw+        condInBounds (DimSlice i n s) rw =+          0 .<=. i .&&. i + n * s .<. rw+        in_bounds = foldl1 (.&&.) $ zipWith condInBounds slice' rws'+        when_in_bounds = copyDWIM (patElemName pe) slice' v []+    sWhen in_bounds when_in_bounds+writeResult _ _ res =+  error $ "writeResult: cannot handle " ++ pretty res++compileSegMapBody ::+  TV Int64 ->+  Pattern MCMem ->+  SegSpace ->+  KernelBody MCMem ->+  MulticoreGen Imp.Code+compileSegMapBody flat_idx pat space (KernelBody _ kstms kres) = do+  let (is, ns) = unzip $ unSegSpace space+      ns' = map toInt64Exp ns+  kstms' <- mapM renameStm kstms+  collect $ do+    emit $ Imp.DebugPrint "SegMap fbody" Nothing+    zipWithM_ dPrimV_ is $ map sExt64 $ unflattenIndex ns' $ tvExp flat_idx+    compileStms (freeIn kres) kstms' $+      zipWithM_ (writeResult is) (patternElements pat) kres++compileSegMap ::+  Pattern MCMem ->+  SegSpace ->+  KernelBody MCMem ->+  MulticoreGen Imp.Code+compileSegMap pat space kbody =+  collect $ do+    flat_par_idx <- dPrim "iter" int64+    body <- compileSegMapBody flat_par_idx pat space kbody+    free_params <- freeParams body [segFlat space, tvVar flat_par_idx]+    let (body_allocs, body') = extractAllocations body+    emit $ Imp.Op $ Imp.ParLoop "segmap" (tvVar flat_par_idx) body_allocs body' mempty free_params $ segFlat space
+ src/Futhark/CodeGen/ImpGen/Multicore/SegRed.hs view
@@ -0,0 +1,267 @@+module Futhark.CodeGen.ImpGen.Multicore.SegRed+  ( compileSegRed,+    compileSegRed',+  )+where++import Control.Monad+import qualified Futhark.CodeGen.ImpCode.Multicore as Imp+import Futhark.CodeGen.ImpGen+import Futhark.CodeGen.ImpGen.Multicore.Base+import Futhark.IR.MCMem+import Futhark.Util (chunks)+import Prelude hiding (quot, rem)++type DoSegBody = (([(SubExp, [Imp.TExp Int64])] -> MulticoreGen ()) -> MulticoreGen ())++-- | Generate code for a SegRed construct+compileSegRed ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  KernelBody MCMem ->+  TV Int32 ->+  MulticoreGen Imp.Code+compileSegRed pat space reds kbody nsubtasks =+  compileSegRed' pat space reds nsubtasks $ \red_cont ->+    compileStms mempty (kernelBodyStms kbody) $ do+      let (red_res, map_res) = splitAt (segBinOpResults reds) $ kernelBodyResult kbody++      sComment "save map-out results" $ do+        let map_arrs = drop (segBinOpResults reds) $ patternElements pat+        zipWithM_ (compileThreadResult space) map_arrs map_res++      red_cont $ zip (map kernelResultSubExp red_res) $ repeat []++-- | Like 'compileSegRed', but where the body is a monadic action.+compileSegRed' ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  TV Int32 ->+  DoSegBody ->+  MulticoreGen Imp.Code+compileSegRed' pat space reds nsubtasks kbody+  | [_] <- unSegSpace space =+    nonsegmentedReduction pat space reds nsubtasks kbody+  | otherwise =+    segmentedReduction pat space reds kbody++-- | A SegBinOp with auxiliary information.+data SegBinOpSlug = SegBinOpSlug+  { slugOp :: SegBinOp MCMem,+    -- | The array in which we write the intermediate results, indexed+    -- by the flat/physical thread ID.+    slugResArrs :: [VName]+  }++slugBody :: SegBinOpSlug -> Body MCMem+slugBody = lambdaBody . segBinOpLambda . slugOp++slugParams :: SegBinOpSlug -> [LParam MCMem]+slugParams = lambdaParams . segBinOpLambda . slugOp++slugNeutral :: SegBinOpSlug -> [SubExp]+slugNeutral = segBinOpNeutral . slugOp++slugShape :: SegBinOpSlug -> Shape+slugShape = segBinOpShape . slugOp++accParams, nextParams :: SegBinOpSlug -> [LParam MCMem]+accParams slug = take (length (slugNeutral slug)) $ slugParams slug+nextParams slug = drop (length (slugNeutral slug)) $ slugParams slug++nonsegmentedReduction ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  TV Int32 ->+  DoSegBody ->+  MulticoreGen Imp.Code+nonsegmentedReduction pat space reds nsubtasks kbody = collect $ do+  thread_res_arrs <- groupResultArrays "reduce_stage_1_tid_res_arr" (tvSize nsubtasks) reds+  let slugs1 = zipWith SegBinOpSlug reds thread_res_arrs+      nsubtasks' = tvExp nsubtasks++  reductionStage1 space slugs1 kbody+  reds2 <- renameSegBinOp reds+  let slugs2 = zipWith SegBinOpSlug reds2 thread_res_arrs+  reductionStage2 pat space nsubtasks' slugs2++reductionStage1 ::+  SegSpace ->+  [SegBinOpSlug] ->+  DoSegBody ->+  MulticoreGen ()+reductionStage1 space slugs kbody = do+  let (is, ns) = unzip $ unSegSpace space+      ns' = map (sExt64 . toInt32Exp) ns+  flat_idx <- dPrim "iter" int64++  -- Create local accumulator variables in which we carry out the+  -- sequential reduction of this function.  If we are dealing with+  -- vectorised operators, then this implies a private allocation.  If+  -- the original operand type of the reduction is a memory block,+  -- then our hands are unfortunately tied, and we have to use exactly+  -- that memory.  This is likely to be slow.++  (slug_local_accs, prebody) <- collect' $ do+    dScope Nothing $ scopeOfLParams $ concatMap slugParams slugs++    forM slugs $ \slug -> do+      let shape = segBinOpShape $ slugOp slug++      forM (zip (accParams slug) (slugNeutral slug)) $ \(p, ne) -> do+        -- Declare accumulator variable.+        acc <-+          case paramType p of+            Prim pt+              | shape == mempty ->+                tvVar <$> dPrim "local_acc" pt+              | otherwise ->+                sAllocArray "local_acc" pt shape DefaultSpace+            _ ->+              pure $ paramName p++        -- Now neutral-initialise the accumulator.+        sLoopNest (slugShape slug) $ \vec_is ->+          copyDWIMFix acc vec_is ne []++        pure acc++  fbody <- collect $ do+    zipWithM_ dPrimV_ is $ unflattenIndex ns' $ tvExp flat_idx+    kbody $ \all_red_res -> do+      let all_red_res' = segBinOpChunks (map slugOp slugs) all_red_res+      forM_ (zip3 all_red_res' slugs slug_local_accs) $ \(red_res, slug, local_accs) ->+        sLoopNest (slugShape slug) $ \vec_is -> do+          let lamtypes = lambdaReturnType $ segBinOpLambda $ slugOp slug+          -- Load accum params+          sComment "Load accum params" $+            forM_ (zip3 (accParams slug) local_accs lamtypes) $+              \(p, local_acc, t) ->+                when (primType t) $+                  copyDWIMFix (paramName p) [] (Var local_acc) vec_is++          sComment "Load next params" $+            forM_ (zip (nextParams slug) red_res) $ \(p, (res, res_is)) ->+              copyDWIMFix (paramName p) [] res (res_is ++ vec_is)++          sComment "Red body" $+            compileStms mempty (bodyStms $ slugBody slug) $+              forM_ (zip local_accs (bodyResult $ slugBody slug)) $+                \(local_acc, se) ->+                  copyDWIMFix local_acc vec_is se []++  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) []++  free_params <- freeParams (prebody <> fbody <> postbody) (segFlat space : [tvVar flat_idx])+  let (body_allocs, fbody') = extractAllocations fbody+  emit $ Imp.Op $ Imp.ParLoop "segred_stage_1" (tvVar flat_idx) (body_allocs <> prebody) fbody' postbody free_params $ segFlat space++reductionStage2 ::+  Pattern MCMem ->+  SegSpace ->+  Imp.TExp Int32 ->+  [SegBinOpSlug] ->+  MulticoreGen ()+reductionStage2 pat space nsubtasks slugs = do+  let per_red_pes = segBinOpChunks (map slugOp slugs) $ patternValueElements pat+      phys_id = Imp.vi64 (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) ->+        sLoopNest (segBinOpShape red) $ \vec_is ->+          copyDWIMFix (patElemName pe) vec_is ne []++  dScope Nothing $ scopeOfLParams $ concatMap slugParams slugs++  sFor "i" nsubtasks $ \i' -> do+    mkTV (segFlat space) int64 <-- i'+    sComment "Apply main thread reduction" $+      forM_ (zip slugs per_red_pes) $ \(slug, red_res) ->+        sLoopNest (slugShape slug) $ \vec_is -> do+          sComment "load acc params" $+            forM_ (zip (accParams slug) red_res) $ \(p, pe) ->+              copyDWIMFix (paramName p) [] (Var $ patElemName pe) vec_is+          sComment "load next params" $+            forM_ (zip (nextParams slug) (slugResArrs slug)) $ \(p, acc) ->+              copyDWIMFix (paramName p) [] (Var acc) (phys_id : vec_is)+          sComment "red body" $+            compileStms mempty (bodyStms $ slugBody slug) $+              forM_ (zip red_res (bodyResult $ slugBody slug)) $+                \(pe, se') -> copyDWIMFix (patElemName pe) vec_is se' []++-- Each thread reduces over the number of segments+-- each of which is done sequentially+-- Maybe we should select the work of the inner loop+-- based on n_segments and dimensions etc.+segmentedReduction ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  DoSegBody ->+  MulticoreGen Imp.Code+segmentedReduction pat space reds kbody =+  collect $ do+    n_par_segments <- dPrim "segment_iter" $ IntType Int64+    body <- compileSegRedBody n_par_segments pat space reds kbody+    free_params <- freeParams body (segFlat space : [tvVar n_par_segments])+    let (body_allocs, body') = extractAllocations body+    emit $ Imp.Op $ Imp.ParLoop "segmented_segred" (tvVar n_par_segments) body_allocs body' mempty free_params $ segFlat space++compileSegRedBody ::+  TV Int64 ->+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  DoSegBody ->+  MulticoreGen Imp.Code+compileSegRedBody n_segments pat space reds kbody = do+  let (is, ns) = unzip $ unSegSpace space+      ns_64 = map toInt64Exp ns+      inner_bound = last ns_64+      n_segments' = tvExp n_segments++  let per_red_pes = segBinOpChunks reds $ patternValueElements pat+  -- Perform sequential reduce on inner most dimension+  collect $ do+    flat_idx <- dPrimVE "flat_idx" $ n_segments' * inner_bound+    zipWithM_ dPrimV_ is $ unflattenIndex ns_64 flat_idx+    sComment "neutral-initialise the accumulators" $+      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 []++    sComment "main body" $ do+      dScope Nothing $ scopeOfLParams $ concatMap (lambdaParams . segBinOpLambda) reds+      sFor "i" inner_bound $ \i -> do+        zipWithM_+          (<--)+          (map (`mkTV` int64) $ init is)+          (unflattenIndex (init ns_64) (sExt64 n_segments'))+        dPrimV_ (last is) i+        kbody $ \all_red_res -> do+          let red_res' = chunks (map (length . segBinOpNeutral) reds) all_red_res+          forM_ (zip3 per_red_pes reds red_res') $ \(pes, red, res') ->+            sLoopNest (segBinOpShape red) $ \vec_is -> do+              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)++              sComment "load new val" $ do+                let next_params = drop (length (segBinOpNeutral red)) $ (lambdaParams . segBinOpLambda) red+                forM_ (zip next_params res') $ \(p, (res, res_is)) ->+                  copyDWIMFix (paramName p) [] res (res_is ++ vec_is)++              sComment "apply reduction" $ do+                let lbody = (lambdaBody . segBinOpLambda) red+                compileStms mempty (bodyStms lbody) $+                  sComment "write back to res" $+                    forM_ (zip pes (bodyResult lbody)) $+                      \(pe, se') -> copyDWIMFix (patElemName pe) (map Imp.vi64 (init is) ++ vec_is) se' []
+ src/Futhark/CodeGen/ImpGen/Multicore/SegScan.hs view
@@ -0,0 +1,298 @@+module Futhark.CodeGen.ImpGen.Multicore.SegScan+  ( compileSegScan,+  )+where++import Control.Monad+import Data.List (zip4)+import qualified Futhark.CodeGen.ImpCode.Multicore as Imp+import Futhark.CodeGen.ImpGen+import Futhark.CodeGen.ImpGen.Multicore.Base+import Futhark.IR.MCMem+import Futhark.Util.IntegralExp (quot, rem)+import Prelude hiding (quot, rem)++-- Compile a SegScan construct+compileSegScan ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  KernelBody MCMem ->+  TV Int32 ->+  MulticoreGen Imp.Code+compileSegScan pat space reds kbody nsubtasks+  | [_] <- unSegSpace space =+    nonsegmentedScan pat space reds kbody nsubtasks+  | otherwise =+    segmentedScan pat space reds kbody++xParams, yParams :: SegBinOp MCMem -> [LParam MCMem]+xParams scan =+  take (length (segBinOpNeutral scan)) (lambdaParams (segBinOpLambda scan))+yParams scan =+  drop (length (segBinOpNeutral scan)) (lambdaParams (segBinOpLambda scan))++lamBody :: SegBinOp MCMem -> Body MCMem+lamBody = lambdaBody . segBinOpLambda++nonsegmentedScan ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  KernelBody MCMem ->+  TV Int32 ->+  MulticoreGen Imp.Code+nonsegmentedScan pat space scan_ops kbody nsubtasks = do+  emit $ Imp.DebugPrint "nonsegmented segScan" Nothing+  collect $ do+    scanStage1 pat space scan_ops kbody++    let nsubtasks' = tvExp nsubtasks+    sWhen (nsubtasks' .>. 1) $ do+      scan_ops2 <- renameSegBinOp scan_ops+      scanStage2 pat nsubtasks space scan_ops2 kbody+      scan_ops3 <- renameSegBinOp scan_ops+      scanStage3 pat space scan_ops3 kbody++scanStage1 ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  KernelBody MCMem ->+  MulticoreGen ()+scanStage1 pat space scan_ops kbody = do+  let (all_scan_res, map_res) = splitAt (segBinOpResults scan_ops) $ kernelBodyResult kbody+      per_scan_res = segBinOpChunks scan_ops all_scan_res+      per_scan_pes = segBinOpChunks scan_ops $ patternValueElements pat+  let (is, ns) = unzip $ unSegSpace space+      ns' = map toInt64Exp ns+  iter <- dPrim "iter" $ IntType Int32++  -- Stage 1 : each thread partially scans a chunk of the input+  -- Writes directly to the resulting array+  (local_accs, prebody) <- collect' $ do+    dScope Nothing $ scopeOfLParams $ concatMap (lambdaParams . segBinOpLambda) scan_ops+    forM scan_ops $ \scan_op -> do+      let shape = segBinOpShape scan_op+          ts = lambdaReturnType $ segBinOpLambda scan_op+      forM (zip3 (xParams scan_op) (segBinOpNeutral scan_op) ts) $ \(p, ne, t) -> do+        acc <-+          case shapeDims shape of+            [] -> pure $ paramName p+            _ -> do+              let pt = elemType t+              sAllocArray "local_acc" pt (shape <> arrayShape t) DefaultSpace++        -- Now neutral-initialise the accumulator.+        sLoopNest (segBinOpShape scan_op) $ \vec_is ->+          copyDWIMFix acc vec_is ne []++        pure acc++  body <- collect $ do+    zipWithM_ dPrimV_ is $ unflattenIndex ns' $ tvExp iter+    sComment "stage 1 scan body" $+      compileStms mempty (kernelBodyStms kbody) $ do+        sComment "write mapped values results to memory" $ do+          let map_arrs = drop (segBinOpResults scan_ops) $ patternElements pat+          zipWithM_ (compileThreadResult space) map_arrs map_res++        forM_ (zip4 per_scan_pes scan_ops per_scan_res local_accs) $ \(pes, scan_op, scan_res, acc) ->+          sLoopNest (segBinOpShape scan_op) $ \vec_is -> do+            -- Read accum value+            forM_ (zip (xParams scan_op) acc) $ \(p, acc') ->+              copyDWIMFix (paramName p) [] (Var acc') vec_is++            -- Read next value+            sComment "Read next values" $+              forM_ (zip (yParams scan_op) scan_res) $ \(p, se) ->+                copyDWIMFix (paramName p) [] (kernelResultSubExp se) vec_is++            compileStms mempty (bodyStms $ lamBody scan_op) $+              forM_ (zip3 acc pes (bodyResult $ lamBody scan_op)) $+                \(acc', pe, se) -> do+                  copyDWIMFix (patElemName pe) (map Imp.vi64 is ++ vec_is) se []+                  copyDWIMFix acc' vec_is se []++  free_params <- freeParams (prebody <> body) (segFlat space : [tvVar iter])+  let (body_allocs, body') = extractAllocations body+  emit $ Imp.Op $ Imp.ParLoop "scan_stage_1" (tvVar iter) (body_allocs <> prebody) body' mempty free_params $ segFlat space++scanStage2 ::+  Pattern MCMem ->+  TV Int32 ->+  SegSpace ->+  [SegBinOp MCMem] ->+  KernelBody MCMem ->+  MulticoreGen ()+scanStage2 pat nsubtasks space scan_ops kbody = do+  emit $ Imp.DebugPrint "nonsegmentedScan stage 2" Nothing+  let (is, ns) = unzip $ unSegSpace space+      ns_64 = map toInt64Exp ns+      per_scan_pes = segBinOpChunks scan_ops $ patternValueElements pat+      nsubtasks' = tvExp nsubtasks++  dScope Nothing $ scopeOfLParams $ concatMap (lambdaParams . segBinOpLambda) scan_ops+  offset <- dPrimV "offset" (0 :: Imp.TExp Int64)+  let offset' = tvExp offset+  offset_index <- dPrimV "offset_index" (0 :: Imp.TExp Int64)+  let offset_index' = tvExp offset_index++  -- Parameters used to find the chunk sizes+  -- Perhaps get this information from ``scheduling information``+  -- instead of computing it manually here.+  let iter_pr_subtask = product ns_64 `quot` sExt64 nsubtasks'+      remainder = product ns_64 `rem` sExt64 nsubtasks'++  accs <- resultArrays "scan_stage_2_accum" scan_ops+  forM_ (zip scan_ops accs) $ \(scan_op, acc) ->+    sLoopNest (segBinOpShape scan_op) $ \vec_is ->+      forM_ (zip acc $ segBinOpNeutral scan_op) $ \(acc', ne) ->+        copyDWIMFix acc' vec_is ne []++  -- Perform sequential scan over the last element of each chunk+  sFor "i" (nsubtasks' - 1) $ \i -> do+    offset <-- iter_pr_subtask+    sWhen (sExt64 i .<. remainder) (offset <-- offset' + 1)+    offset_index <-- offset_index' + offset'+    zipWithM_ dPrimV_ is $ unflattenIndex ns_64 $ sExt64 offset_index'++    compileStms mempty (kernelBodyStms kbody) $+      forM_ (zip3 per_scan_pes scan_ops accs) $ \(pes, scan_op, acc) ->+        sLoopNest (segBinOpShape scan_op) $ \vec_is -> do+          sComment "Read carry in" $+            forM_ (zip (xParams scan_op) acc) $ \(p, acc') ->+              copyDWIMFix (paramName p) [] (Var acc') vec_is++          sComment "Read next values" $+            forM_ (zip (yParams scan_op) pes) $ \(p, pe) ->+              copyDWIMFix (paramName p) [] (Var $ patElemName pe) ((offset_index' - 1) : vec_is)++          compileStms mempty (bodyStms $ lamBody scan_op) $+            forM_ (zip3 acc pes (bodyResult $ lamBody scan_op)) $+              \(acc', pe, se) -> do+                copyDWIMFix (patElemName pe) ((offset_index' - 1) : vec_is) se []+                copyDWIMFix acc' vec_is se []++-- Stage 3 : Finally each thread partially scans a chunk of the input+--           reading its corresponding carry-in+scanStage3 ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  KernelBody MCMem ->+  MulticoreGen ()+scanStage3 pat space scan_ops kbody = do+  let (is, ns) = unzip $ unSegSpace space+      all_scan_res = take (segBinOpResults scan_ops) $ kernelBodyResult kbody+      per_scan_res = segBinOpChunks scan_ops all_scan_res+      per_scan_pes = segBinOpChunks scan_ops $ patternValueElements pat+      ns' = map toInt64Exp ns++  iter <- dPrimV "iter" (0 :: Imp.TExp Int64)+  let iter' = tvExp iter++  (local_accs, prebody) <- collect' $ do+    dScope Nothing $ scopeOfLParams $ concatMap (lambdaParams . segBinOpLambda) scan_ops+    forM (zip scan_ops per_scan_pes) $ \(scan_op, pes) -> do+      let shape = segBinOpShape scan_op+          ts = lambdaReturnType $ segBinOpLambda scan_op+      forM (zip4 (xParams scan_op) pes ts $ segBinOpNeutral scan_op) $ \(p, pe, t, ne) -> do+        acc <-+          case shapeDims shape of+            [] -> pure $ paramName p+            _ -> do+              let pt = elemType t+              sAllocArray "local_acc" pt (shape <> arrayShape t) DefaultSpace++        -- Initialise the accumulator with neutral from previous chunk.+        -- or read neutral if first ``iter``+        sLoopNest (segBinOpShape scan_op) $ \vec_is -> do+          let read_carry_in =+                copyDWIMFix acc vec_is (Var $ patElemName pe) (iter' - 1 : vec_is)+              read_neutral =+                copyDWIMFix acc vec_is ne []+          sIf (iter' .==. 0) read_neutral read_carry_in+        pure acc++  body <- collect $ do+    zipWithM_ dPrimV_ is $ unflattenIndex ns' iter'+    sComment "stage 3 scan body" $+      compileStms mempty (kernelBodyStms kbody) $+        forM_ (zip4 per_scan_pes scan_ops per_scan_res local_accs) $ \(pes, scan_op, scan_res, acc) ->+          sLoopNest (segBinOpShape scan_op) $ \vec_is -> do+            forM_ (zip (xParams scan_op) acc) $ \(p, acc') ->+              copyDWIMFix (paramName p) [] (Var acc') vec_is++            -- Read next value+            forM_ (zip (yParams scan_op) scan_res) $ \(p, se) ->+              copyDWIMFix (paramName p) [] (kernelResultSubExp se) vec_is++            compileStms mempty (bodyStms $ lamBody scan_op) $+              forM_ (zip3 pes (bodyResult $ lamBody scan_op) acc) $+                \(pe, se, acc') -> do+                  copyDWIMFix (patElemName pe) (map Imp.vi64 is ++ vec_is) se []+                  copyDWIMFix acc' vec_is se []++  free_params' <- freeParams (prebody <> body) (segFlat space : [tvVar iter])+  let (body_allocs, body') = extractAllocations body+  emit $ Imp.Op $ Imp.ParLoop "scan_stage_3" (tvVar iter) (body_allocs <> prebody) body' mempty free_params' $ segFlat space++-- This implementation for a Segmented scan only+-- parallelize over the segments and each segment is+-- scanned sequentially.+segmentedScan ::+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  KernelBody MCMem ->+  MulticoreGen Imp.Code+segmentedScan pat space scan_ops kbody = do+  emit $ Imp.DebugPrint "segmented segScan" Nothing+  collect $ do+    segment_iter <- dPrim "segment_iter" $ IntType Int64+    body <- compileSegScanBody (tvExp segment_iter) pat space scan_ops kbody+    free_params <- freeParams body (segFlat space : [tvVar segment_iter])+    let (body_allocs, body') = extractAllocations body+    emit $ Imp.Op $ Imp.ParLoop "seg_scan" (tvVar segment_iter) body_allocs body' mempty free_params $ segFlat space++compileSegScanBody ::+  Imp.TExp Int64 ->+  Pattern MCMem ->+  SegSpace ->+  [SegBinOp MCMem] ->+  KernelBody MCMem ->+  MulticoreGen Imp.Code+compileSegScanBody segment_i pat space scan_ops kbody = do+  let (is, ns) = unzip $ unSegSpace space+      ns_64 = map toInt64Exp ns++  let per_scan_pes = segBinOpChunks scan_ops $ patternValueElements pat+  collect $+    forM_ (zip scan_ops per_scan_pes) $ \(scan_op, scan_pes) -> do+      dScope Nothing $ scopeOfLParams $ lambdaParams $ segBinOpLambda scan_op+      let (scan_x_params, scan_y_params) = splitAt (length $ segBinOpNeutral scan_op) $ (lambdaParams . segBinOpLambda) scan_op++      forM_ (zip scan_x_params $ segBinOpNeutral scan_op) $ \(p, ne) ->+        copyDWIMFix (paramName p) [] ne []++      let inner_bound = last ns_64+      -- Perform a sequential scan over the segment ``segment_i``+      sFor "i" inner_bound $ \i -> do+        zipWithM_ dPrimV_ (init is) $ unflattenIndex (init ns_64) segment_i+        dPrimV_ (last is) i+        compileStms mempty (kernelBodyStms kbody) $ do+          let (scan_res, map_res) = splitAt (length $ segBinOpNeutral scan_op) $ kernelBodyResult kbody+          sComment "write to-scan values to parameters" $+            forM_ (zip scan_y_params scan_res) $ \(p, se) ->+              copyDWIMFix (paramName p) [] (kernelResultSubExp se) []++          sComment "write mapped values results to memory" $+            forM_ (zip (drop (length $ segBinOpNeutral scan_op) $ patternElements pat) map_res) $ \(pe, se) ->+              copyDWIMFix (patElemName pe) (map Imp.vi64 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 (bodyResult $ lambdaBody $ segBinOpLambda scan_op)) $ \(p, pe, se) -> do+                copyDWIMFix (patElemName pe) (map Imp.vi64 is) se []+                copyDWIMFix (paramName p) [] se []
src/Futhark/Construct.hs view
@@ -330,12 +330,12 @@   m (Exp (Lore m)) eSliceArray d arr i n = do   arr_t <- lookupType arr-  let skips = map (slice (constant (0 :: Int32))) $ take d $ arrayDims arr_t+  let skips = map (slice (constant (0 :: Int64))) $ take d $ arrayDims arr_t   i' <- letSubExp "slice_i" =<< i   n' <- letSubExp "slice_n" =<< n   return $ BasicOp $ Index arr $ fullSlice arr_t $ skips ++ [slice i' n']   where-    slice j m = DimSlice j m (constant (1 :: Int32))+    slice j m = DimSlice j m (constant (1 :: Int64))  -- | Are these indexes out-of-bounds for the array? eOutOfBounds ::@@ -350,10 +350,10 @@   let checkDim w i = do         less_than_zero <-           letSubExp "less_than_zero" $-            BasicOp $ CmpOp (CmpSlt Int32) i (constant (0 :: Int32))+            BasicOp $ CmpOp (CmpSlt Int64) i (constant (0 :: Int64))         greater_than_size <-           letSubExp "greater_than_size" $-            BasicOp $ CmpOp (CmpSle Int32) w i+            BasicOp $ CmpOp (CmpSle Int64) w i         letSubExp "outside_bounds_dim" $           BasicOp $ BinOp LogOr less_than_zero greater_than_size   foldBinOp LogOr (constant False) =<< zipWithM checkDim ws is'@@ -479,7 +479,7 @@  -- | Slice a full dimension of the given size. sliceDim :: SubExp -> DimIndex SubExp-sliceDim d = DimSlice (constant (0 :: Int32)) d (constant (1 :: Int32))+sliceDim d = DimSlice (constant (0 :: Int64)) d (constant (1 :: Int64))  -- | @fullSlice t slice@ returns @slice@, but with 'DimSlice's of -- entire dimensions appended to the full dimensionality of @t@.  This@@ -579,7 +579,7 @@   runWriterT $ instantiateShapes instantiate ts   where     instantiate _ = do-      v <- lift $ newIdent "size" $ Prim int32+      v <- lift $ newIdent "size" $ Prim int64       tell [v]       return $ Var $ identName v 
src/Futhark/IR/Kernels/Kernel.hs view
@@ -204,11 +204,11 @@   cheapOp _ = True  instance TypedOp SizeOp where-  opType SplitSpace {} = pure [Prim int32]-  opType (GetSize _ _) = pure [Prim int32]-  opType (GetSizeMax _) = pure [Prim int32]+  opType SplitSpace {} = pure [Prim int64]+  opType (GetSize _ _) = pure [Prim int64]+  opType (GetSizeMax _) = pure [Prim int64]   opType CmpSizeLe {} = pure [Prim Bool]-  opType CalcNumGroups {} = pure [Prim int32]+  opType CalcNumGroups {} = pure [Prim int64]  instance AliasedOp SizeOp where   opAliases _ = [mempty]@@ -251,14 +251,14 @@ typeCheckSizeOp (SplitSpace o w i elems_per_thread) = do   case o of     SplitContiguous -> return ()-    SplitStrided stride -> TC.require [Prim int32] stride-  mapM_ (TC.require [Prim int32]) [w, i, elems_per_thread]+    SplitStrided stride -> TC.require [Prim int64] stride+  mapM_ (TC.require [Prim int64]) [w, i, elems_per_thread] typeCheckSizeOp GetSize {} = return () typeCheckSizeOp GetSizeMax {} = return ()-typeCheckSizeOp (CmpSizeLe _ _ x) = TC.require [Prim int32] x+typeCheckSizeOp (CmpSizeLe _ _ x) = TC.require [Prim int64] x typeCheckSizeOp (CalcNumGroups w _ group_size) = do   TC.require [Prim int64] w-  TC.require [Prim int32] group_size+  TC.require [Prim int64] group_size  -- | A host-level operation; parameterised by what else it can do. data HostOp lore op@@ -357,8 +357,8 @@   SegLevel ->   TC.TypeM lore () checkSegLevel Nothing lvl = do-  TC.require [Prim int32] $ unCount $ segNumGroups lvl-  TC.require [Prim int32] $ unCount $ segGroupSize lvl+  TC.require [Prim int64] $ unCount $ segNumGroups lvl+  TC.require [Prim int64] $ unCount $ segGroupSize lvl checkSegLevel (Just SegThread {}) _ =   TC.bad $ TC.TypeError "SegOps cannot occur when already at thread level." checkSegLevel (Just x) y
src/Futhark/IR/Kernels/Sizes.hs view
@@ -17,7 +17,7 @@ where  import Control.Category-import Data.Int (Int32)+import Data.Int (Int64) import Data.Traversable import Futhark.IR.Prop.Names (FreeIn) import Futhark.Transform.Substitute@@ -37,7 +37,7 @@ -- impose constraints on the valid values. data SizeClass   = -- | A threshold with an optional default.-    SizeThreshold KernelPath (Maybe Int32)+    SizeThreshold KernelPath (Maybe Int64)   | SizeGroup   | SizeNumGroups   | SizeTile@@ -45,7 +45,7 @@     -- maximum can be handy.     SizeLocalMemory   | -- | A bespoke size with a default.-    SizeBespoke Name Int32+    SizeBespoke Name Int64   deriving (Eq, Ord, Show, Generic)  instance SexpIso SizeClass where@@ -72,7 +72,7 @@   ppr (SizeBespoke k _) = ppr k  -- | The default value for the size.  If 'Nothing', that means the backend gets to decide.-sizeDefault :: SizeClass -> Maybe Int32+sizeDefault :: SizeClass -> Maybe Int64 sizeDefault (SizeThreshold _ x) = x sizeDefault (SizeBespoke _ x) = Just x sizeDefault _ = Nothing
+ src/Futhark/IR/MC.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}++-- | A representation for multicore CPU parallelism.+module Futhark.IR.MC+  ( -- * The Lore definition+    MC,++    -- * Simplification+    simplifyProg,++    -- * Module re-exports+    module Futhark.IR.Prop,+    module Futhark.IR.Traversals,+    module Futhark.IR.Pretty,+    module Futhark.IR.Syntax,+    module Futhark.IR.SegOp,+    module Futhark.IR.SOACS.SOAC,+    module Futhark.IR.MC.Op,+  )+where++import Futhark.Binder+import Futhark.Construct+import Futhark.IR.MC.Op+import Futhark.IR.Pretty+import Futhark.IR.Prop+import Futhark.IR.SOACS.SOAC hiding (HistOp (..))+import qualified Futhark.IR.SOACS.Simplify as SOAC+import Futhark.IR.SegOp+import Futhark.IR.Syntax+import Futhark.IR.Traversals+import qualified Futhark.Optimise.Simplify as Simplify+import qualified Futhark.Optimise.Simplify.Engine as Engine+import Futhark.Optimise.Simplify.Rules+import Futhark.Pass+import qualified Futhark.TypeCheck as TypeCheck++data MC++instance Decorations MC where+  type Op MC = MCOp MC (SOAC MC)++instance ASTLore MC where+  expTypesFromPattern = return . expExtTypesFromPattern++instance TypeCheck.CheckableOp MC where+  checkOp = typeCheckMCOp typeCheckSOAC++instance TypeCheck.Checkable MC++instance Bindable MC where+  mkBody = Body ()+  mkExpPat ctx val _ = basicPattern ctx val+  mkExpDec _ _ = ()+  mkLetNames = simpleMkLetNames++instance BinderOps MC++instance BinderOps (Engine.Wise MC)++instance PrettyLore MC++simpleMC :: Simplify.SimpleOps MC+simpleMC = Simplify.bindableSimpleOps $ simplifyMCOp SOAC.simplifySOAC++simplifyProg :: Prog MC -> PassM (Prog MC)+simplifyProg = Simplify.simplifyProg simpleMC rules blockers+  where+    blockers = Engine.noExtraHoistBlockers+    rules = standardRules <> segOpRules++instance HasSegOp MC where+  type SegOpLevel MC = ()+  asSegOp = const Nothing+  segOp = ParOp Nothing++instance HasSegOp (Engine.Wise MC) where+  type SegOpLevel (Engine.Wise MC) = ()+  asSegOp = const Nothing+  segOp = ParOp Nothing
+ src/Futhark/IR/MC/Op.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++-- | Definitions for multicore operations.+--+-- Most of the interesting stuff is in "Futhark.IR.SegOp", which is+-- also re-exported from here.+module Futhark.IR.MC.Op+  ( MCOp (..),+    typeCheckMCOp,+    simplifyMCOp,+    module Futhark.IR.SegOp,+  )+where++import Control.Category+import Data.Bifunctor (first)+import Futhark.Analysis.Metrics+import qualified Futhark.Analysis.SymbolTable as ST+import Futhark.IR+import Futhark.IR.Aliases (Aliases)+import Futhark.IR.Prop.Aliases+import Futhark.IR.SegOp+import qualified Futhark.Optimise.Simplify as Simplify+import qualified Futhark.Optimise.Simplify.Engine as Engine+import Futhark.Optimise.Simplify.Lore+import Futhark.Transform.Rename+import Futhark.Transform.Substitute+import qualified Futhark.TypeCheck as TC+import Futhark.Util.Pretty+  ( Pretty,+    nestedBlock,+    ppr,+    (<+>),+    (</>),+  )+import GHC.Generics (Generic)+import Language.SexpGrammar as Sexp+import Language.SexpGrammar.Generic+import Prelude hiding (id, (.))++-- | An operation for the multicore representation.  Feel free to+-- extend this on an ad hoc basis as needed.  Parameterised with some+-- other operation.+data MCOp lore op+  = -- | The first 'SegOp' (if it exists) contains nested parallelism,+    -- while the second one has a fully sequential body.  They are+    -- semantically fully equivalent.+    ParOp+      (Maybe (SegOp () lore))+      (SegOp () lore)+  | -- | Something else (in practice often a SOAC).+    OtherOp op+  deriving (Eq, Ord, Show, Generic)++instance (Decorations lore, SexpIso op) => SexpIso (MCOp lore op) where+  sexpIso =+    match $+      With (. Sexp.list (Sexp.el sexpIso >>> Sexp.el sexpIso)) $+        With+          (. Sexp.list (Sexp.el sexpIso))+          End++instance (ASTLore lore, Substitute op) => Substitute (MCOp lore op) where+  substituteNames substs (ParOp par_op op) =+    ParOp (substituteNames substs <$> par_op) (substituteNames substs op)+  substituteNames substs (OtherOp op) =+    OtherOp $ substituteNames substs op++instance (ASTLore lore, Rename op) => Rename (MCOp lore op) where+  rename (ParOp par_op op) = ParOp <$> rename par_op <*> rename op+  rename (OtherOp op) = OtherOp <$> rename op++instance (ASTLore lore, FreeIn op) => FreeIn (MCOp lore op) where+  freeIn' (ParOp par_op op) = freeIn' par_op <> freeIn' op+  freeIn' (OtherOp op) = freeIn' op++instance (ASTLore lore, IsOp op) => IsOp (MCOp lore op) where+  safeOp (ParOp _ op) = safeOp op+  safeOp (OtherOp op) = safeOp op++  cheapOp (ParOp _ op) = cheapOp op+  cheapOp (OtherOp op) = cheapOp op++instance TypedOp op => TypedOp (MCOp lore op) where+  opType (ParOp _ op) = opType op+  opType (OtherOp op) = opType op++instance+  (Aliased lore, AliasedOp op, ASTLore lore) =>+  AliasedOp (MCOp lore op)+  where+  opAliases (ParOp _ op) = opAliases op+  opAliases (OtherOp op) = opAliases op++  consumedInOp (ParOp _ op) = consumedInOp op+  consumedInOp (OtherOp op) = consumedInOp op++instance+  (CanBeAliased (Op lore), CanBeAliased op, ASTLore lore) =>+  CanBeAliased (MCOp lore op)+  where+  type OpWithAliases (MCOp lore op) = MCOp (Aliases lore) (OpWithAliases op)++  addOpAliases (ParOp par_op op) =+    ParOp (addOpAliases <$> par_op) (addOpAliases op)+  addOpAliases (OtherOp op) =+    OtherOp $ addOpAliases op++  removeOpAliases (ParOp par_op op) =+    ParOp (removeOpAliases <$> par_op) (removeOpAliases op)+  removeOpAliases (OtherOp op) =+    OtherOp $ removeOpAliases op++instance+  (CanBeWise (Op lore), CanBeWise op, ASTLore lore) =>+  CanBeWise (MCOp lore op)+  where+  type OpWithWisdom (MCOp lore op) = MCOp (Wise lore) (OpWithWisdom op)++  removeOpWisdom (ParOp par_op op) =+    ParOp (removeOpWisdom <$> par_op) (removeOpWisdom op)+  removeOpWisdom (OtherOp op) =+    OtherOp $ removeOpWisdom op++instance (ASTLore lore, ST.IndexOp op) => ST.IndexOp (MCOp lore 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++instance (PrettyLore lore, Pretty op) => Pretty (MCOp lore op) where+  ppr (ParOp Nothing op) = ppr op+  ppr (ParOp (Just par_op) op) =+    "par" <+> nestedBlock "{" "}" (ppr par_op)+      </> "seq" <+> nestedBlock "{" "}" (ppr op)+  ppr (OtherOp op) = ppr op++instance (OpMetrics (Op lore), OpMetrics op) => OpMetrics (MCOp lore op) where+  opMetrics (ParOp par_op op) = opMetrics par_op >> opMetrics op+  opMetrics (OtherOp op) = opMetrics op++typeCheckMCOp ::+  TC.Checkable lore =>+  (op -> TC.TypeM lore ()) ->+  MCOp (Aliases lore) op ->+  TC.TypeM lore ()+typeCheckMCOp _ (ParOp (Just par_op) op) = do+  -- It is valid for the same array to be consumed in both par_op and op.+  _ <- typeCheckSegOp return par_op `TC.alternative` typeCheckSegOp return op+  return ()+typeCheckMCOp _ (ParOp Nothing op) =+  typeCheckSegOp return op+typeCheckMCOp f (OtherOp op) = f op++simplifyMCOp ::+  ( Engine.SimplifiableLore lore,+    BodyDec lore ~ ()+  ) =>+  Simplify.SimplifyOp lore op ->+  MCOp lore op ->+  Engine.SimpleM lore (MCOp (Wise lore) (OpWithWisdom op), Stms (Wise lore))+simplifyMCOp f (OtherOp op) = do+  (op', stms) <- f op+  return (OtherOp op', stms)+simplifyMCOp _ (ParOp par_op op) = do+  (par_op', par_op_hoisted) <-+    case par_op of+      Nothing -> return (Nothing, mempty)+      Just x -> first Just <$> simplifySegOp x++  (op', op_hoisted) <- simplifySegOp op++  return (ParOp par_op' op', par_op_hoisted <> op_hoisted)
+ src/Futhark/IR/MCMem.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}++module Futhark.IR.MCMem+  ( MCMem,++    -- * Simplification+    simplifyProg,++    -- * Module re-exports+    module Futhark.IR.Mem,+    module Futhark.IR.SegOp,+    module Futhark.IR.MC.Op,+  )+where++import Futhark.Analysis.PrimExp.Convert+import Futhark.IR.MC.Op+import Futhark.IR.Mem+import Futhark.IR.Mem.Simplify+import Futhark.IR.SegOp+import qualified Futhark.Optimise.Simplify.Engine as Engine+import Futhark.Pass+import Futhark.Pass.ExplicitAllocations (BinderOps (..), mkLetNamesB', mkLetNamesB'')+import qualified Futhark.TypeCheck as TC++data MCMem++instance Decorations MCMem where+  type LetDec MCMem = LetDecMem+  type FParamInfo MCMem = FParamMem+  type LParamInfo MCMem = LParamMem+  type RetType MCMem = RetTypeMem+  type BranchType MCMem = BranchTypeMem+  type Op MCMem = MemOp (MCOp MCMem ())++instance ASTLore MCMem where+  expTypesFromPattern = return . map snd . snd . bodyReturnsFromPattern++instance OpReturns MCMem where+  opReturns (Alloc _ space) = return [MemMem space]+  opReturns (Inner (ParOp _ op)) = segOpReturns op+  opReturns (Inner (OtherOp ())) = pure []++instance PrettyLore MCMem++instance TC.CheckableOp MCMem where+  checkOp = typeCheckMemoryOp+    where+      typeCheckMemoryOp (Alloc size _) =+        TC.require [Prim int64] size+      typeCheckMemoryOp (Inner op) =+        typeCheckMCOp pure op++instance TC.Checkable MCMem where+  checkFParamLore = checkMemInfo+  checkLParamLore = checkMemInfo+  checkLetBoundLore = checkMemInfo+  checkRetType = mapM_ (TC.checkExtType . declExtTypeOf)+  primFParam name t = return $ Param name (MemPrim t)+  matchPattern = matchPatternToExp+  matchReturnType = matchFunctionReturnType+  matchBranchType = matchBranchReturnType+  matchLoopResult = matchLoopResultMem++instance BinderOps MCMem where+  mkExpDecB _ _ = return ()+  mkBodyB stms res = return $ Body () stms res+  mkLetNamesB = mkLetNamesB' ()++instance BinderOps (Engine.Wise MCMem) where+  mkExpDecB pat e = return $ Engine.mkWiseExpDec pat () e+  mkBodyB stms res = return $ Engine.mkWiseBody () stms res+  mkLetNamesB = mkLetNamesB''++simplifyProg :: Prog MCMem -> PassM (Prog MCMem)+simplifyProg = simplifyProgGeneric simpleMCMem++simpleMCMem :: Engine.SimpleOps MCMem+simpleMCMem =+  simpleGeneric (const mempty) $ simplifyMCOp $ const $ return ((), mempty)
src/Futhark/IR/Mem.hs view
@@ -248,10 +248,10 @@   indexOp _ _ _ _ = Nothing  -- | The index function representation used for memory annotations.-type IxFun = IxFun.IxFun (TPrimExp Int32 VName)+type IxFun = IxFun.IxFun (TPrimExp Int64 VName)  -- | An index function that may contain existential variables.-type ExtIxFun = IxFun.IxFun (TPrimExp Int32 (Ext VName))+type ExtIxFun = IxFun.IxFun (TPrimExp Int64 (Ext VName))  -- | A summary of the memory information for every let-bound -- identifier, function parameter, and return value.  Parameterisered@@ -333,13 +333,13 @@   Engine.SimplifiableLore lore =>   IxFun ->   Engine.SimpleM lore IxFun-simplifyIxFun = traverse $ fmap isInt32 . simplifyPrimExp . untyped+simplifyIxFun = traverse $ fmap isInt64 . simplifyPrimExp . untyped  simplifyExtIxFun ::   Engine.SimplifiableLore lore =>   ExtIxFun ->   Engine.SimpleM lore ExtIxFun-simplifyExtIxFun = traverse $ fmap isInt32 . simplifyExtPrimExp . untyped+simplifyExtIxFun = traverse $ fmap isInt64 . simplifyExtPrimExp . untyped  isStaticIxFun :: ExtIxFun -> Maybe IxFun isStaticIxFun = traverse $ traverse inst@@ -467,22 +467,22 @@       ReturnsInBlock v $         fixExtIxFun           i-          (primExpFromSubExp int32 (Var v))+          (primExpFromSubExp int64 (Var v))           ixfun   fixExt i se (ReturnsNewBlock space j ixfun) =     ReturnsNewBlock       space       j'-      (fixExtIxFun i (primExpFromSubExp int32 se) ixfun)+      (fixExtIxFun i (primExpFromSubExp int64 se) ixfun)     where       j'         | i < j = j -1         | otherwise = j   fixExt i se (ReturnsInBlock mem ixfun) =-    ReturnsInBlock mem (fixExtIxFun i (primExpFromSubExp int32 se) ixfun)+    ReturnsInBlock mem (fixExtIxFun i (primExpFromSubExp int64 se) ixfun)  fixExtIxFun :: Int -> PrimExp VName -> ExtIxFun -> ExtIxFun-fixExtIxFun i e = fmap $ isInt32 . replaceInPrimExp update . untyped+fixExtIxFun i e = fmap $ isInt64 . replaceInPrimExp update . untyped   where     update (Ext j) t       | j > i = LeafExp (Ext $ j - 1) t@@ -490,8 +490,8 @@       | otherwise = LeafExp (Ext j) t     update (Free x) t = LeafExp (Free x) t -leafExp :: Int -> TPrimExp Int32 (Ext a)-leafExp i = isInt32 $ LeafExp (Ext i) int32+leafExp :: Int -> TPrimExp Int64 (Ext a)+leafExp i = isInt64 $ LeafExp (Ext i) int64  existentialiseIxFun :: [VName] -> IxFun -> ExtIxFun existentialiseIxFun ctx = IxFun.substituteInIxFun ctx' . fmap (fmap Free)@@ -657,15 +657,15 @@ -- occurs. getExtMaps ::   [(VName, Int)] ->-  ( M.Map (Ext VName) (TPrimExp Int32 (Ext VName)),-    M.Map (Ext VName) (TPrimExp Int32 (Ext VName))+  ( M.Map (Ext VName) (TPrimExp Int64 (Ext VName)),+    M.Map (Ext VName) (TPrimExp Int64 (Ext VName))   ) getExtMaps ctx_lst_ids =   ( M.map leafExp $ M.mapKeys Free $ M.fromListWith (flip const) ctx_lst_ids,     M.fromList $       mapMaybe         ( traverse-            ( fmap (\i -> isInt32 $ LeafExp (Ext i) int32)+            ( fmap (\i -> isInt64 $ LeafExp (Ext i) int64)                 . (`lookup` ctx_lst_ids)             )             . uncurry (flip (,))@@ -928,7 +928,7 @@ lookupArraySummary ::   (Mem lore, HasScope lore m, Monad m) =>   VName ->-  m (VName, IxFun.IxFun (TPrimExp Int32 VName))+  m (VName, IxFun.IxFun (TPrimExp Int64 VName)) lookupArraySummary name = do   summary <- lookupMemInfo name   case summary of@@ -943,7 +943,7 @@   MemInfo SubExp u MemBind ->   TC.TypeM lore () checkMemInfo _ (MemPrim _) = return ()-checkMemInfo _ (MemMem (ScalarSpace d _)) = mapM_ (TC.require [Prim int32]) d+checkMemInfo _ (MemMem (ScalarSpace d _)) = mapM_ (TC.require [Prim int64]) d checkMemInfo _ (MemMem _) = return () checkMemInfo name (MemArray _ shape _ (ArrayIn v ixfun)) = do   t <- lookupType v@@ -959,7 +959,7 @@             ++ "."    TC.context ("in index function " ++ pretty ixfun) $ do-    traverse_ (TC.requirePrimExp int32 . untyped) ixfun+    traverse_ (TC.requirePrimExp int64 . untyped) ixfun     let ixfun_rank = IxFun.rank ixfun         ident_rank = shapeRank shape     unless (ixfun_rank == ident_rank) $@@ -1044,8 +1044,8 @@                 IxFun.iota $ map convert $ shapeDims shape       | otherwise =         return $ MemArray bt shape u Nothing-    convert (Ext i) = le32 (Ext i)-    convert (Free v) = Free <$> pe32 v+    convert (Ext i) = le64 (Ext i)+    convert (Free v) = Free <$> pe64 v  arrayVarReturns ::   (HasScope lore m, Monad m, Mem lore) =>@@ -1095,7 +1095,7 @@         Just $           ReturnsInBlock mem $             existentialiseIxFun [] $-              IxFun.reshape ixfun $ map (fmap pe32) newshape+              IxFun.reshape ixfun $ map (fmap pe64) newshape     ] expReturns (BasicOp (Rearrange perm v)) = do   (et, Shape dims, mem, ixfun) <- arrayVarReturns v@@ -1107,7 +1107,7 @@     ] expReturns (BasicOp (Rotate offsets v)) = do   (et, Shape dims, mem, ixfun) <- arrayVarReturns v-  let offsets' = map pe32 offsets+  let offsets' = map pe64 offsets       ixfun' = IxFun.rotate ixfun offsets'   return     [ MemArray et (Shape $ map Free dims) NoUniqueness $@@ -1176,7 +1176,7 @@           ArrayIn mem $             IxFun.slice               ixfun-              (map (fmap (isInt32 . primExpFromSubExp int32)) slice)+              (map (fmap (isInt64 . primExpFromSubExp int64)) slice)  class TypedOp (Op lore) => OpReturns lore where   opReturns ::
src/Futhark/IR/Pretty.hs view
@@ -237,6 +237,7 @@     where       p (ErrorString s) = text $ show s       p (ErrorInt32 x) = ppr x+      p (ErrorInt64 x) = ppr x  instance PrettyLore lore => Pretty (Exp lore) where   ppr (If c t f (IfDec _ ifsort)) =
src/Futhark/IR/Prop/TypeOf.hs view
@@ -66,7 +66,7 @@ primOpType (ArrayLit es rt) =   pure [arrayOf rt (Shape [n]) NoUniqueness]   where-    n = intConst Int32 $ toInteger $ length es+    n = intConst Int64 $ toInteger $ length es primOpType (BinOp bop _ _) =   pure [Prim $ binOpType bop] primOpType (UnOp _ x) =@@ -147,7 +147,7 @@   f <*> x = FeelBad $ feelBad f $ feelBad x  instance Decorations lore => HasScope lore (FeelBad lore) where-  lookupType = const $ pure $ Prim $ IntType Int32+  lookupType = const $ pure $ Prim $ IntType Int64   askScope = pure mempty  -- | Given the context and value merge parameters of a Futhark @loop@,
src/Futhark/IR/Prop/Types.hs view
@@ -246,7 +246,7 @@ shapeSize :: Int -> Shape -> SubExp shapeSize i shape = case drop i $ shapeDims shape of   e : _ -> e-  [] -> constant (0 :: Int32)+  [] -> constant (0 :: Int64)  -- | Return the dimensions of a type - for non-arrays, this is the -- empty list.@@ -267,7 +267,7 @@ -- the given type list.  If the dimension does not exist, or no types -- are given, the zero constant is returned. arraysSize :: Int -> [TypeBase Shape u] -> SubExp-arraysSize _ [] = constant (0 :: Int32)+arraysSize _ [] = constant (0 :: Int64) arraysSize i (t : _) = arraySize i t  -- | Return the immediate row-type of an array.  For @[[int]]@, this
src/Futhark/IR/SOACS/SOAC.hs view
@@ -659,13 +659,13 @@ typeCheckSOAC :: TC.Checkable lore => SOAC (Aliases lore) -> TC.TypeM lore () typeCheckSOAC (Stream size form lam arrexps) = do   let accexps = getStreamAccums form-  TC.require [Prim int32] size+  TC.require [Prim int64] size   accargs <- mapM TC.checkArg accexps   arrargs <- mapM lookupType arrexps   _ <- TC.checkSOACArrayArgs size arrexps   let chunk = head $ lambdaParams lam   let asArg t = (t, mempty)-      inttp = Prim int32+      inttp = Prim int64       lamarrs' = map (`setOuterSize` Var (paramName chunk)) arrargs   let acc_len = length accexps   let lamrtp = take acc_len $ lambdaReturnType lam@@ -698,7 +698,7 @@   --   1. The number of index types must be equal to the number of value types   --      and the number of writes to arrays in @as@.   ---  --   2. Each index type must have the type i32.+  --   2. Each index type must have the type i64.   --   --   3. Each array in @as@ and the value types must have the same type   --@@ -712,7 +712,7 @@   -- Code:    -- First check the input size.-  TC.require [Prim int32] w+  TC.require [Prim int64] w    -- 0.   let (_as_ws, as_ns, _as_vs) = unzip3 as@@ -727,12 +727,12 @@    -- 2.   forM_ rtsI $ \rtI ->-    unless (Prim int32 == rtI) $-      TC.bad $ TC.TypeError "Scatter: Index return type must be i32."+    unless (Prim int64 == rtI) $+      TC.bad $ TC.TypeError "Scatter: Index return type must be i64."    forM_ (zip (chunks as_ns rtsV) as) $ \(rtVs, (aw, _, a)) -> do-    -- All lengths must have type i32.-    TC.require [Prim int32] aw+    -- All lengths must have type i64.+    TC.require [Prim int64] aw      -- 3.     forM_ rtVs $ \rtV -> TC.requireI [rtV `arrayOfRow` aw] a@@ -744,13 +744,13 @@   arrargs <- TC.checkSOACArrayArgs w ivs   TC.checkLambda lam arrargs typeCheckSOAC (Hist len ops bucket_fun imgs) = do-  TC.require [Prim int32] len+  TC.require [Prim int64] len    -- Check the operators.   forM_ ops $ \(HistOp dest_w rf dests nes op) -> do     nes' <- mapM TC.checkArg nes-    TC.require [Prim int32] dest_w-    TC.require [Prim int32] rf+    TC.require [Prim int64] dest_w+    TC.require [Prim int64] rf      -- Operator type must match the type of neutral elements.     TC.checkLambda op $ map TC.noArgAliases $ nes' ++ nes'@@ -775,7 +775,7 @@   -- Return type of bucket function must be an index for each   -- operation followed by the values to write.   nes_ts <- concat <$> mapM (mapM subExpType . histNeutral) ops-  let bucket_ret_t = replicate (length ops) (Prim int32) ++ nes_ts+  let bucket_ret_t = replicate (length ops) (Prim int64) ++ nes_ts   unless (bucket_ret_t == lambdaReturnType bucket_fun) $     TC.bad $       TC.TypeError $@@ -784,7 +784,7 @@           ++ " but should have type "           ++ prettyTuple bucket_ret_t typeCheckSOAC (Screma w (ScremaForm scans reds map_lam) arrs) = do-  TC.require [Prim int32] w+  TC.require [Prim int64] w   arrs' <- TC.checkSOACArrayArgs w arrs   TC.checkLambda map_lam $ map TC.noArgAliases arrs' 
src/Futhark/IR/SOACS/Simplify.hs view
@@ -517,7 +517,7 @@     Simplify $       certifying (stmAuxCerts aux1 <> cs) $         letBind pat $-          BasicOp $ Rotate (intConst Int32 0 : rots) arr+          BasicOp $ Rotate (intConst Int64 0 : rots) arr mapOpToOp _ _ _ _ = Skip  isMapWithOp ::@@ -680,7 +680,7 @@         bindMapParam p a = do           a_t <- lookupType a           letBindNames [paramName p] $-            BasicOp $ Index a $ fullSlice a_t [DimFix $ constant (0 :: Int32)]+            BasicOp $ Index a $ fullSlice a_t [DimFix $ constant (0 :: Int64)]         bindArrayResult pe se =           letBindNames [patElemName pe] $             BasicOp $ ArrayLit [se] $ rowType $ patElemType pe@@ -705,7 +705,7 @@           partitionChunkedFoldParameters (length nes) (lambdaParams fold_lam)      letBindNames [paramName chunk_param] $-      BasicOp $ SubExp $ intConst Int32 1+      BasicOp $ SubExp $ intConst Int64 1      forM_ (zip acc_params nes) $ \(p, ne) ->       letBindNames [paramName p] $ BasicOp $ SubExp ne@@ -858,7 +858,7 @@               letExp (baseString arr ++ "_prefix") $                 BasicOp $                   Index arr $-                    fullSlice arr_t [DimSlice (intConst Int32 0) w (intConst Int32 1)]+                    fullSlice arr_t [DimSlice (intConst Int64 0) w (intConst Int64 1)]       return $         Just           ( arr',@@ -920,7 +920,7 @@     mapOverArr op       | Just (_, arr) <- find ((== arrayOpArr op) . fst) (zip map_param_names arrs) = do         arr_t <- lookupType arr-        let whole_dim = DimSlice (intConst Int32 0) (arraySize 0 arr_t) (intConst Int32 1)+        let whole_dim = DimSlice (intConst Int64 0) (arraySize 0 arr_t) (intConst Int64 1)         arr_transformed <- certifying (arrayOpCerts op) $           letExp (baseString arr ++ "_transformed") $             case op of@@ -929,7 +929,7 @@               ArrayRearrange _ _ perm ->                 BasicOp $ Rearrange (0 : map (+ 1) perm) arr               ArrayRotate _ _ rots ->-                BasicOp $ Rotate (intConst Int32 0 : rots) arr+                BasicOp $ Rotate (intConst Int64 0 : rots) arr               ArrayVar {} ->                 BasicOp $ SubExp $ Var arr         arr_transformed_t <- lookupType arr_transformed
src/Futhark/IR/SegOp.hs view
@@ -395,10 +395,10 @@     checkKernelResult (Returns _ what) t =       TC.require [t] what     checkKernelResult (WriteReturns rws arr res) t = do-      mapM_ (TC.require [Prim int32]) rws+      mapM_ (TC.require [Prim int64]) rws       arr_t <- lookupType arr       forM_ res $ \(slice, e) -> do-        mapM_ (traverse $ TC.require [Prim int32]) slice+        mapM_ (traverse $ TC.require [Prim int64]) slice         TC.require [t] e         unless (arr_t == t `arrayOfShape` Shape rws) $           TC.bad $@@ -415,16 +415,16 @@     checkKernelResult (ConcatReturns o w per_thread_elems v) t = do       case o of         SplitContiguous -> return ()-        SplitStrided stride -> TC.require [Prim int32] stride-      TC.require [Prim int32] w-      TC.require [Prim int32] per_thread_elems+        SplitStrided stride -> TC.require [Prim int64] stride+      TC.require [Prim int64] w+      TC.require [Prim int64] per_thread_elems       vt <- lookupType v       unless (vt == t `arrayOfRow` arraySize 0 vt) $         TC.bad $ TC.TypeError $ "Invalid type for ConcatReturns " ++ pretty v     checkKernelResult (TileReturns dims v) t = do       forM_ dims $ \(dim, tile) -> do-        TC.require [Prim int32] dim-        TC.require [Prim int32] tile+        TC.require [Prim int64] dim+        TC.require [Prim int64] tile       vt <- lookupType v       unless (vt == t `arrayOfShape` Shape (map snd dims)) $         TC.bad $ TC.TypeError $ "Invalid type for TileReturns " ++ pretty v@@ -514,11 +514,11 @@ -- this 'SegSpace'. scopeOfSegSpace :: SegSpace -> Scope lore scopeOfSegSpace (SegSpace phys space) =-  M.fromList $ zip (phys : map fst space) $ repeat $ IndexName Int32+  M.fromList $ zip (phys : map fst space) $ repeat $ IndexName Int64  checkSegSpace :: TC.Checkable lore => SegSpace -> TC.TypeM lore () checkSegSpace (SegSpace _ dims) =-  mapM_ (TC.require [Prim int32] . snd) dims+  mapM_ (TC.require [Prim int64] . snd) dims  -- | A 'SegOp' is semantically a perfectly nested stack of maps, on -- top of some bottommost computation (scalar computation, reduction,@@ -662,10 +662,10 @@    TC.binding (scopeOfSegSpace space) $ do     nes_ts <- forM ops $ \(HistOp dest_w rf dests nes shape op) -> do-      TC.require [Prim int32] dest_w-      TC.require [Prim int32] rf+      TC.require [Prim int64] dest_w+      TC.require [Prim int64] rf       nes' <- mapM TC.checkArg nes-      mapM_ (TC.require [Prim int32]) $ shapeDims shape+      mapM_ (TC.require [Prim int64]) $ shapeDims shape        -- Operator type must match the type of neutral elements.       let stripVecDims = stripArray $ shapeRank shape@@ -691,7 +691,7 @@      -- Return type of bucket function must be an index for each     -- operation followed by the values to write.-    let bucket_ret_t = replicate (length ops) (Prim int32) ++ concat nes_ts+    let bucket_ret_t = replicate (length ops) (Prim int64) ++ concat nes_ts     unless (bucket_ret_t == ts) $       TC.bad $         TC.TypeError $@@ -715,7 +715,7 @@    TC.binding (scopeOfSegSpace space) $ do     ne_ts <- forM ops $ \(lam, nes, shape) -> do-      mapM_ (TC.require [Prim int32]) $ shapeDims shape+      mapM_ (TC.require [Prim int64]) $ shapeDims shape       nes' <- mapM TC.checkArg nes        -- Operator type must match the type of neutral elements.@@ -1018,7 +1018,7 @@                 ST.IndexedArray                   (stmCerts stm <> cs)                   arr-                  (fixSlice (map (fmap isInt32) slice') excess_is)+                  (fixSlice (map (fmap isInt64) slice') excess_is)            in M.insert v idx table         | otherwise =           table@@ -1119,9 +1119,9 @@  segSpaceSymbolTable :: ASTLore lore => SegSpace -> ST.SymbolTable lore segSpaceSymbolTable (SegSpace flat gtids_and_dims) =-  foldl' f (ST.fromScope $ M.singleton flat $ IndexName Int32) gtids_and_dims+  foldl' f (ST.fromScope $ M.singleton flat $ IndexName Int64) gtids_and_dims   where-    f vtable (gtid, dim) = ST.insertLoopVar gtid Int32 dim vtable+    f vtable (gtid, dim) = ST.insertLoopVar gtid Int64 dim vtable  simplifySegBinOp ::   Engine.SimplifiableLore lore =>@@ -1385,9 +1385,9 @@               map                 ( \d ->                     DimSlice-                      (constant (0 :: Int32))+                      (constant (0 :: Int64))                       d-                      (constant (1 :: Int32))+                      (constant (1 :: Int64))                 )                 $ segSpaceDims space             index kpe' =
src/Futhark/IR/Syntax/Core.hs view
@@ -498,15 +498,18 @@     ErrorString String   | -- | A run-time integer value.     ErrorInt32 a+  | -- | A bigger run-time integer value.+    ErrorInt64 a   deriving (Eq, Ord, Show, Generic)  instance SexpIso a => SexpIso (ErrorMsgPart a) where   sexpIso =     match $       With (. Sexp.list (Sexp.el (Sexp.sym "error-string") . Sexp.el (iso T.unpack T.pack . sexpIso))) $-        With-          (. Sexp.list (Sexp.el (Sexp.sym "error-int32") . Sexp.el sexpIso))-          End+        With (. Sexp.list (Sexp.el (Sexp.sym "error-int32") . Sexp.el sexpIso)) $+          With+            (. Sexp.list (Sexp.el (Sexp.sym "error-int64") . Sexp.el sexpIso))+            End  instance IsString (ErrorMsgPart a) where   fromString = ErrorString@@ -523,14 +526,17 @@ instance Functor ErrorMsgPart where   fmap _ (ErrorString s) = ErrorString s   fmap f (ErrorInt32 a) = ErrorInt32 $ f a+  fmap f (ErrorInt64 a) = ErrorInt64 $ f a  instance Foldable ErrorMsgPart where   foldMap _ ErrorString {} = mempty   foldMap f (ErrorInt32 a) = f a+  foldMap f (ErrorInt64 a) = f a  instance Traversable ErrorMsgPart where   traverse _ (ErrorString s) = pure $ ErrorString s   traverse f (ErrorInt32 a) = ErrorInt32 <$> f a+  traverse f (ErrorInt64 a) = ErrorInt64 <$> f a  -- | How many non-constant parts does the error message have, and what -- is their type?@@ -539,3 +545,4 @@   where     onPart ErrorString {} = Nothing     onPart ErrorInt32 {} = Just $ IntType Int32+    onPart ErrorInt64 {} = Just $ IntType Int64
src/Futhark/Internalise.hs view
@@ -106,7 +106,7 @@         return $ Param v $ toDecl v_t Nonunique        let free_shape_params =-            map (`Param` I.Prim int32) $+            map (`Param` I.Prim int64) $               concatMap (I.shapeVars . I.arrayShape . I.paramType) used_free_params           free_params = nub $ free_shape_params ++ used_free_params           all_params = free_params ++ shapeparams ++ concat params'@@ -397,7 +397,7 @@       flat_arr_t <- lookupType flat_arr       let new_shape' =             reshapeOuter-              (map (DimNew . intConst Int32 . toInteger) new_shape)+              (map (DimNew . intConst Int64 . toInteger) new_shape)               1               $ I.arrayShape flat_arr_t       letSubExp desc $ I.BasicOp $ I.Reshape new_shape' flat_arr@@ -453,25 +453,25 @@    -- Construct an error message in case the range is invalid.   let conv = case E.typeOf start of-        E.Scalar (E.Prim (E.Unsigned _)) -> asIntS Int32-        _ -> asIntS Int32-  start'_i32 <- conv start'-  end'_i32 <- conv end'-  maybe_second'_i32 <- traverse conv maybe_second'+        E.Scalar (E.Prim (E.Unsigned _)) -> asIntZ Int64+        _ -> asIntS Int64+  start'_i64 <- conv start'+  end'_i64 <- conv end'+  maybe_second'_i64 <- traverse conv maybe_second'   let errmsg =         errorMsg $           ["Range "]-            ++ [ErrorInt32 start'_i32]-            ++ ( case maybe_second'_i32 of+            ++ [ErrorInt64 start'_i64]+            ++ ( case maybe_second'_i64 of                    Nothing -> []-                   Just second_i32 -> ["..", ErrorInt32 second_i32]+                   Just second_i64 -> ["..", ErrorInt64 second_i64]                )             ++ ( case end of                    DownToExclusive {} -> ["..>"]                    ToInclusive {} -> ["..."]                    UpToExclusive {} -> ["..<"]                )-            ++ [ErrorInt32 end'_i32, " is invalid."]+            ++ [ErrorInt64 end'_i64, " is invalid."]    (it, le_op, lt_op) <-     case E.typeOf start of@@ -497,7 +497,7 @@       return (default_step, constant False)    step_sign <- letSubExp "s_sign" $ BasicOp $ I.UnOp (I.SSignum it) step-  step_sign_i32 <- asIntS Int32 step_sign+  step_sign_i64 <- asIntS Int64 step_sign    bounds_invalid_downwards <-     letSubExp "bounds_invalid_downwards" $@@ -514,15 +514,15 @@       distance <-         letSubExp "distance" $           I.BasicOp $ I.BinOp (Sub it I.OverflowWrap) start' end'-      distance_i32 <- asIntS Int32 distance-      return (distance_i32, step_wrong_dir, bounds_invalid_downwards)+      distance_i64 <- asIntS Int64 distance+      return (distance_i64, step_wrong_dir, bounds_invalid_downwards)     UpToExclusive {} -> do       step_wrong_dir <-         letSubExp "step_wrong_dir" $           I.BasicOp $ I.CmpOp (I.CmpEq $ IntType it) step_sign negone       distance <- letSubExp "distance" $ I.BasicOp $ I.BinOp (Sub it I.OverflowWrap) end' start'-      distance_i32 <- asIntS Int32 distance-      return (distance_i32, step_wrong_dir, bounds_invalid_upwards)+      distance_i64 <- asIntS Int64 distance+      return (distance_i64, step_wrong_dir, bounds_invalid_upwards)     ToInclusive {} -> do       downwards <-         letSubExp "downwards" $@@ -548,14 +548,14 @@             (resultBody [distance_downwards_exclusive])             (resultBody [distance_upwards_exclusive])             $ ifCommon [I.Prim $ IntType it]-      distance_exclusive_i32 <- asIntS Int32 distance_exclusive+      distance_exclusive_i64 <- asIntS Int64 distance_exclusive       distance <-         letSubExp "distance" $           I.BasicOp $             I.BinOp-              (Add Int32 I.OverflowWrap)-              distance_exclusive_i32-              (intConst Int32 1)+              (Add Int64 I.OverflowWrap)+              distance_exclusive_i64+              (intConst Int64 1)       return (distance, constant False, bounds_invalid)    step_invalid <-@@ -568,15 +568,15 @@   valid <- letSubExp "valid" $ I.BasicOp $ I.UnOp I.Not invalid   cs <- assert "range_valid_c" valid errmsg loc -  step_i32 <- asIntS Int32 step+  step_i64 <- asIntS Int64 step   pos_step <-     letSubExp "pos_step" $-      I.BasicOp $ I.BinOp (Mul Int32 I.OverflowWrap) step_i32 step_sign_i32+      I.BasicOp $ I.BinOp (Mul Int64 I.OverflowWrap) step_i64 step_sign_i64    num_elems <-     certifying cs $       letSubExp "num_elems" $-        I.BasicOp $ I.BinOp (SDivUp Int32 I.Unsafe) distance pos_step+        I.BasicOp $ I.BinOp (SDivUp Int64 I.Unsafe) distance pos_step    se <- letSubExp desc (I.BasicOp $ I.Iota num_elems start' step it)   bindExtSizes (E.toStruct ret) retext [se]@@ -592,7 +592,7 @@     dims <- arrayDims <$> subExpType e'     let parts =           ["Value of (core language) shape ("]-            ++ intersperse ", " (map ErrorInt32 dims)+            ++ intersperse ", " (map ErrorInt64 dims)             ++ [") cannot match shape of type `"]             ++ dt'             ++ ["`."]@@ -721,7 +721,7 @@           bindingLambdaParams [x] (map rowType arr_ts) $ \x_params -> do             let loopvars = zip x_params arr'             forLoop mergepat' shapepat mergeinit $-              I.ForLoop i Int32 w loopvars+              I.ForLoop i Int64 w loopvars     handleForm mergeinit (E.For i num_iterations) = do       num_iterations' <- internaliseExp1 "upper_bound" num_iterations       i' <- internaliseIdent i@@ -858,7 +858,7 @@   (ts, constr_map) <- internaliseSumType $ M.map (map E.toStruct) fs   es' <- concat <$> mapM (internaliseExp "payload") es -  let noExt _ = return $ intConst Int32 0+  let noExt _ = return $ intConst Int64 0   ts' <- instantiateShapes noExt $ map fromDecl ts    case M.lookup c constr_map of@@ -1081,7 +1081,7 @@         errorMsg $           ["Index ["] ++ intercalate [", "] parts             ++ ["] out of bounds for array of shape ["]-            ++ intersperse "][" (map ErrorInt32 $ take (length idxs) dims)+            ++ intersperse "][" (map ErrorInt64 $ take (length idxs) dims)             ++ ["]."]   c <- assert "index_certs" ok msg loc   return (idxs', c)@@ -1094,12 +1094,12 @@   (i', _) <- internaliseDimExp "i" i   let lowerBound =         I.BasicOp $-          I.CmpOp (I.CmpSle I.Int32) (I.constant (0 :: I.Int32)) i'+          I.CmpOp (I.CmpSle I.Int64) (I.constant (0 :: I.Int64)) i'       upperBound =         I.BasicOp $-          I.CmpOp (I.CmpSlt I.Int32) i' w+          I.CmpOp (I.CmpSlt I.Int64) i' w   ok <- letSubExp "bounds_check" =<< eBinOp I.LogAnd (pure lowerBound) (pure upperBound)-  return (I.DimFix i', ok, [ErrorInt32 i'])+  return (I.DimFix i', ok, [ErrorInt64 i'])  -- Special-case an important common case that otherwise leads to horrible code. internaliseDimIndex@@ -1111,45 +1111,45 @@     ) = do     w_minus_1 <-       letSubExp "w_minus_1" $-        BasicOp $ I.BinOp (Sub Int32 I.OverflowWrap) w one+        BasicOp $ I.BinOp (Sub Int64 I.OverflowWrap) w one     return-      ( I.DimSlice w_minus_1 w $ intConst Int32 (-1),+      ( I.DimSlice w_minus_1 w $ intConst Int64 (-1),         constant True,         mempty       )     where-      one = constant (1 :: Int32)+      one = constant (1 :: Int64) internaliseDimIndex w (E.DimSlice i j s) = do   s' <- maybe (return one) (fmap fst . internaliseDimExp "s") s-  s_sign <- letSubExp "s_sign" $ BasicOp $ I.UnOp (I.SSignum Int32) s'-  backwards <- letSubExp "backwards" $ I.BasicOp $ I.CmpOp (I.CmpEq int32) s_sign negone-  w_minus_1 <- letSubExp "w_minus_1" $ BasicOp $ I.BinOp (Sub Int32 I.OverflowWrap) w one+  s_sign <- letSubExp "s_sign" $ BasicOp $ I.UnOp (I.SSignum Int64) s'+  backwards <- letSubExp "backwards" $ I.BasicOp $ I.CmpOp (I.CmpEq int64) s_sign negone+  w_minus_1 <- letSubExp "w_minus_1" $ BasicOp $ I.BinOp (Sub Int64 I.OverflowWrap) w one   let i_def =         letSubExp "i_def" $           I.If             backwards             (resultBody [w_minus_1])             (resultBody [zero])-            $ ifCommon [I.Prim int32]+            $ ifCommon [I.Prim int64]       j_def =         letSubExp "j_def" $           I.If             backwards             (resultBody [negone])             (resultBody [w])-            $ ifCommon [I.Prim int32]+            $ ifCommon [I.Prim int64]   i' <- maybe i_def (fmap fst . internaliseDimExp "i") i   j' <- maybe j_def (fmap fst . internaliseDimExp "j") j-  j_m_i <- letSubExp "j_m_i" $ BasicOp $ I.BinOp (Sub Int32 I.OverflowWrap) j' i'+  j_m_i <- letSubExp "j_m_i" $ BasicOp $ I.BinOp (Sub Int64 I.OverflowWrap) j' i'   -- Something like a division-rounding-up, but accomodating negative   -- operands.   let divRounding x y =         eBinOp-          (SQuot Int32 Unsafe)+          (SQuot Int64 Unsafe)           ( eBinOp-              (Add Int32 I.OverflowWrap)+              (Add Int64 I.OverflowWrap)               x-              (eBinOp (Sub Int32 I.OverflowWrap) y (eSignum $ toExp s'))+              (eBinOp (Sub Int64 I.OverflowWrap) y (eSignum $ toExp s'))           )           y   n <- letSubExp "n" =<< divRounding (toExp j_m_i) (toExp s')@@ -1158,29 +1158,29 @@   -- backwards.  If forwards, we must check '0 <= i && i <= j'.  If   -- backwards, '-1 <= j && j <= i'.  In both cases, we check '0 <=   -- i+n*s && i+(n-1)*s < w'.  We only check if the slice is nonempty.-  empty_slice <- letSubExp "empty_slice" $ I.BasicOp $ I.CmpOp (CmpEq int32) n zero+  empty_slice <- letSubExp "empty_slice" $ I.BasicOp $ I.CmpOp (CmpEq int64) n zero -  m <- letSubExp "m" $ I.BasicOp $ I.BinOp (Sub Int32 I.OverflowWrap) n one-  m_t_s <- letSubExp "m_t_s" $ I.BasicOp $ I.BinOp (Mul Int32 I.OverflowWrap) m s'-  i_p_m_t_s <- letSubExp "i_p_m_t_s" $ I.BasicOp $ I.BinOp (Add Int32 I.OverflowWrap) i' m_t_s+  m <- letSubExp "m" $ I.BasicOp $ I.BinOp (Sub Int64 I.OverflowWrap) n one+  m_t_s <- letSubExp "m_t_s" $ I.BasicOp $ I.BinOp (Mul Int64 I.OverflowWrap) m s'+  i_p_m_t_s <- letSubExp "i_p_m_t_s" $ I.BasicOp $ I.BinOp (Add Int64 I.OverflowWrap) i' m_t_s   zero_leq_i_p_m_t_s <-     letSubExp "zero_leq_i_p_m_t_s" $-      I.BasicOp $ I.CmpOp (I.CmpSle Int32) zero i_p_m_t_s+      I.BasicOp $ I.CmpOp (I.CmpSle Int64) zero i_p_m_t_s   i_p_m_t_s_leq_w <-     letSubExp "i_p_m_t_s_leq_w" $-      I.BasicOp $ I.CmpOp (I.CmpSle Int32) i_p_m_t_s w+      I.BasicOp $ I.CmpOp (I.CmpSle Int64) i_p_m_t_s w   i_p_m_t_s_lth_w <-     letSubExp "i_p_m_t_s_leq_w" $-      I.BasicOp $ I.CmpOp (I.CmpSlt Int32) i_p_m_t_s w+      I.BasicOp $ I.CmpOp (I.CmpSlt Int64) i_p_m_t_s w -  zero_lte_i <- letSubExp "zero_lte_i" $ I.BasicOp $ I.CmpOp (I.CmpSle Int32) zero i'-  i_lte_j <- letSubExp "i_lte_j" $ I.BasicOp $ I.CmpOp (I.CmpSle Int32) i' j'+  zero_lte_i <- letSubExp "zero_lte_i" $ I.BasicOp $ I.CmpOp (I.CmpSle Int64) zero i'+  i_lte_j <- letSubExp "i_lte_j" $ I.BasicOp $ I.CmpOp (I.CmpSle Int64) i' j'   forwards_ok <-     letSubExp "forwards_ok"       =<< eAll [zero_lte_i, zero_lte_i, i_lte_j, zero_leq_i_p_m_t_s, i_p_m_t_s_lth_w] -  negone_lte_j <- letSubExp "negone_lte_j" $ I.BasicOp $ I.CmpOp (I.CmpSle Int32) negone j'-  j_lte_i <- letSubExp "j_lte_i" $ I.BasicOp $ I.CmpOp (I.CmpSle Int32) j' i'+  negone_lte_j <- letSubExp "negone_lte_j" $ I.BasicOp $ I.CmpOp (I.CmpSle Int64) negone j'+  j_lte_i <- letSubExp "j_lte_i" $ I.BasicOp $ I.CmpOp (I.CmpSle Int64) j' i'   backwards_ok <-     letSubExp "backwards_ok"       =<< eAll@@ -1199,25 +1199,25 @@    let parts = case (i, j, s) of         (_, _, Just {}) ->-          [ maybe "" (const $ ErrorInt32 i') i,+          [ maybe "" (const $ ErrorInt64 i') i,             ":",-            maybe "" (const $ ErrorInt32 j') j,+            maybe "" (const $ ErrorInt64 j') j,             ":",-            ErrorInt32 s'+            ErrorInt64 s'           ]         (_, Just {}, _) ->-          [ maybe "" (const $ ErrorInt32 i') i,+          [ maybe "" (const $ ErrorInt64 i') i,             ":",-            ErrorInt32 j'+            ErrorInt64 j'           ]-            ++ maybe mempty (const [":", ErrorInt32 s']) s+            ++ maybe mempty (const [":", ErrorInt64 s']) s         (_, Nothing, Nothing) ->-          [ErrorInt32 i', ":"]+          [ErrorInt64 i', ":"]   return (I.DimSlice i' n s', ok_or_empty, parts)   where-    zero = constant (0 :: Int32)-    negone = constant (-1 :: Int32)-    one = constant (1 :: Int32)+    zero = constant (0 :: Int64)+    negone = constant (-1 :: Int64)+    one = constant (1 :: Int64)  internaliseScanOrReduce ::   String ->@@ -1276,10 +1276,10 @@    -- reshape return type of bucket function to have same size as neutral element   -- (modulo the index)-  bucket_param <- newParam "bucket_p" $ I.Prim int32+  bucket_param <- newParam "bucket_p" $ I.Prim int64   img_params <- mapM (newParam "img_p" . rowType) =<< mapM lookupType img'   let params = bucket_param : img_params-      rettype = I.Prim int32 : ne_ts+      rettype = I.Prim int64 : ne_ts       body = mkBody mempty $ map (I.Var . paramName) params   body' <-     localScope (scopeOfLParams params) $@@ -1297,7 +1297,7 @@   -- img' are the same size.   b_shape <- I.arrayShape <$> lookupType buckets'   let b_w = shapeSize 0 b_shape-  cmp <- letSubExp "bucket_cmp" $ I.BasicOp $ I.CmpOp (I.CmpEq I.int32) b_w w_img+  cmp <- letSubExp "bucket_cmp" $ I.BasicOp $ I.CmpOp (I.CmpEq I.int64) b_w w_img   c <-     assert       "bucket_cert"@@ -1345,7 +1345,7 @@   -- Synthesize neutral elements by applying the fold function   -- to an empty chunk.   letBindNames [I.paramName chunk_param] $-    I.BasicOp $ I.SubExp $ constant (0 :: Int32)+    I.BasicOp $ I.SubExp $ constant (0 :: Int64)   forM_ lam_val_params $ \p ->     letBindNames [I.paramName p] $       I.BasicOp $@@ -1410,7 +1410,7 @@ internaliseDimExp s e = do   e' <- internaliseExp1 s e   case E.typeOf e of-    E.Scalar (E.Prim (Signed it)) -> (,it) <$> asIntS Int32 e'+    E.Scalar (E.Prim (Signed it)) -> (,it) <$> asIntS Int64 e'     _ -> error "internaliseDimExp: bad type"  internaliseExpToVars :: String -> E.Exp -> InternaliseM [I.VName]@@ -1709,13 +1709,13 @@               let x_dims = I.arrayDims x_t                   y_dims = I.arrayDims y_t               dims_match <- forM (zip x_dims y_dims) $ \(x_dim, y_dim) ->-                letSubExp "dim_eq" $ I.BasicOp $ I.CmpOp (I.CmpEq int32) x_dim y_dim+                letSubExp "dim_eq" $ I.BasicOp $ I.CmpOp (I.CmpEq int64) x_dim y_dim               shapes_match <- letSubExp "shapes_match" =<< eAll dims_match               compare_elems_body <- runBodyBinder $ do                 -- Flatten both x and y.                 x_num_elems <-                   letSubExp "x_num_elems"-                    =<< foldBinOp (I.Mul Int32 I.OverflowUndef) (constant (1 :: Int32)) x_dims+                    =<< foldBinOp (I.Mul Int64 I.OverflowUndef) (constant (1 :: Int64)) x_dims                 x' <- letExp "x" $ I.BasicOp $ I.SubExp x                 y' <- letExp "x" $ I.BasicOp $ I.SubExp y                 x_flat <- letExp "x_flat" $ I.BasicOp $ I.Reshape [I.DimNew x_num_elems] x'@@ -1760,7 +1760,7 @@       Just $ \_desc -> do         arrs <- internaliseExpToVars "partition_input" arr         lam' <- internalisePartitionLambda internaliseLambda k' lam $ map I.Var arrs-        uncurry (++) <$> partitionWithSOACS k' lam' arrs+        uncurry (++) <$> partitionWithSOACS (fromIntegral k') lam' arrs       where         fromInt32 (Literal (SignedValue (Int32Value k')) _) = Just k'         fromInt32 (IntLit k' (Info (E.Scalar (E.Prim (Signed Int32)))) _) = Just $ fromInteger k'@@ -1808,8 +1808,8 @@       dim_ok <-         letSubExp "dim_ok"           =<< eCmpOp-            (I.CmpEq I.int32)-            (eBinOp (I.Mul Int32 I.OverflowUndef) (eSubExp n') (eSubExp m'))+            (I.CmpEq I.int64)+            (eBinOp (I.Mul Int64 I.OverflowUndef) (eSubExp n') (eSubExp m'))             (eSubExp old_dim)       dim_ok_cert <-         assert@@ -1829,7 +1829,7 @@         arr_t <- lookupType arr'         let n = arraySize 0 arr_t             m = arraySize 1 arr_t-        k <- letSubExp "flat_dim" $ I.BasicOp $ I.BinOp (Mul Int32 I.OverflowUndef) n m+        k <- letSubExp "flat_dim" $ I.BasicOp $ I.BinOp (Mul Int64 I.OverflowUndef) n m         letSubExp desc $           I.BasicOp $             I.Reshape (reshapeOuter [DimNew k] 2 $ I.arrayShape arr_t) arr'@@ -1840,7 +1840,7 @@       let sumdims xsize ysize =             letSubExp "conc_tmp" $               I.BasicOp $-                I.BinOp (I.Add I.Int32 I.OverflowUndef) xsize ysize+                I.BinOp (I.Add I.Int64 I.OverflowUndef) xsize ysize       ressize <-         foldM sumdims outer_size           =<< mapM (fmap (arraysSize 0) . mapM lookupType) [ys]@@ -1852,7 +1852,7 @@       offset' <- internaliseExp1 "rotation_offset" offset       internaliseOperation desc e $ \v -> do         r <- I.arrayRank <$> lookupType v-        let zero = intConst Int32 0+        let zero = intConst Int64 0             offsets = offset' : replicate (r -1) zero         return $ I.Rotate offsets v     handleRest [e] "transpose" = Just $ \desc ->@@ -1932,7 +1932,7 @@         cmp <-           letSubExp "write_cmp" $             I.BasicOp $-              I.CmpOp (I.CmpEq I.int32) si_w sv_w+              I.CmpOp (I.CmpEq I.int64) si_w sv_w         c <-           assert             "write_cert"@@ -2061,9 +2061,9 @@     _ -> error "partitionWithSOACS"    add_lam_x_params <--    replicateM k $ I.Param <$> newVName "x" <*> pure (I.Prim int32)+    replicateM k $ I.Param <$> newVName "x" <*> pure (I.Prim int64)   add_lam_y_params <--    replicateM k $ I.Param <$> newVName "y" <*> pure (I.Prim int32)+    replicateM k $ I.Param <$> newVName "y" <*> pure (I.Prim int64)   add_lam_body <- runBodyBinder $     localScope (scopeOfLParams $ add_lam_x_params ++ add_lam_y_params) $       fmap resultBody $@@ -2071,16 +2071,16 @@           letSubExp "z" $             I.BasicOp $               I.BinOp-                (I.Add Int32 I.OverflowUndef)+                (I.Add Int64 I.OverflowUndef)                 (I.Var $ I.paramName x)                 (I.Var $ I.paramName y)   let add_lam =         I.Lambda           { I.lambdaBody = add_lam_body,             I.lambdaParams = add_lam_x_params ++ add_lam_y_params,-            I.lambdaReturnType = replicate k $ I.Prim int32+            I.lambdaReturnType = replicate k $ I.Prim int64           }-      nes = replicate (length increments) $ constant (0 :: Int32)+      nes = replicate (length increments) $ intConst Int64 0    scan <- I.scanSOAC [I.Scan add_lam nes]   all_offsets <- letTupExp "offsets" $ I.Op $ I.Screma w scan increments@@ -2088,17 +2088,17 @@   -- We have the offsets for each of the partitions, but we also need   -- the total sizes, which are the last elements in the offests.  We   -- just have to be careful in case the array is empty.-  last_index <- letSubExp "last_index" $ I.BasicOp $ I.BinOp (I.Sub Int32 OverflowUndef) w $ constant (1 :: Int32)+  last_index <- letSubExp "last_index" $ I.BasicOp $ I.BinOp (I.Sub Int64 OverflowUndef) w $ constant (1 :: Int64)   nonempty_body <- runBodyBinder $     fmap resultBody $       forM all_offsets $ \offset_array ->         letSubExp "last_offset" $ I.BasicOp $ I.Index offset_array [I.DimFix last_index]-  let empty_body = resultBody $ replicate k $ constant (0 :: Int32)-  is_empty <- letSubExp "is_empty" $ I.BasicOp $ I.CmpOp (CmpEq int32) w $ constant (0 :: Int32)+  let empty_body = resultBody $ replicate k $ constant (0 :: Int64)+  is_empty <- letSubExp "is_empty" $ I.BasicOp $ I.CmpOp (CmpEq int64) w $ constant (0 :: Int64)   sizes <-     letTupExp "partition_size" $       I.If is_empty empty_body nonempty_body $-        ifCommon $ replicate k $ I.Prim int32+        ifCommon $ replicate k $ I.Prim int64    -- The total size of all partitions must necessarily be equal to the   -- size of the input array.@@ -2111,8 +2111,8 @@    -- Now write into the result.   write_lam <- do-    c_param <- I.Param <$> newVName "c" <*> pure (I.Prim int32)-    offset_params <- replicateM k $ I.Param <$> newVName "offset" <*> pure (I.Prim int32)+    c_param <- I.Param <$> newVName "c" <*> pure (I.Prim int64)+    offset_params <- replicateM k $ I.Param <$> newVName "offset" <*> pure (I.Prim int64)     value_params <- forM arr_ts $ \arr_t ->       I.Param <$> newVName "v" <*> pure (I.rowType arr_t)     (offset, offset_stms) <-@@ -2126,7 +2126,7 @@       I.Lambda         { I.lambdaParams = c_param : offset_params ++ value_params,           I.lambdaReturnType =-            replicate (length arr_ts) (I.Prim int32)+            replicate (length arr_ts) (I.Prim int64)               ++ map I.rowType arr_ts,           I.lambdaBody =             mkBody offset_stms $@@ -2144,7 +2144,7 @@   sizes' <-     letSubExp "partition_sizes" $       I.BasicOp $-        I.ArrayLit (map I.Var sizes) $ I.Prim int32+        I.ArrayLit (map I.Var sizes) $ I.Prim int64   return (map I.Var results, [sizes'])   where     mkOffsetLambdaBody ::@@ -2154,26 +2154,26 @@       [I.LParam] ->       InternaliseM SubExp     mkOffsetLambdaBody _ _ _ [] =-      return $ constant (-1 :: Int32)+      return $ constant (-1 :: Int64)     mkOffsetLambdaBody sizes c i (p : ps) = do       is_this_one <-         letSubExp "is_this_one" $           I.BasicOp $-            I.CmpOp (CmpEq int32) c $-              intConst Int32 $ toInteger i+            I.CmpOp (CmpEq int64) c $+              intConst Int64 $ toInteger i       next_one <- mkOffsetLambdaBody sizes c (i + 1) ps       this_one <-         letSubExp "this_offset"           =<< foldBinOp-            (Add Int32 OverflowUndef)-            (constant (-1 :: Int32))+            (Add Int64 OverflowUndef)+            (constant (-1 :: Int64))             (I.Var (I.paramName p) : take i sizes)       letSubExp "total_res" $         I.If           is_this_one           (resultBody [this_one])           (resultBody [next_one])-          $ ifCommon [I.Prim int32]+          $ ifCommon [I.Prim int64]  typeExpForError :: E.TypeExp VName -> InternaliseM [ErrorMsgPart SubExp] typeExpForError (E.TEVar qn _) =@@ -2217,7 +2217,7 @@   d' <- case substs of     Just [v] -> return v     _ -> return $ I.Var $ E.qualLeaf d-  return $ ErrorInt32 d'+  return $ ErrorInt64 d' dimExpForError (DimExpConst d _) =   return $ ErrorString $ pretty d dimExpForError DimExpAny = return ""
src/Futhark/Internalise/AccurateSizes.hs view
@@ -47,7 +47,7 @@   let addShape name =         case M.lookup name mapping of           Just se -> se-          _ -> intConst Int32 0 -- FIXME: we only need this because+          _ -> intConst Int64 0 -- FIXME: we only need this because           -- the defunctionaliser throws away           -- sizes.   return $ map addShape shapes@@ -156,4 +156,4 @@   | otherwise = return v   where     checkDim desired has =-      letSubExp "dim_match" $ BasicOp $ CmpOp (CmpEq int32) desired has+      letSubExp "dim_match" $ BasicOp $ CmpOp (CmpEq int64) desired has
src/Futhark/Internalise/Bindings.hs view
@@ -32,7 +32,7 @@   let num_param_idents = map length flattened_params       num_param_ts = map (sum . map length) $ chunks num_param_idents params_ts -  let shape_params = [I.Param v $ I.Prim I.int32 | E.TypeParamDim v _ <- tparams]+  let shape_params = [I.Param v $ I.Prim I.int64 | E.TypeParamDim v _ <- tparams]       shape_subst = M.fromList [(I.paramName p, [I.Var $ I.paramName p]) | p <- shape_params]   bindingFlatPattern params_idents (concat params_ts) $ \valueparams ->     I.localScope (I.scopeOfFParams $ shape_params ++ concat valueparams) $@@ -49,7 +49,7 @@   pat_idents <- flattenPattern pat   pat_ts <- internaliseLoopParamType (E.patternStructType pat) -  let shape_params = [I.Param v $ I.Prim I.int32 | E.TypeParamDim v _ <- tparams]+  let shape_params = [I.Param v $ I.Prim I.int64 | E.TypeParamDim v _ <- tparams]       shape_subst = M.fromList [(I.paramName p, [I.Var $ I.paramName p]) | p <- shape_params]    bindingFlatPattern pat_idents pat_ts $ \valueparams ->
src/Futhark/Internalise/Defunctionalise.hs view
@@ -126,7 +126,7 @@       | baseTag x <= maxIntrinsicTag -> return IntrinsicSV       | otherwise -> -- Anything not in scope is going to be an       -- existential size.-        return $ Dynamic $ Scalar $ Prim $ Signed Int32+        return $ Dynamic $ Scalar $ Prim $ Signed Int64       | otherwise ->         error $           "Variable " ++ pretty x ++ " at "@@ -842,7 +842,7 @@           ++ "."  envFromDimNames :: [VName] -> Env-envFromDimNames = M.fromList . flip zip (repeat $ Dynamic $ Scalar $ Prim $ Signed Int32)+envFromDimNames = M.fromList . flip zip (repeat $ Dynamic $ Scalar $ Prim $ Signed Int64)  -- | Create a new top-level value declaration with the given function name, -- return type, list of parameters, and body expression.
src/Futhark/Internalise/Lambdas.hs view
@@ -44,12 +44,12 @@   InternaliseM I.Lambda internaliseStreamMapLambda internaliseLambda lam args = do   chunk_size <- newVName "chunk_size"-  let chunk_param = I.Param chunk_size (I.Prim int32)+  let chunk_param = I.Param chunk_size (I.Prim int64)       outer = (`setOuterSize` I.Var chunk_size)   localScope (scopeOfLParams [chunk_param]) $ do     argtypes <- mapM I.subExpType args     (lam_params, orig_body, rettype) <--      internaliseLambda lam $ I.Prim int32 : map outer argtypes+      internaliseLambda lam $ I.Prim int64 : map outer argtypes     let orig_chunk_param : params = lam_params     body <- runBodyBinder $ do       letBindNames [paramName orig_chunk_param] $ I.BasicOp $ I.SubExp $ I.Var chunk_size@@ -96,11 +96,11 @@   InternaliseM ([LParam], Body) internaliseStreamLambda internaliseLambda lam rowts = do   chunk_size <- newVName "chunk_size"-  let chunk_param = I.Param chunk_size $ I.Prim int32+  let chunk_param = I.Param chunk_size $ I.Prim int64       chunktypes = map (`arrayOfRow` I.Var chunk_size) rowts   localScope (scopeOfLParams [chunk_param]) $ do     (lam_params, orig_body, _) <--      internaliseLambda lam $ I.Prim int32 : chunktypes+      internaliseLambda lam $ I.Prim int64 : chunktypes     let orig_chunk_param : params = lam_params     body <- runBodyBinder $ do       letBindNames [paramName orig_chunk_param] $ I.BasicOp $ I.SubExp $ I.Var chunk_size@@ -126,19 +126,19 @@       lambdaWithIncrement body   return $ I.Lambda params body' rettype   where-    rettype = replicate (k + 2) $ I.Prim int32+    rettype = replicate (k + 2) $ I.Prim int64     result i =       map constant $-        (fromIntegral i :: Int32) :-        (replicate i 0 ++ [1 :: Int32] ++ replicate (k - i) 0)+        fromIntegral i :+        (replicate i 0 ++ [1 :: Int64] ++ replicate (k - i) 0)      mkResult _ i | i >= k = return $ result i     mkResult eq_class i = do       is_i <-         letSubExp "is_i" $           BasicOp $-            CmpOp (CmpEq int32) eq_class $-              intConst Int32 $ toInteger i+            CmpOp (CmpEq int64) eq_class $+              intConst Int64 $ toInteger i       fmap (map I.Var) . letTupExp "part_res"         =<< eIf           (eSubExp is_i)
src/Futhark/Internalise/Monomorphise.hs view
@@ -46,8 +46,8 @@ import Language.Futhark.Traversals import Language.Futhark.TypeChecker.Types -i32 :: TypeBase dim als-i32 = Scalar $ Prim $ Signed Int32+i64 :: TypeBase dim als+i64 = Scalar $ Prim $ Signed Int64  -- The monomorphization monad reads 'PolyBinding's and writes -- 'ValBind's.  The 'TypeParam's in the 'ValBind's can only be size@@ -223,7 +223,7 @@           f           size_arg           (Info (Observe, Nothing))-          (Info (foldFunType (replicate i i32) (fromStruct t)), Info [])+          (Info (foldFunType (replicate i i64) (fromStruct t)), Info [])           loc       ) @@ -236,7 +236,7 @@               (qualName fname')               ( Info                   ( foldFunType-                      (map (const i32) size_args)+                      (map (const i64) size_args)                       (fromStruct t')                   )               )@@ -593,7 +593,7 @@ noticeDims :: TypeBase (DimDecl VName) as -> MonoM () noticeDims = mapM_ notice . nestedDims   where-    notice (NamedDim v) = void $ transformFName mempty v i32+    notice (NamedDim v) = void $ transformFName mempty v i64     notice _ = return ()  -- Convert a collection of 'ValBind's to a nested sequence of let-bound,@@ -670,9 +670,9 @@     tparamArg dinst tp =       case M.lookup (typeParamName tp) dinst of         Just (NamedDim d) ->-          Just $ Var d (Info i32) mempty+          Just $ Var d (Info i64) mempty         Just (ConstDim x) ->-          Just $ Literal (SignedValue $ Int32Value $ fromIntegral x) mempty+          Just $ Literal (SignedValue $ Int64Value $ fromIntegral x) mempty         _ ->           Nothing @@ -768,7 +768,7 @@           mapOnPatternType = pure . applySubst substs         } -    shapeParam tp = Id (typeParamName tp) (Info i32) $ srclocOf tp+    shapeParam tp = Id (typeParamName tp) (Info i64) $ srclocOf tp      toValBinding name' tparams' params'' rettype' body'' =       ValBind
src/Futhark/Internalise/TypesValues.hs view
@@ -102,7 +102,7 @@ internaliseDim d =   case d of     E.AnyDim -> Ext <$> newId-    E.ConstDim n -> return $ Free $ intConst I.Int32 $ toInteger n+    E.ConstDim n -> return $ Free $ intConst I.Int64 $ toInteger n     E.NamedDim name -> namedDim name   where     namedDim (E.QualName _ name) = do
src/Futhark/Optimise/CSE.hs view
@@ -47,6 +47,7 @@     removeStmAliases,   ) import qualified Futhark.IR.Kernels.Kernel as Kernel+import qualified Futhark.IR.MC as MC import qualified Futhark.IR.Mem as Memory import Futhark.IR.Prop.Aliases import qualified Futhark.IR.SOACS.SOAC as SOAC@@ -281,6 +282,19 @@   cseInOp (Kernel.SegOp op) = Kernel.SegOp <$> cseInOp op   cseInOp (Kernel.OtherOp op) = Kernel.OtherOp <$> cseInOp op   cseInOp x = return x++instance+  ( ASTLore lore,+    Aliased lore,+    CSEInOp (Op lore),+    CSEInOp op+  ) =>+  CSEInOp (MC.MCOp lore op)+  where+  cseInOp (MC.ParOp par_op op) =+    MC.ParOp <$> traverse cseInOp par_op <*> cseInOp op+  cseInOp (MC.OtherOp op) =+    MC.OtherOp <$> cseInOp op  instance   (ASTLore lore, Aliased lore, CSEInOp (Op lore)) =>
src/Futhark/Optimise/DoubleBuffer.hs view
@@ -22,7 +22,7 @@ -- value.  This has the effect of making the memory block returned by -- the array non-existential, which is important for later memory -- expansion to work.-module Futhark.Optimise.DoubleBuffer (doubleBuffer) where+module Futhark.Optimise.DoubleBuffer (doubleBufferKernels, doubleBufferMC) where  import Control.Monad.Reader import Control.Monad.State@@ -31,17 +31,25 @@ import qualified Data.Map.Strict as M import Data.Maybe import Futhark.Construct-import Futhark.IR-import Futhark.IR.KernelsMem+import Futhark.IR.KernelsMem as Kernels+import Futhark.IR.MCMem as MC import qualified Futhark.IR.Mem.IxFun as IxFun import Futhark.Pass import Futhark.Pass.ExplicitAllocations (arraySizeInBytesExp) import Futhark.Pass.ExplicitAllocations.Kernels () import Futhark.Util (maybeHead) +-- | The pass for GPU kernels.+doubleBufferKernels :: Pass KernelsMem KernelsMem+doubleBufferKernels = doubleBuffer optimiseKernelsOp++-- | The pass for multicore+doubleBufferMC :: Pass MCMem MCMem+doubleBufferMC = doubleBuffer optimiseMCOp+ -- | The double buffering pass definition.-doubleBuffer :: Pass KernelsMem KernelsMem-doubleBuffer =+doubleBuffer :: Mem lore => OptimiseOp lore -> Pass lore lore+doubleBuffer onOp =   Pass     { passName = "Double buffer",       passDescription = "Perform double buffering for merge parameters of sequential loops.",@@ -55,36 +63,54 @@                 fmap stmsFromList $ optimiseStms $ stmsToList stms        in runState (runReaderT m env) src -    env = Env mempty doNotTouchLoop+    env = Env mempty doNotTouchLoop onOp     doNotTouchLoop ctx val body = return (mempty, ctx, val, body) -data Env = Env-  { envScope :: Scope KernelsMem,-    envOptimiseLoop :: OptimiseLoop+type OptimiseLoop lore =+  [(FParam lore, SubExp)] ->+  [(FParam lore, SubExp)] ->+  Body lore ->+  DoubleBufferM+    lore+    ( [Stm lore],+      [(FParam lore, SubExp)],+      [(FParam lore, SubExp)],+      Body lore+    )++type OptimiseOp lore =+  Op lore -> DoubleBufferM lore (Op lore)++data Env lore = Env+  { envScope :: Scope lore,+    envOptimiseLoop :: OptimiseLoop lore,+    envOptimiseOp :: OptimiseOp lore   } -newtype DoubleBufferM a = DoubleBufferM {runDoubleBufferM :: ReaderT Env (State VNameSource) a}-  deriving (Functor, Applicative, Monad, MonadReader Env, MonadFreshNames)+newtype DoubleBufferM lore a = DoubleBufferM+  { runDoubleBufferM :: ReaderT (Env lore) (State VNameSource) a+  }+  deriving (Functor, Applicative, Monad, MonadReader (Env lore), MonadFreshNames) -instance HasScope KernelsMem DoubleBufferM where+instance ASTLore lore => HasScope lore (DoubleBufferM lore) where   askScope = asks envScope -instance LocalScope KernelsMem DoubleBufferM where+instance ASTLore lore => LocalScope lore (DoubleBufferM lore) where   localScope scope = local $ \env -> env {envScope = envScope env <> scope} -optimiseBody :: Body KernelsMem -> DoubleBufferM (Body KernelsMem)+optimiseBody :: ASTLore lore => Body lore -> DoubleBufferM lore (Body lore) optimiseBody body = do   bnds' <- optimiseStms $ stmsToList $ bodyStms body   return $ body {bodyStms = stmsFromList bnds'} -optimiseStms :: [Stm KernelsMem] -> DoubleBufferM [Stm KernelsMem]+optimiseStms :: ASTLore lore => [Stm lore] -> DoubleBufferM lore [Stm lore] optimiseStms [] = return [] optimiseStms (e : es) = do   e_es <- optimiseStm e   es' <- localScope (castScope $ scopeOf e_es) $ optimiseStms es   return $ e_es ++ es' -optimiseStm :: Stm KernelsMem -> DoubleBufferM [Stm KernelsMem]+optimiseStm :: forall lore. ASTLore lore => Stm lore -> DoubleBufferM lore [Stm lore] optimiseStm (Let pat aux (DoLoop ctx val form body)) = do   body' <-     localScope (scopeOf form <> scopeOfFParams (map fst $ ctx ++ val)) $@@ -92,20 +118,19 @@   opt_loop <- asks envOptimiseLoop   (bnds, ctx', val', body'') <- opt_loop ctx val body'   return $ bnds ++ [Let pat aux $ DoLoop ctx' val' form body'']-optimiseStm (Let pat aux e) =-  pure . Let pat aux <$> mapExpM optimise e+optimiseStm (Let pat aux e) = do+  onOp <- asks envOptimiseOp+  pure . Let pat aux <$> mapExpM (optimise onOp) e   where-    optimise =+    optimise onOp =       identityMapper         { mapOnBody = \_ x ->-            optimiseBody x :: DoubleBufferM (Body KernelsMem),-          mapOnOp = optimiseOp+            optimiseBody x :: DoubleBufferM lore (Body lore),+          mapOnOp = onOp         } -optimiseOp ::-  Op KernelsMem ->-  DoubleBufferM (Op KernelsMem)-optimiseOp (Inner (SegOp op)) =+optimiseKernelsOp :: OptimiseOp KernelsMem+optimiseKernelsOp (Inner (SegOp op)) =   local inSegOp $ Inner . SegOp <$> mapSegOpM mapper op   where     mapper =@@ -114,32 +139,51 @@           mapOnSegOpBody = optimiseKernelBody         }     inSegOp env = env {envOptimiseLoop = optimiseLoop}-optimiseOp op = return op+optimiseKernelsOp op = return op +optimiseMCOp :: OptimiseOp MCMem+optimiseMCOp (Inner (ParOp par_op op)) =+  local inSegOp $+    Inner+      <$> (ParOp <$> traverse (mapSegOpM mapper) par_op <*> mapSegOpM mapper op)+  where+    mapper =+      identitySegOpMapper+        { mapOnSegOpLambda = optimiseLambda,+          mapOnSegOpBody = optimiseKernelBody+        }+    inSegOp env = env {envOptimiseLoop = optimiseLoop}+optimiseMCOp op = return op+ optimiseKernelBody ::-  KernelBody KernelsMem ->-  DoubleBufferM (KernelBody KernelsMem)+  ASTLore lore =>+  KernelBody lore ->+  DoubleBufferM lore (KernelBody lore) optimiseKernelBody kbody = do   stms' <- optimiseStms $ stmsToList $ kernelBodyStms kbody   return $ kbody {kernelBodyStms = stmsFromList stms'} -optimiseLambda :: Lambda KernelsMem -> DoubleBufferM (Lambda KernelsMem)+optimiseLambda ::+  ASTLore lore =>+  Lambda lore ->+  DoubleBufferM lore (Lambda lore) optimiseLambda lam = do   body <- localScope (castScope $ scopeOf lam) $ optimiseBody $ lambdaBody lam   return lam {lambdaBody = body} -type OptimiseLoop =-  [(FParam KernelsMem, SubExp)] ->-  [(FParam KernelsMem, SubExp)] ->-  Body KernelsMem ->-  DoubleBufferM-    ( [Stm KernelsMem],-      [(FParam KernelsMem, SubExp)],-      [(FParam KernelsMem, SubExp)],-      Body KernelsMem-    )+type Constraints lore =+  ( ASTLore lore,+    FParamInfo lore ~ FParamMem,+    LParamInfo lore ~ LParamMem,+    RetType lore ~ RetTypeMem,+    LetDec lore ~ LetDecMem,+    BranchType lore ~ BranchTypeMem,+    ExpDec lore ~ (),+    BodyDec lore ~ (),+    OpReturns lore+  ) -optimiseLoop :: OptimiseLoop+optimiseLoop :: (Constraints lore, Op lore ~ MemOp inner, BinderOps lore) => OptimiseLoop lore optimiseLoop ctx val body = do   -- We start out by figuring out which of the merge variables should   -- be double-buffered.@@ -171,8 +215,8 @@  doubleBufferMergeParams ::   MonadFreshNames m =>-  [(FParam KernelsMem, SubExp)] ->-  [FParam KernelsMem] ->+  [(Param FParamMem, SubExp)] ->+  [Param FParamMem] ->   Names ->   m [DoubleBuffer] doubleBufferMergeParams ctx_and_res val_params bound_in_loop =@@ -229,9 +273,10 @@       _ -> return NoBuffer  allocStms ::-  [(FParam KernelsMem, SubExp)] ->+  (Constraints lore, Op lore ~ MemOp inner, BinderOps lore) =>+  [(FParam lore, SubExp)] ->   [DoubleBuffer] ->-  DoubleBufferM ([(FParam KernelsMem, SubExp)], [Stm KernelsMem])+  DoubleBufferM lore ([(FParam lore, SubExp)], [Stm lore]) allocStms merge = runWriterT . zipWithM allocation merge   where     allocation m@(Param pname _, _) (BufferAlloc name size space b) = do@@ -265,11 +310,12 @@       return (f, se)  doubleBufferResult ::-  [FParam KernelsMem] ->+  (Constraints lore) =>+  [FParam lore] ->   [DoubleBuffer] ->-  Body KernelsMem ->-  Body KernelsMem-doubleBufferResult valparams buffered (Body () bnds res) =+  Body lore ->+  Body lore+doubleBufferResult valparams buffered (Body _ bnds res) =   let (ctx_res, val_res) = splitAt (length res - length valparams) res       (copybnds, val_res') =         unzip $ zipWith3 buffer valparams buffered val_res
src/Futhark/Optimise/Fusion.hs view
@@ -690,7 +690,7 @@           (loop_params, loop_arrs) = unzip loop_vars       chunk_size <- newVName "chunk_size"       offset <- newVName "offset"-      let chunk_param = Param chunk_size $ Prim int32+      let chunk_param = Param chunk_size $ Prim int64           offset_param = Param offset $ Prim $ IntType it        acc_params <- forM merge_params $ \p ->@@ -719,7 +719,7 @@             [ pure $                 DoLoop [] merge' (ForLoop j it (Futhark.Var chunk_size) []) loop_body,               pure $-                BasicOp $ BinOp (Add Int32 OverflowUndef) (Futhark.Var offset) (Futhark.Var chunk_size)+                BasicOp $ BinOp (Add Int64 OverflowUndef) (Futhark.Var offset) (Futhark.Var chunk_size)             ]       let lam =             Lambda@@ -733,7 +733,7 @@       -- first element in the pattern, as we use the first element to       -- identify the SOAC in the second phase of fusion.       discard <- newVName "discard"-      let discard_pe = PatElem discard $ Prim int32+      let discard_pe = PatElem discard $ Prim int64        fusionGatherStms         fres@@ -805,8 +805,8 @@   fres' <- addNamesToInfusible fres $ freeIn form <> freeIn ctx <> freeIn val   let form_idents =         case form of-          ForLoop i _ _ loopvars ->-            Ident i (Prim int32) : map (paramIdent . fst) loopvars+          ForLoop i it _ loopvars ->+            Ident i (Prim (IntType it)) : map (paramIdent . fst) loopvars           WhileLoop {} -> []    new_res <-
src/Futhark/Optimise/Fusion/LoopKernel.hs view
@@ -442,7 +442,7 @@                   { lambdaParams = lambdaParams lam_c ++ lambdaParams lam_p,                     lambdaBody = body',                     lambdaReturnType =-                      replicate (c_num_buckets + p_num_buckets) (Prim int32)+                      replicate (c_num_buckets + p_num_buckets) (Prim int64)                         ++ drop c_num_buckets (lambdaReturnType lam_c)                         ++ drop p_num_buckets (lambdaReturnType lam_p)                   }@@ -844,7 +844,7 @@     SOAC.Reshape cs shape SOAC.:< ots' <- SOAC.viewf ots,     all primType $ lambdaReturnType maplam = do     let mapw' = case reverse $ newDims shape of-          [] -> intConst Int32 0+          [] -> intConst Int64 0           d : _ -> d         inputs' = map (SOAC.addTransform $ SOAC.ReshapeOuter cs shape) inps         inputTypes = map SOAC.inputType inputs'
src/Futhark/Optimise/InPlaceLowering.hs view
@@ -64,6 +64,7 @@ module Futhark.Optimise.InPlaceLowering   ( inPlaceLoweringKernels,     inPlaceLoweringSeq,+    inPlaceLoweringMC,   ) where @@ -73,6 +74,7 @@ import Futhark.Binder import Futhark.IR.Aliases import Futhark.IR.Kernels+import Futhark.IR.MC import Futhark.IR.Seq (Seq) import Futhark.Optimise.InPlaceLowering.LowerIntoStm import Futhark.Pass@@ -86,6 +88,10 @@ inPlaceLoweringSeq = inPlaceLowering pure lowerUpdate  -- | Apply the in-place lowering optimisation to the given program.+inPlaceLoweringMC :: Pass MC MC+inPlaceLoweringMC = inPlaceLowering onMCOp lowerUpdate++-- | Apply the in-place lowering optimisation to the given program. inPlaceLowering ::   Constraints lore =>   OnOp lore ->@@ -192,8 +198,11 @@         { mapOnBody = const optimiseBody         } -onKernelOp :: OnOp Kernels-onKernelOp (SegOp op) =+onSegOp ::+  (Bindable lore, CanBeAliased (Op lore)) =>+  SegOp lvl (Aliases lore) ->+  ForwardingM lore (SegOp lvl (Aliases lore))+onSegOp op =   bindingScope (scopeOfSegSpace (segSpace op)) $ do     let mapper = identitySegOpMapper {mapOnSegOpBody = onKernelBody}         onKernelBody kbody = do@@ -202,7 +211,14 @@               optimiseStms (stmsToList (kernelBodyStms kbody)) $                 mapM_ seenVar $ namesToList $ freeIn $ kernelBodyResult kbody           return kbody {kernelBodyStms = stmsFromList stms}-    SegOp <$> mapSegOpM mapper op+    mapSegOpM mapper op++onMCOp :: OnOp MC+onMCOp (ParOp par_op op) = ParOp <$> traverse onSegOp par_op <*> onSegOp op+onMCOp op = return op++onKernelOp :: OnOp Kernels+onKernelOp (SegOp op) = SegOp <$> onSegOp op onKernelOp op = return op  data Entry lore = Entry
src/Futhark/Optimise/Simplify/ClosedForm.hs view
@@ -62,14 +62,14 @@       (patternNames pat)       inputsize       mempty-      Int32+      Int64       knownBnds       (map paramName (lambdaParams lam))       (lambdaBody lam)       accs   isEmpty <- newVName "fold_input_is_empty"   letBindNames [isEmpty] $-    BasicOp $ CmpOp (CmpEq int32) inputsize (intConst Int32 0)+    BasicOp $ CmpOp (CmpEq int64) inputsize (intConst Int64 0)   letBind pat     =<< ( If (Var isEmpty)             <$> resultBodyM accs@@ -183,7 +183,7 @@       | v `nameIn` nonFree = M.lookup v knownBnds     asFreeSubExp se = Just se -    properIntSize Int32 = Just $ return size+    properIntSize Int64 = Just $ return size     properIntSize t =       Just $         letSubExp "converted_size" $
src/Futhark/Optimise/Simplify/Rules.hs view
@@ -340,7 +340,7 @@                 letExp "for_in_partial" $                   BasicOp $                     Index arr' $-                      DimSlice (intConst Int32 0) w (intConst Int32 1) : slice'+                      DimSlice (intConst Int64 0) w (intConst Int64 1) : slice'             return (Just (p, for_in_partial), mempty)         SubExpResult cs se           | all (notIndex . stmExp) x_stms -> do@@ -355,16 +355,15 @@     notIndex _ = True simplifyLoopVariables _ _ _ _ = Skip --- If a for-loop with no loop variables has a counter of a large--- integer type, and the bound is just a constant or sign-extended--- integer of smaller type, then change the loop to iterate over the--- smaller type instead.  We then move the sign extension inside the--- loop instead.  This addresses loops of the form @for i in x..<y@ in--- the source language.+-- If a for-loop with no loop variables has a counter of type Int64,+-- and the bound is just a constant or sign-extended integer of+-- smaller type, then change the loop to iterate over the smaller type+-- instead.  We then move the sign extension inside the loop instead.+-- This addresses loops of the form @for i in x..<y@ in the source+-- language. narrowLoopType :: (BinderOps lore) => TopDownRuleDoLoop lore-narrowLoopType vtable pat aux (ctx, val, ForLoop i it n [], body)-  | Just (n', it', cs) <- smallerType,-    it' < it =+narrowLoopType vtable pat aux (ctx, val, ForLoop i Int64 n [], body)+  | Just (n', it', cs) <- smallerType =     Simplify $ do       i' <- newVName $ baseString i       let form' = ForLoop i' it' n' []@@ -409,7 +408,7 @@         letBindNames [paramName p] $           BasicOp $             Index arr $-              DimFix (intConst Int32 i) : fullSlice (paramType p) []+              DimFix (intConst Int64 i) : fullSlice (paramType p) []        -- Some of the sizes in the types here might be temporarily wrong       -- until copy propagation fixes it up.@@ -753,7 +752,7 @@                 `add` primExpFromSubExp (IntType to_it) i_offset'           i_stride'' <-             letSubExp "iota_offset" $-              BasicOp $ BinOp (Mul Int32 OverflowWrap) s i_stride'+              BasicOp $ BinOp (Mul Int64 OverflowWrap) s i_stride'           fmap (SubExpResult cs) $             letSubExp "slice_iota" $               BasicOp $ Iota i_n i_offset'' i_stride'' to_it@@ -763,8 +762,8 @@       | not $ or $ zipWith rotateAndSlice offsets inds -> Just $ do         dims <- arrayDims <$> lookupType a         let adjustI i o d = do-              i_p_o <- letSubExp "i_p_o" $ BasicOp $ BinOp (Add Int32 OverflowWrap) i o-              letSubExp "rot_i" (BasicOp $ BinOp (SMod Int32 Unsafe) i_p_o d)+              i_p_o <- letSubExp "i_p_o" $ BasicOp $ BinOp (Add Int64 OverflowWrap) i o+              letSubExp "rot_i" (BasicOp $ BinOp (SMod Int64 Unsafe) i_p_o d)             adjust (DimFix i, o, d) =               DimFix <$> adjustI i o d             adjust (DimSlice i n s, o, d) =@@ -791,7 +790,7 @@           return $ IndexResult cs arr $ ds_inds' ++ rest_inds       where         index DimFix {} = Nothing-        index (DimSlice _ n s) = Just (n, DimSlice (constant (0 :: Int32)) n s)+        index (DimSlice _ n s) = Just (n, DimSlice (constant (0 :: Int64)) n s)     Just (Rearrange perm src, cs)       | rearrangeReach perm <= length (takeWhile isIndex inds) ->         let inds' = rearrangeShape (rearrangeInverse perm) inds@@ -836,7 +835,7 @@         xs_lens <- mapM (fmap (arraySize d) . lookupType) xs          let add n m = do-              added <- letSubExp "index_concat_add" $ BasicOp $ BinOp (Add Int32 OverflowWrap) n m+              added <- letSubExp "index_concat_add" $ BasicOp $ BinOp (Add Int64 OverflowWrap) n m               return (added, n)         (_, starts) <- mapAccumLM add x_len xs_lens         let xs_and_starts = reverse $ zip xs starts@@ -844,9 +843,9 @@         let mkBranch [] =               letSubExp "index_concat" $ BasicOp $ Index x $ ibef ++ DimFix i : iaft             mkBranch ((x', start) : xs_and_starts') = do-              cmp <- letSubExp "index_concat_cmp" $ BasicOp $ CmpOp (CmpSle Int32) start i+              cmp <- letSubExp "index_concat_cmp" $ BasicOp $ CmpOp (CmpSle Int64) start i               (thisres, thisbnds) <- collectStms $ do-                i' <- letSubExp "index_concat_i" $ BasicOp $ BinOp (Sub Int32 OverflowWrap) i start+                i' <- letSubExp "index_concat_i" $ BasicOp $ BinOp (Sub Int64 OverflowWrap) i start                 letSubExp "index_concat" $ BasicOp $ Index x' $ ibef ++ DimFix i' : iaft               thisbody <- mkBodyM thisbnds [thisres]               (altres, altbnds) <- collectStms $ mkBranch xs_and_starts'@@ -856,7 +855,7 @@                   IfDec [primBodyType res_t] IfNormal         SubExpResult cs <$> mkBranch xs_and_starts     Just (ArrayLit ses _, cs)-      | DimFix (Constant (IntValue (Int32Value i))) : inds' <- inds,+      | DimFix (Constant (IntValue (Int64Value i))) : inds' <- inds,         Just se <- maybeNth i ses ->         case inds' of           [] -> Just $ pure $ SubExpResult cs se@@ -871,7 +870,7 @@         Just $           pure $             IndexResult mempty idd $-              DimFix (constant (0 :: Int32)) : inds'+              DimFix (constant (0 :: Int64)) : inds'     _ -> Nothing   where     defOf v = do@@ -920,7 +919,7 @@ fromConcatArg elem_type (ArgReplicate ws se, cs) = do   let elem_shape = arrayShape elem_type   certifying cs $ do-    w <- letSubExp "concat_rep_w" =<< toExp (sum $ map pe32 ws)+    w <- letSubExp "concat_rep_w" =<< toExp (sum $ map pe64 ws)     letExp "concat_rep" $ BasicOp $ Replicate (setDim 0 elem_shape w) se fromConcatArg _ (ArgVar v, _) =   pure v@@ -1241,7 +1240,7 @@ ruleBasicOp vtable pat aux (Update src [DimSlice i n s] (Var v))   | isCt1 n,     isCt1 s,-    Just (ST.Indexed cs e) <- ST.index v [intConst Int32 0] vtable =+    Just (ST.Indexed cs e) <- ST.index v [intConst Int64 0] vtable =     Simplify $ do       e' <- toSubExp "update_elem" e       auxing aux $@@ -1330,7 +1329,7 @@ ruleBasicOp _ pat _ (ArrayLit (se : ses) _)   | all (== se) ses =     Simplify $-      let n = constant (fromIntegral (length ses) + 1 :: Int32)+      let n = constant (fromIntegral (length ses) + 1 :: Int64)        in letBind pat $ BasicOp $ Replicate (Shape [n]) se ruleBasicOp vtable pat aux (Index idd slice)   | Just inds <- sliceIndices slice,@@ -1347,9 +1346,9 @@           oldshape <- arrayDims <$> lookupType idd2           let new_inds =                 reshapeIndex-                  (map pe32 oldshape)-                  (map pe32 $ newDims newshape)-                  (map pe32 inds)+                  (map pe64 oldshape)+                  (map pe64 $ newDims newshape)+                  (map pe64 inds)           new_inds' <-             mapM (toSubExp "new_index") new_inds           certifying idd_cs $@@ -1400,7 +1399,7 @@   | Just (BasicOp (Rearrange perm v2), v_cs) <- ST.lookupExp v vtable,     Just (BasicOp (Rotate offsets2 v3), v2_cs) <- ST.lookupExp v2 vtable = Simplify $ do     let offsets2' = rearrangeShape (rearrangeInverse perm) offsets2-        addOffsets x y = letSubExp "summed_offset" $ BasicOp $ BinOp (Add Int32 OverflowWrap) x y+        addOffsets x y = letSubExp "summed_offset" $ BasicOp $ BinOp (Add Int64 OverflowWrap) x y     offsets' <- zipWithM addOffsets offsets offsets2'     rotate_rearrange <-       auxing aux $ letExp "rotate_rearrange" $ BasicOp $ Rearrange perm v3@@ -1415,7 +1414,7 @@       auxing aux $         letBind pat $ BasicOp $ Rotate offsets v2   where-    add x y = letSubExp "offset" $ BasicOp $ BinOp (Add Int32 OverflowWrap) x y+    add x y = letSubExp "offset" $ BasicOp $ BinOp (Add Int64 OverflowWrap) x y  -- If we see an Update with a scalar where the value to be written is -- the result of indexing some other array, then we convert it into an@@ -1430,8 +1429,8 @@     arr_y /= arr_x,     Just (slice_x_bef, DimFix i, []) <- focusNth (length slice_x - 1) slice_x,     Just (slice_y_bef, DimFix j, []) <- focusNth (length slice_y - 1) slice_y = Simplify $ do-    let slice_x' = slice_x_bef ++ [DimSlice i (intConst Int32 1) (intConst Int32 1)]-        slice_y' = slice_y_bef ++ [DimSlice j (intConst Int32 1) (intConst Int32 1)]+    let slice_x' = slice_x_bef ++ [DimSlice i (intConst Int64 1) (intConst Int64 1)]+        slice_y' = slice_y_bef ++ [DimSlice j (intConst Int64 1) (intConst Int64 1)]     v' <- letExp (baseString v ++ "_slice") $ BasicOp $ Index arr_y slice_y'     certifying cs_y $       auxing aux $@@ -1439,7 +1438,7 @@  -- Simplify away 0<=i when 'i' is from a loop of form 'for i < n'. ruleBasicOp vtable pat aux (CmpOp CmpSle {} x y)-  | Constant (IntValue (Int32Value 0)) <- x,+  | Constant (IntValue (Int64Value 0)) <- x,     Var v <- y,     Just _ <- ST.lookupLoopVar v vtable =     Simplify $ auxing aux $ letBind pat $ BasicOp $ SubExp $ constant True
src/Futhark/Optimise/Sink.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} @@ -42,9 +43,10 @@ -- This pass is defined on the Kernels representation.  This is not -- because we do anything kernel-specific here, but simply because -- more explicit indexing is going on after SOACs are gone.-module Futhark.Optimise.Sink (sink) where+module Futhark.Optimise.Sink (sinkKernels, sinkMC) where  import Control.Monad.State+import Data.Bifunctor import Data.List (foldl') import qualified Data.Map as M import qualified Data.Set as S@@ -52,20 +54,27 @@ import qualified Futhark.Analysis.SymbolTable as ST import Futhark.IR.Aliases import Futhark.IR.Kernels+import Futhark.IR.MC import Futhark.Pass -type SinkLore = Aliases Kernels--type SymbolTable = ST.SymbolTable SinkLore+type SymbolTable lore = ST.SymbolTable lore -type Sinking = M.Map VName (Stm SinkLore)+type Sinking lore = M.Map VName (Stm lore)  type Sunk = S.Set VName +type Sinker lore a = SymbolTable lore -> Sinking lore -> a -> (a, Sunk)++type Constraints lore =+  ( ASTLore lore,+    Aliased lore,+    ST.IndexOp (Op lore)+  )+ -- | Given a statement, compute how often each of its free variables -- are used.  Not accurate: what we care about are only 1, and greater -- than 1.-multiplicity :: Stm SinkLore -> M.Map VName Int+multiplicity :: Constraints lore => Stm lore -> M.Map VName Int multiplicity stm =   case stmExp stm of     If cond tbranch fbranch _ ->@@ -78,12 +87,11 @@     comb = M.unionWith (+)  optimiseBranch ::-  SymbolTable ->-  Sinking ->-  Body SinkLore ->-  (Body SinkLore, Sunk)-optimiseBranch vtable sinking (Body dec stms res) =-  let (stms', stms_sunk) = optimiseStms vtable sinking' stms $ freeIn res+  Constraints lore =>+  Sinker lore (Op lore) ->+  Sinker lore (Body lore)+optimiseBranch onOp vtable sinking (Body dec stms res) =+  let (stms', stms_sunk) = optimiseStms onOp vtable sinking' stms $ freeIn res    in ( Body dec (sunk_stms <> stms') res,         sunk <> stms_sunk       )@@ -97,12 +105,14 @@     sunk = S.fromList $ concatMap (patternNames . stmPattern) sunk_stms  optimiseStms ::-  SymbolTable ->-  Sinking ->-  Stms SinkLore ->+  Constraints lore =>+  Sinker lore (Op lore) ->+  SymbolTable lore ->+  Sinking lore ->+  Stms lore ->   Names ->-  (Stms SinkLore, Sunk)-optimiseStms init_vtable init_sinking all_stms free_in_res =+  (Stms lore, Sunk)+optimiseStms onOp init_vtable init_sinking all_stms free_in_res =   let (all_stms', sunk) =         optimiseStms' init_vtable init_sinking $ stmsToList all_stms    in (stmsFromList all_stms', sunk)@@ -125,17 +135,16 @@               then (stms', sunk)               else (stm : stms', sunk)       | If cond tbranch fbranch ret <- stmExp stm =-        let (tbranch', tsunk) = optimiseBranch vtable sinking tbranch-            (fbranch', fsunk) = optimiseBranch vtable sinking fbranch+        let (tbranch', tsunk) = optimiseBranch onOp vtable sinking tbranch+            (fbranch', fsunk) = optimiseBranch onOp vtable sinking fbranch             (stms', sunk) = optimiseStms' vtable' sinking stms          in ( stm {stmExp = If cond tbranch' fbranch' ret} : stms',               tsunk <> fsunk <> sunk             )-      | Op (SegOp op) <- stmExp stm =-        let scope = scopeOfSegSpace $ segSpace op+      | Op op <- stmExp stm =+        let (op', op_sunk) = onOp vtable sinking op             (stms', stms_sunk) = optimiseStms' vtable' sinking stms-            (op', op_sunk) = runState (mapSegOpM (opMapper scope) op) mempty-         in ( stm {stmExp = Op (SegOp op')} : stms',+         in ( stm {stmExp = Op op'} : stms',               stms_sunk <> op_sunk             )       | otherwise =@@ -150,49 +159,66 @@           identityMapper             { mapOnBody = \scope body -> do                 let (body', sunk) =-                      optimiseBody (ST.fromScope scope <> vtable) sinking body+                      optimiseBody+                        onOp+                        (ST.fromScope scope <> vtable)+                        sinking+                        body                 modify (<> sunk)                 return body'             } -        opMapper scope =-          identitySegOpMapper-            { mapOnSegOpLambda = \lam -> do-                let (body, sunk) =-                      optimiseBody op_vtable sinking $-                        lambdaBody lam-                modify (<> sunk)-                return lam {lambdaBody = body},-              mapOnSegOpBody = \body -> do-                let (body', sunk) =-                      optimiseKernelBody op_vtable sinking body-                modify (<> sunk)-                return body'-            }-          where-            op_vtable = ST.fromScope scope <> vtable- optimiseBody ::-  SymbolTable ->-  Sinking ->-  Body SinkLore ->-  (Body SinkLore, Sunk)-optimiseBody vtable sinking (Body dec stms res) =-  let (stms', sunk) = optimiseStms vtable sinking stms $ freeIn res-   in (Body dec stms' res, sunk)+  Constraints lore =>+  Sinker lore (Op lore) ->+  Sinker lore (Body lore)+optimiseBody onOp vtable sinking (Body attr stms res) =+  let (stms', sunk) = optimiseStms onOp vtable sinking stms $ freeIn res+   in (Body attr stms' res, sunk)  optimiseKernelBody ::-  SymbolTable ->-  Sinking ->-  KernelBody SinkLore ->-  (KernelBody SinkLore, Sunk)-optimiseKernelBody vtable sinking (KernelBody dec stms res) =-  let (stms', sunk) = optimiseStms vtable sinking stms $ freeIn res-   in (KernelBody dec stms' res, sunk)+  Constraints lore =>+  Sinker lore (Op lore) ->+  Sinker lore (KernelBody lore)+optimiseKernelBody onOp vtable sinking (KernelBody attr stms res) =+  let (stms', sunk) = optimiseStms onOp vtable sinking stms $ freeIn res+   in (KernelBody attr stms' res, sunk) --- | The pass definition.-sink :: Pass Kernels Kernels-sink =+optimiseSegOp ::+  Constraints lore =>+  Sinker lore (Op lore) ->+  Sinker lore (SegOp lvl lore)+optimiseSegOp onOp vtable sinking op =+  let scope = scopeOfSegSpace $ segSpace op+   in runState (mapSegOpM (opMapper scope) op) mempty+  where+    opMapper scope =+      identitySegOpMapper+        { mapOnSegOpLambda = \lam -> do+            let (body, sunk) =+                  optimiseBody onOp op_vtable sinking $+                    lambdaBody lam+            modify (<> sunk)+            return lam {lambdaBody = body},+          mapOnSegOpBody = \body -> do+            let (body', sunk) =+                  optimiseKernelBody onOp op_vtable sinking body+            modify (<> sunk)+            return body'+        }+      where+        op_vtable = ST.fromScope scope <> vtable++type SinkLore lore = Aliases lore++sink ::+  ( ASTLore lore,+    CanBeAliased (Op lore),+    ST.IndexOp (OpWithAliases (Op lore))+  ) =>+  Sinker (SinkLore lore) (Op (SinkLore lore)) ->+  Pass lore lore+sink onOp =   Pass "sink" "move memory loads closer to their uses" $     fmap removeProgAliases       . intraproceduralTransformationWithConsts onConsts onFun@@ -200,11 +226,35 @@   where     onFun _ fd = do       let vtable = ST.insertFParams (funDefParams fd) mempty-          (body, _) = optimiseBody vtable mempty $ funDefBody fd+          (body, _) = optimiseBody onOp vtable mempty $ funDefBody fd       return fd {funDefBody = body}      onConsts consts =       pure $         fst $-          optimiseStms mempty mempty consts $+          optimiseStms onOp mempty mempty consts $             namesFromList $ M.keys $ scopeOf consts++-- | Sinking in GPU kernels.+sinkKernels :: Pass Kernels Kernels+sinkKernels = sink onHostOp+  where+    onHostOp :: Sinker (SinkLore Kernels) (Op (SinkLore Kernels))+    onHostOp vtable sinking (SegOp op) =+      first SegOp $ optimiseSegOp onHostOp vtable sinking op+    onHostOp _ _ op = (op, mempty)++-- | Sinking for multicore.+sinkMC :: Pass MC MC+sinkMC = sink onHostOp+  where+    onHostOp :: Sinker (SinkLore MC) (Op (SinkLore MC))+    onHostOp vtable sinking (ParOp par_op op) =+      let (par_op', par_sunk) =+            maybe+              (Nothing, mempty)+              (first Just . optimiseSegOp onHostOp vtable sinking)+              par_op+          (op', sunk) = optimiseSegOp onHostOp vtable sinking op+       in (ParOp par_op' op', par_sunk <> sunk)+    onHostOp _ _ op = (op, mempty)
src/Futhark/Optimise/TileLoops.hs view
@@ -614,7 +614,7 @@           <*> pure (Var mergeinit)        tile_id <- newVName "tile_id"-      let loopform = ForLoop tile_id Int32 num_whole_tiles []+      let loopform = ForLoop tile_id Int64 num_whole_tiles []       loopbody <- renameBody <=< runBodyBinder $         inScopeOf loopform $           localScope (scopeOfFParams $ map fst merge) $ do@@ -664,7 +664,7 @@  tileReturns :: [(VName, SubExp)] -> [(SubExp, SubExp)] -> VName -> Binder Kernels KernelResult tileReturns dims_on_top dims arr = do-  let unit_dims = replicate (length dims_on_top) (intConst Int32 1)+  let unit_dims = replicate (length dims_on_top) (intConst Int64 1)   arr' <-     if null dims_on_top       then return arr@@ -697,9 +697,6 @@       SegOp $         SegMap lvl space ts $ KernelBody () stms' $ map (Returns manifest) res' -v32 :: VName -> TPrimExp Int32 VName-v32 v = TPrimExp $ LeafExp v int32- reconstructGtids1D ::   Count GroupSize SubExp ->   VName ->@@ -708,7 +705,7 @@   Binder Kernels () reconstructGtids1D group_size gtid gid ltid =   letBindNames [gtid]-    =<< toExp (v32 gid * pe32 (unCount group_size) + v32 ltid)+    =<< toExp (le64 gid * pe64 (unCount group_size) + le64 ltid)  readTile1D ::   SubExp ->@@ -734,7 +731,7 @@     segMap1D "full_tile" (SegThread num_groups group_size SegNoVirt) ResultNoSimplify $ \ltid -> do       j <-         letSubExp "j"-          =<< toExp (pe32 tile_id * pe32 tile_size + v32 ltid)+          =<< toExp (pe64 tile_id * pe64 tile_size + le64 ltid)        reconstructGtids1D group_size gtid gid ltid       addPrivStms [DimFix $ Var ltid] privstms@@ -752,7 +749,7 @@           TilePartial ->             letTupExp "pre"               =<< eIf-                (toExp $ pe32 j .<. pe32 w)+                (toExp $ pe64 j .<. pe64 w)                 (resultBody <$> mapM (fmap Var . readTileElem) arrs)                 (eBody $ map eBlank tile_ts)           TileFull ->@@ -801,7 +798,7 @@       fmap (map Var) $         letTupExp "acc"           =<< eIf-            (toExp $ v32 gtid .<. pe32 kdim)+            (toExp $ le64 gtid .<. pe64 kdim)             (eBody [pure $ Op $ OtherOp $ Screma tile_size form' tile])             (resultBodyM thread_accs) @@ -840,11 +837,11 @@     -- the whole tiles.     residual_input <-       letSubExp "residual_input" $-        BasicOp $ BinOp (SRem Int32 Unsafe) w tile_size+        BasicOp $ BinOp (SRem Int64 Unsafe) w tile_size      letTupExp "acc_after_residual"       =<< eIf-        (toExp $ pe32 residual_input .==. 0)+        (toExp $ pe64 residual_input .==. 0)         (resultBodyM $ map Var accs)         (nonemptyTile residual_input)     where@@ -867,7 +864,7 @@             BasicOp $               Index                 tile-                [DimSlice (intConst Int32 0) residual_input (intConst Int32 1)]+                [DimSlice (intConst Int64 0) residual_input (intConst Int64 1)]          -- Now each thread performs a traversal of the tile and         -- updates its accumulator.@@ -901,16 +898,16 @@       else do         group_size <-           letSubExp "computed_group_size" $-            BasicOp $ BinOp (SMin Int32) (unCount (segGroupSize initial_lvl)) kdim+            BasicOp $ BinOp (SMin Int64) (unCount (segGroupSize initial_lvl)) kdim          -- How many groups we need to exhaust the innermost dimension.         ldim <-           letSubExp "ldim" $-            BasicOp $ BinOp (SDivUp Int32 Unsafe) kdim group_size+            BasicOp $ BinOp (SDivUp Int64 Unsafe) kdim group_size          num_groups <-           letSubExp "computed_num_groups"-            =<< foldBinOp (Mul Int32 OverflowUndef) ldim (map snd dims_on_top)+            =<< foldBinOp (Mul Int64 OverflowUndef) ldim (map snd dims_on_top)          return           ( SegGroup (Count num_groups) (Count group_size) SegNoVirt,@@ -922,8 +919,8 @@     Tiling       { tilingSegMap = \desc lvl' manifest f -> segMap1D desc lvl' manifest $ \ltid -> do           letBindNames [gtid]-            =<< toExp (v32 gid * pe32 tile_size + v32 ltid)-          f (untyped $ v32 gtid .<. pe32 kdim) [DimFix $ Var ltid],+            =<< toExp (le64 gid * pe64 tile_size + le64 ltid)+          f (untyped $ le64 gtid .<. pe64 kdim) [DimFix $ Var ltid],         tilingReadTile =           readTile1D tile_size gid gtid (segNumGroups lvl) (segGroupSize lvl),         tilingProcessTile =@@ -934,7 +931,7 @@         tilingTileShape = Shape [tile_size],         tilingNumWholeTiles =           letSubExp "num_whole_tiles" $-            BasicOp $ BinOp (SQuot Int32 Unsafe) w tile_size,+            BasicOp $ BinOp (SQuot Int64 Unsafe) w tile_size,         tilingLevel = lvl,         tilingSpace = space       }@@ -990,9 +987,9 @@ reconstructGtids2D tile_size (gtid_x, gtid_y) (gid_x, gid_y) (ltid_x, ltid_y) = do   -- Reconstruct the original gtids from gid_x/gid_y and ltid_x/ltid_y.   letBindNames [gtid_x]-    =<< toExp (v32 gid_x * pe32 tile_size + v32 ltid_x)+    =<< toExp (le64 gid_x * pe64 tile_size + le64 ltid_x)   letBindNames [gtid_y]-    =<< toExp (v32 gid_y * pe32 tile_size + v32 ltid_y)+    =<< toExp (le64 gid_y * pe64 tile_size + le64 ltid_y)  readTile2D ::   (SubExp, SubExp) ->@@ -1015,10 +1012,10 @@     $ \(ltid_x, ltid_y) -> do       i <-         letSubExp "i"-          =<< toExp (pe32 tile_id * pe32 tile_size + v32 ltid_x)+          =<< toExp (pe64 tile_id * pe64 tile_size + le64 ltid_x)       j <-         letSubExp "j"-          =<< toExp (pe32 tile_id * pe32 tile_size + v32 ltid_y)+          =<< toExp (pe64 tile_id * pe64 tile_size + le64 ltid_y)        reconstructGtids2D tile_size (gtid_x, gtid_y) (gid_x, gid_y) (ltid_x, ltid_y)       addPrivStms [DimFix $ Var ltid_x, DimFix $ Var ltid_y] privstms@@ -1041,11 +1038,11 @@                   last $                     rearrangeShape                       perm-                      [ isInt32 (LeafExp gtid_y int32) .<. pe32 kdim_y,-                        isInt32 (LeafExp gtid_x int32) .<. pe32 kdim_x+                      [ le64 gtid_y .<. pe64 kdim_y,+                        le64 gtid_x .<. pe64 kdim_x                       ]             eIf-              (toExp $ pe32 idx .<. pe32 w .&&. othercheck)+              (toExp $ pe64 idx .<. pe64 w .&&. othercheck)               (eBody [return $ BasicOp $ Index arr [DimFix idx]])               (eBody [eBlank tile_t]) @@ -1116,9 +1113,7 @@         fmap (map Var) $           letTupExp "acc"             =<< eIf-              ( toExp $-                  isInt32 (LeafExp gtid_x int32) .<. pe32 kdim_x-                    .&&. isInt32 (LeafExp gtid_y int32) .<. pe32 kdim_y+              ( toExp $ le64 gtid_x .<. pe64 kdim_x .&&. le64 gtid_y .<. pe64 kdim_y               )               (eBody [pure $ Op $ OtherOp $ Screma actual_tile_size form' tiles'])               (resultBodyM thread_accs)@@ -1158,11 +1153,11 @@     -- the whole tiles.     residual_input <-       letSubExp "residual_input" $-        BasicOp $ BinOp (SRem Int32 Unsafe) w tile_size+        BasicOp $ BinOp (SRem Int64 Unsafe) w tile_size      letTupExp "acc_after_residual"       =<< eIf-        (toExp $ pe32 residual_input .==. 0)+        (toExp $ pe64 residual_input .==. 0)         (resultBodyM $ map Var accs)         (nonemptyTile residual_input)     where@@ -1187,8 +1182,8 @@             BasicOp $               Index                 tile-                [ DimSlice (intConst Int32 0) residual_input (intConst Int32 1),-                  DimSlice (intConst Int32 0) residual_input (intConst Int32 1)+                [ DimSlice (intConst Int64 0) residual_input (intConst Int64 1),+                  DimSlice (intConst Int64 0) residual_input (intConst Int64 1)                 ]          -- Now each thread performs a traversal of the tile and@@ -1215,19 +1210,19 @@    tile_size_key <- nameFromString . pretty <$> newVName "tile_size"   tile_size <- letSubExp "tile_size" $ Op $ SizeOp $ GetSize tile_size_key SizeTile-  group_size <- letSubExp "group_size" $ BasicOp $ BinOp (Mul Int32 OverflowUndef) tile_size tile_size+  group_size <- letSubExp "group_size" $ BasicOp $ BinOp (Mul Int64 OverflowUndef) tile_size tile_size    num_groups_x <-     letSubExp "num_groups_x" $-      BasicOp $ BinOp (SDivUp Int32 Unsafe) kdim_x tile_size+      BasicOp $ BinOp (SDivUp Int64 Unsafe) kdim_x tile_size   num_groups_y <-     letSubExp "num_groups_y" $-      BasicOp $ BinOp (SDivUp Int32 Unsafe) kdim_y tile_size+      BasicOp $ BinOp (SDivUp Int64 Unsafe) kdim_y tile_size    num_groups <-     letSubExp "num_groups_top"       =<< foldBinOp-        (Mul Int32 OverflowUndef)+        (Mul Int64 OverflowUndef)         num_groups_x         (num_groups_y : map snd dims_on_top) @@ -1244,8 +1239,8 @@             reconstructGtids2D tile_size (gtid_x, gtid_y) (gid_x, gid_y) (ltid_x, ltid_y)             f               ( untyped $-                  isInt32 (LeafExp gtid_x int32) .<. pe32 kdim_x-                    .&&. isInt32 (LeafExp gtid_y int32) .<. pe32 kdim_y+                  le64 gtid_x .<. pe64 kdim_x+                    .&&. le64 gtid_y .<. pe64 kdim_y               )               [DimFix $ Var ltid_x, DimFix $ Var ltid_y],         tilingReadTile = readTile2D (kdim_x, kdim_y) (gtid_x, gtid_y) (gid_x, gid_y) tile_size (segNumGroups lvl) (segGroupSize lvl),@@ -1255,7 +1250,7 @@         tilingTileShape = Shape [tile_size, tile_size],         tilingNumWholeTiles =           letSubExp "num_whole_tiles" $-            BasicOp $ BinOp (SQuot Int32 Unsafe) w tile_size,+            BasicOp $ BinOp (SQuot Int64 Unsafe) w tile_size,         tilingLevel = lvl,         tilingSpace = space       }
src/Futhark/Optimise/Unstream.hs view
@@ -18,78 +18,158 @@ -- simplified away, but only *before* they are turned into loops.  In -- principle this pass could be split into multiple, but for now it is -- kept together.-module Futhark.Optimise.Unstream (unstream) where+module Futhark.Optimise.Unstream (unstreamKernels, unstreamMC) where  import Control.Monad.Reader import Control.Monad.State import Futhark.IR.Kernels+import qualified Futhark.IR.Kernels as Kernels import Futhark.IR.Kernels.Simplify (simplifyKernels)+import Futhark.IR.MC+import qualified Futhark.IR.MC as MC import Futhark.MonadFreshNames import Futhark.Pass import Futhark.Tools import qualified Futhark.Transform.FirstOrderTransform as FOT +-- | The pass for GPU kernels.+unstreamKernels :: Pass Kernels Kernels+unstreamKernels = unstream onHostOp simplifyKernels++-- | The pass for multicore.+unstreamMC :: Pass MC MC+unstreamMC = unstream onMCOp MC.simplifyProg+ data Stage = SeqStreams | SeqAll --- | The pass definition.-unstream :: Pass Kernels Kernels-unstream =+unstream ::+  ASTLore lore =>+  (Stage -> OnOp lore) ->+  (Prog lore -> PassM (Prog lore)) ->+  Pass lore lore+unstream onOp simplify =   Pass "unstream" "sequentialise remaining SOACs" $     intraproceduralTransformation (optimise SeqStreams)-      >=> simplifyKernels+      >=> simplify       >=> intraproceduralTransformation (optimise SeqAll)   where     optimise stage scope stms =-      modifyNameSource $ runState $ runReaderT (optimiseStms stage stms) scope+      modifyNameSource $+        runState $+          runReaderT (optimiseStms (onOp stage) stms) scope -type UnstreamM = ReaderT (Scope Kernels) (State VNameSource)+type UnstreamM lore = ReaderT (Scope lore) (State VNameSource) -optimiseStms :: Stage -> Stms Kernels -> UnstreamM (Stms Kernels)-optimiseStms stage stms =+type OnOp lore =+  Pattern lore -> StmAux (ExpDec lore) -> Op lore -> UnstreamM lore [Stm lore]++optimiseStms ::+  ASTLore lore =>+  OnOp lore ->+  Stms lore ->+  UnstreamM lore (Stms lore)+optimiseStms onOp stms =   localScope (scopeOf stms) $-    stmsFromList . concat <$> mapM (optimiseStm stage) (stmsToList stms)+    stmsFromList . concat <$> mapM (optimiseStm onOp) (stmsToList stms) -optimiseBody :: Stage -> Body Kernels -> UnstreamM (Body Kernels)-optimiseBody stage (Body () stms res) =-  Body () <$> optimiseStms stage stms <*> pure res+optimiseBody ::+  ASTLore lore =>+  OnOp lore ->+  Body lore ->+  UnstreamM lore (Body lore)+optimiseBody onOp (Body aux stms res) =+  Body aux <$> optimiseStms onOp stms <*> pure res -optimiseKernelBody :: Stage -> KernelBody Kernels -> UnstreamM (KernelBody Kernels)-optimiseKernelBody stage (KernelBody () stms res) =+optimiseKernelBody ::+  ASTLore lore =>+  OnOp lore ->+  KernelBody lore ->+  UnstreamM lore (KernelBody lore)+optimiseKernelBody onOp (KernelBody attr stms res) =   localScope (scopeOf stms) $-    KernelBody ()-      <$> (stmsFromList . concat <$> mapM (optimiseStm stage) (stmsToList stms))+    KernelBody attr+      <$> (stmsFromList . concat <$> mapM (optimiseStm onOp) (stmsToList stms))       <*> pure res -optimiseLambda :: Stage -> Lambda Kernels -> UnstreamM (Lambda Kernels)-optimiseLambda stage lam = localScope (scopeOfLParams $ lambdaParams lam) $ do-  body <- optimiseBody stage $ lambdaBody lam+optimiseLambda ::+  ASTLore lore =>+  OnOp lore ->+  Lambda lore ->+  UnstreamM lore (Lambda lore)+optimiseLambda onOp lam = localScope (scopeOfLParams $ lambdaParams lam) $ do+  body <- optimiseBody onOp $ lambdaBody lam   return lam {lambdaBody = body} -sequentialise :: Stage -> SOAC Kernels -> Bool+optimiseStm ::+  ASTLore lore =>+  OnOp lore ->+  Stm lore ->+  UnstreamM lore [Stm lore]+optimiseStm onOp (Let pat aux (Op op)) =+  onOp pat aux op+optimiseStm onOp (Let pat aux e) =+  pure <$> (Let pat aux <$> mapExpM optimise e)+  where+    optimise =+      identityMapper+        { mapOnBody = \scope ->+            localScope scope . optimiseBody onOp+        }++optimiseSegOp ::+  ASTLore lore =>+  OnOp lore ->+  SegOp lvl lore ->+  UnstreamM lore (SegOp lvl lore)+optimiseSegOp onOp op =+  localScope (scopeOfSegSpace $ segSpace op) $ mapSegOpM optimise op+  where+    optimise =+      identitySegOpMapper+        { mapOnSegOpBody = optimiseKernelBody onOp,+          mapOnSegOpLambda = optimiseLambda onOp+        }++onMCOp :: Stage -> OnOp MC+onMCOp stage pat aux (ParOp par_op op) = do+  par_op' <- traverse (optimiseSegOp (onMCOp stage)) par_op+  op' <- optimiseSegOp (onMCOp stage) op+  pure [Let pat aux $ Op $ ParOp par_op' op']+onMCOp stage pat aux (MC.OtherOp soac)+  | sequentialise stage soac = do+    stms <- runBinder_ $ FOT.transformSOAC pat soac+    fmap concat $+      localScope (scopeOf stms) $+        mapM (optimiseStm (onMCOp stage)) $ stmsToList stms+  | otherwise =+    -- Still sequentialise whatever's inside.+    pure <$> (Let pat aux . Op . MC.OtherOp <$> mapSOACM optimise soac)+  where+    optimise =+      identitySOACMapper+        { mapOnSOACLambda = optimiseLambda (onMCOp stage)+        }++sequentialise :: Stage -> SOAC lore -> Bool sequentialise SeqStreams Stream {} = True sequentialise SeqStreams _ = False sequentialise SeqAll _ = True -optimiseStm :: Stage -> Stm Kernels -> UnstreamM [Stm Kernels]-optimiseStm stage (Let pat aux (Op (OtherOp soac)))+onHostOp :: Stage -> OnOp Kernels+onHostOp stage pat aux (Kernels.OtherOp soac)   | sequentialise stage soac = do     stms <- runBinder_ $ FOT.transformSOAC pat soac-    fmap concat $ localScope (scopeOf stms) $ mapM (optimiseStm stage) $ stmsToList stms-  | otherwise = do+    fmap concat $+      localScope (scopeOf stms) $+        mapM (optimiseStm (onHostOp stage)) $ stmsToList stms+  | otherwise =     -- Still sequentialise whatever's inside.-    pure <$> (Let pat aux . Op . OtherOp <$> mapSOACM optimise soac)-  where-    optimise = identitySOACMapper {mapOnSOACLambda = optimiseLambda stage}-optimiseStm stage (Let pat aux (Op (SegOp op))) =-  localScope (scopeOfSegSpace $ segSpace op) $-    pure <$> (Let pat aux . Op . SegOp <$> mapSegOpM optimise op)+    pure <$> (Let pat aux . Op . Kernels.OtherOp <$> mapSOACM optimise soac)   where     optimise =-      identitySegOpMapper-        { mapOnSegOpBody = optimiseKernelBody stage,-          mapOnSegOpLambda = optimiseLambda stage+      identitySOACMapper+        { mapOnSOACLambda = optimiseLambda (onHostOp stage)         }-optimiseStm stage (Let pat aux e) =-  pure <$> (Let pat aux <$> mapExpM optimise e)-  where-    optimise = identityMapper {mapOnBody = \scope -> localScope scope . optimiseBody stage}+onHostOp stage pat aux (SegOp op) =+  pure <$> (Let pat aux . Op . SegOp <$> optimiseSegOp (onHostOp stage) op)+onHostOp _ pat aux op = return [Let pat aux $ Op op]
src/Futhark/Pass/ExpandAllocations.hs view
@@ -212,24 +212,19 @@   Extraction ->   ExpandM (RebaseMap, Stms KernelsMem) memoryRequirements lvl space kstms variant_allocs invariant_allocs = do-  ((num_threads, num_groups64, num_threads64), num_threads_stms) <- runBinder $ do-    num_threads <-+  (num_threads, num_threads_stms) <-+    runBinder $       letSubExp "num_threads" $         BasicOp $           BinOp-            (Mul Int32 OverflowUndef)+            (Mul Int64 OverflowUndef)             (unCount $ segNumGroups lvl)             (unCount $ segGroupSize lvl)-    num_groups64 <--      letSubExp "num_groups64" $-        BasicOp $ ConvOp (SExt Int32 Int64) (unCount $ segNumGroups lvl)-    num_threads64 <- letSubExp "num_threads64" $ BasicOp $ ConvOp (SExt Int32 Int64) num_threads-    return (num_threads, num_groups64, num_threads64)    (invariant_alloc_stms, invariant_alloc_offsets) <-     inScopeOf num_threads_stms $       expandedInvariantAllocations-        (num_threads64, num_groups64, segNumGroups lvl, segGroupSize lvl)+        (num_threads, segNumGroups lvl, segGroupSize lvl)         space         invariant_allocs @@ -356,7 +351,6 @@  expandedInvariantAllocations ::   ( SubExp,-    SubExp,     Count NumGroups SubExp,     Count GroupSize SubExp   ) ->@@ -364,8 +358,7 @@   Extraction ->   ExpandM (Stms KernelsMem, RebaseMap) expandedInvariantAllocations-  ( num_threads64,-    num_groups64,+  ( num_threads,     Count num_groups,     Count group_size     )@@ -382,8 +375,8 @@         let sizepat = Pattern [] [PatElem total_size $ MemPrim int64]             allocpat = Pattern [] [PatElem mem $ MemMem space]             num_users = case lvl of-              SegThread {} -> num_threads64-              SegGroup {} -> num_groups64+              SegThread {} -> num_threads+              SegGroup {} -> num_groups         return           ( stmsFromList               [ Let sizepat (defAux ()) $@@ -402,21 +395,20 @@             root_ixfun =               IxFun.iota                 ( old_shape-                    ++ [ pe32 num_groups-                           * pe32 group_size+                    ++ [ pe64 num_groups * pe64 group_size                        ]                 )             permuted_ixfun = IxFun.permute root_ixfun perm             offset_ixfun =               IxFun.slice permuted_ixfun $-                DimFix (le32 (segFlat segspace)) :+                DimFix (le64 (segFlat segspace)) :                 map untouched old_shape          in offset_ixfun       newBase SegGroup {} (old_shape, _) =-        let root_ixfun = IxFun.iota (pe32 num_groups : old_shape)+        let root_ixfun = IxFun.iota (pe64 num_groups : old_shape)             offset_ixfun =               IxFun.slice root_ixfun $-                DimFix (le32 (segFlat segspace)) :+                DimFix (le64 (segFlat segspace)) :                 map untouched old_shape          in offset_ixfun @@ -463,15 +455,14 @@           M.singleton mem $ newBase offset         ) -    num_threads' = pe32 num_threads-    gtid = isInt32 $ LeafExp (segFlat kspace) int32+    num_threads' = pe64 num_threads+    gtid = le64 $ segFlat kspace      -- For the variant allocations, we add an inner dimension,     -- which is then offset by a thread-specific amount.     newBase size_per_thread (old_shape, pt) =       let elems_per_thread =-            isInt32 (sExt Int32 (primExpFromSubExp int64 size_per_thread))-              `quot` primByteSize pt+            pe64 size_per_thread `quot` primByteSize pt           root_ixfun = IxFun.iota [elems_per_thread, num_threads']           offset_ixfun =             IxFun.slice@@ -486,7 +477,7 @@        in IxFun.reshape offset_ixfun shapechange  -- | A map from memory block names to new index function bases.-type RebaseMap = M.Map VName (([TPrimExp Int32 VName], PrimType) -> IxFun)+type RebaseMap = M.Map VName (([TPrimExp Int64 VName], PrimType) -> IxFun)  newtype OffsetM a   = OffsetM@@ -511,7 +502,7 @@ askRebaseMap :: OffsetM RebaseMap askRebaseMap = OffsetM $ lift ask -lookupNewBase :: VName -> ([TPrimExp Int32 VName], PrimType) -> OffsetM (Maybe IxFun)+lookupNewBase :: VName -> ([TPrimExp Int64 VName], PrimType) -> OffsetM (Maybe IxFun) lookupNewBase name x = do   offsets <- askRebaseMap   return $ ($ x) <$> M.lookup name offsets@@ -754,7 +745,7 @@           letSubExp "z" $ BasicOp $ BinOp (SMax Int64) (Var $ paramName x) (Var $ paramName y)     return $ Lambda (xs ++ ys) (mkBody stms zs) i64s -  flat_gtid_lparam <- Param <$> newVName "flat_gtid" <*> pure (Prim (IntType Int32))+  flat_gtid_lparam <- Param <$> newVName "flat_gtid" <*> pure (Prim (IntType Int64))    (size_lam', _) <- flip runBinderT kernels_scope $ do     params <- replicateM num_sizes $ newParam "x" (Prim int64)@@ -769,8 +760,8 @@         let (kspace_gtids, kspace_dims) = unzip $ unSegSpace space             new_inds =               unflattenIndex-                (map pe32 kspace_dims)-                (pe32 $ Var $ paramName flat_gtid_lparam)+                (map pe64 kspace_dims)+                (pe64 $ Var $ paramName flat_gtid_lparam)         zipWithM_ letBindNames (map pure kspace_gtids) =<< mapM toExp new_inds          mapM_ addStm kstms'@@ -780,10 +771,6 @@       Kernels.simplifyLambda (Lambda [flat_gtid_lparam] (Body () stms zs) i64s)    ((maxes_per_thread, size_sums), slice_stms) <- flip runBinderT kernels_scope $ do-    num_threads_64 <--      letSubExp "num_threads" $-        BasicOp $ ConvOp (SExt Int32 Int64) num_threads-     pat <-       basicPattern []         <$> replicateM@@ -792,12 +779,12 @@      w <-       letSubExp "size_slice_w"-        =<< foldBinOp (Mul Int32 OverflowUndef) (intConst Int32 1) (segSpaceDims space)+        =<< foldBinOp (Mul Int64 OverflowUndef) (intConst Int64 1) (segSpaceDims space)      thread_space_iota <-       letExp "thread_space_iota" $         BasicOp $-          Iota w (intConst Int32 0) (intConst Int32 1) Int32+          Iota w (intConst Int64 0) (intConst Int64 1) Int64     let red_op =           SegBinOp             Commutative@@ -811,7 +798,7 @@      size_sums <- forM (patternNames pat) $ \threads_max ->       letExp "size_sum" $-        BasicOp $ BinOp (Mul Int64 OverflowUndef) (Var threads_max) num_threads_64+        BasicOp $ BinOp (Mul Int64 OverflowUndef) (Var threads_max) num_threads      return (patternNames pat, size_sums) 
src/Futhark/Pass/ExplicitAllocations.hs view
@@ -273,14 +273,14 @@  arraySizeInBytesExp :: Type -> PrimExp VName arraySizeInBytesExp t =-  untyped $ foldl' (*) (elemSize t) $ map (sExt64 . pe32) (arrayDims t)+  untyped $ foldl' (*) (elemSize t) $ map pe64 (arrayDims t)  arraySizeInBytesExpM :: Allocator lore m => Type -> m (PrimExp VName) arraySizeInBytesExpM t = do   dims <- mapM dimAllocationSize (arrayDims t)-  let dim_prod_i32 = product $ map (sExt64 . pe32) dims+  let dim_prod_i64 = product $ map pe64 dims       elm_size_i64 = primByteSize $ elemType t-  return $ untyped $ dim_prod_i32 * elm_size_i64+  return $ untyped $ dim_prod_i64 * elm_size_i64  arraySizeInBytes :: Allocator lore m => Type -> m SubExp arraySizeInBytes = computeSize "bytes" <=< arraySizeInBytesExpM@@ -330,7 +330,7 @@       [PatElem lore]     ) allocsForPattern sizeidents validents rts hints = do-  let sizes' = [PatElem size $ MemPrim int32 | size <- map identName sizeidents]+  let sizes' = [PatElem size $ MemPrim int64 | size <- map identName sizeidents]   (vals, (exts, mems)) <-     runWriterT $       forM (zip3 validents rts hints) $ \(ident, rt, hint) -> do@@ -414,7 +414,7 @@               size_exts               sizeidents           substs = M.fromList $ new_substs <> size_substs-      ixfn <- instantiateIxFun $ IxFun.substituteInIxFun (fmap isInt32 substs) ext_ixfn+      ixfn <- instantiateIxFun $ IxFun.substituteInIxFun (fmap isInt64 substs) ext_ixfn        return (patels, ixfn) @@ -446,8 +446,8 @@     computeSize "bytes" $       untyped $         product-          [ product $ map sExt64 $ IxFun.base ixfun,-            fromIntegral (primByteSize (elemType t) :: Int64)+          [ product $ IxFun.base ixfun,+            primByteSize (elemType t)           ]   m <- allocateMemory "mem" bytes space   return $ MemArray bt (arrayShape t) NoUniqueness $ ArrayIn m ixfun@@ -461,7 +461,7 @@  directIxFun :: PrimType -> Shape -> u -> VName -> Type -> MemBound u directIxFun bt shape u mem t =-  let ixf = IxFun.iota $ map pe32 $ arrayDims t+  let ixf = IxFun.iota $ map pe64 $ arrayDims t    in MemArray bt shape u $ ArrayIn mem ixf  allocInFParams ::@@ -488,7 +488,7 @@   case paramDeclType param of     Array bt shape u -> do       let memname = baseString (paramName param) <> "_mem"-          ixfun = IxFun.iota $ map pe32 $ shapeDims shape+          ixfun = IxFun.iota $ map pe64 $ shapeDims shape       mem <- lift $ newVName memname       tell ([], [Param mem $ MemMem pspace])       return param {paramDec = MemArray bt shape u $ ArrayIn mem ixfun}@@ -541,8 +541,8 @@               ( \_ -> do                   vname <- lift $ newVName "ctx_param_ext"                   return-                    ( Param vname $ MemPrim int32,-                      fmap Free $ pe32 $ Var vname+                    ( Param vname $ MemPrim int64,+                      fmap Free $ pe64 $ Var vname                     )               )               substs@@ -573,7 +573,7 @@   (Allocable fromlore tolore, Allocator tolore (AllocM fromlore tolore)) =>   Space ->   VName ->-  AllocM fromlore tolore (SubExp, ExtIxFun, [TPrimExp Int32 VName], VName)+  AllocM fromlore tolore (SubExp, ExtIxFun, [TPrimExp Int64 VName], VName) existentializeArray space v = do   (mem', ixfun) <- lookupArraySummary v   sp <- lookupMemSpace mem'@@ -604,7 +604,7 @@       <$> mapM         ( \s -> do             vname <- lift $ letExp "ctx_val" =<< toExp s-            return (Var vname, fmap Free $ primExpFromSubExp int32 $ Var vname)+            return (Var vname, fmap Free $ primExpFromSubExp int64 $ Var vname)         )         substs @@ -726,8 +726,8 @@           ReturnsNewBlock DefaultSpace i $             IxFun.iota $ map convert $ shapeDims shape -    convert (Ext i) = le32 $ Ext i-    convert (Free v) = Free <$> pe32 v+    convert (Ext i) = le64 $ Ext i+    convert (Free v) = Free <$> pe64 v  startOfFreeIDRange :: [TypeBase ExtShape u] -> Int startOfFreeIDRange = S.size . shapeContext@@ -877,7 +877,7 @@     generalize ::       (Maybe Space, Maybe IxFun) ->       (Maybe Space, Maybe IxFun) ->-      (Maybe Space, Maybe (ExtIxFun, [(TPrimExp Int32 VName, TPrimExp Int32 VName)]))+      (Maybe Space, Maybe (ExtIxFun, [(TPrimExp Int64 VName, TPrimExp Int64 VName)]))     generalize (Just sp1, Just ixf1) (Just sp2, Just ixf2) =       if sp1 /= sp2         then (Just sp1, Nothing)@@ -938,7 +938,7 @@   [ExtType] ->   Body tolore ->   [Maybe Space] ->-  [Maybe (ExtIxFun, [TPrimExp Int32 VName])] ->+  [Maybe (ExtIxFun, [TPrimExp Int64 VName])] ->   AllocM fromlore tolore (Body tolore, [BodyReturns]) addResCtxInIfBody ifrets (Body _ bnds res) spaces substs = do   let num_vals = length ifrets@@ -1006,8 +1006,8 @@     inspect (Prim pt) _ = MemPrim pt     inspect (Mem space) _ = MemMem space -    convert (Ext i) = le32 (Ext i)-    convert (Free v) = Free <$> pe32 v+    convert (Ext i) = le64 (Ext i)+    convert (Free v) = Free <$> pe64 v      adjustExtV :: Int -> Ext VName -> Ext VName     adjustExtV _ (Free v) = Free v@@ -1050,10 +1050,10 @@       (mem, ixfun) <- lookupArraySummary a       case paramType p of         Array bt shape u -> do-          dims <- map pe32 . arrayDims <$> lookupType a+          dims <- map pe64 . arrayDims <$> lookupType a           let ixfun' =                 IxFun.slice ixfun $-                  fullSliceNum dims [DimFix $ le32 i]+                  fullSliceNum dims [DimFix $ le64 i]           return (p {paramDec = MemArray bt shape u $ ArrayIn mem ixfun'}, a)         Prim bt ->           return (p {paramDec = MemPrim bt}, a)
src/Futhark/Pass/ExplicitAllocations/Kernels.hs view
@@ -27,9 +27,6 @@   opIsConst (SizeOp GetSizeMax {}) = True   opIsConst _ = False -instance SizeSubst (SegOp lvl lore) where-  opSizeSubst _ _ = mempty- allocAtLevel :: SegLevel -> AllocM fromlore tlore a -> AllocM fromlore tlore a allocAtLevel lvl = local $ \env ->   env@@ -49,7 +46,7 @@     letSubExp "num_threads" $       BasicOp $         BinOp-          (Mul Int32 OverflowUndef)+          (Mul Int64 OverflowUndef)           (unCount (segNumGroups lvl))           (unCount (segGroupSize lvl))   allocAtLevel lvl $ mapSegOpM (mapper num_threads) op@@ -85,7 +82,7 @@   dims <- arrayDims <$> lookupType v   let perm_inv = rearrangeInverse perm       dims' = rearrangeShape perm dims-      ixfun = IxFun.permute (IxFun.iota $ map pe32 dims') perm_inv+      ixfun = IxFun.permute (IxFun.iota $ map pe64 dims') perm_inv   return [Hint ixfun DefaultSpace] kernelExpHints (Op (Inner (SegOp (SegMap lvl@SegThread {} space ts body)))) =   zipWithM (mapResultHint lvl space) ts $ kernelBodyResult body@@ -107,12 +104,12 @@ mapResultHint lvl space = hint   where     num_threads =-      pe32 (unCount $ segNumGroups lvl) * pe32 (unCount $ segGroupSize lvl)+      pe64 (unCount $ segNumGroups lvl) * pe64 (unCount $ segGroupSize lvl)      -- Heuristic: do not rearrange for returned arrays that are     -- sufficiently small.     coalesceReturnOfShape _ [] = False-    coalesceReturnOfShape bs [Constant (IntValue (Int32Value d))] = bs * d > 4+    coalesceReturnOfShape bs [Constant (IntValue (Int64Value d))] = bs * d > 4     coalesceReturnOfShape _ _ = True      hint t Returns {}@@ -124,9 +121,9 @@       t_dims <- mapM dimAllocationSize $ arrayDims t       return $ Hint (innermost [w] t_dims) DefaultSpace     hint Prim {} (ConcatReturns SplitContiguous w elems_per_thread _) = do-      let ixfun_base = IxFun.iota [num_threads, pe32 elems_per_thread]+      let ixfun_base = IxFun.iota [sExt64 num_threads, pe64 elems_per_thread]           ixfun_tr = IxFun.permute ixfun_base [1, 0]-          ixfun = IxFun.reshape ixfun_tr $ map (DimNew . pe32) [w]+          ixfun = IxFun.reshape ixfun_tr $ map (DimNew . pe64) [w]       return $ Hint ixfun DefaultSpace     hint _ _ = return NoHint @@ -139,7 +136,7 @@           ++ [0 .. length space_dims -1]       perm_inv = rearrangeInverse perm       dims_perm = rearrangeShape perm dims-      ixfun_base = IxFun.iota $ map pe32 dims_perm+      ixfun_base = IxFun.iota $ map pe64 dims_perm       ixfun_rearranged = IxFun.permute ixfun_base perm_inv    in ixfun_rearranged @@ -156,8 +153,8 @@       return $         if private r && all (semiStatic consts) (arrayDims t)           then-            let seg_dims = map pe32 $ segSpaceDims space-                dims = seg_dims ++ map pe32 (arrayDims t)+            let seg_dims = map pe64 $ segSpaceDims space+                dims = seg_dims ++ map pe64 (arrayDims t)                 nilSlice d = DimSlice 0 d 0              in Hint                   ( IxFun.slice (IxFun.iota dims) $@@ -178,7 +175,7 @@     maybePrivate consts t       | Just (Array pt shape _) <- hasStaticShape t,         all (semiStatic consts) $ shapeDims shape = do-        let ixfun = IxFun.iota $ map pe32 $ shapeDims shape+        let ixfun = IxFun.iota $ map pe64 $ shapeDims shape         return $ Hint ixfun $ ScalarSpace (shapeDims shape) pt       | otherwise =         return NoHint
+ src/Futhark/Pass/ExplicitAllocations/MC.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Futhark.Pass.ExplicitAllocations.MC (explicitAllocations) where++import Futhark.IR.MC+import Futhark.IR.MCMem+import Futhark.Pass.ExplicitAllocations+import Futhark.Pass.ExplicitAllocations.SegOp++instance SizeSubst (MCOp lore op) where+  opSizeSubst _ _ = mempty++handleSegOp :: SegOp () MC -> AllocM MC MCMem (SegOp () MCMem)+handleSegOp op = do+  let num_threads = intConst Int64 256 -- FIXME+  mapSegOpM (mapper num_threads) op+  where+    scope = scopeOfSegSpace $ segSpace op+    mapper num_threads =+      identitySegOpMapper+        { mapOnSegOpBody =+            localScope scope . allocInKernelBody,+          mapOnSegOpLambda =+            allocInBinOpLambda num_threads (segSpace op)+        }++handleMCOp :: Op MC -> AllocM MC MCMem (Op MCMem)+handleMCOp (ParOp par_op op) =+  Inner <$> (ParOp <$> traverse handleSegOp par_op <*> handleSegOp op)+handleMCOp (OtherOp soac) =+  error $ "Cannot allocate memory in SOAC: " ++ pretty soac++explicitAllocations :: Pass MC MCMem+explicitAllocations = explicitAllocationsGeneric handleMCOp defaultExpHints
src/Futhark/Pass/ExplicitAllocations/SegOp.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}  module Futhark.Pass.ExplicitAllocations.SegOp   ( allocInKernelBody,@@ -12,6 +13,9 @@ import qualified Futhark.IR.Mem.IxFun as IxFun import Futhark.Pass.ExplicitAllocations +instance SizeSubst (SegOp lvl lore) where+  opSizeSubst _ _ = mempty+ allocInKernelBody ::   Allocable fromlore tolore =>   KernelBody fromlore ->@@ -34,8 +38,8 @@ allocInBinOpParams ::   Allocable fromlore tolore =>   SubExp ->-  TPrimExp Int32 VName ->-  TPrimExp Int32 VName ->+  TPrimExp Int64 VName ->+  TPrimExp Int64 VName ->   [LParam fromlore] ->   [LParam fromlore] ->   AllocM fromlore tolore ([LParam tolore], [LParam tolore])@@ -46,12 +50,12 @@         Array bt shape u -> do           twice_num_threads <-             letSubExp "twice_num_threads" $-              BasicOp $ BinOp (Mul Int32 OverflowUndef) num_threads $ intConst Int32 2+              BasicOp $ BinOp (Mul Int64 OverflowUndef) num_threads $ intConst Int64 2           let t = paramType x `arrayOfRow` twice_num_threads           mem <- allocForArray t DefaultSpace           -- XXX: this iota ixfun is a bit inefficient; leading to           -- uncoalesced access.-          let base_dims = map pe32 $ arrayDims t+          let base_dims = map pe64 $ arrayDims t               ixfun_base = IxFun.iota base_dims               ixfun_x =                 IxFun.slice ixfun_base $@@ -83,8 +87,8 @@ allocInBinOpLambda num_threads (SegSpace flat _) lam = do   let (acc_params, arr_params) =         splitAt (length (lambdaParams lam) `div` 2) $ lambdaParams lam-      index_x = TPrimExp $ LeafExp flat int32-      index_y = index_x + pe32 num_threads+      index_x = TPrimExp $ LeafExp flat int64+      index_y = index_x + pe64 num_threads   (acc_params', arr_params') <-     allocInBinOpParams num_threads index_x index_y acc_params arr_params 
src/Futhark/Pass/ExplicitAllocations/Seq.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}  module Futhark.Pass.ExplicitAllocations.Seq   ( explicitAllocations,
src/Futhark/Pass/ExtractKernels.hs view
@@ -315,7 +315,7 @@   runBinder $ do     to_what' <-       letSubExp "comparatee"-        =<< foldBinOp (Mul Int32 OverflowUndef) (intConst Int32 1) to_what+        =<< foldBinOp (Mul Int64 OverflowUndef) (intConst Int64 1) to_what     cmp_res <- letSubExp desc $ Op $ SizeOp $ CmpSizeLe size_key size_class to_what'     return (cmp_res, size_key) @@ -594,7 +594,7 @@   String ->   [SubExp] ->   KernelPath ->-  Maybe Int32 ->+  Maybe Int64 ->   DistribM ((SubExp, Name), Out.Stms Out.Kernels) sufficientParallelism desc ws path def =   cmpSizeLe desc (Out.SizeThreshold path def) ws@@ -733,7 +733,7 @@ -- The minimum amount of inner parallelism we require (by default) in -- intra-group versions.  Less than this is usually pointless on a GPU -- (but we allow tuning to change it).-intraMinInnerPar :: Int32+intraMinInnerPar :: Int64 intraMinInnerPar = 32 -- One NVIDIA warp  onMap' ::@@ -796,7 +796,7 @@           fits <-             letSubExp "fits" $               BasicOp $-                CmpOp (CmpSle Int32) group_size max_group_size+                CmpOp (CmpSle Int64) group_size max_group_size            addStms check_suff_stms 
src/Futhark/Pass/ExtractKernels/BlockedKernel.hs view
@@ -135,10 +135,10 @@   -- device afterwards, as this may save an expensive   -- host-device copy (scalars are kept on the host, but arrays   -- may be on the device).-  let addDummyDim t = t `arrayOfRow` intConst Int32 1+  let addDummyDim t = t `arrayOfRow` intConst Int64 1   pat' <- fmap addDummyDim <$> renamePattern pat   dummy <- newVName "dummy"-  let ispace = [(dummy, intConst Int32 1)]+  let ispace = [(dummy, intConst Int64 1)]    return     ( pat',@@ -148,7 +148,7 @@         letBindNames [to] $           BasicOp $             Index from $-              fullSlice from_t [DimFix $ intConst Int32 0]+              fullSlice from_t [DimFix $ intConst Int64 0]     )  nonSegRed ::
src/Futhark/Pass/ExtractKernels/DistributeNests.hs view
@@ -580,7 +580,7 @@     return $ oneStm $ Let outerpat aux $ BasicOp $ Reshape reshape' arr maybeDistributeStm stm@(Let _ aux (BasicOp (Rotate rots _))) acc =   distributeSingleUnaryStm acc stm $ \nest outerpat arr -> do-    let rots' = map (const $ intConst Int32 0) (kernelNestWidths nest) ++ rots+    let rots' = map (const $ intConst Int64 0) (kernelNestWidths nest) ++ rots     return $ oneStm $ Let outerpat aux $ BasicOp $ Rotate rots' arr maybeDistributeStm stm@(Let pat aux (BasicOp (Update arr slice (Var v)))) acc   | not $ null $ sliceDims slice =@@ -614,10 +614,10 @@         lam =           Lambda             { lambdaParams = [],-              lambdaReturnType = [Prim int32, et],+              lambdaReturnType = [Prim int64, et],               lambdaBody = mkBody mempty [i, v]             }-    maybeDistributeStm (Let pat aux $ Op $ Scatter (intConst Int32 1) lam [] [(w, 1, arr)]) acc+    maybeDistributeStm (Let pat aux $ Op $ Scatter (intConst Int64 1) lam [] [(w, 1, arr)]) acc   where     amortises DoLoop {} = True     amortises Op {} = True@@ -839,7 +839,7 @@         letSubExp "v" $ BasicOp $ Index v $ map (DimFix . Var) slice_gtids     slice_is <-       traverse (toSubExp "index") $-        fixSlice (map (fmap pe32) slice) $ map (pe32 . Var) slice_gtids+        fixSlice (map (fmap pe64) slice) $ map (pe64 . Var) slice_gtids      let write_is = map (Var . fst) base_ispace ++ slice_is         arr' =@@ -991,7 +991,7 @@           BasicOp $             Index ne_v $               fullSlice ne_v_t $-                replicate (shapeRank shape) $ DimFix $ intConst Int32 0+                replicate (shapeRank shape) $ DimFix $ intConst Int64 0       return (lam', nes', shape)     Nothing ->       return (lam, nes, mempty)
src/Futhark/Pass/ExtractKernels/Distribution.hs view
@@ -256,7 +256,7 @@ constructKernel mk_lvl kernel_nest inner_body = runBinderT' $ do   (ispace, inps) <- flatKernel kernel_nest   let aux = loopNestingAux first_nest-      ispace_scope = M.fromList $ zip (map fst ispace) $ repeat $ IndexName Int32+      ispace_scope = M.fromList $ zip (map fst ispace) $ repeat $ IndexName Int64       pat = loopNestingPattern first_nest       rts = map (stripArray (length ispace)) $ patternTypes pat 
src/Futhark/Pass/ExtractKernels/ISRWIM.hs view
@@ -103,7 +103,7 @@           letSubExp "acc" $             BasicOp $               Index v $-                fullSlice v_t [DimFix $ intConst Int32 0]+                fullSlice v_t [DimFix $ intConst Int64 0]         indexAcc Constant {} =           error "irwim: array accumulator is a constant."     accs' <- mapM indexAcc accs
src/Futhark/Pass/ExtractKernels/Intragroup.hs view
@@ -59,7 +59,7 @@     lift $       runBinder $         letSubExp "intra_num_groups"-          =<< foldBinOp (Mul Int32 OverflowUndef) (intConst Int32 1) (map snd ispace)+          =<< foldBinOp (Mul Int64 OverflowUndef) (intConst Int64 1) (map snd ispace)    let body = lambdaBody lam @@ -82,18 +82,18 @@    ((intra_avail_par, kspace, read_input_stms), prelude_stms) <- lift $     runBinder $ do-      let foldBinOp' _ [] = eSubExp $ intConst Int32 0+      let foldBinOp' _ [] = eSubExp $ intConst Int64 0           foldBinOp' bop (x : xs) = foldBinOp bop x xs       ws_min <--        mapM (letSubExp "one_intra_par_min" <=< foldBinOp' (Mul Int32 OverflowUndef)) $+        mapM (letSubExp "one_intra_par_min" <=< foldBinOp' (Mul Int64 OverflowUndef)) $           filter (not . null) wss_min       ws_avail <--        mapM (letSubExp "one_intra_par_avail" <=< foldBinOp' (Mul Int32 OverflowUndef)) $+        mapM (letSubExp "one_intra_par_avail" <=< foldBinOp' (Mul Int64 OverflowUndef)) $           filter (not . null) wss_avail        -- The amount of parallelism available *in the worst case* is       -- equal to the smallest parallel loop.-      intra_avail_par <- letSubExp "intra_avail_par" =<< foldBinOp' (SMin Int32) ws_avail+      intra_avail_par <- letSubExp "intra_avail_par" =<< foldBinOp' (SMin Int64) ws_avail        -- The group size is either the maximum of the minimum parallelism       -- exploited, or the desired parallelism (bounded by the max group@@ -102,10 +102,10 @@         =<< if null ws_min           then             eBinOp-              (SMin Int32)+              (SMin Int64)               (eSubExp =<< letSubExp "max_group_size" (Op $ SizeOp $ Out.GetSizeMax Out.SizeGroup))               (eSubExp intra_avail_par)-          else foldBinOp' (SMax Int32) ws_min+          else foldBinOp' (SMax Int64) ws_min        let inputIsUsed input = kernelInputName input `nameIn` freeIn body           used_inps = filter inputIsUsed inps
src/Futhark/Pass/ExtractKernels/StreamKernel.hs view
@@ -48,12 +48,14 @@   SubExp ->   SubExp ->   m (SubExp, SubExp)-numberOfGroups desc w64 group_size = do+numberOfGroups desc w group_size = do   max_num_groups_key <- nameFromString . pretty <$> newVName (desc ++ "_num_groups")   num_groups <-     letSubExp "num_groups" $-      Op $ SizeOp $ CalcNumGroups w64 max_num_groups_key group_size-  num_threads <- letSubExp "num_threads" $ BasicOp $ BinOp (Mul Int32 OverflowUndef) num_groups group_size+      Op $ SizeOp $ CalcNumGroups w max_num_groups_key group_size+  num_threads <-+    letSubExp "num_threads" $+      BasicOp $ BinOp (Mul Int64 OverflowUndef) num_groups group_size   return (num_groups, num_threads)  blockedKernelSize ::@@ -64,12 +66,11 @@ blockedKernelSize desc w = do   group_size <- getSize (desc ++ "_group_size") SizeGroup -  w64 <- letSubExp "w64" $ BasicOp $ ConvOp (SExt Int32 Int64) w-  (_, num_threads) <- numberOfGroups desc w64 group_size+  (_, num_threads) <- numberOfGroups desc w group_size    per_thread_elements <-     letSubExp "per_thread_elements"-      =<< eBinOp (SDivUp Int64 Unsafe) (eSubExp w64) (toExp =<< asIntS Int64 num_threads)+      =<< eBinOp (SDivUp Int64 Unsafe) (eSubExp w) (eSubExp num_threads)    return $ KernelSize per_thread_elements num_threads @@ -87,13 +88,13 @@   letBindNames [chunk_size] $ Op $ SizeOp $ SplitSpace ordering w i elems_per_i   case ordering of     SplitContiguous -> do-      offset <- letSubExp "slice_offset" $ BasicOp $ BinOp (Mul Int32 OverflowUndef) i elems_per_i+      offset <- letSubExp "slice_offset" $ BasicOp $ BinOp (Mul Int64 OverflowUndef) i elems_per_i       zipWithM_ (contiguousSlice offset) split_bound arrs     SplitStrided stride -> zipWithM_ (stridedSlice stride) split_bound arrs   where     contiguousSlice offset slice_name arr = do       arr_t <- lookupType arr-      let slice = fullSlice arr_t [DimSlice offset (Var chunk_size) (constant (1 :: Int32))]+      let slice = fullSlice arr_t [DimSlice offset (Var chunk_size) (constant (1 :: Int64))]       letBindNames [slice_name] $ BasicOp $ Index arr slice      stridedSlice stride slice_name arr = do@@ -132,7 +133,7 @@       red_ts = take num_nonconcat $ lambdaReturnType lam       map_ts = map rowType $ drop num_nonconcat $ lambdaReturnType lam -  per_thread <- asIntS Int32 $ kernelElementsPerThread kernel_size+  per_thread <- asIntS Int64 $ kernelElementsPerThread kernel_size   splitArrays     (paramName chunk_size)     (map paramName arr_params)@@ -175,7 +176,7 @@   m (Lambda Kernels) kerneliseLambda nes lam = do   thread_index <- newVName "thread_index"-  let thread_index_param = Param thread_index $ Prim int32+  let thread_index_param = Param thread_index $ Prim int64       (fold_chunk_param, fold_acc_params, fold_inp_params) =         partitionChunkedFoldParameters (length nes) $ lambdaParams lam @@ -214,8 +215,6 @@    fold_lam' <- kerneliseLambda nes fold_lam -  elems_per_thread_32 <- asIntS Int32 elems_per_thread-   gtid <- newVName "gtid"   space <- mkSegSpace $ ispace ++ [(gtid, num_threads)]   kbody <- fmap (uncurry (flip (KernelBody ()))) $@@ -224,7 +223,7 @@         (chunk_red_pes, chunk_map_pes) <-           blockedPerThread gtid w size ordering fold_lam' (length nes) arrs         let concatReturns pe =-              ConcatReturns split_ordering w elems_per_thread_32 $ patElemName pe+              ConcatReturns split_ordering w elems_per_thread $ patElemName pe         return           ( map (Returns ResultMaySimplify . Var . patElemName) chunk_red_pes               ++ map concatReturns chunk_map_pes@@ -304,24 +303,20 @@ -- array. segThreadCapped :: MonadFreshNames m => MkSegLevel Kernels m segThreadCapped ws desc r = do-  w64 <-+  w <-     letSubExp "nest_size"-      =<< foldBinOp (Mul Int64 OverflowUndef) (intConst Int64 1)-      =<< mapM (asIntS Int64) ws+      =<< foldBinOp (Mul Int64 OverflowUndef) (intConst Int64 1) ws   group_size <- getSize (desc ++ "_group_size") SizeGroup    case r of     ManyThreads -> do       usable_groups <-         letSubExp "segmap_usable_groups"-          . BasicOp-          . ConvOp (SExt Int64 Int32)-          =<< letSubExp "segmap_usable_groups_64"           =<< eBinOp             (SDivUp Int64 Unsafe)-            (eSubExp w64)+            (eSubExp w)             (eSubExp =<< asIntS Int64 group_size)       return $ SegThread (Count usable_groups) (Count group_size) SegNoVirt     NoRecommendation v -> do-      (num_groups, _) <- numberOfGroups desc w64 group_size+      (num_groups, _) <- numberOfGroups desc w group_size       return $ SegThread (Count num_groups) (Count group_size) v
src/Futhark/Pass/ExtractKernels/ToKernels.hs view
@@ -9,6 +9,7 @@     soacsStmToKernels,     scopeForKernels,     scopeForSOACs,+    injectSOACS,   ) where 
+ src/Futhark/Pass/ExtractMulticore.hs view
@@ -0,0 +1,406 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Futhark.Pass.ExtractMulticore (extractMulticore) where++import Control.Monad.Identity+import Control.Monad.Reader+import Control.Monad.State+import Futhark.Analysis.Rephrase+import Futhark.IR+import Futhark.IR.MC+import qualified Futhark.IR.MC as MC+import Futhark.IR.SOACS hiding+  ( Body,+    Exp,+    LParam,+    Lambda,+    Pattern,+    Stm,+  )+import qualified Futhark.IR.SOACS as SOACS+import qualified Futhark.IR.SOACS.Simplify as SOACS+import Futhark.Pass+import Futhark.Pass.ExtractKernels.DistributeNests+import Futhark.Pass.ExtractKernels.ToKernels (injectSOACS)+import Futhark.Tools+import qualified Futhark.Transform.FirstOrderTransform as FOT+import Futhark.Transform.Rename (Rename, renameSomething)+import Futhark.Util (chunks, takeLast)+import Futhark.Util.Log++newtype ExtractM a = ExtractM (ReaderT (Scope MC) (State VNameSource) a)+  deriving+    ( Functor,+      Applicative,+      Monad,+      HasScope MC,+      LocalScope MC,+      MonadFreshNames+    )++-- XXX: throwing away the log here...+instance MonadLogger ExtractM where+  addLog _ = pure ()++indexArray :: VName -> LParam SOACS -> VName -> Stm MC+indexArray i (Param p t) arr =+  Let (Pattern [] [PatElem p t]) (defAux ()) $+    BasicOp $ Index arr $ DimFix (Var i) : map sliceDim (arrayDims t)++mapLambdaToBody ::+  (Body SOACS -> ExtractM (Body MC)) ->+  VName ->+  Lambda SOACS ->+  [VName] ->+  ExtractM (Body MC)+mapLambdaToBody onBody i lam arrs = do+  let indexings = zipWith (indexArray i) (lambdaParams lam) arrs+  Body () stms res <- inScopeOf indexings $ onBody $ lambdaBody lam+  return $ Body () (stmsFromList indexings <> stms) res++mapLambdaToKernelBody ::+  (Body SOACS -> ExtractM (Body MC)) ->+  VName ->+  Lambda SOACS ->+  [VName] ->+  ExtractM (KernelBody MC)+mapLambdaToKernelBody onBody i lam arrs = do+  Body () stms res <- mapLambdaToBody onBody i lam arrs+  return $ KernelBody () stms $ map (Returns ResultMaySimplify) res++reduceToSegBinOp :: Reduce SOACS -> ExtractM (Stms MC, SegBinOp MC)+reduceToSegBinOp (Reduce comm lam nes) = do+  ((lam', nes', shape), stms) <- runBinder $ determineReduceOp lam nes+  lam'' <- transformLambda lam'+  return (stms, SegBinOp comm lam'' nes' shape)++scanToSegBinOp :: Scan SOACS -> ExtractM (Stms MC, SegBinOp MC)+scanToSegBinOp (Scan lam nes) = do+  ((lam', nes', shape), stms) <- runBinder $ determineReduceOp lam nes+  lam'' <- transformLambda lam'+  return (stms, SegBinOp Noncommutative lam'' nes' shape)++histToSegBinOp :: SOACS.HistOp SOACS -> ExtractM (Stms MC, MC.HistOp MC)+histToSegBinOp (SOACS.HistOp num_bins rf dests nes op) = do+  ((op', nes', shape), stms) <- runBinder $ determineReduceOp op nes+  op'' <- transformLambda op'+  return (stms, MC.HistOp num_bins rf dests nes' shape op'')++mkSegSpace :: MonadFreshNames m => SubExp -> m (VName, SegSpace)+mkSegSpace w = do+  flat <- newVName "flat_tid"+  gtid <- newVName "gtid"+  let space = SegSpace flat [(gtid, w)]+  return (gtid, space)++transformLoopForm :: LoopForm SOACS -> LoopForm MC+transformLoopForm (WhileLoop cond) = WhileLoop cond+transformLoopForm (ForLoop i it bound params) = ForLoop i it bound params++transformStm :: Stm SOACS -> ExtractM (Stms MC)+transformStm (Let pat aux (BasicOp op)) =+  pure $ oneStm $ Let pat aux $ BasicOp op+transformStm (Let pat aux (Apply f args ret info)) =+  pure $ oneStm $ Let pat aux $ Apply f args ret info+transformStm (Let pat aux (DoLoop ctx val form body)) = do+  let form' = transformLoopForm form+  body' <-+    localScope+      ( scopeOfFParams (map fst ctx)+          <> scopeOfFParams (map fst val)+          <> scopeOf form'+      )+      $ transformBody body+  return $ oneStm $ Let pat aux $ DoLoop ctx val form' body'+transformStm (Let pat aux (If cond tbranch fbranch ret)) =+  oneStm . Let pat aux+    <$> (If cond <$> transformBody tbranch <*> transformBody fbranch <*> pure ret)+transformStm (Let pat aux (Op op)) =+  fmap (certify (stmAuxCerts aux)) <$> transformSOAC pat (stmAuxAttrs aux) op++transformLambda :: Lambda SOACS -> ExtractM (Lambda MC)+transformLambda (Lambda params body ret) =+  Lambda params+    <$> localScope (scopeOfLParams params) (transformBody body)+    <*> pure ret++transformStms :: Stms SOACS -> ExtractM (Stms MC)+transformStms stms =+  case stmsHead stms of+    Nothing -> return mempty+    Just (stm, stms') -> do+      stm_stms <- transformStm stm+      inScopeOf stm_stms $ (stm_stms <>) <$> transformStms stms'++transformBody :: Body SOACS -> ExtractM (Body MC)+transformBody (Body () stms res) =+  Body () <$> transformStms stms <*> pure res++sequentialiseBody :: Body SOACS -> ExtractM (Body MC)+sequentialiseBody = pure . runIdentity . rephraseBody toMC+  where+    toMC = injectSOACS OtherOp++transformFunDef :: FunDef SOACS -> ExtractM (FunDef MC)+transformFunDef (FunDef entry attrs name rettype params body) = do+  body' <- localScope (scopeOfFParams params) $ transformBody body+  return $ FunDef entry attrs name rettype params body'++-- Sets the chunk size to one.+unstreamLambda :: Attrs -> [SubExp] -> Lambda SOACS -> ExtractM (Lambda SOACS)+unstreamLambda attrs nes lam = do+  let (chunk_param, acc_params, slice_params) =+        partitionChunkedFoldParameters (length nes) (lambdaParams lam)++  inp_params <- forM slice_params $ \(Param p t) ->+    newParam (baseString p) (rowType t)++  body <- runBodyBinder $+    localScope (scopeOfLParams inp_params) $ do+      letBindNames [paramName chunk_param] $+        BasicOp $ SubExp $ intConst Int64 1++      forM_ (zip acc_params nes) $ \(p, ne) ->+        letBindNames [paramName p] $ BasicOp $ SubExp ne++      forM_ (zip slice_params inp_params) $ \(slice, v) ->+        letBindNames [paramName slice] $+          BasicOp $ ArrayLit [Var $ paramName v] (paramType v)++      (red_res, map_res) <- splitAt (length nes) <$> bodyBind (lambdaBody lam)++      map_res' <- forM map_res $ \se -> do+        v <- letExp "map_res" $ BasicOp $ SubExp se+        v_t <- lookupType v+        letSubExp "chunk" $+          BasicOp $+            Index v $+              fullSlice v_t [DimFix $ intConst Int64 0]++      pure $ resultBody $ red_res <> map_res'++  let (red_ts, map_ts) = splitAt (length nes) $ lambdaReturnType lam+      map_lam =+        Lambda+          { lambdaReturnType = red_ts ++ map rowType map_ts,+            lambdaParams = inp_params,+            lambdaBody = body+          }++  soacs_scope <- castScope <$> askScope+  map_lam' <- runReaderT (SOACS.simplifyLambda map_lam) soacs_scope++  if "sequential_inner" `inAttrs` attrs+    then FOT.transformLambda map_lam'+    else return map_lam'++-- Code generation for each parallel basic block is parameterised over+-- how we handle parallelism in the body (whether it's sequentialised+-- by keeping it as SOACs, or turned into SegOps).++data NeedsRename = DoRename | DoNotRename++renameIfNeeded :: Rename a => NeedsRename -> a -> ExtractM a+renameIfNeeded DoRename = renameSomething+renameIfNeeded DoNotRename = pure++transformMap ::+  NeedsRename ->+  (Body SOACS -> ExtractM (Body MC)) ->+  SubExp ->+  Lambda SOACS ->+  [VName] ->+  ExtractM (SegOp () MC)+transformMap rename onBody w map_lam arrs = do+  (gtid, space) <- mkSegSpace w+  kbody <- mapLambdaToKernelBody onBody gtid map_lam arrs+  renameIfNeeded rename $+    SegMap () space (lambdaReturnType map_lam) kbody++transformRedomap ::+  NeedsRename ->+  (Body SOACS -> ExtractM (Body MC)) ->+  SubExp ->+  [Reduce SOACS] ->+  Lambda SOACS ->+  [VName] ->+  ExtractM ([Stms MC], SegOp () MC)+transformRedomap rename onBody w reds map_lam arrs = do+  (gtid, space) <- mkSegSpace w+  kbody <- mapLambdaToKernelBody onBody gtid map_lam arrs+  (reds_stms, reds') <- unzip <$> mapM reduceToSegBinOp reds+  op' <-+    renameIfNeeded rename $+      SegRed () space reds' (lambdaReturnType map_lam) kbody+  return (reds_stms, op')++transformHist ::+  NeedsRename ->+  (Body SOACS -> ExtractM (Body MC)) ->+  SubExp ->+  [SOACS.HistOp SOACS] ->+  Lambda SOACS ->+  [VName] ->+  ExtractM ([Stms MC], SegOp () MC)+transformHist rename onBody w hists map_lam arrs = do+  (gtid, space) <- mkSegSpace w+  kbody <- mapLambdaToKernelBody onBody gtid map_lam arrs+  (hists_stms, hists') <- unzip <$> mapM histToSegBinOp hists+  op' <-+    renameIfNeeded rename $+      SegHist () space hists' (lambdaReturnType map_lam) kbody+  return (hists_stms, op')++transformParStream ::+  NeedsRename ->+  (Body SOACS -> ExtractM (Body MC)) ->+  SubExp ->+  Commutativity ->+  Lambda SOACS ->+  [SubExp] ->+  Lambda SOACS ->+  [VName] ->+  ExtractM (Stms MC, SegOp () MC)+transformParStream rename onBody w comm red_lam red_nes map_lam arrs = do+  (gtid, space) <- mkSegSpace w+  kbody <- mapLambdaToKernelBody onBody gtid map_lam arrs+  (red_stms, red) <- reduceToSegBinOp $ Reduce comm red_lam red_nes+  op <-+    renameIfNeeded rename $+      SegRed () space [red] (lambdaReturnType map_lam) kbody+  return (red_stms, op)++transformSOAC :: Pattern SOACS -> Attrs -> SOAC SOACS -> ExtractM (Stms MC)+transformSOAC pat _ (Screma w form arrs)+  | Just lam <- isMapSOAC form = do+    seq_op <- transformMap DoNotRename sequentialiseBody w lam arrs+    if lambdaContainsParallelism lam+      then do+        par_op <- transformMap DoRename transformBody w lam arrs+        return $ oneStm (Let pat (defAux ()) $ Op $ ParOp (Just par_op) seq_op)+      else return $ oneStm (Let pat (defAux ()) $ Op $ ParOp Nothing seq_op)+  | Just (reds, map_lam) <- isRedomapSOAC form = do+    (seq_reds_stms, seq_op) <-+      transformRedomap DoNotRename sequentialiseBody w reds map_lam arrs+    if lambdaContainsParallelism map_lam+      then do+        (par_reds_stms, par_op) <-+          transformRedomap DoRename transformBody w reds map_lam arrs+        return $+          mconcat (seq_reds_stms <> par_reds_stms)+            <> oneStm (Let pat (defAux ()) $ Op $ ParOp (Just par_op) seq_op)+      else+        return $+          mconcat seq_reds_stms+            <> oneStm (Let pat (defAux ()) $ Op $ ParOp Nothing seq_op)+  | Just (scans, map_lam) <- isScanomapSOAC form = do+    (gtid, space) <- mkSegSpace w+    kbody <- mapLambdaToKernelBody transformBody gtid map_lam arrs+    (scans_stms, scans') <- unzip <$> mapM scanToSegBinOp scans+    return $+      mconcat scans_stms+        <> oneStm+          ( Let pat (defAux ()) $+              Op $+                ParOp Nothing $+                  SegScan () space scans' (lambdaReturnType map_lam) kbody+          )+  | otherwise = do+    -- This screma is too complicated for us to immediately do+    -- anything, so split it up and try again.+    scope <- castScope <$> askScope+    transformStms =<< runBinderT_ (dissectScrema pat w form arrs) scope+transformSOAC pat _ (Scatter w lam ivs dests) = do+  (gtid, space) <- mkSegSpace w++  Body () kstms res <- mapLambdaToBody transformBody gtid lam ivs++  let (dests_ws, dests_ns, dests_vs) = unzip3 dests+      (i_res, v_res) = splitAt (sum dests_ns) res+      rets = takeLast (length dests) $ lambdaReturnType lam+      kres = do+        (a_w, a, is_vs) <-+          zip3 dests_ws dests_vs $+            chunks dests_ns $ zip i_res v_res+        return $ WriteReturns [a_w] a [([DimFix i], v) | (i, v) <- is_vs]+      kbody = KernelBody () kstms kres+  return $+    oneStm $+      Let pat (defAux ()) $+        Op $+          ParOp Nothing $+            SegMap () space rets kbody+transformSOAC pat _ (Hist w hists map_lam arrs) = do+  (seq_hist_stms, seq_op) <-+    transformHist DoNotRename sequentialiseBody w hists map_lam arrs++  if lambdaContainsParallelism map_lam+    then do+      (par_hist_stms, par_op) <-+        transformHist DoRename transformBody w hists map_lam arrs+      return $+        mconcat (seq_hist_stms <> par_hist_stms)+          <> oneStm (Let pat (defAux ()) $ Op $ ParOp (Just par_op) seq_op)+    else+      return $+        mconcat seq_hist_stms+          <> oneStm (Let pat (defAux ()) $ Op $ ParOp Nothing seq_op)+transformSOAC pat attrs (Stream w (Parallel _ comm red_lam red_nes) fold_lam arrs)+  | not $ null red_nes = do+    map_lam <- unstreamLambda attrs red_nes fold_lam+    (seq_red_stms, seq_op) <-+      transformParStream+        DoNotRename+        sequentialiseBody+        w+        comm+        red_lam+        red_nes+        map_lam+        arrs++    if lambdaContainsParallelism map_lam+      then do+        (par_red_stms, par_op) <-+          transformParStream+            DoRename+            transformBody+            w+            comm+            red_lam+            red_nes+            map_lam+            arrs+        return $+          seq_red_stms <> par_red_stms+            <> oneStm (Let pat (defAux ()) $ Op $ ParOp (Just par_op) seq_op)+      else+        return $+          seq_red_stms+            <> oneStm (Let pat (defAux ()) $ Op $ ParOp Nothing seq_op)+transformSOAC pat _ (Stream w form lam arrs) = do+  -- Just remove the stream and transform the resulting stms.+  soacs_scope <- castScope <$> askScope+  stream_stms <-+    flip runBinderT_ soacs_scope $+      sequentialStreamWholeArray pat w (getStreamAccums form) lam arrs+  transformStms stream_stms++transformProg :: Prog SOACS -> PassM (Prog MC)+transformProg (Prog consts funs) =+  modifyNameSource $ runState (runReaderT m mempty)+  where+    ExtractM m = do+      consts' <- transformStms consts+      funs' <- inScopeOf consts' $ mapM transformFunDef funs+      return $ Prog consts' funs'++extractMulticore :: Pass SOACS MC+extractMulticore =+  Pass+    { passName = "extract multicore parallelism",+      passDescription = "Extract multicore parallelism",+      passFunction = transformProg+    }
src/Futhark/Pass/KernelBabysitting.hs view
@@ -118,7 +118,7 @@     letSubExp "num_threads" $       BasicOp $         BinOp-          (Mul Int32 OverflowUndef)+          (Mul Int64 OverflowUndef)           (unCount $ segNumGroups lvl)           (unCount $ segGroupSize lvl)   evalStateT@@ -310,11 +310,10 @@                 if null is                   then untyped $ pe32 num_threads                   else-                    coerceIntPrimExp Int32 $-                      untyped $-                        product $-                          map pe32 $-                            drop (length is) thread_gdims+                    untyped $+                      product $+                        map pe64 $+                          drop (length is) thread_gdims           replace =<< lift (rearrangeSlice (length is) (arraySize (length is) t) num_chunks arr)          -- Everything is fine... assuming that the array is in row-major@@ -456,7 +455,7 @@    per_chunk <-     letSubExp "per_chunk" $-      BasicOp $ BinOp (SQuot Int32 Unsafe) w_padded num_chunks'+      BasicOp $ BinOp (SQuot Int64 Unsafe) w_padded num_chunks'   arr_t <- lookupType arr   arr_padded <- padArray w_padded padding arr_t   rearrange num_chunks' w_padded per_chunk (baseString arr) arr_padded arr_t@@ -489,7 +488,7 @@               (map DimCoercion pre_dims ++ map DimNew (w_padded : post_dims))               arr_extradim_tr       letExp (arr_name <> "_inv_tr_init")-        =<< eSliceArray d arr_inv_tr (eSubExp $ constant (0 :: Int32)) (eSubExp w)+        =<< eSliceArray d arr_inv_tr (eSubExp $ constant (0 :: Int64)) (eSubExp w)  paddedScanReduceInput ::   MonadBinder m =>@@ -499,8 +498,8 @@ paddedScanReduceInput w stride = do   w_padded <-     letSubExp "padded_size"-      =<< eRoundToMultipleOf Int32 (eSubExp w) (eSubExp stride)-  padding <- letSubExp "padding" $ BasicOp $ BinOp (Sub Int32 OverflowUndef) w_padded w+      =<< eRoundToMultipleOf Int64 (eSubExp w) (eSubExp stride)+  padding <- letSubExp "padding" $ BasicOp $ BinOp (Sub Int64 OverflowUndef) w_padded w   return (w_padded, padding)  --- Computing variance.
src/Futhark/Pass/Simplify.hs view
@@ -4,14 +4,18 @@   ( simplify,     simplifySOACS,     simplifySeq,+    simplifyMC,     simplifyKernels,     simplifyKernelsMem,     simplifySeqMem,+    simplifyMCMem,   ) where  import qualified Futhark.IR.Kernels.Simplify as Kernels import qualified Futhark.IR.KernelsMem as KernelsMem+import qualified Futhark.IR.MC as MC+import qualified Futhark.IR.MCMem as MCMem import qualified Futhark.IR.SOACS.Simplify as SOACS import qualified Futhark.IR.Seq as Seq import qualified Futhark.IR.SeqMem as SeqMem@@ -32,8 +36,14 @@ simplifySeq :: Pass Seq.Seq Seq.Seq simplifySeq = simplify Seq.simplifyProg +simplifyMC :: Pass MC.MC MC.MC+simplifyMC = simplify MC.simplifyProg+ simplifyKernelsMem :: Pass KernelsMem.KernelsMem KernelsMem.KernelsMem simplifyKernelsMem = simplify KernelsMem.simplifyProg  simplifySeqMem :: Pass SeqMem.SeqMem SeqMem.SeqMem simplifySeqMem = simplify SeqMem.simplifyProg++simplifyMCMem :: Pass MCMem.MCMem MCMem.MCMem+simplifyMCMem = simplify MCMem.simplifyProg
src/Futhark/Passes.hs view
@@ -7,12 +7,16 @@     kernelsPipeline,     sequentialCpuPipeline,     gpuPipeline,+    mcPipeline,+    multicorePipeline,   ) where  import Control.Category ((>>>)) import Futhark.IR.Kernels (Kernels) import Futhark.IR.KernelsMem (KernelsMem)+import Futhark.IR.MC (MC)+import Futhark.IR.MCMem (MCMem) import Futhark.IR.SOACS (SOACS) import Futhark.IR.Seq (Seq) import Futhark.IR.SeqMem (SeqMem)@@ -26,8 +30,10 @@ import Futhark.Optimise.Unstream import Futhark.Pass.ExpandAllocations import qualified Futhark.Pass.ExplicitAllocations.Kernels as Kernels+import qualified Futhark.Pass.ExplicitAllocations.MC as MC import qualified Futhark.Pass.ExplicitAllocations.Seq as Seq import Futhark.Pass.ExtractKernels+import Futhark.Pass.ExtractMulticore import Futhark.Pass.FirstOrderTransform import Futhark.Pass.KernelBabysitting import Futhark.Pass.Simplify@@ -59,10 +65,10 @@       [ simplifyKernels,         babysitKernels,         tileLoops,-        unstream,+        unstreamKernels,         performCSE True,         simplifyKernels,-        sink,+        sinkKernels,         inPlaceLoweringKernels       ] @@ -93,8 +99,33 @@       [ simplifyKernelsMem,         performCSE False,         simplifyKernelsMem,-        doubleBuffer,+        doubleBufferKernels,         simplifyKernelsMem,         expandAllocations,         simplifyKernelsMem+      ]++mcPipeline :: Pipeline SOACS MC+mcPipeline =+  standardPipeline+    >>> onePass extractMulticore+    >>> passes+      [ simplifyMC,+        unstreamMC,+        performCSE True,+        simplifyMC,+        sinkMC,+        inPlaceLoweringMC+      ]++multicorePipeline :: Pipeline SOACS MCMem+multicorePipeline =+  mcPipeline+    >>> onePass MC.explicitAllocations+    >>> passes+      [ simplifyMCMem,+        performCSE False,+        simplifyMCMem,+        doubleBufferMC,+        simplifyMCMem       ]
src/Futhark/Transform/FirstOrderTransform.hs view
@@ -142,7 +142,7 @@             zip mapout_params $ map Var map_arrs           ]   i <- newVName "i"-  let loopform = ForLoop i Int32 w []+  let loopform = ForLoop i Int64 w []    loop_body <- runBodyBinder $     localScope (scopeOfFParams $ map fst merge) $@@ -220,10 +220,10 @@    i <- newVName "i" -  let loop_form = ForLoop i Int32 w []+  let loop_form = ForLoop i Int64 w []    letBindNames [paramName chunk_size_param] $-    BasicOp $ SubExp $ intConst Int32 1+    BasicOp $ SubExp $ intConst Int64 1    loop_body <- runBodyBinder $     localScope@@ -232,7 +232,7 @@       )       $ do         let slice =-              [DimSlice (Var i) (Var (paramName chunk_size_param)) (intConst Int32 1)]+              [DimSlice (Var i) (Var (paramName chunk_size_param)) (intConst Int64 1)]         forM_ (zip chunk_params arrs) $ \(p, arr) ->           letBindNames [paramName p] $             BasicOp $@@ -265,7 +265,7 @@   let merge = loopMerge asOuts $ map Var as_vs   loopBody <- runBodyBinder $     localScope-      ( M.insert iter (IndexName Int32) $+      ( M.insert iter (IndexName Int64) $           scopeOfFParams $ map fst merge       )       $ do@@ -283,7 +283,7 @@            foldM saveInArray arr $ zip indexes' values'         return $ resultBody (map Var ress)-  letBind pat $ DoLoop [] merge (ForLoop iter Int32 len []) loopBody+  letBind pat $ DoLoop [] merge (ForLoop iter Int64 len []) loopBody transformSOAC pat (Hist len ops bucket_fun imgs) = do   iter <- newVName "iter" @@ -295,7 +295,7 @@   -- Bind lambda-bodies for operators.   loopBody <- runBodyBinder $     localScope-      ( M.insert iter (IndexName Int32) $+      ( M.insert iter (IndexName Int64) $           scopeOfFParams $ map fst merge       )       $ do@@ -345,7 +345,7 @@         return $ resultBody $ map Var $ concat hists_out''    -- Wrap up the above into a for-loop.-  letBind pat $ DoLoop [] merge (ForLoop iter Int32 len []) loopBody+  letBind pat $ DoLoop [] merge (ForLoop iter Int64 len []) loopBody  -- | Recursively first-order-transform a lambda. transformLambda ::
src/Futhark/Transform/Rename.hs view
@@ -20,6 +20,7 @@     renameBody,     renameLambda,     renamePattern,+    renameSomething,      -- * Renaming annotations     RenameM,@@ -111,6 +112,13 @@ renamePattern = modifyNameSource . runRenamer . rename'   where     rename' pat = bind (patternNames pat) $ rename pat++-- | Rename the bound variables in something (does not affect free variables).+renameSomething ::+  (Rename a, MonadFreshNames m) =>+  a ->+  m a+renameSomething = modifyNameSource . runRenamer . rename  newtype RenameEnv = RenameEnv {envNameMap :: M.Map VName VName} 
src/Futhark/TypeCheck.hs view
@@ -49,6 +49,7 @@     consume,     consumeOnlyParams,     binding,+    alternative,   ) where @@ -810,17 +811,17 @@   require [Prim (elemType src_t) `arrayOfShape` Shape (sliceDims idxes)] se   consume =<< lookupAliases src checkBasicOp (Iota e x s et) = do-  require [Prim int32] e+  require [Prim int64] e   require [Prim $ IntType et] x   require [Prim $ IntType et] s checkBasicOp (Replicate (Shape dims) valexp) = do-  mapM_ (require [Prim int32]) dims+  mapM_ (require [Prim int64]) dims   void $ checkSubExp valexp checkBasicOp (Scratch _ shape) =   mapM_ checkSubExp shape checkBasicOp (Reshape newshape arrexp) = do   rank <- arrayRank <$> checkArrIdent arrexp-  mapM_ (require [Prim int32] . newDim) newshape+  mapM_ (require [Prim int64] . newDim) newshape   zipWithM_ (checkDimChange rank) newshape [0 ..]   where     checkDimChange _ (DimNew _) _ =@@ -845,7 +846,7 @@ checkBasicOp (Rotate rots arr) = do   arrt <- lookupType arr   let rank = arrayRank arrt-  mapM_ (require [Prim int32]) rots+  mapM_ (require [Prim int64]) rots   when (length rots /= rank) $     bad $       TypeError $@@ -870,7 +871,7 @@           ++ pretty arr1t           ++ " and "           ++ intercalate ", " (map pretty arr2ts)-  require [Prim int32] ressize+  require [Prim int64] ressize checkBasicOp (Copy e) =   void $ checkArrIdent e checkBasicOp (Manifest perm arr) =@@ -1054,7 +1055,7 @@   Checkable lore =>   TypeBase Shape u ->   TypeM lore ()-checkType (Mem (ScalarSpace d _)) = mapM_ (require [Prim int32]) d+checkType (Mem (ScalarSpace d _)) = mapM_ (require [Prim int64]) d checkType t = mapM_ checkSubExp $ arrayDims t  checkExtType ::@@ -1106,8 +1107,8 @@   Checkable lore =>   DimIndex SubExp ->   TypeM lore ()-checkDimIndex (DimFix i) = require [Prim int32] i-checkDimIndex (DimSlice i n s) = mapM_ (require [Prim int32]) [i, n, s]+checkDimIndex (DimFix i) = require [Prim int64] i+checkDimIndex (DimSlice i n s) = mapM_ (require [Prim int64]) [i, n, s]  checkStm ::   Checkable lore =>@@ -1199,7 +1200,7 @@    let ctx_vals = zip ctx_res ctx_ts       instantiateExt i = case maybeNth i ctx_vals of-        Just (se, Prim (IntType Int32)) -> return se+        Just (se, Prim (IntType Int64)) -> return se         _ -> problem    rettype' <- instantiateShapes instantiateExt rettype
src/Language/Futhark/Interpreter.hs view
@@ -80,7 +80,7 @@  type Stack = [StackFrame] -type Sizes = M.Map VName Int32+type Sizes = M.Map VName Int64  -- | The monad in which evaluation takes place. newtype EvalM a@@ -119,14 +119,14 @@ lookupImport :: FilePath -> EvalM (Maybe Env) lookupImport f = asks $ M.lookup f . snd -putExtSize :: VName -> Int32 -> EvalM ()+putExtSize :: VName -> Int64 -> EvalM () putExtSize v x = modify $ M.insert v x  getSizes :: EvalM Sizes getSizes = get  extSizeEnv :: EvalM Env-extSizeEnv = i32Env <$> getSizes+extSizeEnv = i64Env <$> getSizes  prettyRecord :: Pretty a => M.Map Name a -> Doc prettyRecord m@@ -149,7 +149,7 @@   | ShapeSum (M.Map Name [Shape d])   deriving (Eq, Show, Functor, Foldable, Traversable) -type ValueShape = Shape Int32+type ValueShape = Shape Int64  instance Pretty d => Pretty (Shape d) where   ppr ShapeLeaf = mempty@@ -180,7 +180,7 @@     go _ =       ShapeLeaf -structTypeShape :: M.Map VName ValueShape -> StructType -> Shape (Maybe Int32)+structTypeShape :: M.Map VName ValueShape -> StructType -> Shape (Maybe Int64) structTypeShape shapes = fmap dim . typeShape shapes'   where     dim (ConstDim d) = Just $ fromIntegral d@@ -212,10 +212,10 @@      matchDims (NamedDim (QualName _ d1)) (ConstDim d2)       | d1 `elem` names =-        i32Env $ M.singleton d1 $ fromIntegral d2+        i64Env $ M.singleton d1 $ fromIntegral d2     matchDims _ _ = mempty -resolveExistentials :: [VName] -> StructType -> ValueShape -> M.Map VName Int32+resolveExistentials :: [VName] -> StructType -> ValueShape -> M.Map VName Int64 resolveExistentials names = match   where     match (Scalar (Record poly_fields)) (ShapeRecord fields) =@@ -280,7 +280,7 @@ valueShape (ValueSum shape _ _) = shape valueShape _ = ShapeLeaf -checkShape :: Shape (Maybe Int32) -> ValueShape -> Maybe ValueShape+checkShape :: Shape (Maybe Int64) -> ValueShape -> Maybe ValueShape checkShape (ShapeDim Nothing shape1) (ShapeDim d2 shape2) =   ShapeDim d2 <$> checkShape shape1 shape2 checkShape (ShapeDim (Just d1) shape1) (ShapeDim d2 shape2) = do@@ -319,7 +319,7 @@  -- | Create an array value; failing if that would result in an -- irregular array.-mkArray :: TypeBase Int32 () -> [Value] -> Maybe Value+mkArray :: TypeBase Int64 () -> [Value] -> Maybe Value mkArray t [] =   return $ toArray (typeShape mempty t) [] mkArray _ (v : vs) = do@@ -350,8 +350,8 @@ asSigned (ValuePrim (SignedValue v)) = v asSigned v = error $ "Unexpected not a signed integer: " ++ pretty v -asInt32 :: Value -> Int32-asInt32 = fromIntegral . asInteger+asInt64 :: Value -> Int64+asInt64 = fromIntegral . asInteger  asBool :: Value -> Bool asBool (ValuePrim (BoolValue x)) = x@@ -434,12 +434,12 @@   where     tbind = T.TypeAbbr Unlifted [] -i32Env :: M.Map VName Int32 -> Env-i32Env = valEnv . M.map f+i64Env :: M.Map VName Int64 -> Env+i64Env = valEnv . M.map f   where     f x =-      ( Just $ T.BoundV [] $ Scalar $ Prim $ Signed Int32,-        ValuePrim $ SignedValue $ Int32Value x+      ( Just $ T.BoundV [] $ Scalar $ Prim $ Signed Int64,+        ValuePrim $ SignedValue $ Int64Value x       )  instance Show InterpreterError where@@ -538,8 +538,8 @@ patternMatch _ _ _ = mzero  data Indexing-  = IndexingFix Int32-  | IndexingSlice (Maybe Int32) (Maybe Int32) (Maybe Int32)+  = IndexingFix Int64+  | IndexingSlice (Maybe Int64) (Maybe Int64) (Maybe Int64)  instance Pretty Indexing where   ppr (IndexingFix i) = ppr i@@ -556,10 +556,10 @@     maybe mempty ppr i <> text ":"  indexesFor ::-  Maybe Int32 ->-  Maybe Int32 ->-  Maybe Int32 ->-  Int32 ->+  Maybe Int64 ->+  Maybe Int64 ->+  Maybe Int64 ->+  Int64 ->   Maybe [Int] indexesFor start end stride n   | (start', end', stride') <- slice,@@ -640,11 +640,11 @@  evalDimIndex :: Env -> DimIndex -> EvalM Indexing evalDimIndex env (DimFix x) =-  IndexingFix . asInt32 <$> eval env x+  IndexingFix . asInt64 <$> eval env x evalDimIndex env (DimSlice start end stride) =-  IndexingSlice <$> traverse (fmap asInt32 . eval env) start-    <*> traverse (fmap asInt32 . eval env) end-    <*> traverse (fmap asInt32 . eval env) stride+  IndexingSlice <$> traverse (fmap asInt64 . eval env) start+    <*> traverse (fmap asInt64 . eval env) end+    <*> traverse (fmap asInt64 . eval env) stride  evalIndex :: SrcLoc -> Env -> [Indexing] -> Value -> EvalM Value evalIndex loc env is arr = do@@ -670,7 +670,7 @@    in arrayOf et' shape' u   where     evalDim (NamedDim qn)-      | Just (TermValue _ (ValuePrim (SignedValue (Int32Value x)))) <-+      | Just (TermValue _ (ValuePrim (SignedValue (Int64Value x)))) <-           lookupVar qn env =         ConstDim $ fromIntegral x     evalDim d = d@@ -742,7 +742,7 @@             | null missing_sizes = env'             | otherwise =               env'-                <> i32Env+                <> i64Env                   ( resolveExistentials                       missing_sizes                       (patternStructType p)@@ -786,7 +786,7 @@ evalArg env e ext = do   v <- eval env e   case ext of-    Just ext' -> putExtSize ext' $ asInt32 v+    Just ext' -> putExtSize ext' $ asInt64 v     Nothing -> return ()   return v @@ -1037,7 +1037,7 @@               sparams               (patternStructType pat)               (valueShape v)-       in matchPattern (i32Env sparams' <> env) pat v+       in matchPattern (i64Env sparams' <> env) pat v      inc = (`P.doAdd` Int64Value 1)     zero = (`P.doMul` Int64Value 0)@@ -1051,7 +1051,7 @@             ( valEnv                 ( M.singleton                     iv-                    ( Just $ T.BoundV [] $ Scalar $ Prim $ Signed Int32,+                    ( Just $ T.BoundV [] $ Scalar $ Prim $ Signed Int64,                       ValuePrim (SignedValue i)                     )                 )@@ -1579,7 +1579,7 @@               toTuple                 [ toArray' rowshape $ concat parts,                   toArray' rowshape $-                    map (ValuePrim . SignedValue . Int32Value . genericLength) parts+                    map (ValuePrim . SignedValue . Int64Value . genericLength) parts                 ]          pack . map reverse@@ -1635,8 +1635,8 @@     def "unflatten" = Just $       fun3t $ \n m xs -> do         let (ShapeDim _ innershape, xs') = fromArray xs-            rowshape = ShapeDim (asInt32 m) innershape-            shape = ShapeDim (asInt32 n) rowshape+            rowshape = ShapeDim (asInt64 m) innershape+            shape = ShapeDim (asInt64 n) rowshape         return $ toArray shape $ map (toArray rowshape) $ chunk (asInt m) xs'     def "opaque" = Just $ fun1 return     def "trace" = Just $ fun1 $ \v -> trace v >> return v@@ -1652,7 +1652,7 @@       return $ T.TypeAbbr Unlifted [] $ Scalar $ Prim t      stream f arg@(ValueArray _ xs) =-      let n = ValuePrim $ SignedValue $ Int32Value $ arrayLength xs+      let n = ValuePrim $ SignedValue $ Int64Value $ arrayLength xs        in apply2 noLoc mempty f n arg     stream _ arg = error $ "Cannot stream: " ++ pretty arg 
src/Language/Futhark/Parser/Parser.y view
@@ -974,7 +974,7 @@            | '[' ']'              {% emptyArrayError $1 } -Dim :: { Int32 }+Dim :: { Int64 } Dim : intlit { let L _ (INTLIT num) = $1 in fromInteger num }  ValueType :: { ValueType }
src/Language/Futhark/Pretty.hs view
@@ -115,7 +115,7 @@ instance Pretty (ShapeDecl ()) where   ppr (ShapeDecl ds) = mconcat $ replicate (length ds) $ text "[]" -instance Pretty (ShapeDecl Int32) where+instance Pretty (ShapeDecl Int64) where   ppr (ShapeDecl ds) = mconcat (map (brackets . ppr) ds)  instance Pretty (ShapeDecl Bool) where
src/Language/Futhark/Prop.hs view
@@ -832,8 +832,8 @@              ( "unflatten",                IntrinsicPolyFun                  [tp_a]-                 [ Scalar $ Prim $ Signed Int32,-                   Scalar $ Prim $ Signed Int32,+                 [ Scalar $ Prim $ Signed Int64,+                   Scalar $ Prim $ Signed Int64,                    Array () Nonunique t_a (rank 1)                  ]                  $ Array () Nonunique t_a (rank 2)@@ -847,7 +847,7 @@              ( "rotate",                IntrinsicPolyFun                  [tp_a]-                 [Scalar $ Prim $ Signed Int32, arr_a]+                 [Scalar $ Prim $ Signed Int64, arr_a]                  arr_a              ),              ("transpose", IntrinsicPolyFun [tp_a] [arr_2d_a] arr_2d_a),@@ -855,7 +855,7 @@                IntrinsicPolyFun                  [tp_a]                  [ Array () Unique t_a (rank 1),-                   Array () Nonunique (Prim $ Signed Int32) (rank 1),+                   Array () Nonunique (Prim $ Signed Int64) (rank 1),                    Array () Nonunique t_a (rank 1)                  ]                  $ Array () Unique t_a (rank 1)@@ -865,11 +865,11 @@              ( "hist",                IntrinsicPolyFun                  [tp_a]-                 [ Scalar $ Prim $ Signed Int32,+                 [ Scalar $ Prim $ Signed Int64,                    uarr_a,                    Scalar t_a `arr` (Scalar t_a `arr` Scalar t_a),                    Scalar t_a,-                   Array () Nonunique (Prim $ Signed Int32) (rank 1),+                   Array () Nonunique (Prim $ Signed Int64) (rank 1),                    arr_a                  ]                  uarr_a@@ -897,28 +897,28 @@                IntrinsicPolyFun                  [tp_a]                  [ Scalar (Prim $ Signed Int32),-                   Scalar t_a `arr` Scalar (Prim $ Signed Int32),+                   Scalar t_a `arr` Scalar (Prim $ Signed Int64),                    arr_a                  ]-                 $ tupleRecord [uarr_a, Array () Unique (Prim $ Signed Int32) (rank 1)]+                 $ tupleRecord [uarr_a, Array () Unique (Prim $ Signed Int64) (rank 1)]              ),              ( "map_stream",                IntrinsicPolyFun                  [tp_a, tp_b]-                 [Scalar (Prim $ Signed Int32) `karr` (arr_ka `arr` arr_kb), arr_a]+                 [Scalar (Prim $ Signed Int64) `karr` (arr_ka `arr` arr_kb), arr_a]                  uarr_b              ),              ( "map_stream_per",                IntrinsicPolyFun                  [tp_a, tp_b]-                 [Scalar (Prim $ Signed Int32) `karr` (arr_ka `arr` arr_kb), arr_a]+                 [Scalar (Prim $ Signed Int64) `karr` (arr_ka `arr` arr_kb), arr_a]                  uarr_b              ),              ( "reduce_stream",                IntrinsicPolyFun                  [tp_a, tp_b]                  [ Scalar t_b `arr` (Scalar t_b `arr` Scalar t_b),-                   Scalar (Prim $ Signed Int32) `karr` (arr_ka `arr` Scalar t_b),+                   Scalar (Prim $ Signed Int64) `karr` (arr_ka `arr` Scalar t_b),                    arr_a                  ]                  $ Scalar t_b@@ -927,7 +927,7 @@                IntrinsicPolyFun                  [tp_a, tp_b]                  [ Scalar t_b `arr` (Scalar t_b `arr` Scalar t_b),-                   Scalar (Prim $ Signed Int32) `karr` (arr_ka `arr` Scalar t_b),+                   Scalar (Prim $ Signed Int64) `karr` (arr_ka `arr` Scalar t_b),                    arr_a                  ]                  $ Scalar t_b
src/Language/Futhark/Syntax.hs view
@@ -433,7 +433,7 @@ type StructType = TypeBase (DimDecl VName) ()  -- | A value type contains full, manifest size information.-type ValueType = TypeBase Int32 ()+type ValueType = TypeBase Int64 ()  -- | A dimension declaration expression for use in a 'TypeExp'. data DimExp vn
src/Language/Futhark/TypeChecker.hs view
@@ -181,7 +181,7 @@     typeParamEnv (TypeParamDim v _) =       mempty         { envVtable =-            M.singleton v $ BoundV [] (Scalar $ Prim $ Signed Int32)+            M.singleton v $ BoundV [] (Scalar $ Prim $ Signed Int64)         }     typeParamEnv (TypeParamType l v _) =       mempty
src/Language/Futhark/TypeChecker/Monad.hs view
@@ -220,10 +220,10 @@   checkNamedDim loc v = do     (v', t) <- lookupVar loc v     case t of-      Scalar (Prim (Signed Int32)) -> return v'+      Scalar (Prim (Signed Int64)) -> return v'       _ ->         typeError loc mempty $-          "Dimension declaration" <+> ppr v <+> "should be of type i32."+          "Dimension declaration" <+> ppr v <+> "should be of type i64."    typeError :: Located loc => loc -> Notes -> Doc -> m a 
src/Language/Futhark/TypeChecker/Terms.hs view
@@ -576,9 +576,9 @@    checkNamedDim loc v = do     (v', t) <- lookupVar loc v-    onFailure (CheckingRequired [Scalar $ Prim $ Signed Int32] (toStruct t)) $+    onFailure (CheckingRequired [Scalar $ Prim $ Signed Int64] (toStruct t)) $       unify (mkUsage loc "use as array size") (toStruct t) $-        Scalar $ Prim $ Signed Int32+        Scalar $ Prim $ Signed Int64     return v'    typeError loc notes s = do@@ -635,7 +635,7 @@   return tdecl'   where     observeDim (NamedDim v) =-      observe $ Ident (qualLeaf v) (Info $ Scalar $ Prim $ Signed Int32) mempty+      observe $ Ident (qualLeaf v) (Info $ Scalar $ Prim $ Signed Int64) mempty     observeDim _ = return ()  -- | Instantiate a type scheme with fresh type variables for its type@@ -983,7 +983,7 @@  typeParamIdent :: TypeParam -> Maybe Ident typeParamIdent (TypeParamDim v loc) =-  Just $ Ident v (Info $ Scalar $ Prim $ Signed Int32) loc+  Just $ Ident v (Info $ Scalar $ Prim $ Signed Int64) loc typeParamIdent _ = Nothing  bindingIdent ::@@ -1086,13 +1086,13 @@     -- Pattern match some known slices to be non-existential.     adjustDims (DimSlice i j stride : idxes') (_ : dims)       | refine_sizes,-        maybe True ((== Just 0) . isInt32) i,+        maybe True ((== Just 0) . isInt64) i,         Just j' <- maybeDimFromExp =<< j,-        maybe True ((== Just 1) . isInt32) stride =+        maybe True ((== Just 1) . isInt64) stride =         (j' :) <$> adjustDims idxes' dims     adjustDims (DimSlice Nothing Nothing stride : idxes') (d : dims)       | refine_sizes,-        maybe True (maybe False ((== 1) . abs) . isInt32) stride =+        maybe True (maybe False ((== 1) . abs) . isInt64) stride =         (d :) <$> adjustDims idxes' dims     adjustDims (DimSlice i j stride : idxes') (d : dims) =       (:) <$> sliceSize d i j stride <*> adjustDims idxes' dims@@ -1290,21 +1290,26 @@       Just <$> (unifies "use in range expression" start_t =<< checkExp step)    let unifyRange e = unifies "use in range expression" start_t =<< checkExp e-  end' <- case end of-    DownToExclusive e -> DownToExclusive <$> unifyRange e-    UpToExclusive e -> UpToExclusive <$> unifyRange e-    ToInclusive e -> ToInclusive <$> unifyRange e+  end' <- traverse unifyRange end +  end_t <- case end' of+    DownToExclusive e -> expType e+    ToInclusive e -> expType e+    UpToExclusive e -> expType e+   -- Special case some ranges to give them a known size.   let dimFromBound = dimFromExp (SourceBound . bareExp)   (dim, retext) <--    case (isInt32 start', isInt32 <$> maybe_step', end') of-      (Just 0, Just (Just 1), UpToExclusive end'') ->-        dimFromBound end''-      (Just 0, Nothing, UpToExclusive end'') ->-        dimFromBound end''-      (Just 1, Just (Just 2), ToInclusive end'') ->-        dimFromBound end''+    case (isInt64 start', isInt64 <$> maybe_step', end') of+      (Just 0, Just (Just 1), UpToExclusive end'')+        | Scalar (Prim (Signed Int64)) <- end_t ->+          dimFromBound end''+      (Just 0, Nothing, UpToExclusive end'')+        | Scalar (Prim (Signed Int64)) <- end_t ->+          dimFromBound end''+      (Just 1, Just (Just 2), ToInclusive end'')+        | Scalar (Prim (Signed Int64)) <- end_t ->+          dimFromBound end''       _ -> do         d <- newDimVar loc (Rigid RigidRange) "range_dim"         return (NamedDim $ qualName d, Just d)@@ -2282,7 +2287,7 @@   where     check =       maybe (return Nothing) $-        fmap Just . unifies "use as index" (Scalar $ Prim $ Signed Int32) <=< checkExp+        fmap Just . unifies "use as index" (Scalar $ Prim $ Signed Int64) <=< checkExp  sequentially :: TermTypeM a -> (a -> Occurences -> TermTypeM b) -> TermTypeM b sequentially m1 m2 = do@@ -2386,7 +2391,7 @@        return (tp1', tp2'', argext, ext)     where-      sizeSubst (Scalar (Prim (Signed Int32))) e = dimFromArg fname e+      sizeSubst (Scalar (Prim (Signed Int64))) e = dimFromArg fname e       sizeSubst _ _ = return (AnyDim, Nothing) checkApply loc fname tfun@(Scalar TypeVar {}) arg = do   tv <- newTypeVar loc "b"@@ -2415,17 +2420,17 @@       | prev_applied == 1 = "argument"       | otherwise = "arguments" -isInt32 :: Exp -> Maybe Int32-isInt32 (Literal (SignedValue (Int32Value k')) _) = Just $ fromIntegral k'-isInt32 (IntLit k' _ _) = Just $ fromInteger k'-isInt32 (Negate x _) = negate <$> isInt32 x-isInt32 _ = Nothing+isInt64 :: Exp -> Maybe Int64+isInt64 (Literal (SignedValue (Int64Value k')) _) = Just $ fromIntegral k'+isInt64 (IntLit k' _ _) = Just $ fromInteger k'+isInt64 (Negate x _) = negate <$> isInt64 x+isInt64 _ = Nothing  maybeDimFromExp :: Exp -> Maybe (DimDecl VName) maybeDimFromExp (Var v _ _) = Just $ NamedDim v maybeDimFromExp (Parens e _) = maybeDimFromExp e maybeDimFromExp (QualParens _ e _) = maybeDimFromExp e-maybeDimFromExp e = ConstDim . fromIntegral <$> isInt32 e+maybeDimFromExp e = ConstDim . fromIntegral <$> isInt64 e  dimFromExp :: (Exp -> SizeSource) -> Exp -> TermTypeM (DimDecl VName, Maybe VName) dimFromExp rf (Parens e _) = dimFromExp rf e
src/futhark.hs view
@@ -19,6 +19,7 @@ import qualified Futhark.CLI.Dev as Dev import qualified Futhark.CLI.Doc as Doc import qualified Futhark.CLI.Misc as Misc+import qualified Futhark.CLI.Multicore as Multicore import qualified Futhark.CLI.OpenCL as OpenCL import qualified Futhark.CLI.Pkg as Pkg import qualified Futhark.CLI.PyOpenCL as PyOpenCL@@ -48,6 +49,7 @@       ("c", (C.main, "Compile to sequential C.")),       ("opencl", (OpenCL.main, "Compile to C calling OpenCL.")),       ("cuda", (CCUDA.main, "Compile to C calling CUDA.")),+      ("multicore", (Multicore.main, "Compile to multicore C.")),       ("python", (Python.main, "Compile to sequential Python.")),       ("pyopencl", (PyOpenCL.main, "Compile to Python calling PyOpenCL.")),       ("test", (Test.main, "Test Futhark programs.")),