packages feed

futhark 0.21.12 → 0.21.13

raw patch · 233 files changed

+17048/−9768 lines, 233 filesdep +co-log-coredep +fgldep +fgl-visualizedep −hsloggerdep −parser-combinatorsdep ~futhark-manifestdep ~futhark-serverdep ~lspPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: co-log-core, fgl, fgl-visualize

Dependencies removed: hslogger, parser-combinators

Dependency ranges changed: futhark-manifest, futhark-server, lsp, mtl

API changes (from Hackage documentation)

- Futhark.AD.Rev.Monad: insSubExpAdj :: SubExp -> VName -> ADM ()
- Futhark.Analysis.CallGraph: findNoninlined :: Prog SOACS -> Set Name
- Futhark.Analysis.MemAlias: canBeSameMemory :: MemAliases -> VName -> VName -> Bool
- Futhark.CodeGen.Backends.SimpleRep: instance Language.C.Quote.Base.ToExp Futhark.IR.Primitive.FloatValue
- Futhark.CodeGen.Backends.SimpleRep: instance Language.C.Quote.Base.ToExp Futhark.IR.Primitive.IntValue
- Futhark.CodeGen.Backends.SimpleRep: instance Language.C.Quote.Base.ToExp Futhark.IR.Primitive.PrimValue
- Futhark.CodeGen.ImpCode: TypeDirect :: Signedness
- Futhark.CodeGen.ImpCode: TypeUnsigned :: Signedness
- Futhark.CodeGen.ImpCode: [functionArgs] :: FunctionT a -> [(Name, ExternalValue)]
- Futhark.CodeGen.ImpCode: [functionResult] :: FunctionT a -> [ExternalValue]
- Futhark.CodeGen.ImpCode: instance GHC.Classes.Eq Futhark.CodeGen.ImpCode.Signedness
- Futhark.CodeGen.ImpCode: instance GHC.Classes.Ord Futhark.CodeGen.ImpCode.Signedness
- Futhark.CodeGen.ImpCode: instance GHC.Show.Show Futhark.CodeGen.ImpCode.Signedness
- Futhark.CodeGen.ImpGen.Multicore: AllowDynamicScheduling :: SchedulingMode
- Futhark.CodeGen.ImpGen.Multicore: NoDynamicScheduling :: SchedulingMode
- Futhark.CodeGen.ImpGen.Multicore: data SchedulingMode
- Futhark.IR.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Syntax.EntryPointType
- Futhark.IR.Primitive: AShr :: IntType -> BinOp
- Futhark.IR.Primitive: Abs :: IntType -> UnOp
- Futhark.IR.Primitive: Add :: IntType -> Overflow -> BinOp
- Futhark.IR.Primitive: And :: IntType -> BinOp
- Futhark.IR.Primitive: BToF :: FloatType -> ConvOp
- Futhark.IR.Primitive: BToI :: IntType -> ConvOp
- Futhark.IR.Primitive: Bool :: PrimType
- Futhark.IR.Primitive: BoolValue :: !Bool -> PrimValue
- Futhark.IR.Primitive: CmpEq :: PrimType -> CmpOp
- Futhark.IR.Primitive: CmpLle :: CmpOp
- Futhark.IR.Primitive: CmpLlt :: CmpOp
- Futhark.IR.Primitive: CmpSle :: IntType -> CmpOp
- Futhark.IR.Primitive: CmpSlt :: IntType -> CmpOp
- Futhark.IR.Primitive: CmpUle :: IntType -> CmpOp
- Futhark.IR.Primitive: CmpUlt :: IntType -> CmpOp
- Futhark.IR.Primitive: Complement :: IntType -> UnOp
- Futhark.IR.Primitive: FAbs :: FloatType -> UnOp
- Futhark.IR.Primitive: FAdd :: FloatType -> BinOp
- Futhark.IR.Primitive: FCmpLe :: FloatType -> CmpOp
- Futhark.IR.Primitive: FCmpLt :: FloatType -> CmpOp
- Futhark.IR.Primitive: FDiv :: FloatType -> BinOp
- Futhark.IR.Primitive: FMax :: FloatType -> BinOp
- Futhark.IR.Primitive: FMin :: FloatType -> BinOp
- Futhark.IR.Primitive: FMod :: FloatType -> BinOp
- Futhark.IR.Primitive: FMul :: FloatType -> BinOp
- Futhark.IR.Primitive: FPConv :: FloatType -> FloatType -> ConvOp
- Futhark.IR.Primitive: FPToSI :: FloatType -> IntType -> ConvOp
- Futhark.IR.Primitive: FPToUI :: FloatType -> IntType -> ConvOp
- Futhark.IR.Primitive: FPow :: FloatType -> BinOp
- Futhark.IR.Primitive: FSignum :: FloatType -> UnOp
- Futhark.IR.Primitive: FSub :: FloatType -> BinOp
- Futhark.IR.Primitive: FToB :: FloatType -> ConvOp
- Futhark.IR.Primitive: Float16 :: FloatType
- Futhark.IR.Primitive: Float16Value :: !Half -> FloatValue
- Futhark.IR.Primitive: Float32 :: FloatType
- Futhark.IR.Primitive: Float32Value :: !Float -> FloatValue
- Futhark.IR.Primitive: Float64 :: FloatType
- Futhark.IR.Primitive: Float64Value :: !Double -> FloatValue
- Futhark.IR.Primitive: FloatType :: FloatType -> PrimType
- Futhark.IR.Primitive: FloatValue :: !FloatValue -> PrimValue
- Futhark.IR.Primitive: IToB :: IntType -> ConvOp
- Futhark.IR.Primitive: Int16 :: IntType
- Futhark.IR.Primitive: Int16Value :: !Int16 -> IntValue
- Futhark.IR.Primitive: Int32 :: IntType
- Futhark.IR.Primitive: Int32Value :: !Int32 -> IntValue
- Futhark.IR.Primitive: Int64 :: IntType
- Futhark.IR.Primitive: Int64Value :: !Int64 -> IntValue
- Futhark.IR.Primitive: Int8 :: IntType
- Futhark.IR.Primitive: Int8Value :: !Int8 -> IntValue
- Futhark.IR.Primitive: IntType :: IntType -> PrimType
- Futhark.IR.Primitive: IntValue :: !IntValue -> PrimValue
- Futhark.IR.Primitive: LShr :: IntType -> BinOp
- Futhark.IR.Primitive: LogAnd :: BinOp
- Futhark.IR.Primitive: LogOr :: BinOp
- Futhark.IR.Primitive: Mul :: IntType -> Overflow -> BinOp
- Futhark.IR.Primitive: Not :: UnOp
- Futhark.IR.Primitive: Or :: IntType -> BinOp
- Futhark.IR.Primitive: OverflowUndef :: Overflow
- Futhark.IR.Primitive: OverflowWrap :: Overflow
- Futhark.IR.Primitive: Pow :: IntType -> BinOp
- Futhark.IR.Primitive: SDiv :: IntType -> Safety -> BinOp
- Futhark.IR.Primitive: SDivUp :: IntType -> Safety -> BinOp
- Futhark.IR.Primitive: SExt :: IntType -> IntType -> ConvOp
- Futhark.IR.Primitive: SIToFP :: IntType -> FloatType -> ConvOp
- Futhark.IR.Primitive: SMax :: IntType -> BinOp
- Futhark.IR.Primitive: SMin :: IntType -> BinOp
- Futhark.IR.Primitive: SMod :: IntType -> Safety -> BinOp
- Futhark.IR.Primitive: SQuot :: IntType -> Safety -> BinOp
- Futhark.IR.Primitive: SRem :: IntType -> Safety -> BinOp
- Futhark.IR.Primitive: SSignum :: IntType -> UnOp
- Futhark.IR.Primitive: Safe :: Safety
- Futhark.IR.Primitive: Shl :: IntType -> BinOp
- Futhark.IR.Primitive: Sub :: IntType -> Overflow -> BinOp
- Futhark.IR.Primitive: UDiv :: IntType -> Safety -> BinOp
- Futhark.IR.Primitive: UDivUp :: IntType -> Safety -> BinOp
- Futhark.IR.Primitive: UIToFP :: IntType -> FloatType -> ConvOp
- Futhark.IR.Primitive: UMax :: IntType -> BinOp
- Futhark.IR.Primitive: UMin :: IntType -> BinOp
- Futhark.IR.Primitive: UMod :: IntType -> Safety -> BinOp
- Futhark.IR.Primitive: USignum :: IntType -> UnOp
- Futhark.IR.Primitive: Unit :: PrimType
- Futhark.IR.Primitive: UnitValue :: PrimValue
- Futhark.IR.Primitive: Unsafe :: Safety
- Futhark.IR.Primitive: Xor :: IntType -> BinOp
- Futhark.IR.Primitive: ZExt :: IntType -> IntType -> ConvOp
- Futhark.IR.Primitive: allBinOps :: [BinOp]
- Futhark.IR.Primitive: allCmpOps :: [CmpOp]
- Futhark.IR.Primitive: allConvOps :: [ConvOp]
- Futhark.IR.Primitive: allFloatTypes :: [FloatType]
- Futhark.IR.Primitive: allIntTypes :: [IntType]
- Futhark.IR.Primitive: allPrimTypes :: [PrimType]
- Futhark.IR.Primitive: allUnOps :: [UnOp]
- Futhark.IR.Primitive: associativeBinOp :: BinOp -> Bool
- Futhark.IR.Primitive: binOpType :: BinOp -> PrimType
- Futhark.IR.Primitive: blankPrimValue :: PrimType -> PrimValue
- Futhark.IR.Primitive: cmpOpType :: CmpOp -> PrimType
- Futhark.IR.Primitive: commutativeBinOp :: BinOp -> Bool
- Futhark.IR.Primitive: convOpFun :: ConvOp -> String
- Futhark.IR.Primitive: convOpType :: ConvOp -> (PrimType, PrimType)
- Futhark.IR.Primitive: data BinOp
- Futhark.IR.Primitive: data CmpOp
- Futhark.IR.Primitive: data ConvOp
- Futhark.IR.Primitive: data FloatType
- Futhark.IR.Primitive: data FloatValue
- Futhark.IR.Primitive: data Half
- Futhark.IR.Primitive: data Int16
- Futhark.IR.Primitive: data Int32
- Futhark.IR.Primitive: data Int64
- Futhark.IR.Primitive: data Int8
- Futhark.IR.Primitive: data IntType
- Futhark.IR.Primitive: data IntValue
- Futhark.IR.Primitive: data Overflow
- Futhark.IR.Primitive: data PrimType
- Futhark.IR.Primitive: data PrimValue
- Futhark.IR.Primitive: data Safety
- Futhark.IR.Primitive: data UnOp
- Futhark.IR.Primitive: doAbs :: IntValue -> IntValue
- Futhark.IR.Primitive: doAdd :: IntValue -> IntValue -> IntValue
- Futhark.IR.Primitive: doBinOp :: BinOp -> PrimValue -> PrimValue -> Maybe PrimValue
- Futhark.IR.Primitive: doCmpEq :: PrimValue -> PrimValue -> Bool
- Futhark.IR.Primitive: doCmpOp :: CmpOp -> PrimValue -> PrimValue -> Maybe Bool
- Futhark.IR.Primitive: doCmpSle :: IntValue -> IntValue -> Bool
- Futhark.IR.Primitive: doCmpSlt :: IntValue -> IntValue -> Bool
- Futhark.IR.Primitive: doCmpUle :: IntValue -> IntValue -> Bool
- Futhark.IR.Primitive: doCmpUlt :: IntValue -> IntValue -> Bool
- Futhark.IR.Primitive: doComplement :: IntValue -> IntValue
- Futhark.IR.Primitive: doConvOp :: ConvOp -> PrimValue -> Maybe PrimValue
- Futhark.IR.Primitive: doFAbs :: FloatValue -> FloatValue
- Futhark.IR.Primitive: doFCmpLe :: FloatValue -> FloatValue -> Bool
- Futhark.IR.Primitive: doFCmpLt :: FloatValue -> FloatValue -> Bool
- Futhark.IR.Primitive: doFPConv :: FloatValue -> FloatType -> FloatValue
- Futhark.IR.Primitive: doFPToSI :: FloatValue -> IntType -> IntValue
- Futhark.IR.Primitive: doFPToUI :: FloatValue -> IntType -> IntValue
- Futhark.IR.Primitive: doMul :: IntValue -> IntValue -> IntValue
- Futhark.IR.Primitive: doPow :: IntValue -> IntValue -> Maybe IntValue
- Futhark.IR.Primitive: doSDiv :: IntValue -> IntValue -> Maybe IntValue
- Futhark.IR.Primitive: doSExt :: IntValue -> IntType -> IntValue
- Futhark.IR.Primitive: doSIToFP :: IntValue -> FloatType -> FloatValue
- Futhark.IR.Primitive: doSMod :: IntValue -> IntValue -> Maybe IntValue
- Futhark.IR.Primitive: doSSignum :: IntValue -> IntValue
- Futhark.IR.Primitive: doUIToFP :: IntValue -> FloatType -> FloatValue
- Futhark.IR.Primitive: doUSignum :: IntValue -> IntValue
- Futhark.IR.Primitive: doUnOp :: UnOp -> PrimValue -> Maybe PrimValue
- Futhark.IR.Primitive: doZExt :: IntValue -> IntType -> IntValue
- Futhark.IR.Primitive: flipConvOp :: ConvOp -> ConvOp
- Futhark.IR.Primitive: floatByteSize :: Num a => FloatType -> a
- Futhark.IR.Primitive: floatValue :: Real num => FloatType -> num -> FloatValue
- Futhark.IR.Primitive: floatValueType :: FloatValue -> FloatType
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.BinOp
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.CmpOp
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.ConvOp
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.FloatType
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.FloatValue
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.IntType
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.IntValue
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.Overflow
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.PrimType
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.PrimValue
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.Safety
- Futhark.IR.Primitive: instance GHC.Classes.Eq Futhark.IR.Primitive.UnOp
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.BinOp
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.CmpOp
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.ConvOp
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.FloatType
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.FloatValue
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.IntType
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.IntValue
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.Overflow
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.PrimType
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.PrimValue
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.Safety
- Futhark.IR.Primitive: instance GHC.Classes.Ord Futhark.IR.Primitive.UnOp
- Futhark.IR.Primitive: instance GHC.Enum.Bounded Futhark.IR.Primitive.FloatType
- Futhark.IR.Primitive: instance GHC.Enum.Bounded Futhark.IR.Primitive.IntType
- Futhark.IR.Primitive: instance GHC.Enum.Bounded Futhark.IR.Primitive.PrimType
- Futhark.IR.Primitive: instance GHC.Enum.Enum Futhark.IR.Primitive.FloatType
- Futhark.IR.Primitive: instance GHC.Enum.Enum Futhark.IR.Primitive.IntType
- Futhark.IR.Primitive: instance GHC.Enum.Enum Futhark.IR.Primitive.PrimType
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.BinOp
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.CmpOp
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.ConvOp
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.FloatType
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.FloatValue
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.IntType
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.IntValue
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.Overflow
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.PrimType
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.PrimValue
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.Safety
- Futhark.IR.Primitive: instance GHC.Show.Show Futhark.IR.Primitive.UnOp
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.BinOp
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.CmpOp
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.ConvOp
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.FloatType
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.FloatValue
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.IntType
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.IntValue
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.PrimType
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.PrimValue
- Futhark.IR.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Primitive.UnOp
- Futhark.IR.Primitive: intByteSize :: Num a => IntType -> a
- Futhark.IR.Primitive: intToInt64 :: IntValue -> Int64
- Futhark.IR.Primitive: intToWord64 :: IntValue -> Word64
- Futhark.IR.Primitive: intValue :: Integral int => IntType -> int -> IntValue
- Futhark.IR.Primitive: intValueType :: IntValue -> IntType
- Futhark.IR.Primitive: negativeIsh :: PrimValue -> Bool
- Futhark.IR.Primitive: oneIsh :: PrimValue -> Bool
- Futhark.IR.Primitive: oneIshInt :: IntValue -> Bool
- Futhark.IR.Primitive: prettySigned :: Bool -> PrimType -> String
- Futhark.IR.Primitive: primBitSize :: PrimType -> Int
- Futhark.IR.Primitive: primByteSize :: Num a => PrimType -> a
- Futhark.IR.Primitive: primFuns :: Map String ([PrimType], PrimType, [PrimValue] -> Maybe PrimValue)
- Futhark.IR.Primitive: primValueType :: PrimValue -> PrimType
- Futhark.IR.Primitive: unOpType :: UnOp -> PrimType
- Futhark.IR.Primitive: valueIntegral :: Integral int => IntValue -> int
- Futhark.IR.Primitive: zeroIsh :: PrimValue -> Bool
- Futhark.IR.Primitive: zeroIshInt :: IntValue -> Bool
- Futhark.IR.Primitive.Parse: constituent :: Char -> Bool
- Futhark.IR.Primitive.Parse: keyword :: Text -> Parsec Void Text ()
- Futhark.IR.Primitive.Parse: lexeme :: Parsec Void Text a -> Parsec Void Text a
- Futhark.IR.Primitive.Parse: pFloatType :: Parsec Void Text FloatType
- Futhark.IR.Primitive.Parse: pIntType :: Parsec Void Text IntType
- Futhark.IR.Primitive.Parse: pPrimType :: Parsec Void Text PrimType
- Futhark.IR.Primitive.Parse: pPrimValue :: Parsec Void Text PrimValue
- Futhark.IR.Primitive.Parse: whitespace :: Parsec Void Text ()
- Futhark.IR.Prop: entryPointSize :: EntryPointType -> Int
- Futhark.IR.Prop.Constants: instance Futhark.IR.Prop.Constants.IsValue Futhark.IR.Primitive.FloatValue
- Futhark.IR.Prop.Constants: instance Futhark.IR.Prop.Constants.IsValue Futhark.IR.Primitive.IntValue
- Futhark.IR.Prop.Constants: instance Futhark.IR.Prop.Constants.IsValue Futhark.IR.Primitive.PrimValue
- Futhark.IR.Prop.Names: instance Futhark.IR.Prop.Names.FreeIn Futhark.IR.Primitive.PrimType
- Futhark.IR.Syntax: TypeDirect :: Uniqueness -> EntryPointType
- Futhark.IR.Syntax: TypeOpaque :: Uniqueness -> String -> Int -> EntryPointType
- Futhark.IR.Syntax: TypeUnsigned :: Uniqueness -> EntryPointType
- Futhark.IR.Syntax: data EntryPointType
- Futhark.IR.Syntax: instance GHC.Classes.Eq Futhark.IR.Syntax.EntryPointType
- Futhark.IR.Syntax: instance GHC.Classes.Ord Futhark.IR.Syntax.EntryPointType
- Futhark.IR.Syntax: instance GHC.Show.Show Futhark.IR.Syntax.EntryPointType
- Futhark.Internalise.FreeVars: NameSet :: Map VName StructType -> NameSet
- Futhark.Internalise.FreeVars: [unNameSet] :: NameSet -> Map VName StructType
- Futhark.Internalise.FreeVars: freeVars :: Exp -> NameSet
- Futhark.Internalise.FreeVars: ident :: Ident -> NameSet
- Futhark.Internalise.FreeVars: instance GHC.Base.Monoid Futhark.Internalise.FreeVars.NameSet
- Futhark.Internalise.FreeVars: instance GHC.Base.Semigroup Futhark.Internalise.FreeVars.NameSet
- Futhark.Internalise.FreeVars: instance GHC.Show.Show Futhark.Internalise.FreeVars.NameSet
- Futhark.Internalise.FreeVars: newtype NameSet
- Futhark.Internalise.FreeVars: patVars :: Pat -> NameSet
- Futhark.Internalise.FreeVars: sizes :: Set VName -> NameSet
- Futhark.Internalise.FreeVars: without :: NameSet -> Set VName -> NameSet
- Futhark.Internalise.Lambdas: internaliseMapLambda :: InternaliseLambda -> Exp -> [SubExp] -> InternaliseM (Lambda SOACS)
- Futhark.Internalise.Monad: localConstsScope :: InternaliseM a -> InternaliseM a
- Futhark.Internalise.Monomorphise: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl Futhark.Internalise.Monomorphise.MonoSize)
- Futhark.Optimise.Fusion: instance Control.Monad.Error.Class.MonadError Futhark.Optimise.Fusion.Error Futhark.Optimise.Fusion.FusionGM
- Futhark.Optimise.Fusion: instance Control.Monad.Reader.Class.MonadReader Futhark.Optimise.Fusion.FusionGEnv Futhark.Optimise.Fusion.FusionGM
- Futhark.Optimise.Fusion: instance Control.Monad.State.Class.MonadState Futhark.FreshNames.VNameSource Futhark.Optimise.Fusion.FusionGM
- Futhark.Optimise.Fusion: instance Futhark.IR.Prop.Scope.HasScope Futhark.IR.SOACS.SOACS Futhark.Optimise.Fusion.FusionGM
- Futhark.Optimise.Fusion: instance Futhark.MonadFreshNames.MonadFreshNames Futhark.Optimise.Fusion.FusionGM
- Futhark.Optimise.Fusion: instance GHC.Base.Applicative Futhark.Optimise.Fusion.FusionGM
- Futhark.Optimise.Fusion: instance GHC.Base.Functor Futhark.Optimise.Fusion.FusionGM
- Futhark.Optimise.Fusion: instance GHC.Base.Monad Futhark.Optimise.Fusion.FusionGM
- Futhark.Optimise.Fusion: instance GHC.Base.Monoid Futhark.Optimise.Fusion.FusedRes
- Futhark.Optimise.Fusion: instance GHC.Base.Semigroup Futhark.Optimise.Fusion.FusedRes
- Futhark.Optimise.Fusion: instance GHC.Classes.Eq Futhark.Optimise.Fusion.KernName
- Futhark.Optimise.Fusion: instance GHC.Classes.Ord Futhark.Optimise.Fusion.KernName
- Futhark.Optimise.Fusion: instance GHC.Show.Show Futhark.Optimise.Fusion.Error
- Futhark.Optimise.Fusion: instance GHC.Show.Show Futhark.Optimise.Fusion.KernName
- Futhark.Optimise.Fusion.LoopKernel: FusedKer :: SOAC -> Names -> [VName] -> Names -> Scope SOACS -> ArrayTransforms -> [VName] -> StmAux () -> FusedKer
- Futhark.Optimise.Fusion.LoopKernel: [fsoac] :: FusedKer -> SOAC
- Futhark.Optimise.Fusion.LoopKernel: [fusedConsumed] :: FusedKer -> Names
- Futhark.Optimise.Fusion.LoopKernel: [fusedVars] :: FusedKer -> [VName]
- Futhark.Optimise.Fusion.LoopKernel: [inplace] :: FusedKer -> Names
- Futhark.Optimise.Fusion.LoopKernel: [kerAux] :: FusedKer -> StmAux ()
- Futhark.Optimise.Fusion.LoopKernel: [kernelScope] :: FusedKer -> Scope SOACS
- Futhark.Optimise.Fusion.LoopKernel: [outNames] :: FusedKer -> [VName]
- Futhark.Optimise.Fusion.LoopKernel: [outputTransform] :: FusedKer -> ArrayTransforms
- Futhark.Optimise.Fusion.LoopKernel: arrInputs :: FusedKer -> Set VName
- Futhark.Optimise.Fusion.LoopKernel: attemptFusion :: MonadFreshNames m => Names -> [VName] -> SOAC -> Names -> FusedKer -> m (Maybe FusedKer)
- Futhark.Optimise.Fusion.LoopKernel: data FusedKer
- Futhark.Optimise.Fusion.LoopKernel: inputs :: FusedKer -> [Input]
- Futhark.Optimise.Fusion.LoopKernel: instance Control.Monad.Fail.MonadFail Futhark.Optimise.Fusion.LoopKernel.TryFusion
- Futhark.Optimise.Fusion.LoopKernel: instance Futhark.IR.Prop.Scope.HasScope Futhark.IR.SOACS.SOACS Futhark.Optimise.Fusion.LoopKernel.TryFusion
- Futhark.Optimise.Fusion.LoopKernel: instance Futhark.IR.Prop.Scope.LocalScope Futhark.IR.SOACS.SOACS Futhark.Optimise.Fusion.LoopKernel.TryFusion
- Futhark.Optimise.Fusion.LoopKernel: instance Futhark.MonadFreshNames.MonadFreshNames Futhark.Optimise.Fusion.LoopKernel.TryFusion
- Futhark.Optimise.Fusion.LoopKernel: instance GHC.Base.Alternative Futhark.Optimise.Fusion.LoopKernel.TryFusion
- Futhark.Optimise.Fusion.LoopKernel: instance GHC.Base.Applicative Futhark.Optimise.Fusion.LoopKernel.TryFusion
- Futhark.Optimise.Fusion.LoopKernel: instance GHC.Base.Functor Futhark.Optimise.Fusion.LoopKernel.TryFusion
- Futhark.Optimise.Fusion.LoopKernel: instance GHC.Base.Monad Futhark.Optimise.Fusion.LoopKernel.TryFusion
- Futhark.Optimise.Fusion.LoopKernel: instance GHC.Show.Show Futhark.Optimise.Fusion.LoopKernel.FusedKer
- Futhark.Optimise.Fusion.LoopKernel: newKernel :: StmAux () -> SOAC -> Names -> [VName] -> Scope SOACS -> FusedKer
- Futhark.Optimise.Fusion.LoopKernel: setInputs :: [Input] -> FusedKer -> FusedKer
- Futhark.Optimise.Fusion.LoopKernel: transformOutput :: ArrayTransforms -> [VName] -> [Ident] -> Builder SOACS ()
- Futhark.Optimise.Fusion.LoopKernel: type MapNest = MapNest SOACS
- Futhark.Optimise.Fusion.LoopKernel: type SOAC = SOAC SOACS
- Futhark.Optimise.ReduceDeviceSyncs.MigrationTable: analyseProg :: Prog GPU -> MigrationTable
- Futhark.Optimise.Simplify.Engine: instance Futhark.Optimise.Simplify.Engine.Simplifiable Futhark.IR.Primitive.PrimType
- Futhark.Pass: liftEither :: Show err => Either err a -> PassM a
- Futhark.Pass: liftEitherM :: Show err => PassM (Either err a) -> PassM a
- Futhark.Transform.Rename: instance Futhark.Transform.Rename.Rename Futhark.IR.Primitive.PrimType
- Futhark.Transform.Substitute: instance Futhark.Transform.Substitute.Substitute Futhark.IR.Primitive.PrimType
- Futhark.Util: debug :: MonadIO m => String -> m ()
- Language.Futhark.Core: defaultEntryPoint :: Name
- Language.Futhark.Pretty: instance Language.Futhark.Pretty.IsName vn => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.DimDecl vn)
- Language.Futhark.Pretty: instance Language.Futhark.Pretty.IsName vn => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.DimExp vn)
- Language.Futhark.Pretty: instance Language.Futhark.Pretty.IsName vn => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl (Language.Futhark.Syntax.DimDecl vn))
- Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl ())
- Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl GHC.Int.Int64)
- Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl GHC.Types.Bool)
- Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl dim) => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.RetTypeBase dim as)
- Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl dim) => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ScalarTypeBase dim as)
- Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl dim) => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.TypeArg dim)
- Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ShapeDecl dim) => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.TypeBase dim as)
- Language.Futhark.Prop: determineSizeWitnesses :: StructType -> (Set VName, Set VName)
- Language.Futhark.Prop: mustBeExplicit :: StructType -> Set VName
- Language.Futhark.Prop: mustBeExplicitInType :: StructType -> Set VName
- Language.Futhark.Prop: nestedDims :: TypeBase (DimDecl VName) as -> [DimDecl VName]
- Language.Futhark.Prop: patternDimNames :: PatBase Info VName -> Set VName
- Language.Futhark.Prop: typeDimNames :: TypeBase (DimDecl VName) als -> Set VName
- Language.Futhark.Prop: typeName :: VName -> TypeName
- Language.Futhark.Syntax: AnyDim :: Maybe vn -> DimDecl vn
- Language.Futhark.Syntax: ConstDim :: Int -> DimDecl vn
- Language.Futhark.Syntax: DimExpAny :: DimExp vn
- Language.Futhark.Syntax: DimExpConst :: Int -> SrcLoc -> DimExp vn
- Language.Futhark.Syntax: DimExpNamed :: QualName vn -> SrcLoc -> DimExp vn
- Language.Futhark.Syntax: NamedDim :: QualName vn -> DimDecl vn
- Language.Futhark.Syntax: ShapeDecl :: [dim] -> ShapeDecl dim
- Language.Futhark.Syntax: TypeName :: [VName] -> VName -> TypeName
- Language.Futhark.Syntax: [typeLeaf] :: TypeName -> VName
- Language.Futhark.Syntax: [typeQuals] :: TypeName -> [VName]
- Language.Futhark.Syntax: class Eq dim => ArrayDim dim
- Language.Futhark.Syntax: data DimDecl vn
- Language.Futhark.Syntax: data DimExp vn
- Language.Futhark.Syntax: data TypeName
- Language.Futhark.Syntax: instance Data.Foldable.Foldable Language.Futhark.Syntax.DimDecl
- Language.Futhark.Syntax: instance Data.Foldable.Foldable Language.Futhark.Syntax.ShapeDecl
- Language.Futhark.Syntax: instance Data.Traversable.Traversable Language.Futhark.Syntax.DimDecl
- Language.Futhark.Syntax: instance Data.Traversable.Traversable Language.Futhark.Syntax.ShapeDecl
- Language.Futhark.Syntax: instance GHC.Base.Functor Language.Futhark.Syntax.DimDecl
- Language.Futhark.Syntax: instance GHC.Base.Functor Language.Futhark.Syntax.ShapeDecl
- Language.Futhark.Syntax: instance GHC.Base.Monoid (Language.Futhark.Syntax.ShapeDecl dim)
- Language.Futhark.Syntax: instance GHC.Base.Semigroup (Language.Futhark.Syntax.ShapeDecl dim)
- Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName)
- Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.DimExp Language.Futhark.Core.Name)
- Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.DimExp Language.Futhark.Core.VName)
- Language.Futhark.Syntax: instance GHC.Classes.Eq Language.Futhark.Syntax.TypeName
- Language.Futhark.Syntax: instance GHC.Classes.Eq dim => GHC.Classes.Eq (Language.Futhark.Syntax.ShapeDecl dim)
- Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName)
- Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.DimExp Language.Futhark.Core.Name)
- Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.DimExp Language.Futhark.Core.VName)
- Language.Futhark.Syntax: instance GHC.Classes.Ord Language.Futhark.Syntax.TypeName
- Language.Futhark.Syntax: instance GHC.Classes.Ord dim => GHC.Classes.Ord (Language.Futhark.Syntax.ShapeDecl dim)
- Language.Futhark.Syntax: instance GHC.Show.Show Language.Futhark.Syntax.TypeName
- Language.Futhark.Syntax: instance GHC.Show.Show dim => GHC.Show.Show (Language.Futhark.Syntax.ShapeDecl dim)
- Language.Futhark.Syntax: instance GHC.Show.Show vn => GHC.Show.Show (Language.Futhark.Syntax.DimDecl vn)
- Language.Futhark.Syntax: instance GHC.Show.Show vn => GHC.Show.Show (Language.Futhark.Syntax.DimExp vn)
- Language.Futhark.Syntax: instance Language.Futhark.Syntax.ArrayDim ()
- Language.Futhark.Syntax: instance Language.Futhark.Syntax.ArrayDim (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName)
- Language.Futhark.Syntax: newtype ShapeDecl dim
- Language.Futhark.Syntax: qualNameFromTypeName :: TypeName -> QualName VName
- Language.Futhark.Syntax: typeNameFromQualName :: QualName VName -> TypeName
- Language.Futhark.Syntax: unifyDims :: ArrayDim dim => dim -> dim -> Maybe dim
- Language.Futhark.Traversals: [mapOnQualName] :: ASTMapper m -> QualName VName -> m (QualName VName)
- Language.Futhark.Traversals: instance Language.Futhark.Traversals.ASTMappable (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName)
- Language.Futhark.Traversals: instance Language.Futhark.Traversals.ASTMappable (Language.Futhark.Syntax.DimExp Language.Futhark.Core.VName)
- Language.Futhark.TypeChecker.Monad: checkNamedDim :: MonadTypeChecker m => SrcLoc -> QualName Name -> m (QualName VName)
- Language.Futhark.TypeChecker.Terms.Monad: dimFromArg :: Maybe (QualName VName) -> Exp -> TermTypeM (DimDecl VName, Maybe VName)
- Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName)
- Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.RetTypeBase (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName) ())
- Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.RetTypeBase (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName) Language.Futhark.Syntax.Aliasing)
- Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.TypeBase (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName) ())
- Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.TypeBase (Language.Futhark.Syntax.DimDecl Language.Futhark.Core.VName) Language.Futhark.Syntax.Aliasing)
- Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable d => Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.ShapeDecl d)
+ Futhark.Actions: compileMulticoreToISPCAction :: FutharkConfig -> CompilerMode -> FilePath -> Action MCMem
+ Futhark.Analysis.HORep.SOAC: applyTransforms :: MonadBuilder m => ArrayTransforms -> VName -> m VName
+ Futhark.Analysis.HORep.SOAC: inputTransforms :: Input -> ArrayTransforms
+ Futhark.Analysis.LastUse: type LastUse = Map VName VName
+ Futhark.CLI.Misc: mainTokens :: String -> [String] -> IO ()
+ Futhark.CLI.MulticoreISPC: main :: String -> [String] -> IO ()
+ Futhark.CodeGen.Backends.GenericC: CopyBarrier :: CopyBarrier
+ Futhark.CodeGen.Backends.GenericC: CopyNoBarrier :: CopyBarrier
+ Futhark.CodeGen.Backends.GenericC: OpaqueTypeDecl :: String -> HeaderSection
+ Futhark.CodeGen.Backends.GenericC: compileProg' :: MonadFreshNames m => Text -> Text -> Operations op s -> s -> CompilerM op s () -> Text -> (Space, [Space]) -> [Option] -> Definitions op -> m (CParts, CompilerState s)
+ Futhark.CodeGen.Backends.GenericC: data CompilerEnv op s
+ Futhark.CodeGen.Backends.GenericC: data CopyBarrier
+ Futhark.CodeGen.Backends.GenericC: derefPointer :: Exp -> Exp -> Type -> Exp
+ Futhark.CodeGen.Backends.GenericC: errorMsgString :: ErrorMsg Exp -> CompilerM op s (String, [Exp])
+ Futhark.CodeGen.Backends.GenericC: fatMemAlloc :: Space -> String
+ Futhark.CodeGen.Backends.GenericC: fatMemSet :: Space -> String
+ Futhark.CodeGen.Backends.GenericC: fatMemUnRef :: Space -> String
+ Futhark.CodeGen.Backends.GenericC: instance GHC.Classes.Eq Futhark.CodeGen.Backends.GenericC.CopyBarrier
+ Futhark.CodeGen.Backends.GenericC: instance GHC.Show.Show Futhark.CodeGen.Backends.GenericC.CopyBarrier
+ Futhark.CodeGen.Backends.GenericC: linearCode :: Code op -> [Code op]
+ Futhark.CodeGen.Backends.MulticoreC: MemBlock :: ValueType
+ Futhark.CodeGen.Backends.MulticoreC: Prim :: PrimType -> ValueType
+ Futhark.CodeGen.Backends.MulticoreC: RawMem :: ValueType
+ Futhark.CodeGen.Backends.MulticoreC: addTimingFields :: Name -> CompilerM op s ()
+ Futhark.CodeGen.Backends.MulticoreC: atomicOps :: AtomicOp -> (Type -> VName -> CompilerM op s Type) -> CompilerM op s ()
+ Futhark.CodeGen.Backends.MulticoreC: closureFreeStructField :: VName -> Name
+ Futhark.CodeGen.Backends.MulticoreC: compileOp :: OpCompiler Multicore s
+ Futhark.CodeGen.Backends.MulticoreC: data ValueType
+ Futhark.CodeGen.Backends.MulticoreC: functionIterations :: Name -> Id
+ Futhark.CodeGen.Backends.MulticoreC: functionTiming :: Name -> Id
+ Futhark.CodeGen.Backends.MulticoreC: generateParLoopFn :: ToIdent a => Map VName Space -> String -> MCCode -> a -> [(VName, (Type, ValueType))] -> [(VName, (Type, ValueType))] -> CompilerM Multicore s Name
+ Futhark.CodeGen.Backends.MulticoreC: multiCoreReport :: [(Name, Bool)] -> [BlockItem]
+ Futhark.CodeGen.Backends.MulticoreC: multicoreDef :: DefSpecifier s
+ Futhark.CodeGen.Backends.MulticoreC: multicoreName :: String -> CompilerM op s Name
+ Futhark.CodeGen.Backends.MulticoreC: paramToCType :: Param -> CompilerM op s (Type, ValueType)
+ Futhark.CodeGen.Backends.MulticoreC: prepareTaskStruct :: DefSpecifier s -> String -> [VName] -> [(Type, ValueType)] -> [VName] -> [(Type, ValueType)] -> CompilerM Multicore s Name
+ Futhark.CodeGen.Backends.MulticoreC: type DefSpecifier s = String -> (Name -> CompilerM Multicore s Definition) -> CompilerM Multicore s Name
+ Futhark.CodeGen.Backends.MulticoreISPC: CParts :: Text -> Text -> Text -> Text -> Text -> Text -> CParts
+ Futhark.CodeGen.Backends.MulticoreISPC: [cCLI] :: CParts -> Text
+ Futhark.CodeGen.Backends.MulticoreISPC: [cHeader] :: CParts -> Text
+ Futhark.CodeGen.Backends.MulticoreISPC: [cJsonManifest] :: CParts -> Text
+ Futhark.CodeGen.Backends.MulticoreISPC: [cLib] :: CParts -> Text
+ Futhark.CodeGen.Backends.MulticoreISPC: [cServer] :: CParts -> Text
+ Futhark.CodeGen.Backends.MulticoreISPC: [cUtils] :: CParts -> Text
+ Futhark.CodeGen.Backends.MulticoreISPC: asExecutable :: CParts -> Text
+ Futhark.CodeGen.Backends.MulticoreISPC: asLibrary :: CParts -> (Text, Text, Text)
+ Futhark.CodeGen.Backends.MulticoreISPC: asServer :: CParts -> Text
+ Futhark.CodeGen.Backends.MulticoreISPC: compileProg :: MonadFreshNames m => Text -> Prog MCMem -> m (Warnings, (CParts, Text))
+ Futhark.CodeGen.Backends.MulticoreISPC: data CParts
+ Futhark.CodeGen.Backends.MulticoreISPC: data ISPCState
+ Futhark.CodeGen.Backends.MulticoreISPC: instance Control.Monad.Reader.Class.MonadReader Futhark.IR.Prop.Names.Names Futhark.CodeGen.Backends.MulticoreISPC.VariabilityM
+ Futhark.CodeGen.Backends.MulticoreISPC: instance Control.Monad.State.Class.MonadState Futhark.CodeGen.Backends.MulticoreISPC.Dependencies Futhark.CodeGen.Backends.MulticoreISPC.VariabilityM
+ Futhark.CodeGen.Backends.MulticoreISPC: instance GHC.Base.Applicative Futhark.CodeGen.Backends.MulticoreISPC.VariabilityM
+ Futhark.CodeGen.Backends.MulticoreISPC: instance GHC.Base.Functor Futhark.CodeGen.Backends.MulticoreISPC.VariabilityM
+ Futhark.CodeGen.Backends.MulticoreISPC: instance GHC.Base.Monad Futhark.CodeGen.Backends.MulticoreISPC.VariabilityM
+ Futhark.CodeGen.Backends.MulticoreISPC: instance GHC.Classes.Eq Futhark.CodeGen.Backends.MulticoreISPC.Variability
+ Futhark.CodeGen.Backends.MulticoreISPC: instance GHC.Classes.Ord Futhark.CodeGen.Backends.MulticoreISPC.Variability
+ Futhark.CodeGen.Backends.MulticoreISPC: instance GHC.Show.Show Futhark.CodeGen.Backends.MulticoreISPC.Variability
+ Futhark.CodeGen.Backends.MulticoreISPC: operations :: Operations Multicore ISPCState
+ Futhark.CodeGen.Backends.SimpleRep: instance Language.C.Quote.Base.ToExp Language.Futhark.Primitive.FloatValue
+ Futhark.CodeGen.Backends.SimpleRep: instance Language.C.Quote.Base.ToExp Language.Futhark.Primitive.IntValue
+ Futhark.CodeGen.Backends.SimpleRep: instance Language.C.Quote.Base.ToExp Language.Futhark.Primitive.PrimValue
+ Futhark.CodeGen.ImpCode: EntryPoint :: Name -> [(Uniqueness, ExternalValue)] -> [((Name, Uniqueness), ExternalValue)] -> EntryPoint
+ Futhark.CodeGen.ImpCode: OpaqueRecord :: [(Name, EntryPointType)] -> OpaqueType
+ Futhark.CodeGen.ImpCode: OpaqueType :: [ValueType] -> OpaqueType
+ Futhark.CodeGen.ImpCode: OpaqueTypes :: [(String, OpaqueType)] -> OpaqueTypes
+ Futhark.CodeGen.ImpCode: Rank :: Int -> Rank
+ Futhark.CodeGen.ImpCode: Signed :: Signedness
+ Futhark.CodeGen.ImpCode: TypeOpaque :: String -> EntryPointType
+ Futhark.CodeGen.ImpCode: TypeTransparent :: ValueType -> EntryPointType
+ Futhark.CodeGen.ImpCode: Unsigned :: Signedness
+ Futhark.CodeGen.ImpCode: ValueType :: Signedness -> Rank -> PrimType -> ValueType
+ Futhark.CodeGen.ImpCode: [defTypes] :: Definitions a -> OpaqueTypes
+ Futhark.CodeGen.ImpCode: [entryPointArgs] :: EntryPoint -> [((Name, Uniqueness), ExternalValue)]
+ Futhark.CodeGen.ImpCode: [entryPointName] :: EntryPoint -> Name
+ Futhark.CodeGen.ImpCode: [entryPointResults] :: EntryPoint -> [(Uniqueness, ExternalValue)]
+ Futhark.CodeGen.ImpCode: data EntryPoint
+ Futhark.CodeGen.ImpCode: data EntryPointType
+ Futhark.CodeGen.ImpCode: data OpaqueType
+ Futhark.CodeGen.ImpCode: data ValueType
+ Futhark.CodeGen.ImpCode: instance Futhark.IR.Prop.Names.FreeIn Futhark.CodeGen.ImpCode.EntryPoint
+ Futhark.CodeGen.ImpCode: instance GHC.Show.Show Futhark.CodeGen.ImpCode.EntryPoint
+ Futhark.CodeGen.ImpCode: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.CodeGen.ImpCode.EntryPoint
+ Futhark.CodeGen.ImpCode: newtype OpaqueTypes
+ Futhark.CodeGen.ImpCode: newtype Rank
+ Futhark.CodeGen.ImpCode.Multicore: ExtractLane :: VName -> Exp -> Exp -> Multicore
+ Futhark.CodeGen.ImpCode.Multicore: ForEach :: VName -> Exp -> Exp -> MCCode -> Multicore
+ Futhark.CodeGen.ImpCode.Multicore: ForEachActive :: VName -> MCCode -> Multicore
+ Futhark.CodeGen.ImpCode.Multicore: ISPCKernel :: MCCode -> [Param] -> Multicore
+ Futhark.CodeGen.ImpGen: askAttrs :: ImpM rep r op Attrs
+ Futhark.CodeGen.ImpGen.GPU.Base: [kernelGroupSizeCount] :: KernelConstants -> Count GroupSize SubExp
+ Futhark.CodeGen.ImpGen.GPU.Base: [kernelNumGroupsCount] :: KernelConstants -> Count NumGroups SubExp
+ Futhark.CodeGen.ImpGen.Multicore.Base: Scalar :: ChunkLoopVectorization
+ Futhark.CodeGen.ImpGen.Multicore.Base: Vectorized :: ChunkLoopVectorization
+ Futhark.CodeGen.ImpGen.Multicore.Base: data ChunkLoopVectorization
+ Futhark.CodeGen.ImpGen.Multicore.Base: extractVectorLane :: TExp Int64 -> MulticoreGen MCCode -> MulticoreGen ()
+ Futhark.CodeGen.ImpGen.Multicore.Base: generateUniformizeLoop :: (TExp Int64 -> MulticoreGen ()) -> MulticoreGen ()
+ Futhark.CodeGen.ImpGen.Multicore.Base: inISPC :: MulticoreGen () -> MulticoreGen ()
+ Futhark.CodeGen.ImpGen.Multicore.Base: sLoopNestVectorized :: Shape -> ([TExp Int64] -> MulticoreGen ()) -> MulticoreGen ()
+ Futhark.CodeGen.ImpGen.Multicore.Base: toParam :: VName -> TypeBase shape u -> MulticoreGen [Param]
+ Futhark.CodeGen.RTS.C: ispcUtilH :: Text
+ Futhark.CodeGen.RTS.C: uniformH :: Text
+ Futhark.IR.GPU: ppScatter :: (PrettyRep rep, Pretty inp) => SubExp -> [inp] -> Lambda rep -> [(Shape, Int, VName)] -> Doc
+ Futhark.IR.GPU: ppStream :: (PrettyRep rep, Pretty inp) => SubExp -> [inp] -> StreamForm rep -> [SubExp] -> Lambda rep -> Doc
+ Futhark.IR.MC: ppScatter :: (PrettyRep rep, Pretty inp) => SubExp -> [inp] -> Lambda rep -> [(Shape, Int, VName)] -> Doc
+ Futhark.IR.MC: ppStream :: (PrettyRep rep, Pretty inp) => SubExp -> [inp] -> StreamForm rep -> [SubExp] -> Lambda rep -> Doc
+ Futhark.IR.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Syntax.Core.EntryPointType
+ Futhark.IR.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Syntax.Core.OpaqueType
+ Futhark.IR.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Syntax.Core.OpaqueTypes
+ Futhark.IR.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Syntax.Core.Rank
+ Futhark.IR.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Syntax.Core.Signedness
+ Futhark.IR.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Syntax.Core.ValueType
+ Futhark.IR.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Futhark.IR.Syntax.EntryResult
+ Futhark.IR.Prop.Constants: instance Futhark.IR.Prop.Constants.IsValue Language.Futhark.Primitive.FloatValue
+ Futhark.IR.Prop.Constants: instance Futhark.IR.Prop.Constants.IsValue Language.Futhark.Primitive.IntValue
+ Futhark.IR.Prop.Constants: instance Futhark.IR.Prop.Constants.IsValue Language.Futhark.Primitive.PrimValue
+ Futhark.IR.Prop.Names: instance Futhark.IR.Prop.Names.FreeIn Language.Futhark.Primitive.PrimType
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.HistOp rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.Reduce rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.Scan rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.ScremaForm rep)
+ Futhark.IR.SOACS.SOAC: instance Futhark.IR.Prop.ASTRep rep => Futhark.IR.Prop.Names.FreeIn (Futhark.IR.SOACS.SOAC.StreamForm rep)
+ Futhark.IR.SOACS.SOAC: ppScatter :: (PrettyRep rep, Pretty inp) => SubExp -> [inp] -> Lambda rep -> [(Shape, Int, VName)] -> Doc
+ Futhark.IR.SOACS.SOAC: ppStream :: (PrettyRep rep, Pretty inp) => SubExp -> [inp] -> StreamForm rep -> [SubExp] -> Lambda rep -> Doc
+ Futhark.IR.Syntax: EntryResult :: Uniqueness -> EntryPointType -> EntryResult
+ Futhark.IR.Syntax: [entryParamUniqueness] :: EntryParam -> Uniqueness
+ Futhark.IR.Syntax: [entryResultType] :: EntryResult -> EntryPointType
+ Futhark.IR.Syntax: [entryResultUniqueness] :: EntryResult -> Uniqueness
+ Futhark.IR.Syntax: [progTypes] :: Prog rep -> OpaqueTypes
+ Futhark.IR.Syntax: data EntryResult
+ Futhark.IR.Syntax: instance GHC.Classes.Eq Futhark.IR.Syntax.EntryResult
+ Futhark.IR.Syntax: instance GHC.Classes.Ord Futhark.IR.Syntax.EntryResult
+ Futhark.IR.Syntax: instance GHC.Show.Show Futhark.IR.Syntax.EntryResult
+ Futhark.IR.Syntax.Core: OpaqueRecord :: [(Name, EntryPointType)] -> OpaqueType
+ Futhark.IR.Syntax.Core: OpaqueType :: [ValueType] -> OpaqueType
+ Futhark.IR.Syntax.Core: OpaqueTypes :: [(String, OpaqueType)] -> OpaqueTypes
+ Futhark.IR.Syntax.Core: Signed :: Signedness
+ Futhark.IR.Syntax.Core: TypeOpaque :: String -> EntryPointType
+ Futhark.IR.Syntax.Core: TypeTransparent :: ValueType -> EntryPointType
+ Futhark.IR.Syntax.Core: Unsigned :: Signedness
+ Futhark.IR.Syntax.Core: ValueType :: Signedness -> Rank -> PrimType -> ValueType
+ Futhark.IR.Syntax.Core: data EntryPointType
+ Futhark.IR.Syntax.Core: data OpaqueType
+ Futhark.IR.Syntax.Core: data Signedness
+ Futhark.IR.Syntax.Core: data ValueType
+ Futhark.IR.Syntax.Core: instance GHC.Base.Monoid Futhark.IR.Syntax.Core.OpaqueTypes
+ Futhark.IR.Syntax.Core: instance GHC.Base.Semigroup Futhark.IR.Syntax.Core.OpaqueTypes
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Eq Futhark.IR.Syntax.Core.EntryPointType
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Eq Futhark.IR.Syntax.Core.OpaqueType
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Eq Futhark.IR.Syntax.Core.OpaqueTypes
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Eq Futhark.IR.Syntax.Core.Signedness
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Eq Futhark.IR.Syntax.Core.ValueType
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Ord Futhark.IR.Syntax.Core.EntryPointType
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Ord Futhark.IR.Syntax.Core.OpaqueType
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Ord Futhark.IR.Syntax.Core.OpaqueTypes
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Ord Futhark.IR.Syntax.Core.Signedness
+ Futhark.IR.Syntax.Core: instance GHC.Classes.Ord Futhark.IR.Syntax.Core.ValueType
+ Futhark.IR.Syntax.Core: instance GHC.Show.Show Futhark.IR.Syntax.Core.EntryPointType
+ Futhark.IR.Syntax.Core: instance GHC.Show.Show Futhark.IR.Syntax.Core.OpaqueType
+ Futhark.IR.Syntax.Core: instance GHC.Show.Show Futhark.IR.Syntax.Core.OpaqueTypes
+ Futhark.IR.Syntax.Core: instance GHC.Show.Show Futhark.IR.Syntax.Core.Signedness
+ Futhark.IR.Syntax.Core: instance GHC.Show.Show Futhark.IR.Syntax.Core.ValueType
+ Futhark.IR.Syntax.Core: newtype OpaqueTypes
+ Futhark.Internalise.Entry: data VisibleTypes
+ Futhark.Internalise.Entry: entryPoint :: VisibleTypes -> Name -> [(EntryParam, [Param DeclType])] -> (EntryType, [[TypeBase Rank Uniqueness]]) -> (EntryPoint, OpaqueTypes)
+ Futhark.Internalise.Entry: visibleTypes :: Imports -> VisibleTypes
+ Futhark.Internalise.Monad: addOpaques :: OpaqueTypes -> InternaliseM ()
+ Futhark.Internalise.Monomorphise: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape Futhark.Internalise.Monomorphise.MonoSize)
+ Futhark.Optimise.Fusion: instance Control.Monad.State.Class.MonadState Futhark.Optimise.Fusion.FusionEnv Futhark.Optimise.Fusion.FusionM
+ Futhark.Optimise.Fusion: instance Futhark.IR.Prop.Scope.HasScope Futhark.IR.SOACS.SOACS Futhark.Optimise.Fusion.FusionM
+ Futhark.Optimise.Fusion: instance Futhark.IR.Prop.Scope.LocalScope Futhark.IR.SOACS.SOACS Futhark.Optimise.Fusion.FusionM
+ Futhark.Optimise.Fusion: instance Futhark.MonadFreshNames.MonadFreshNames Futhark.Optimise.Fusion.FusionM
+ Futhark.Optimise.Fusion: instance GHC.Base.Applicative Futhark.Optimise.Fusion.FusionM
+ Futhark.Optimise.Fusion: instance GHC.Base.Functor Futhark.Optimise.Fusion.FusionM
+ Futhark.Optimise.Fusion: instance GHC.Base.Monad Futhark.Optimise.Fusion.FusionM
+ Futhark.Optimise.Fusion.GraphRep: Alias :: VName -> EdgeT
+ Futhark.Optimise.Fusion.GraphRep: Cons :: VName -> EdgeT
+ Futhark.Optimise.Fusion.GraphRep: Dep :: VName -> EdgeT
+ Futhark.Optimise.Fusion.GraphRep: DepGraph :: Gr NodeT EdgeT -> ProducerMapping -> AliasTable -> DepGraph
+ Futhark.Optimise.Fusion.GraphRep: DoNode :: Stm SOACS -> [(NodeT, [EdgeT])] -> NodeT
+ Futhark.Optimise.Fusion.GraphRep: Fake :: VName -> EdgeT
+ Futhark.Optimise.Fusion.GraphRep: FinalNode :: Stms SOACS -> NodeT -> Stms SOACS -> NodeT
+ Futhark.Optimise.Fusion.GraphRep: FreeNode :: VName -> NodeT
+ Futhark.Optimise.Fusion.GraphRep: IfNode :: Stm SOACS -> [(NodeT, [EdgeT])] -> NodeT
+ Futhark.Optimise.Fusion.GraphRep: InfDep :: VName -> EdgeT
+ Futhark.Optimise.Fusion.GraphRep: Res :: VName -> EdgeT
+ Futhark.Optimise.Fusion.GraphRep: ResNode :: VName -> NodeT
+ Futhark.Optimise.Fusion.GraphRep: SoacNode :: ArrayTransforms -> Pat Type -> SOAC SOACS -> StmAux (ExpDec SOACS) -> NodeT
+ Futhark.Optimise.Fusion.GraphRep: StmNode :: Stm SOACS -> NodeT
+ Futhark.Optimise.Fusion.GraphRep: [dgAliasTable] :: DepGraph -> AliasTable
+ Futhark.Optimise.Fusion.GraphRep: [dgGraph] :: DepGraph -> Gr NodeT EdgeT
+ Futhark.Optimise.Fusion.GraphRep: [dgProducerMapping] :: DepGraph -> ProducerMapping
+ Futhark.Optimise.Fusion.GraphRep: applyAugs :: Monad m => [DepGraphAug m] -> DepGraphAug m
+ Futhark.Optimise.Fusion.GraphRep: contractEdge :: Monad m => Node -> DepContext -> DepGraphAug m
+ Futhark.Optimise.Fusion.GraphRep: data DepGraph
+ Futhark.Optimise.Fusion.GraphRep: data EdgeT
+ Futhark.Optimise.Fusion.GraphRep: data NodeT
+ Futhark.Optimise.Fusion.GraphRep: depsFromEdge :: DepEdge -> VName
+ Futhark.Optimise.Fusion.GraphRep: edgesBetween :: DepGraph -> Node -> Node -> [DepEdge]
+ Futhark.Optimise.Fusion.GraphRep: getName :: EdgeT -> VName
+ Futhark.Optimise.Fusion.GraphRep: instance GHC.Classes.Eq Futhark.Optimise.Fusion.GraphRep.Classification
+ Futhark.Optimise.Fusion.GraphRep: instance GHC.Classes.Eq Futhark.Optimise.Fusion.GraphRep.EdgeT
+ Futhark.Optimise.Fusion.GraphRep: instance GHC.Classes.Eq Futhark.Optimise.Fusion.GraphRep.NodeT
+ Futhark.Optimise.Fusion.GraphRep: instance GHC.Classes.Ord Futhark.Optimise.Fusion.GraphRep.Classification
+ Futhark.Optimise.Fusion.GraphRep: instance GHC.Classes.Ord Futhark.Optimise.Fusion.GraphRep.EdgeT
+ Futhark.Optimise.Fusion.GraphRep: instance GHC.Show.Show Futhark.Optimise.Fusion.GraphRep.Classification
+ Futhark.Optimise.Fusion.GraphRep: instance GHC.Show.Show Futhark.Optimise.Fusion.GraphRep.EdgeT
+ Futhark.Optimise.Fusion.GraphRep: instance GHC.Show.Show Futhark.Optimise.Fusion.GraphRep.NodeT
+ Futhark.Optimise.Fusion.GraphRep: isCons :: EdgeT -> Bool
+ Futhark.Optimise.Fusion.GraphRep: isDep :: EdgeT -> Bool
+ Futhark.Optimise.Fusion.GraphRep: isInf :: (Node, Node, EdgeT) -> Bool
+ Futhark.Optimise.Fusion.GraphRep: isRealNode :: NodeT -> Bool
+ Futhark.Optimise.Fusion.GraphRep: mapAcross :: Monad m => (DepContext -> m DepContext) -> DepGraphAug m
+ Futhark.Optimise.Fusion.GraphRep: mergedContext :: Ord b => a -> Context a b -> Context a b -> Context a b
+ Futhark.Optimise.Fusion.GraphRep: mkDepGraph :: (HasScope SOACS m, Monad m) => Body SOACS -> m DepGraph
+ Futhark.Optimise.Fusion.GraphRep: nodeFromLNode :: DepNode -> Node
+ Futhark.Optimise.Fusion.GraphRep: pprg :: DepGraph -> String
+ Futhark.Optimise.Fusion.GraphRep: reachable :: DepGraph -> Node -> Node -> Bool
+ Futhark.Optimise.Fusion.GraphRep: type DepContext = Context NodeT EdgeT
+ Futhark.Optimise.Fusion.GraphRep: type DepGraphAug m = DepGraph -> m DepGraph
+ Futhark.Optimise.Fusion.GraphRep: type DepNode = LNode NodeT
+ Futhark.Optimise.Fusion.TryFusion: FusedSOAC :: SOAC -> ArrayTransforms -> [VName] -> FusedSOAC
+ Futhark.Optimise.Fusion.TryFusion: [fsOutNames] :: FusedSOAC -> [VName]
+ Futhark.Optimise.Fusion.TryFusion: [fsOutputTransform] :: FusedSOAC -> ArrayTransforms
+ Futhark.Optimise.Fusion.TryFusion: [fsSOAC] :: FusedSOAC -> SOAC
+ Futhark.Optimise.Fusion.TryFusion: attemptFusion :: (HasScope SOACS m, MonadFreshNames m) => Names -> [VName] -> SOAC -> FusedSOAC -> m (Maybe FusedSOAC)
+ Futhark.Optimise.Fusion.TryFusion: data FusedSOAC
+ Futhark.Optimise.Fusion.TryFusion: instance Control.Monad.Fail.MonadFail Futhark.Optimise.Fusion.TryFusion.TryFusion
+ Futhark.Optimise.Fusion.TryFusion: instance Futhark.IR.Prop.Scope.HasScope Futhark.IR.SOACS.SOACS Futhark.Optimise.Fusion.TryFusion.TryFusion
+ Futhark.Optimise.Fusion.TryFusion: instance Futhark.IR.Prop.Scope.LocalScope Futhark.IR.SOACS.SOACS Futhark.Optimise.Fusion.TryFusion.TryFusion
+ Futhark.Optimise.Fusion.TryFusion: instance Futhark.MonadFreshNames.MonadFreshNames Futhark.Optimise.Fusion.TryFusion.TryFusion
+ Futhark.Optimise.Fusion.TryFusion: instance GHC.Base.Alternative Futhark.Optimise.Fusion.TryFusion.TryFusion
+ Futhark.Optimise.Fusion.TryFusion: instance GHC.Base.Applicative Futhark.Optimise.Fusion.TryFusion.TryFusion
+ Futhark.Optimise.Fusion.TryFusion: instance GHC.Base.Functor Futhark.Optimise.Fusion.TryFusion.TryFusion
+ Futhark.Optimise.Fusion.TryFusion: instance GHC.Base.Monad Futhark.Optimise.Fusion.TryFusion.TryFusion
+ Futhark.Optimise.Fusion.TryFusion: instance GHC.Show.Show Futhark.Optimise.Fusion.TryFusion.FusedSOAC
+ Futhark.Optimise.ReduceDeviceSyncs: instance Control.Monad.Reader.Class.MonadReader Futhark.Optimise.ReduceDeviceSyncs.MigrationTable.MigrationTable Futhark.Optimise.ReduceDeviceSyncs.ReduceM
+ Futhark.Optimise.ReduceDeviceSyncs: instance Control.Monad.State.Class.MonadState Futhark.Optimise.ReduceDeviceSyncs.State Futhark.Optimise.ReduceDeviceSyncs.ReduceM
+ Futhark.Optimise.ReduceDeviceSyncs: instance Futhark.MonadFreshNames.MonadFreshNames Futhark.Optimise.ReduceDeviceSyncs.ReduceM
+ Futhark.Optimise.ReduceDeviceSyncs: instance GHC.Base.Applicative Futhark.Optimise.ReduceDeviceSyncs.ReduceM
+ Futhark.Optimise.ReduceDeviceSyncs: instance GHC.Base.Functor Futhark.Optimise.ReduceDeviceSyncs.ReduceM
+ Futhark.Optimise.ReduceDeviceSyncs: instance GHC.Base.Monad Futhark.Optimise.ReduceDeviceSyncs.ReduceM
+ Futhark.Optimise.ReduceDeviceSyncs.MigrationTable: analyseConsts :: HostOnlyFuns -> [FunDef GPU] -> Stms GPU -> MigrationTable
+ Futhark.Optimise.ReduceDeviceSyncs.MigrationTable: analyseFunDef :: HostOnlyFuns -> FunDef GPU -> MigrationTable
+ Futhark.Optimise.ReduceDeviceSyncs.MigrationTable: hostOnlyFunDefs :: [FunDef GPU] -> HostOnlyFuns
+ Futhark.Optimise.ReduceDeviceSyncs.MigrationTable: instance GHC.Base.Semigroup Futhark.Optimise.ReduceDeviceSyncs.MigrationTable.MigrationTable
+ Futhark.Optimise.Simplify.Engine: instance Futhark.Optimise.Simplify.Engine.Simplifiable Language.Futhark.Primitive.PrimType
+ Futhark.Transform.Rename: instance Futhark.Transform.Rename.Rename Language.Futhark.Primitive.PrimType
+ Futhark.Transform.Substitute: instance Futhark.Transform.Substitute.Substitute Language.Futhark.Primitive.PrimType
+ Language.Futhark.FreeVars: FV :: Map VName StructType -> FV
+ Language.Futhark.FreeVars: [unFV] :: FV -> Map VName StructType
+ Language.Futhark.FreeVars: freeInExp :: ExpBase Info VName -> FV
+ Language.Futhark.FreeVars: freeInPat :: PatBase Info VName -> Set VName
+ Language.Futhark.FreeVars: freeInType :: TypeBase Size as -> Set VName
+ Language.Futhark.FreeVars: freeWithout :: FV -> Set VName -> FV
+ Language.Futhark.FreeVars: instance GHC.Base.Monoid Language.Futhark.FreeVars.FV
+ Language.Futhark.FreeVars: instance GHC.Base.Semigroup Language.Futhark.FreeVars.FV
+ Language.Futhark.FreeVars: instance GHC.Show.Show Language.Futhark.FreeVars.FV
+ Language.Futhark.FreeVars: newtype FV
+ Language.Futhark.Pretty: instance Language.Futhark.Pretty.IsName vn => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.SizeExp vn)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape ())
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape GHC.Int.Int64)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape GHC.Types.Bool)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape Language.Futhark.Syntax.Size)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape dim) => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.RetTypeBase dim as)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape dim) => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.ScalarTypeBase dim as)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape dim) => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.TypeArg dim)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.Shape dim) => Text.PrettyPrint.Mainland.Class.Pretty (Language.Futhark.Syntax.TypeBase dim as)
+ Language.Futhark.Pretty: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Syntax.Size
+ Language.Futhark.Primitive: AShr :: IntType -> BinOp
+ Language.Futhark.Primitive: Abs :: IntType -> UnOp
+ Language.Futhark.Primitive: Add :: IntType -> Overflow -> BinOp
+ Language.Futhark.Primitive: And :: IntType -> BinOp
+ Language.Futhark.Primitive: BToF :: FloatType -> ConvOp
+ Language.Futhark.Primitive: BToI :: IntType -> ConvOp
+ Language.Futhark.Primitive: Bool :: PrimType
+ Language.Futhark.Primitive: BoolValue :: !Bool -> PrimValue
+ Language.Futhark.Primitive: CmpEq :: PrimType -> CmpOp
+ Language.Futhark.Primitive: CmpLle :: CmpOp
+ Language.Futhark.Primitive: CmpLlt :: CmpOp
+ Language.Futhark.Primitive: CmpSle :: IntType -> CmpOp
+ Language.Futhark.Primitive: CmpSlt :: IntType -> CmpOp
+ Language.Futhark.Primitive: CmpUle :: IntType -> CmpOp
+ Language.Futhark.Primitive: CmpUlt :: IntType -> CmpOp
+ Language.Futhark.Primitive: Complement :: IntType -> UnOp
+ Language.Futhark.Primitive: FAbs :: FloatType -> UnOp
+ Language.Futhark.Primitive: FAdd :: FloatType -> BinOp
+ Language.Futhark.Primitive: FCmpLe :: FloatType -> CmpOp
+ Language.Futhark.Primitive: FCmpLt :: FloatType -> CmpOp
+ Language.Futhark.Primitive: FDiv :: FloatType -> BinOp
+ Language.Futhark.Primitive: FMax :: FloatType -> BinOp
+ Language.Futhark.Primitive: FMin :: FloatType -> BinOp
+ Language.Futhark.Primitive: FMod :: FloatType -> BinOp
+ Language.Futhark.Primitive: FMul :: FloatType -> BinOp
+ Language.Futhark.Primitive: FPConv :: FloatType -> FloatType -> ConvOp
+ Language.Futhark.Primitive: FPToSI :: FloatType -> IntType -> ConvOp
+ Language.Futhark.Primitive: FPToUI :: FloatType -> IntType -> ConvOp
+ Language.Futhark.Primitive: FPow :: FloatType -> BinOp
+ Language.Futhark.Primitive: FSignum :: FloatType -> UnOp
+ Language.Futhark.Primitive: FSub :: FloatType -> BinOp
+ Language.Futhark.Primitive: FToB :: FloatType -> ConvOp
+ Language.Futhark.Primitive: Float16 :: FloatType
+ Language.Futhark.Primitive: Float16Value :: !Half -> FloatValue
+ Language.Futhark.Primitive: Float32 :: FloatType
+ Language.Futhark.Primitive: Float32Value :: !Float -> FloatValue
+ Language.Futhark.Primitive: Float64 :: FloatType
+ Language.Futhark.Primitive: Float64Value :: !Double -> FloatValue
+ Language.Futhark.Primitive: FloatType :: FloatType -> PrimType
+ Language.Futhark.Primitive: FloatValue :: !FloatValue -> PrimValue
+ Language.Futhark.Primitive: IToB :: IntType -> ConvOp
+ Language.Futhark.Primitive: Int16 :: IntType
+ Language.Futhark.Primitive: Int16Value :: !Int16 -> IntValue
+ Language.Futhark.Primitive: Int32 :: IntType
+ Language.Futhark.Primitive: Int32Value :: !Int32 -> IntValue
+ Language.Futhark.Primitive: Int64 :: IntType
+ Language.Futhark.Primitive: Int64Value :: !Int64 -> IntValue
+ Language.Futhark.Primitive: Int8 :: IntType
+ Language.Futhark.Primitive: Int8Value :: !Int8 -> IntValue
+ Language.Futhark.Primitive: IntType :: IntType -> PrimType
+ Language.Futhark.Primitive: IntValue :: !IntValue -> PrimValue
+ Language.Futhark.Primitive: LShr :: IntType -> BinOp
+ Language.Futhark.Primitive: LogAnd :: BinOp
+ Language.Futhark.Primitive: LogOr :: BinOp
+ Language.Futhark.Primitive: Mul :: IntType -> Overflow -> BinOp
+ Language.Futhark.Primitive: Not :: UnOp
+ Language.Futhark.Primitive: Or :: IntType -> BinOp
+ Language.Futhark.Primitive: OverflowUndef :: Overflow
+ Language.Futhark.Primitive: OverflowWrap :: Overflow
+ Language.Futhark.Primitive: Pow :: IntType -> BinOp
+ Language.Futhark.Primitive: SDiv :: IntType -> Safety -> BinOp
+ Language.Futhark.Primitive: SDivUp :: IntType -> Safety -> BinOp
+ Language.Futhark.Primitive: SExt :: IntType -> IntType -> ConvOp
+ Language.Futhark.Primitive: SIToFP :: IntType -> FloatType -> ConvOp
+ Language.Futhark.Primitive: SMax :: IntType -> BinOp
+ Language.Futhark.Primitive: SMin :: IntType -> BinOp
+ Language.Futhark.Primitive: SMod :: IntType -> Safety -> BinOp
+ Language.Futhark.Primitive: SQuot :: IntType -> Safety -> BinOp
+ Language.Futhark.Primitive: SRem :: IntType -> Safety -> BinOp
+ Language.Futhark.Primitive: SSignum :: IntType -> UnOp
+ Language.Futhark.Primitive: Safe :: Safety
+ Language.Futhark.Primitive: Shl :: IntType -> BinOp
+ Language.Futhark.Primitive: Sub :: IntType -> Overflow -> BinOp
+ Language.Futhark.Primitive: UDiv :: IntType -> Safety -> BinOp
+ Language.Futhark.Primitive: UDivUp :: IntType -> Safety -> BinOp
+ Language.Futhark.Primitive: UIToFP :: IntType -> FloatType -> ConvOp
+ Language.Futhark.Primitive: UMax :: IntType -> BinOp
+ Language.Futhark.Primitive: UMin :: IntType -> BinOp
+ Language.Futhark.Primitive: UMod :: IntType -> Safety -> BinOp
+ Language.Futhark.Primitive: USignum :: IntType -> UnOp
+ Language.Futhark.Primitive: Unit :: PrimType
+ Language.Futhark.Primitive: UnitValue :: PrimValue
+ Language.Futhark.Primitive: Unsafe :: Safety
+ Language.Futhark.Primitive: Xor :: IntType -> BinOp
+ Language.Futhark.Primitive: ZExt :: IntType -> IntType -> ConvOp
+ Language.Futhark.Primitive: allBinOps :: [BinOp]
+ Language.Futhark.Primitive: allCmpOps :: [CmpOp]
+ Language.Futhark.Primitive: allConvOps :: [ConvOp]
+ Language.Futhark.Primitive: allFloatTypes :: [FloatType]
+ Language.Futhark.Primitive: allIntTypes :: [IntType]
+ Language.Futhark.Primitive: allPrimTypes :: [PrimType]
+ Language.Futhark.Primitive: allUnOps :: [UnOp]
+ Language.Futhark.Primitive: associativeBinOp :: BinOp -> Bool
+ Language.Futhark.Primitive: binOpType :: BinOp -> PrimType
+ Language.Futhark.Primitive: blankPrimValue :: PrimType -> PrimValue
+ Language.Futhark.Primitive: cmpOpType :: CmpOp -> PrimType
+ Language.Futhark.Primitive: commutativeBinOp :: BinOp -> Bool
+ Language.Futhark.Primitive: convOpFun :: ConvOp -> String
+ Language.Futhark.Primitive: convOpType :: ConvOp -> (PrimType, PrimType)
+ Language.Futhark.Primitive: data BinOp
+ Language.Futhark.Primitive: data CmpOp
+ Language.Futhark.Primitive: data ConvOp
+ Language.Futhark.Primitive: data FloatType
+ Language.Futhark.Primitive: data FloatValue
+ Language.Futhark.Primitive: data Half
+ Language.Futhark.Primitive: data Int16
+ Language.Futhark.Primitive: data Int32
+ Language.Futhark.Primitive: data Int64
+ Language.Futhark.Primitive: data Int8
+ Language.Futhark.Primitive: data IntType
+ Language.Futhark.Primitive: data IntValue
+ Language.Futhark.Primitive: data Overflow
+ Language.Futhark.Primitive: data PrimType
+ Language.Futhark.Primitive: data PrimValue
+ Language.Futhark.Primitive: data Safety
+ Language.Futhark.Primitive: data UnOp
+ Language.Futhark.Primitive: data Word16
+ Language.Futhark.Primitive: data Word32
+ Language.Futhark.Primitive: data Word64
+ Language.Futhark.Primitive: data Word8
+ Language.Futhark.Primitive: doAbs :: IntValue -> IntValue
+ Language.Futhark.Primitive: doAdd :: IntValue -> IntValue -> IntValue
+ Language.Futhark.Primitive: doBinOp :: BinOp -> PrimValue -> PrimValue -> Maybe PrimValue
+ Language.Futhark.Primitive: doCmpEq :: PrimValue -> PrimValue -> Bool
+ Language.Futhark.Primitive: doCmpOp :: CmpOp -> PrimValue -> PrimValue -> Maybe Bool
+ Language.Futhark.Primitive: doCmpSle :: IntValue -> IntValue -> Bool
+ Language.Futhark.Primitive: doCmpSlt :: IntValue -> IntValue -> Bool
+ Language.Futhark.Primitive: doCmpUle :: IntValue -> IntValue -> Bool
+ Language.Futhark.Primitive: doCmpUlt :: IntValue -> IntValue -> Bool
+ Language.Futhark.Primitive: doComplement :: IntValue -> IntValue
+ Language.Futhark.Primitive: doConvOp :: ConvOp -> PrimValue -> Maybe PrimValue
+ Language.Futhark.Primitive: doFAbs :: FloatValue -> FloatValue
+ Language.Futhark.Primitive: doFCmpLe :: FloatValue -> FloatValue -> Bool
+ Language.Futhark.Primitive: doFCmpLt :: FloatValue -> FloatValue -> Bool
+ Language.Futhark.Primitive: doFPConv :: FloatValue -> FloatType -> FloatValue
+ Language.Futhark.Primitive: doFPToSI :: FloatValue -> IntType -> IntValue
+ Language.Futhark.Primitive: doFPToUI :: FloatValue -> IntType -> IntValue
+ Language.Futhark.Primitive: doMul :: IntValue -> IntValue -> IntValue
+ Language.Futhark.Primitive: doPow :: IntValue -> IntValue -> Maybe IntValue
+ Language.Futhark.Primitive: doSDiv :: IntValue -> IntValue -> Maybe IntValue
+ Language.Futhark.Primitive: doSExt :: IntValue -> IntType -> IntValue
+ Language.Futhark.Primitive: doSIToFP :: IntValue -> FloatType -> FloatValue
+ Language.Futhark.Primitive: doSMod :: IntValue -> IntValue -> Maybe IntValue
+ Language.Futhark.Primitive: doSSignum :: IntValue -> IntValue
+ Language.Futhark.Primitive: doUIToFP :: IntValue -> FloatType -> FloatValue
+ Language.Futhark.Primitive: doUSignum :: IntValue -> IntValue
+ Language.Futhark.Primitive: doUnOp :: UnOp -> PrimValue -> Maybe PrimValue
+ Language.Futhark.Primitive: doZExt :: IntValue -> IntType -> IntValue
+ Language.Futhark.Primitive: flipConvOp :: ConvOp -> ConvOp
+ Language.Futhark.Primitive: floatByteSize :: Num a => FloatType -> a
+ Language.Futhark.Primitive: floatValue :: Real num => FloatType -> num -> FloatValue
+ Language.Futhark.Primitive: floatValueType :: FloatValue -> FloatType
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.BinOp
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.CmpOp
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.ConvOp
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.FloatType
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.FloatValue
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.IntType
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.IntValue
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.Overflow
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.PrimType
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.PrimValue
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.Safety
+ Language.Futhark.Primitive: instance GHC.Classes.Eq Language.Futhark.Primitive.UnOp
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.BinOp
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.CmpOp
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.ConvOp
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.FloatType
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.FloatValue
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.IntType
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.IntValue
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.Overflow
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.PrimType
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.PrimValue
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.Safety
+ Language.Futhark.Primitive: instance GHC.Classes.Ord Language.Futhark.Primitive.UnOp
+ Language.Futhark.Primitive: instance GHC.Enum.Bounded Language.Futhark.Primitive.FloatType
+ Language.Futhark.Primitive: instance GHC.Enum.Bounded Language.Futhark.Primitive.IntType
+ Language.Futhark.Primitive: instance GHC.Enum.Bounded Language.Futhark.Primitive.PrimType
+ Language.Futhark.Primitive: instance GHC.Enum.Enum Language.Futhark.Primitive.FloatType
+ Language.Futhark.Primitive: instance GHC.Enum.Enum Language.Futhark.Primitive.IntType
+ Language.Futhark.Primitive: instance GHC.Enum.Enum Language.Futhark.Primitive.PrimType
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.BinOp
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.CmpOp
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.ConvOp
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.FloatType
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.FloatValue
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.IntType
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.IntValue
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.Overflow
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.PrimType
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.PrimValue
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.Safety
+ Language.Futhark.Primitive: instance GHC.Show.Show Language.Futhark.Primitive.UnOp
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.BinOp
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.CmpOp
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.ConvOp
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.FloatType
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.FloatValue
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.IntType
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.IntValue
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.PrimType
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.PrimValue
+ Language.Futhark.Primitive: instance Text.PrettyPrint.Mainland.Class.Pretty Language.Futhark.Primitive.UnOp
+ Language.Futhark.Primitive: intByteSize :: Num a => IntType -> a
+ Language.Futhark.Primitive: intToInt64 :: IntValue -> Int64
+ Language.Futhark.Primitive: intToWord64 :: IntValue -> Word64
+ Language.Futhark.Primitive: intValue :: Integral int => IntType -> int -> IntValue
+ Language.Futhark.Primitive: intValueType :: IntValue -> IntType
+ Language.Futhark.Primitive: negativeIsh :: PrimValue -> Bool
+ Language.Futhark.Primitive: oneIsh :: PrimValue -> Bool
+ Language.Futhark.Primitive: oneIshInt :: IntValue -> Bool
+ Language.Futhark.Primitive: prettySigned :: Bool -> PrimType -> String
+ Language.Futhark.Primitive: primBitSize :: PrimType -> Int
+ Language.Futhark.Primitive: primByteSize :: Num a => PrimType -> a
+ Language.Futhark.Primitive: primFuns :: Map String ([PrimType], PrimType, [PrimValue] -> Maybe PrimValue)
+ Language.Futhark.Primitive: primValueType :: PrimValue -> PrimType
+ Language.Futhark.Primitive: unOpType :: UnOp -> PrimType
+ Language.Futhark.Primitive: valueIntegral :: Integral int => IntValue -> int
+ Language.Futhark.Primitive: zeroIsh :: PrimValue -> Bool
+ Language.Futhark.Primitive: zeroIshInt :: IntValue -> Bool
+ Language.Futhark.Primitive.Parse: constituent :: Char -> Bool
+ Language.Futhark.Primitive.Parse: keyword :: Text -> Parsec Void Text ()
+ Language.Futhark.Primitive.Parse: lexeme :: Parsec Void Text a -> Parsec Void Text a
+ Language.Futhark.Primitive.Parse: pFloatType :: Parsec Void Text FloatType
+ Language.Futhark.Primitive.Parse: pIntType :: Parsec Void Text IntType
+ Language.Futhark.Primitive.Parse: pPrimType :: Parsec Void Text PrimType
+ Language.Futhark.Primitive.Parse: pPrimValue :: Parsec Void Text PrimValue
+ Language.Futhark.Primitive.Parse: whitespace :: Parsec Void Text ()
+ Language.Futhark.Prop: defaultEntryPoint :: Name
+ Language.Futhark.Syntax: AnySize :: Maybe VName -> Size
+ Language.Futhark.Syntax: ConstSize :: Int -> Size
+ Language.Futhark.Syntax: NamedSize :: QualName VName -> Size
+ Language.Futhark.Syntax: Shape :: [dim] -> Shape dim
+ Language.Futhark.Syntax: SizeExpAny :: SizeExp vn
+ Language.Futhark.Syntax: SizeExpConst :: Int -> SrcLoc -> SizeExp vn
+ Language.Futhark.Syntax: SizeExpNamed :: QualName vn -> SrcLoc -> SizeExp vn
+ Language.Futhark.Syntax: data Size
+ Language.Futhark.Syntax: data SizeExp vn
+ Language.Futhark.Syntax: instance Data.Foldable.Foldable Language.Futhark.Syntax.Shape
+ Language.Futhark.Syntax: instance Data.Traversable.Traversable Language.Futhark.Syntax.Shape
+ Language.Futhark.Syntax: instance GHC.Base.Functor Language.Futhark.Syntax.Shape
+ Language.Futhark.Syntax: instance GHC.Base.Monoid (Language.Futhark.Syntax.Shape dim)
+ Language.Futhark.Syntax: instance GHC.Base.Semigroup (Language.Futhark.Syntax.Shape dim)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.AppExpBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.CaseBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.DimIndexBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.ExpBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.FieldBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.LoopFormBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.PatBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.SizeExp Language.Futhark.Core.Name)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq (Language.Futhark.Syntax.SizeExp Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Eq Language.Futhark.Syntax.Size
+ Language.Futhark.Syntax: instance GHC.Classes.Eq dim => GHC.Classes.Eq (Language.Futhark.Syntax.Shape dim)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.AppExpBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.CaseBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.DimIndexBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.ExpBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.FieldBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.LoopFormBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.PatBase Language.Futhark.Syntax.Info Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.SizeExp Language.Futhark.Core.Name)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord (Language.Futhark.Syntax.SizeExp Language.Futhark.Core.VName)
+ Language.Futhark.Syntax: instance GHC.Classes.Ord Language.Futhark.Syntax.Diet
+ Language.Futhark.Syntax: instance GHC.Classes.Ord Language.Futhark.Syntax.Size
+ Language.Futhark.Syntax: instance GHC.Classes.Ord dim => GHC.Classes.Ord (Language.Futhark.Syntax.Shape dim)
+ Language.Futhark.Syntax: instance GHC.Show.Show Language.Futhark.Syntax.Size
+ Language.Futhark.Syntax: instance GHC.Show.Show dim => GHC.Show.Show (Language.Futhark.Syntax.Shape dim)
+ Language.Futhark.Syntax: instance GHC.Show.Show vn => GHC.Show.Show (Language.Futhark.Syntax.SizeExp vn)
+ Language.Futhark.Syntax: newtype Shape dim
+ Language.Futhark.Traversals: instance Language.Futhark.Traversals.ASTMappable (Language.Futhark.Syntax.QualName Language.Futhark.Core.VName)
+ Language.Futhark.Traversals: instance Language.Futhark.Traversals.ASTMappable (Language.Futhark.Syntax.SizeExp Language.Futhark.Core.VName)
+ Language.Futhark.Traversals: instance Language.Futhark.Traversals.ASTMappable Language.Futhark.Syntax.Size
+ Language.Futhark.Tuple: areTupleFields :: Map Name a -> Maybe [a]
+ Language.Futhark.Tuple: sortFields :: Map Name a -> [(Name, a)]
+ Language.Futhark.Tuple: tupleFieldNames :: [Name]
+ Language.Futhark.Tuple: tupleFields :: [a] -> Map Name a
+ Language.Futhark.TypeChecker: data Notes
+ Language.Futhark.TypeChecker.Monad: checkNamedSize :: MonadTypeChecker m => SrcLoc -> QualName Name -> m (QualName VName)
+ Language.Futhark.TypeChecker.Terms.Monad: sizeFromArg :: Maybe (QualName VName) -> Exp -> TermTypeM (Size, Maybe VName)
+ Language.Futhark.TypeChecker.Types: determineSizeWitnesses :: StructType -> (Set VName, Set VName)
+ Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.RetTypeBase Language.Futhark.Syntax.Size ())
+ Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.RetTypeBase Language.Futhark.Syntax.Size Language.Futhark.Syntax.Aliasing)
+ Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.TypeBase Language.Futhark.Syntax.Size ())
+ Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.TypeBase Language.Futhark.Syntax.Size Language.Futhark.Syntax.Aliasing)
+ Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable Language.Futhark.Syntax.Size
+ Language.Futhark.TypeChecker.Types: instance Language.Futhark.TypeChecker.Types.Substitutable d => Language.Futhark.TypeChecker.Types.Substitutable (Language.Futhark.Syntax.Shape d)
+ Language.Futhark.TypeChecker.Types: mustBeExplicitInBinding :: StructType -> Set VName
+ Language.Futhark.TypeChecker.Types: mustBeExplicitInType :: StructType -> Set VName
- Futhark.CodeGen.Backends.GenericC: compileProg :: MonadFreshNames m => Text -> Text -> Operations op () -> CompilerM op () () -> Text -> [Space] -> [Option] -> Definitions op -> m CParts
+ Futhark.CodeGen.Backends.GenericC: compileProg :: MonadFreshNames m => Text -> Text -> Operations op () -> CompilerM op () () -> Text -> (Space, [Space]) -> [Option] -> Definitions op -> m CParts
- Futhark.CodeGen.Backends.GenericC: type Copy op s = Exp -> Exp -> Space -> Exp -> Exp -> Space -> Exp -> CompilerM op s ()
+ Futhark.CodeGen.Backends.GenericC: type Copy op s = CopyBarrier -> Exp -> Exp -> Space -> Exp -> Exp -> Space -> Exp -> CompilerM op s ()
- Futhark.CodeGen.Backends.SimpleRep: opaqueName :: String -> [ValueDesc] -> String
+ Futhark.CodeGen.Backends.SimpleRep: opaqueName :: String -> String
- Futhark.CodeGen.ImpCode: Definitions :: Constants a -> Functions a -> Definitions a
+ Futhark.CodeGen.ImpCode: Definitions :: OpaqueTypes -> Constants a -> Functions a -> Definitions a
- Futhark.CodeGen.ImpCode: Function :: Maybe Name -> [Param] -> [Param] -> Code a -> [ExternalValue] -> [(Name, ExternalValue)] -> FunctionT a
+ Futhark.CodeGen.ImpCode: Function :: Maybe EntryPoint -> [Param] -> [Param] -> Code a -> FunctionT a
- Futhark.CodeGen.ImpCode: OpaqueValue :: Uniqueness -> String -> [ValueDesc] -> ExternalValue
+ Futhark.CodeGen.ImpCode: OpaqueValue :: String -> [ValueDesc] -> ExternalValue
- Futhark.CodeGen.ImpCode: TransparentValue :: Uniqueness -> ValueDesc -> ExternalValue
+ Futhark.CodeGen.ImpCode: TransparentValue :: ValueDesc -> ExternalValue
- Futhark.CodeGen.ImpCode: [functionEntry] :: FunctionT a -> Maybe Name
+ Futhark.CodeGen.ImpCode: [functionEntry] :: FunctionT a -> Maybe EntryPoint
- Futhark.CodeGen.ImpGen.GPU.Base: KernelAttrs :: Bool -> Bool -> Count NumGroups (TExp Int64) -> Count GroupSize (TExp Int64) -> KernelAttrs
+ Futhark.CodeGen.ImpGen.GPU.Base: KernelAttrs :: Bool -> Bool -> Count NumGroups SubExp -> Count GroupSize SubExp -> KernelAttrs
- Futhark.CodeGen.ImpGen.GPU.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] -> Map [SubExp] (TExp Int32) -> KernelConstants
+ Futhark.CodeGen.ImpGen.GPU.Base: KernelConstants :: TExp Int32 -> TExp Int32 -> TExp Int32 -> VName -> VName -> VName -> Count NumGroups SubExp -> Count GroupSize SubExp -> TExp Int64 -> TExp Int64 -> TExp Int32 -> TExp Int32 -> TExp Bool -> Map [SubExp] [TExp Int32] -> Map [SubExp] (TExp Int32) -> KernelConstants
- Futhark.CodeGen.ImpGen.GPU.Base: [kAttrGroupSize] :: KernelAttrs -> Count GroupSize (TExp Int64)
+ Futhark.CodeGen.ImpGen.GPU.Base: [kAttrGroupSize] :: KernelAttrs -> Count GroupSize SubExp
- Futhark.CodeGen.ImpGen.GPU.Base: [kAttrNumGroups] :: KernelAttrs -> Count NumGroups (TExp Int64)
+ Futhark.CodeGen.ImpGen.GPU.Base: [kAttrNumGroups] :: KernelAttrs -> Count NumGroups SubExp
- Futhark.CodeGen.ImpGen.GPU.Base: defKernelAttrs :: Count NumGroups (TExp Int64) -> Count GroupSize (TExp Int64) -> KernelAttrs
+ Futhark.CodeGen.ImpGen.GPU.Base: defKernelAttrs :: Count NumGroups SubExp -> Count GroupSize SubExp -> KernelAttrs
- Futhark.CodeGen.ImpGen.Multicore: compileProg :: MonadFreshNames m => SchedulingMode -> Prog MCMem -> m (Warnings, Definitions Multicore)
+ Futhark.CodeGen.ImpGen.Multicore: compileProg :: MonadFreshNames m => Prog MCMem -> m (Warnings, Definitions Multicore)
- Futhark.CodeGen.ImpGen.Multicore.Base: generateChunkLoop :: String -> (TExp Int64 -> MulticoreGen ()) -> MulticoreGen ()
+ Futhark.CodeGen.ImpGen.Multicore.Base: generateChunkLoop :: String -> ChunkLoopVectorization -> (TExp Int64 -> MulticoreGen ()) -> MulticoreGen ()
- Futhark.CodeGen.ImpGen.Multicore.SegRed: type DoSegBody = (([(SubExp, [TExp Int64])] -> MulticoreGen ()) -> MulticoreGen ())
+ Futhark.CodeGen.ImpGen.Multicore.SegRed: type DoSegBody = (([[(SubExp, [TExp Int64])]] -> MulticoreGen ()) -> MulticoreGen ())
- Futhark.IR.Syntax: EntryParam :: Name -> EntryPointType -> EntryParam
+ Futhark.IR.Syntax: EntryParam :: Name -> Uniqueness -> EntryPointType -> EntryParam
- Futhark.IR.Syntax: Prog :: Stms rep -> [FunDef rep] -> Prog rep
+ Futhark.IR.Syntax: Prog :: OpaqueTypes -> Stms rep -> [FunDef rep] -> Prog rep
- Futhark.IR.Syntax: type EntryPoint = (Name, [EntryParam], [EntryPointType])
+ Futhark.IR.Syntax: type EntryPoint = (Name, [EntryParam], [EntryResult])
- Futhark.Internalise.Exps: transformProg :: MonadFreshNames m => Bool -> [ValBind] -> m (Prog SOACS)
+ Futhark.Internalise.Exps: transformProg :: MonadFreshNames m => Bool -> VisibleTypes -> [ValBind] -> m (Prog SOACS)
- Futhark.Internalise.Monad: runInternaliseM :: MonadFreshNames m => Bool -> InternaliseM () -> m (Stms SOACS, [FunDef SOACS])
+ Futhark.Internalise.Monad: runInternaliseM :: MonadFreshNames m => Bool -> InternaliseM () -> m (OpaqueTypes, Stms SOACS, [FunDef SOACS])
- Futhark.Internalise.TypesValues: internaliseEntryReturnType :: StructRetType -> InternaliseM [[TypeBase ExtShape Uniqueness]]
+ Futhark.Internalise.TypesValues: internaliseEntryReturnType :: StructRetType -> [[TypeBase ExtShape Uniqueness]]
- Futhark.Internalise.TypesValues: internaliseLambdaReturnType :: TypeBase (DimDecl VName) () -> [TypeBase shape u] -> InternaliseM [TypeBase Shape NoUniqueness]
+ Futhark.Internalise.TypesValues: internaliseLambdaReturnType :: TypeBase Size () -> [TypeBase shape u] -> InternaliseM [TypeBase Shape NoUniqueness]
- Futhark.Internalise.TypesValues: internaliseLoopParamType :: TypeBase (DimDecl VName) () -> [TypeBase shape u] -> InternaliseM [TypeBase Shape Uniqueness]
+ Futhark.Internalise.TypesValues: internaliseLoopParamType :: TypeBase Size () -> [TypeBase shape u] -> InternaliseM [TypeBase Shape Uniqueness]
- Futhark.Internalise.TypesValues: internaliseParamTypes :: [TypeBase (DimDecl VName) ()] -> InternaliseM [[TypeBase Shape Uniqueness]]
+ Futhark.Internalise.TypesValues: internaliseParamTypes :: [TypeBase Size ()] -> InternaliseM [[TypeBase Shape Uniqueness]]
- Futhark.Internalise.TypesValues: internaliseReturnType :: StructRetType -> [TypeBase shape u] -> InternaliseM [TypeBase ExtShape Uniqueness]
+ Futhark.Internalise.TypesValues: internaliseReturnType :: StructRetType -> [TypeBase shape u] -> [TypeBase ExtShape Uniqueness]
- Futhark.Internalise.TypesValues: internaliseType :: TypeBase (DimDecl VName) () -> InternaliseM [TypeBase ExtShape Uniqueness]
+ Futhark.Internalise.TypesValues: internaliseType :: TypeBase Size () -> [TypeBase ExtShape Uniqueness]
- Futhark.Internalise.TypesValues: internalisedTypeSize :: TypeBase (DimDecl VName) als -> InternaliseM Int
+ Futhark.Internalise.TypesValues: internalisedTypeSize :: TypeBase Size als -> Int
- Language.Futhark: type StructTypeArg = TypeArg (DimDecl VName)
+ Language.Futhark: type StructTypeArg = TypeArg Size
- Language.Futhark.Prop: IntrinsicPolyFun :: [TypeParamBase VName] -> [StructType] -> RetTypeBase (DimDecl VName) () -> Intrinsic
+ Language.Futhark.Prop: IntrinsicPolyFun :: [TypeParamBase VName] -> [StructType] -> RetTypeBase Size () -> Intrinsic
- Language.Futhark.Prop: arrayOf :: Monoid as => Uniqueness -> ShapeDecl dim -> TypeBase dim as -> TypeBase dim as
+ Language.Futhark.Prop: arrayOf :: Monoid as => Uniqueness -> Shape dim -> TypeBase dim as -> TypeBase dim as
- Language.Futhark.Prop: arrayShape :: TypeBase dim as -> ShapeDecl dim
+ Language.Futhark.Prop: arrayShape :: TypeBase dim as -> Shape dim
- Language.Futhark.Prop: combineTypeShapes :: (Monoid as, ArrayDim dim) => TypeBase dim as -> TypeBase dim as -> TypeBase dim as
+ Language.Futhark.Prop: combineTypeShapes :: Monoid as => TypeBase Size as -> TypeBase Size as -> TypeBase Size as
- Language.Futhark.Prop: noSizes :: TypeBase (DimDecl vn) as -> TypeBase () as
+ Language.Futhark.Prop: noSizes :: TypeBase Size as -> TypeBase () as
- Language.Futhark.Prop: type UncheckedType = TypeBase (ShapeDecl Name) ()
+ Language.Futhark.Prop: type UncheckedType = TypeBase (Shape Name) ()
- Language.Futhark.Syntax: Array :: as -> Uniqueness -> ShapeDecl dim -> ScalarTypeBase dim () -> TypeBase dim as
+ Language.Futhark.Syntax: Array :: as -> Uniqueness -> Shape dim -> ScalarTypeBase dim () -> TypeBase dim as
- Language.Futhark.Syntax: TEArray :: DimExp vn -> TypeExp vn -> SrcLoc -> TypeExp vn
+ Language.Futhark.Syntax: TEArray :: SizeExp vn -> TypeExp vn -> SrcLoc -> TypeExp vn
- Language.Futhark.Syntax: TypeArgExpDim :: DimExp vn -> SrcLoc -> TypeArgExp vn
+ Language.Futhark.Syntax: TypeArgExpDim :: SizeExp vn -> SrcLoc -> TypeArgExp vn
- Language.Futhark.Syntax: TypeVar :: as -> Uniqueness -> TypeName -> [TypeArg dim] -> ScalarTypeBase dim as
+ Language.Futhark.Syntax: TypeVar :: as -> Uniqueness -> QualName VName -> [TypeArg dim] -> ScalarTypeBase dim as
- Language.Futhark.Syntax: [shapeDims] :: ShapeDecl dim -> [dim]
+ Language.Futhark.Syntax: [shapeDims] :: Shape dim -> [dim]
- Language.Futhark.Syntax: shapeRank :: ShapeDecl dim -> Int
+ Language.Futhark.Syntax: shapeRank :: Shape dim -> Int
- Language.Futhark.Syntax: stripDims :: Int -> ShapeDecl dim -> Maybe (ShapeDecl dim)
+ Language.Futhark.Syntax: stripDims :: Int -> Shape dim -> Maybe (Shape dim)
- Language.Futhark.Syntax: type PatRetType = RetTypeBase (DimDecl VName) Aliasing
+ Language.Futhark.Syntax: type PatRetType = RetTypeBase Size Aliasing
- Language.Futhark.Syntax: type PatType = TypeBase (DimDecl VName) Aliasing
+ Language.Futhark.Syntax: type PatType = TypeBase Size Aliasing
- Language.Futhark.Syntax: type StructRetType = RetTypeBase (DimDecl VName) ()
+ Language.Futhark.Syntax: type StructRetType = RetTypeBase Size ()
- Language.Futhark.Syntax: type StructType = TypeBase (DimDecl VName) ()
+ Language.Futhark.Syntax: type StructType = TypeBase Size ()
- Language.Futhark.Traversals: ASTMapper :: (ExpBase Info VName -> m (ExpBase Info VName)) -> (VName -> m VName) -> (QualName VName -> m (QualName VName)) -> (StructType -> m StructType) -> (PatType -> m PatType) -> (StructRetType -> m StructRetType) -> (PatRetType -> m PatRetType) -> ASTMapper m
+ Language.Futhark.Traversals: ASTMapper :: (ExpBase Info VName -> m (ExpBase Info VName)) -> (VName -> m VName) -> (StructType -> m StructType) -> (PatType -> m PatType) -> (StructRetType -> m StructRetType) -> (PatRetType -> m PatRetType) -> ASTMapper m
- Language.Futhark.TypeChecker.Monad: qualifyTypeVars :: Env -> [VName] -> [VName] -> TypeBase (DimDecl VName) as -> TypeBase (DimDecl VName) as
+ Language.Futhark.TypeChecker.Monad: qualifyTypeVars :: Env -> [VName] -> [VName] -> TypeBase Size as -> TypeBase Size as
- Language.Futhark.TypeChecker.Terms.Monad: SourceSlice :: Maybe (DimDecl VName) -> Maybe (ExpBase NoInfo VName) -> Maybe (ExpBase NoInfo VName) -> Maybe (ExpBase NoInfo VName) -> SizeSource
+ Language.Futhark.TypeChecker.Terms.Monad: SourceSlice :: Maybe Size -> Maybe (ExpBase NoInfo VName) -> Maybe (ExpBase NoInfo VName) -> Maybe (ExpBase NoInfo VName) -> SizeSource
- Language.Futhark.TypeChecker.Terms.Monad: allDimsFreshInType :: SrcLoc -> Rigidity -> Name -> TypeBase (DimDecl VName) als -> TermTypeM (TypeBase (DimDecl VName) als, Map VName (DimDecl VName))
+ Language.Futhark.TypeChecker.Terms.Monad: allDimsFreshInType :: SrcLoc -> Rigidity -> Name -> TypeBase Size als -> TermTypeM (TypeBase Size als, Map VName Size)
- Language.Futhark.TypeChecker.Terms.Monad: dimFromExp :: (Exp -> SizeSource) -> Exp -> TermTypeM (DimDecl VName, Maybe VName)
+ Language.Futhark.TypeChecker.Terms.Monad: dimFromExp :: (Exp -> SizeSource) -> Exp -> TermTypeM (Size, Maybe VName)
- Language.Futhark.TypeChecker.Terms.Monad: extSize :: SrcLoc -> SizeSource -> TermTypeM (DimDecl VName, Maybe VName)
+ Language.Futhark.TypeChecker.Terms.Monad: extSize :: SrcLoc -> SizeSource -> TermTypeM (Size, Maybe VName)
- Language.Futhark.TypeChecker.Terms.Monad: maybeDimFromExp :: Exp -> Maybe (DimDecl VName)
+ Language.Futhark.TypeChecker.Terms.Monad: maybeDimFromExp :: Exp -> Maybe Size
- Language.Futhark.TypeChecker.Types: SizeSubst :: DimDecl VName -> Subst t
+ Language.Futhark.TypeChecker.Types: SizeSubst :: Size -> Subst t
- Language.Futhark.TypeChecker.Types: substTypesAny :: Monoid as => (VName -> Maybe (Subst (RetTypeBase (DimDecl VName) as))) -> TypeBase (DimDecl VName) as -> TypeBase (DimDecl VName) as
+ Language.Futhark.TypeChecker.Types: substTypesAny :: Monoid as => (VName -> Maybe (Subst (RetTypeBase Size as))) -> TypeBase Size as -> TypeBase Size as
- Language.Futhark.TypeChecker.Unify: RigidSlice :: Maybe (DimDecl VName) -> String -> RigidSource
+ Language.Futhark.TypeChecker.Unify: RigidSlice :: Maybe Size -> String -> RigidSource
- Language.Futhark.TypeChecker.Unify: Size :: Maybe (DimDecl VName) -> Usage -> Constraint
+ Language.Futhark.TypeChecker.Unify: Size :: Maybe Size -> Usage -> Constraint
- Language.Futhark.TypeChecker.Unify: arrayElemType :: (MonadUnify m, Pretty (ShapeDecl dim), Monoid as) => Usage -> String -> TypeBase dim as -> m ()
+ Language.Futhark.TypeChecker.Unify: arrayElemType :: (MonadUnify m, Pretty (Shape dim), Monoid as) => Usage -> String -> TypeBase dim as -> m ()
- Language.Futhark.TypeChecker.Unify: dimNotes :: (Located a, MonadUnify m) => a -> DimDecl VName -> m Notes
+ Language.Futhark.TypeChecker.Unify: dimNotes :: (Located a, MonadUnify m) => a -> Size -> m Notes
- Language.Futhark.TypeChecker.Unify: equalityType :: (MonadUnify m, Pretty (ShapeDecl dim), Monoid as) => Usage -> TypeBase dim as -> m ()
+ Language.Futhark.TypeChecker.Unify: equalityType :: (MonadUnify m, Pretty (Shape dim), Monoid as) => Usage -> TypeBase dim as -> m ()
- Language.Futhark.TypeChecker.Unify: instantiateEmptyArrayDims :: MonadUnify m => SrcLoc -> Rigidity -> RetTypeBase (DimDecl VName) als -> m (TypeBase (DimDecl VName) als, [VName])
+ Language.Futhark.TypeChecker.Unify: instantiateEmptyArrayDims :: MonadUnify m => SrcLoc -> Rigidity -> RetTypeBase Size als -> m (TypeBase Size als, [VName])
- Language.Futhark.TypeChecker.Unify: zeroOrderType :: (MonadUnify m, Pretty (ShapeDecl dim), Monoid as) => Usage -> String -> TypeBase dim as -> m ()
+ Language.Futhark.TypeChecker.Unify: zeroOrderType :: (MonadUnify m, Pretty (Shape dim), Monoid as) => Usage -> String -> TypeBase dim as -> m ()

Files

LICENSE view
@@ -1,6 +1,6 @@ ISC License -Copyright (c) 2013-2018. DIKU, University of Copenhagen+Copyright (c) 2013-2022. DIKU, University of Copenhagen  Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the
docs/c-api.rst view
@@ -332,19 +332,68 @@     * Otherwise, the serialised representation of the value will be      stored at ``*p``, which *must* have room for at least ``*n``-     bytes.+     bytes.  This is done asynchronously.     Returns 0 on success.  .. c:function:: struct futhark_opaque_foo* futhark_restore_opaque_foo(struct futhark_context *ctx, const void *p) -   Restore a byte sequence previously written with+   Asynchronously restore a byte sequence previously written with    :c:func:`futhark_store_opaque_foo`.  Returns ``NULL`` on failure.    The byte sequence does not need to have been generated by the same    program *instance*, but it *must* have been generated by the same    Futhark program, and compiled with the same version of the Futhark    compiler. +Records+~~~~~~~++A record is an opaque type (see above) that supports additional+functions to *project* individual fields (read their values) to+construct a value given values for the fields.  An opaque type is a+record if its definition is a record at the Futhark level.++The projection and construction functions are equivalent in+functionality to writing entry points by hand, and so serve only to+cut down on boilerplate.  Important things to be aware of:++1. The objects constructed though these functions have their own+   lifetime (like any objects returned from an entry point) and must+   be manually freed, independently of the records from which they are+   projected, or the fields they are constructed from.++2. The objects are however in an *aliasing* relationship with the+   fields or original record.  This means you must be careful when+   passing them to entry points that consume their arguments.  As+   always, you don't have to worry about this if you never write entry+   points that consume their arguments.++The precise functions generated depend on the fields of the record.+The following functions assume a record with Futhark-level type ``type+t = {foo: t1, bar: t2}`` where ``t1`` and ``t2`` are also opaque+types.++.. c:function:: int futhark_new_opaque_t(struct futhark_context *ctx, struct futhark_opaque_t **out, const struct futhark_opaque_t2 *bar, const struct futhark_opaque_t1 *foo);++   Construct a record in ``*out`` which has the given values for the+   ``bar`` and ``foo`` fields.  The parameter ordering constitutes the+   fields in alphabetic order.  Tuple fields are named ``vX`` where+   ``X`` is an integer.  The resulting record *aliases* the values+   provided for ``bar`` and ``foo``, but has its own lifetime, and all+   values must be individually freed when they are no longer needed.++.. c:function:: int futhark_project_opaque_t_bar(struct futhark_context *ctx, struct futhark_opaque_t2 **out, const struct futhark_opaque_t *obj);++   Extract the value of the field ``bar`` from the provided record.+   The resulting value *aliases* the record, but has its own lifetime,+   and must eventually be freed.++.. c:function:: int futhark_project_opaque_t_foo(struct futhark_context *ctx, struct futhark_opaque_t1 **out, const struct futhark_opaque_t *obj);++   Extract the value of the field ``bar`` from the provided record.+   The resulting value *aliases* the record, but has its own lifetime,+   and must eventually be freed.+ Entry points ------------ @@ -507,7 +556,7 @@ The following API functions are available when using the ``multicore`` backend. -.. c:function:: void context_config_set_num_threads(struct futhark_context_config *cfg, int n)+.. c:function:: void futhark_context_config_set_num_threads(struct futhark_context_config *cfg, int n)     The number of threads used to run parallel operations.  If set to a    value less than ``1``, then the runtime system will use one thread@@ -564,15 +613,15 @@   * A list of all *outputs*, including their type and whether they are     *unique*. -* A mapping from the name of each non-scalar types to:+* A mapping from the name of each non-scalar type to: -  * The C type of used to represent type type (which is practice+  * The C type of used to represent the type (which is in practice     always a pointer of some kind).    * For arrays, the element type and rank. -  * A mapping from names of *operations* to the name of the C function-    that implements that operation for the type.  The type of the C+  * A mapping from *operations* to the names of the C functions that+    implement the operations for the type.  The types of the C     functions are as documented above.  The following operations are     listed: 
docs/conf.py view
@@ -343,6 +343,7 @@     ('man/futhark-autotune', 'futhark-autotune', 'calibrate run-time parameters', [], 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-ispc', 'futhark-ispc', 'compile Futhark to multithreaded ISPC', [], 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
@@ -53,6 +53,7 @@    man/futhark-doc.rst    man/futhark-literate.rst    man/futhark-multicore.rst+   man/futhark-ispc.rst    man/futhark-opencl.rst    man/futhark-pkg.rst    man/futhark-pyopencl.rst
docs/installation.rst view
@@ -37,7 +37,7 @@ ---------------------  To compile Futhark you must first install an appropriate version of-GHC, either with [ghcup](https://www.haskell.org/ghcup/) or a package+GHC, either with `ghcup <https://www.haskell.org/ghcup>`_ or a package manager.  Any version since GHC 8.10 should work.  You also need the ``cabal`` command line program, which ghcup will install for you as well.
docs/language-reference.rst view
@@ -396,8 +396,8 @@  A type abbreviation can have zero or more parameters.  A type parameter enclosed with square brackets is a *size parameter*, and-can be used in the definition as an array dimension size, or as a-dimension argument to other type abbreviations.  When passing an+can be used in the definition as an array size, or as a+size argument to other type abbreviations.  When passing an argument for a shape parameter, it must be enclosed in square brackets.  Example:: 
+ docs/man/futhark-ispc.rst view
@@ -0,0 +1,61 @@+.. role:: ref(emphasis)++.. _futhark-ispc(1):++============+futhark-ispc+============++SYNOPSIS+========++futhark ispc [options...] <program.fut>++DESCRIPTION+===========++``futhark ispc`` translates a Futhark program to a combination of C+and ISPC code, with ISPC used for parallel loops.  It otherwise+operates similarly to :ref:`futhark-multicore(1)`.  You need to have+``ispc`` on your ``PATH``.++OPTIONS+=======++Accepts the same options as :ref:`futhark-multicore(1)`.+++ENVIRONMENT VARIABLES+=====================++``CC``++  The C compiler used to compile the program.  Defaults to ``cc`` if+  unset.++``CFLAGS``++  Space-separated list of options passed to the C compiler.  Defaults+  to ``-O3 -std=c99 -pthread`` if unset.++``ISPCFLAGS``++  Space-separated list of options passed to ``ispc``.  Defaults to+  ``-O3 --woff`` if unset.++EXECUTABLE OPTIONS+==================++Generated executables accept the same options as those generated by+:ref:`futhark-multicore(1)`.++BUGS+====++Currently works only on Unix-like systems because of a dependency on+pthreads.  Adding support for Windows would likely not be difficult.++SEE ALSO+========++:ref:`futhark-multicore(1)`, :ref:`futhark-test(1)`
docs/man/futhark-literate.rst view
@@ -239,6 +239,12 @@ running a program from an unknown source, you should always give it a quick read to see if anything looks fishy. +BUGS+====++FutharkScript expressions can only refer to names defined in the file+passed to ``futhark literate``, not any names in imported files.+ SEE ALSO ======== 
docs/man/futhark.rst view
@@ -95,7 +95,12 @@  Expresses gratitude. +futhark tokens FILE+-------------------++Print the tokens the given Futhark source file; one per line.+ SEE ALSO ======== -:ref:`futhark-opencl(1)`, :ref:`futhark-c(1)`, :ref:`futhark-py(1)`, :ref:`futhark-pyopencl(1)`, :ref:`futhark-wasm(1)`, :ref:`futhark-wasm-multicore(1)`, :ref:`futhark-dataset(1)`, :ref:`futhark-doc(1)`, :ref:`futhark-test(1)`, :ref:`futhark-bench(1)`, :ref:`futhark-run(1)`, :ref:`futhark-repl(1)`, :ref:`futhark-literate(1)`+:ref:`futhark-opencl(1)`, :ref:`futhark-c(1)`, :ref:`futhark-py(1)`, :ref:`futhark-pyopencl(1)`, :ref:`futhark-wasm(1)`, :ref:`futhark-wasm-multicore(1)`, :ref:`futhark-ispc(1)`, :ref:`futhark-dataset(1)`, :ref:`futhark-doc(1)`, :ref:`futhark-test(1)`, :ref:`futhark-bench(1)`, :ref:`futhark-run(1)`, :ref:`futhark-repl(1)`, :ref:`futhark-literate(1)`
docs/server-protocol.rst view
@@ -71,6 +71,19 @@  The following commands are supported. +General Commands+~~~~~~~~~~~~~~~~++``types``+.........++Print the names of available types, one per line.++``entry_points``+................++Print the names of available entry points.+ ``call`` *entry* *o1* ... *oN* *i1* ... *iM* ............................................ @@ -138,10 +151,36 @@  Corresponds to :c:func:`futhark_context_config_set_tuning_param`. +Record Commands+~~~~~~~~~~~~~~~++``fields`` *type*+.................++If the given type is a record, print a line for each field of the+record.  The line will contain the name of the field, followed by a+space, followed by the type of the field.  Note that the type name can+contain spaces.  The order of fields is significant, as it is the one+expected by the ``new_record`` command.++``new`` *v0* *type* *v1* ... *vN*+.................................++Create a new variable *v0* of type *type*, which must be a record type+with *N* fields, where *v1* to *vN* are variables with the+corresponding field types (the expected order is given by the+``fields`` command).++``project`` *to* *from* *field*+...............................++Create a new variable *to* whose value is the field *field* of the+record-typed variable *from*.+ Environment Variables ---------------------  ``FUTHARK_COMPILER_DEBUGGING``-..............................+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Turns on debugging output for the server when set to 1.
futhark.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name:           futhark-version:        0.21.12+version:        0.21.13 synopsis:       An optimising compiler for a functional, array-oriented language.  description:    Futhark is a small programming language designed to be compiled to@@ -34,11 +34,44 @@ license-file:   LICENSE build-type:     Simple extra-source-files:-    rts/c/*.h-    rts/futhark-doc/*.css-    rts/javascript/*.js-    rts/python/*.py-    prelude/*.fut+-- Cabal's recompilation tracking doesn't work when we use wildcards+-- here, so for now we spell out every single file.+    rts/c/atomics.h+    rts/c/lock.h+    rts/c/timing.h+    rts/c/errors.h+    rts/c/free_list.h+    rts/c/tuning.h+    rts/c/values.h+    rts/c/half.h+    rts/c/opencl.h+    rts/c/cuda.h+    rts/c/cache.h+    rts/c/ispc_util.h+    rts/c/scalar.h+    rts/c/scalar_f16.h+    rts/c/scheduler.h+    rts/c/uniform.h+    rts/c/util.h+    rts/c/server.h+    rts/futhark-doc/style.css+    rts/javascript/server.js+    rts/javascript/values.js+    rts/javascript/wrapperclasses.js+    rts/python/tuning.py+    rts/python/panic.py+    rts/python/memory.py+    rts/python/server.py+    rts/python/values.py+    rts/python/opencl.py+    rts/python/scalar.py+    prelude/functional.fut+    prelude/math.fut+    prelude/soacs.fut+    prelude/zip.fut+    prelude/ad.fut+    prelude/array.fut+    prelude/prelude.fut -- Just enough of the docs to build the manpages.     docs/**/*.rst     docs/Makefile@@ -51,7 +84,13 @@   type: git   location: https://github.com/diku-dk/futhark +common common+  ghc-options: -Wall -Wcompat -Wno-incomplete-uni-patterns -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -Wunused-packages+  default-language: Haskell2010+ library+  import: common+  hs-source-dirs: src   exposed-modules:       Futhark       Futhark.Actions@@ -101,6 +140,7 @@       Futhark.CLI.Main       Futhark.CLI.Misc       Futhark.CLI.Multicore+      Futhark.CLI.MulticoreISPC       Futhark.CLI.MulticoreWASM       Futhark.CLI.OpenCL       Futhark.CLI.Pkg@@ -124,6 +164,7 @@       Futhark.CodeGen.Backends.GenericPython.Options       Futhark.CodeGen.Backends.GenericWASM       Futhark.CodeGen.Backends.MulticoreC+      Futhark.CodeGen.Backends.MulticoreISPC       Futhark.CodeGen.Backends.MulticoreWASM       Futhark.CodeGen.Backends.PyOpenCL       Futhark.CodeGen.Backends.PyOpenCL.Boilerplate@@ -186,8 +227,6 @@       Futhark.IR.Mem.Simplify       Futhark.IR.Parse       Futhark.IR.Pretty-      Futhark.IR.Primitive-      Futhark.IR.Primitive.Parse       Futhark.IR.Prop       Futhark.IR.Prop.Aliases       Futhark.IR.Prop.Constants@@ -215,8 +254,8 @@       Futhark.Internalise.Bindings       Futhark.Internalise.Defunctionalise       Futhark.Internalise.Defunctorise+      Futhark.Internalise.Entry       Futhark.Internalise.Exps-      Futhark.Internalise.FreeVars       Futhark.Internalise.Lambdas       Futhark.Internalise.LiftLambdas       Futhark.Internalise.Monad@@ -234,7 +273,8 @@       Futhark.Optimise.DoubleBuffer       Futhark.Optimise.Fusion       Futhark.Optimise.Fusion.Composing-      Futhark.Optimise.Fusion.LoopKernel+      Futhark.Optimise.Fusion.GraphRep+      Futhark.Optimise.Fusion.TryFusion       Futhark.Optimise.GenRedOpt       Futhark.Optimise.HistAccs       Futhark.Optimise.InPlaceLowering@@ -309,17 +349,21 @@       Language.Futhark       Language.Futhark.Core       Language.Futhark.Interpreter+      Language.Futhark.FreeVars       Language.Futhark.Parser       Language.Futhark.Parser.Monad       Language.Futhark.Parser.Lexer.Tokens       Language.Futhark.Parser.Lexer.Wrapper       Language.Futhark.Prelude       Language.Futhark.Pretty+      Language.Futhark.Primitive+      Language.Futhark.Primitive.Parse       Language.Futhark.Prop       Language.Futhark.Query       Language.Futhark.Semantic       Language.Futhark.Syntax       Language.Futhark.Traversals+      Language.Futhark.Tuple       Language.Futhark.TypeChecker       Language.Futhark.TypeChecker.Match       Language.Futhark.TypeChecker.Modules@@ -337,9 +381,6 @@       Paths_futhark   autogen-modules:       Paths_futhark-  hs-source-dirs:-      src-  ghc-options: -Wall -Wcompat -Wno-incomplete-uni-patterns -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -Wunused-packages   build-tool-depends:       alex:alex     , happy:happy@@ -354,25 +395,27 @@     , bytestring >=0.10.8     , bytestring-to-vector >=0.3.0.1     , bmp >=1.2.6.3+    , co-log-core     , containers >=0.6.2.1     , cryptohash-md5     , Diff >=0.4.1     , directory >=1.3.0.0     , directory-tree >=0.12.1     , dlist >=0.6.0.1+    , fgl+    , fgl-visualize     , file-embed >=0.0.14.0     , filepath >=1.4.1.1     , free >=4.12.4     , futhark-data >= 1.1.0.0-    , futhark-server >= 1.2.0.0-    , futhark-manifest >= 1.0.0.0+    , futhark-server >= 1.2.1.0+    , futhark-manifest >= 1.1.0.0     , githash >=0.1.6.1     , half >= 0.3     , haskeline-    , hslogger-    , language-c-quote >=0.12+    , language-c-quote >= 0.12     , lens-    , lsp >= 1.4+    , lsp == 1.5.*     , mainland-pretty >=0.7.1     , cmark-gfm >=0.2.1     , megaparsec >=9.0.0@@ -396,19 +439,18 @@     , zlib >=0.6.1.2     , statistics     , mwc-random-  default-language: Haskell2010  executable futhark+  import: common   main-is: src/main.hs-  ghc-options: -Wall -Wcompat -Wno-incomplete-uni-patterns -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -Wunused-packages -threaded -rtsopts "-with-rtsopts=-N -qg1 -A16M"-  build-depends:-      base-    , futhark-  default-language: Haskell2010+  ghc-options: -threaded -rtsopts "-with-rtsopts=-N -qg1 -A16M"+  build-depends: base, futhark  test-suite unit+  import: common   type: exitcode-stdio-1.0   main-is: futhark_tests.hs+  hs-source-dirs: unittests   other-modules:       Futhark.AD.DerivativesTests       Futhark.BenchTests@@ -421,26 +463,20 @@       Futhark.IR.Mem.IxFun.Alg       Futhark.IR.Mem.IxFunTests       Futhark.IR.Mem.IxFunWrapper-      Futhark.IR.PrimitiveTests       Language.Futhark.CoreTests+      Language.Futhark.PrimitiveTests       Language.Futhark.SyntaxTests       Language.Futhark.TypeCheckerTests       Language.Futhark.TypeChecker.TypesTests       Futhark.Optimise.MemoryBlockMerging.GreedyColoringTests       Paths_futhark-  hs-source-dirs:-      unittests-  ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists   build-depends:       QuickCheck >=2.8     , base     , containers     , futhark     , megaparsec-    , mtl-    , parser-combinators     , tasty     , tasty-hunit     , tasty-quickcheck     , text-  default-language: Haskell2010
prelude/soacs.fut view
@@ -1,7 +1,7 @@ -- | Various Second-Order Array Combinators that are operationally -- parallel in a way that can be exploited by the compiler. ----- The functions here are all recognised specially by the compiler (or+-- The functions here are recognised specially by the compiler (or -- built on those that are).  The asymptotic [work and -- span](https://en.wikipedia.org/wiki/Analysis_of_parallel_algorithms) -- is provided for each function, but note that this easily hides very@@ -117,14 +117,26 @@ def reduce_comm [n] 'a (op: a -> a -> a) (ne: a) (as: [n]a): a =   intrinsics.reduce_comm (op, ne, as) --- | `reduce_by_index dest f ne is as` returns `dest`, but with each--- element given by the indices of `is` updated by applying `f` to the--- current value in `dest` and the corresponding value in `as`.  The--- `ne` value must be a neutral element for `f`.  If `is` has--- duplicates, `f` may be applied multiple times, and hence must be--- associative and commutative.  Out-of-bounds indices in `is` are--- ignored.+-- | `h = hist op ne k is as` computes a generalised `k`-bin histogram+-- `h`, such that `h[i]` is the sum of those values `as[j]` for which+-- `is[j]==i`.  The summation is done with `op`, which must be a+-- commutative and associative function with neutral element `ne`.  If+-- a bin has no elements, its value will be `ne`. --+-- **Work:** *O(k + n ✕ W(op))*+--+-- **Span:** *O(n ✕ W(op))* in the worst case (all updates to same+-- position), but *O(W(op))* in the best case.+--+-- In practice, the *O(n)* behaviour only occurs if *m* is also very+-- large.+def hist 'a [n] (op: a -> a -> a) (ne: a) (k: i64) (is: [n]i64) (as: [n]a) : *[k]a =+  intrinsics.hist_1d (1, map (\_ -> ne) (0..1..<k), op, ne, is, as)++-- | Like `hist`, but with initial contents of the histogram, and the+-- complexity is proportional only to the number of input elements,+-- not the total size of the histogram.+-- -- **Work:** *O(n ✕ W(op))* -- -- **Span:** *O(n ✕ W(op))* in the worst case (all updates to same@@ -132,15 +144,15 @@ -- -- In practice, the *O(n)* behaviour only occurs if *m* is also very -- large.-def reduce_by_index 'a [n] [m] (dest : *[m]a) (f : a -> a -> a) (ne : a) (is : [n]i64) (as : [n]a) : *[m]a =+def reduce_by_index 'a [k] [n] (dest : *[k]a) (f : a -> a -> a) (ne : a) (is : [n]i64) (as : [n]a) : *[k]a =   intrinsics.hist_1d (1, dest, f, ne, is, as)  -- | As `reduce_by_index`, but with two-dimensional indexes.-def reduce_by_index_2d 'a [n] [m] [k] (dest : *[m][k]a) (f : a -> a -> a) (ne : a) (is : [n](i64,i64)) (as : [n]a) : *[m][k]a =+def reduce_by_index_2d 'a [k] [n] [m] (dest : *[k][m]a) (f : a -> a -> a) (ne : a) (is : [n](i64,i64)) (as : [n]a) : *[k][m]a =   intrinsics.hist_2d (1, dest, f, ne, is, as)  -- | As `reduce_by_index`, but with three-dimensional indexes.-def reduce_by_index_3d 'a [n] [m] [k] [l] (dest : *[m][k][l]a) (f : a -> a -> a) (ne : a) (is : [n](i64,i64,i64)) (as : [n]a) : *[m][k][l]a =+def reduce_by_index_3d 'a [k] [n] [m] [l] (dest : *[k][m][l]a) (f : a -> a -> a) (ne : a) (is : [n](i64,i64,i64)) (as : [n]a) : *[k][m][l]a =   intrinsics.hist_3d (1, dest, f, ne, is, as)  -- | Inclusive prefix scan.  Has the same caveats with respect to@@ -249,35 +261,27 @@ def any [n] 'a (f: a -> bool) (as: [n]a): bool =   reduce (||) false (map f as) --- | `scatter as is vs` calculates the equivalent of this imperative--- code:------ ```--- for j in 0...length is-1:---   i = is[j]---   v = vs[j]---   if i >= 0 && i < length as:---     as[i] = v--- ```+-- | `r = spread x k is vs` produces an array `r` such that `r[i] =+-- vs[j]` where `is[j] == i`, or `x` if no such `j` exists.+-- Intuitively, `is` is an array indicating where the corresponding+-- elements of `vs` should be located in the result.  Out-of-bounds+-- elements of `is` are ignored.  In-bounds duplicates in `is` result+-- in unspecified behaviour - see `hist`@term for a function that can+-- handle this. ----- The `is` and `vs` arrays must have the same outer size.  `scatter`--- acts in-place and consumes the `as` array, returning a new array--- that has the same type and elements as `as`, except for the indices--- in `is`. Notice that writing outside the index domain of the target--- array has no effect. If `is` contains duplicates for valid indexes--- into the target array (i.e., several writes are performed to the--- same location), the result is unspecified.  It is not guaranteed--- that one of the duplicate writes will complete atomically - they--- may be interleaved.  See `reduce_by_index`@term for a function that--- can handle this case deterministically.+-- **Work:** *O(k + n)* ----- This is technically not a second-order operation, but it is defined--- here because it is closely related to the SOACs.+-- **Span:** *O(1)*+def spread 't [n] (k: i64) (x: t) (is: [n]i64) (vs: [n]t): *[k]t =+  intrinsics.scatter (map (\_ -> x) (0..1..<k), is, vs)++-- | Like `spread`, but takes an array indicating the initial values,+-- and has different work complexity. -- -- **Work:** *O(n)* -- -- **Span:** *O(1)*-def scatter 't [m] [n] (dest: *[m]t) (is: [n]i64) (vs: [n]t): *[m]t =+def scatter 't [k] [n] (dest: *[k]t) (is: [n]i64) (vs: [n]t): *[k]t =   intrinsics.scatter (dest, is, vs)  -- | `scatter_2d as is vs` is the equivalent of a `scatter` on a 2-dimensional@@ -286,7 +290,7 @@ -- **Work:** *O(n)* -- -- **Span:** *O(1)*-def scatter_2d 't [m] [n] [l] (dest: *[m][n]t) (is: [l](i64, i64)) (vs: [l]t): *[m][n]t =+def scatter_2d 't [k] [n] [l] (dest: *[k][n]t) (is: [l](i64, i64)) (vs: [l]t): *[k][n]t =   intrinsics.scatter_2d (dest, is, vs)  -- | `scatter_3d as is vs` is the equivalent of a `scatter` on a 3-dimensional@@ -295,5 +299,5 @@ -- **Work:** *O(n)* -- -- **Span:** *O(1)*-def scatter_3d 't [m] [n] [o] [l] (dest: *[m][n][o]t) (is: [l](i64, i64, i64)) (vs: [l]t): *[m][n][o]t =+def scatter_3d 't [k] [n] [o] [l] (dest: *[k][n][o]t) (is: [l](i64, i64, i64)) (vs: [l]t): *[k][n][o]t =   intrinsics.scatter_3d (dest, is, vs)
+ rts/c/ispc_util.h view
@@ -0,0 +1,457 @@+// Start of ispc_util.h.++// This header file implements various operations that are useful only when+// generating ISPC code. This includes wrappers for parts of Futhark's C runtime.++// Expose gang size+export uniform int64_t get_gang_size() {+  return programCount;+}++// Generate missing overloads for extract on pointers+#define make_extract(ty)                                                                \+static inline uniform ty * uniform extract(uniform ty * varying ptr, uniform int idx) { \+    int64 c = (int64)ptr;                                                               \+    uniform int64 r = extract(c, idx);                                                  \+    return (uniform ty * uniform)r;                                                     \+}++make_extract(int8)+make_extract(int16)+make_extract(int32)+make_extract(int64)+make_extract(uint8)+make_extract(uint16)+make_extract(uint32)+make_extract(uint64)+make_extract(float16)+make_extract(float)+make_extract(double)+make_extract(int8* uniform)+make_extract(int16* uniform)+make_extract(int32* uniform)+make_extract(int64* uniform)+make_extract(uint8* uniform)+make_extract(uint16* uniform)+make_extract(uint32* uniform)+make_extract(uint64* uniform)+make_extract(float16* uniform)+make_extract(float* uniform)+make_extract(double* uniform)+make_extract(struct futhark_context)+make_extract(struct memblock)+++// Handling of atomics+// Atomic CAS acts differently in GCC and ISPC, so we emulate it.+#define make_atomic_compare_exchange_wrapper(ty)                                     \+static inline uniform bool atomic_compare_exchange_wrapper(uniform ty * uniform mem, \+                                                           uniform ty * uniform old, \+                                                           const uniform ty val){    \+  uniform ty actual = atomic_compare_exchange_global(mem, *old, val);                \+  if (actual == *old){                                                               \+    return 1;                                                                        \+  }                                                                                  \+  *old = actual;                                                                     \+  return 0;                                                                          \+}                                                                                    \+static inline varying bool atomic_compare_exchange_wrapper(uniform ty * varying mem, \+                                                           varying ty * uniform old, \+                                                           const varying ty val){    \+  varying ty actual = atomic_compare_exchange_global(mem, *old, val);                \+  bool res = 0;                                                                      \+  if(actual == *old){                                                                \+    res = 1;                                                                         \+  } else {                                                                           \+    *old = actual;                                                                   \+  }                                                                                  \+  return res;                                                                        \+}                                                                                    \+static inline varying bool atomic_compare_exchange_wrapper(varying ty * uniform mem, \+                                                           varying ty * uniform old, \+                                                           const varying ty val){    \+  uniform ty * uniform base_mem = (uniform ty * uniform)mem;                         \+  uniform ty * uniform base_old = (uniform ty * uniform)old;                         \+  bool res = 0;                                                                      \+  foreach_active (i) {                                                               \+    uniform ty * uniform curr_mem = base_mem + i;                                    \+    uniform ty * uniform curr_old = base_old + i;                                    \+    uniform ty curr_val = extract(val, i);                                           \+    uniform bool curr = atomic_compare_exchange_wrapper(                             \+                            curr_mem, curr_old, curr_val);                           \+    res = insert(res, i, curr);                                                      \+  }                                                                                  \+  return res;                                                                        \+}                                                                                    \+static inline uniform bool atomic_compare_exchange_wrapper(uniform ty * uniform mem, \+                                                           uniform ty * uniform old, \+                                                           const varying ty val){    \+  uniform ty v = 0;                                                                  \+  foreach_active (i) v = extract(val, i);                                            \+  return atomic_compare_exchange_wrapper(mem, old, v);                               \+}++make_atomic_compare_exchange_wrapper(int32)+make_atomic_compare_exchange_wrapper(int64)+make_atomic_compare_exchange_wrapper(uint32)+make_atomic_compare_exchange_wrapper(uint64)+make_atomic_compare_exchange_wrapper(float)+make_atomic_compare_exchange_wrapper(double)++// This code generates missing overloads for atomic operations on uniform+// pointers to varying values.+#define make_single_atomic(name, ty)                                        \+static inline ty atomic_##name##_global(varying ty * uniform mem, ty val) { \+  uniform ty * uniform base_mem = (uniform ty * uniform)mem;                \+  ty res = 0;                                                               \+  foreach_active (i) {                                                      \+    uniform ty * uniform curr_mem = base_mem + i;                           \+    uniform ty curr_val = extract(val, i);                                  \+    uniform ty curr = atomic_##name##_global(curr_mem, curr_val);           \+    res = insert(res, i, curr);                                             \+  }                                                                         \+  return res;                                                               \+}++#define make_all_atomic(name)    \+make_single_atomic(name, int32)  \+make_single_atomic(name, int64)  \+make_single_atomic(name, uint32) \+make_single_atomic(name, uint64)++make_all_atomic(add)+make_all_atomic(subtract)+make_all_atomic(and)+make_all_atomic(or)+make_all_atomic(xor)+make_all_atomic(swap)++// This is a hack to prevent literals (which have unbound variability)+// from causing us to pick the wrong overload for atomic operations.+static inline varying int32  make_varying(uniform int32  x) { return x; }+static inline varying int32  make_varying(varying int32  x) { return x; }+static inline varying int64  make_varying(uniform int64  x) { return x; }+static inline varying int64  make_varying(varying int64  x) { return x; }+static inline varying uint32 make_varying(uniform uint32 x) { return x; }+static inline varying uint32 make_varying(varying uint32 x) { return x; }+static inline varying uint64 make_varying(uniform uint64 x) { return x; }+static inline varying uint64 make_varying(varying uint64 x) { return x; }++// Redirect atomic operations to the relevant ISPC overloads.+#define __atomic_fetch_add(x,y,z) atomic_add_global(x,make_varying(y))+#define __atomic_fetch_sub(x,y,z) atomic_sub_global(x,make_varying(y))+#define __atomic_fetch_and(x,y,z) atomic_and_global(x,make_varying(y))+#define __atomic_fetch_or(x,y,z) atomic_or_global(x,make_varying(y))+#define __atomic_fetch_xor(x,y,z) atomic_xor_global(x,make_varying(y))+#define __atomic_exchange_n(x,y,z) atomic_swap_global(x,make_varying(y))+#define __atomic_compare_exchange_n(x,y,z,h,j,k) atomic_compare_exchange_wrapper(x,y,z)+++// Memory allocation handling+struct memblock {+    int32_t * references;+    uint8_t * mem;+    int64_t size;+    const int8_t * desc;+};++static inline void free(void* ptr) {+  delete ptr;+}++static inline void free(void* uniform ptr) {+  delete ptr;+}++extern "C" unmasked uniform unsigned char * uniform realloc(uniform unsigned char * uniform ptr, uniform int64_t new_size);+extern "C" unmasked uniform char * uniform lexical_realloc_error(uniform int64_t new_size);+extern "C" unmasked uniform char * uniform * uniform futhark_get_error_ref(uniform struct futhark_context * uniform ctx);++static inline uniform int lexical_realloc(uniform char * uniform * uniform error,+                                          unsigned char uniform * uniform * uniform ptr,+                                          int64_t uniform * uniform old_size,+                                          uniform int64_t new_size) {+  uniform unsigned char * uniform memptr = realloc(*ptr, new_size);+  if (memptr == NULL) {+    *error = lexical_realloc_error(new_size);+    return FUTHARK_OUT_OF_MEMORY;+  } else {+    *ptr = memptr;+    *old_size = new_size;+    return FUTHARK_SUCCESS;+  }+}+++static inline uniform int lexical_realloc(uniform char * uniform * uniform error,+                                          unsigned char uniform * uniform * uniform ptr,+                                          int64_t uniform * uniform old_size,+                                          varying int64_t new_size) {+  return lexical_realloc(error, ptr, old_size, reduce_max(new_size));+}++static inline uniform int lexical_realloc(uniform char * uniform * uniform error,+                                          unsigned char uniform * varying * uniform ptr,+                                          int64_t uniform * varying old_size,+                                          varying int64_t new_size) {+  uniform int err = FUTHARK_SUCCESS;+  foreach_active(i){+    uniform unsigned char * uniform memptr = realloc(extract(*ptr,i), extract(new_size,i));+    if (memptr == NULL) {+      *error = lexical_realloc_error(extract(new_size,i));+      err = FUTHARK_OUT_OF_MEMORY;+    } else {+      *ptr = (uniform unsigned char * varying)insert((int64_t)*ptr, i, (uniform int64_t) memptr);+      *old_size = new_size;+    }+  }+  return err;+}++static inline uniform int lexical_realloc(uniform char * uniform * uniform error,+                                          unsigned char uniform * varying * uniform ptr,+                                          int64_t varying * uniform old_size,+                                          varying int64_t new_size) {+  uniform int err = FUTHARK_SUCCESS;+  foreach_active(i){+    uniform unsigned char * uniform memptr = realloc(extract(*ptr,i), extract(new_size,i));+    if (memptr == NULL) {+      *error = lexical_realloc_error(extract(new_size,i));+      err = FUTHARK_OUT_OF_MEMORY;+    } else {+      *ptr = (uniform unsigned char * varying)insert((int64_t)*ptr, i, (uniform int64_t) memptr);+      *old_size = new_size;+    }+  }+  return err;+}++static inline uniform int lexical_realloc(uniform char * uniform * uniform error,+                                          unsigned char uniform * varying * uniform ptr,+                                          size_t varying * uniform old_size,+                                          varying int64_t new_size) {+  return lexical_realloc(error, ptr, (varying int64_t * uniform)old_size, new_size);+}++static inline uniform int lexical_realloc(uniform char * uniform * uniform error,+                                          unsigned char varying * uniform * uniform ptr,+                                          size_t varying * uniform old_size,+                                          uniform int64_t new_size) {+  uniform int err = FUTHARK_SUCCESS;+  uniform unsigned char * uniform memptr = realloc((uniform unsigned char * uniform )*ptr,+                                                        new_size*programCount);+  if (memptr == NULL) {+    *error = lexical_realloc_error(new_size);+    err = FUTHARK_OUT_OF_MEMORY;+  } else {+    *ptr = (varying unsigned char * uniform)memptr;+    *old_size = new_size;+  }++  return err;+}++static inline uniform int lexical_realloc(uniform char * uniform * uniform error,+                                          unsigned char varying * uniform * uniform ptr,+                                          size_t varying * uniform old_size,+                                          varying int64_t new_size) {+  return lexical_realloc(error, ptr, old_size, reduce_max(new_size));+}++extern "C" unmasked uniform int memblock_unref(uniform struct futhark_context * uniform ctx,+                                               uniform struct memblock * uniform lhs,+                                               uniform const char * uniform lhs_desc);++static uniform int memblock_unref(uniform struct futhark_context * varying ctx,+                                  uniform struct memblock * varying lhs,+                                  uniform const char * uniform lhs_desc)+{+  uniform int err = 0;++  foreach_active(i) {+    err |= memblock_unref(extract(ctx,i), extract(lhs,i), lhs_desc);+  }++  return err;+}+static uniform int memblock_unref(uniform struct futhark_context * uniform ctx,+                                  varying struct memblock * uniform lhs,+                                  uniform const char * uniform lhs_desc)+{+  uniform int err = 0;++  varying struct memblock _lhs = *lhs;+  uniform struct memblock aos[programCount];+  aos[programIndex] = _lhs;++  foreach_active(i){+    err |= memblock_unref(ctx,+           &aos[i],+           lhs_desc);+  }++  *lhs = aos[programIndex];++  return err;+}++extern "C" unmasked uniform int memblock_alloc(uniform struct futhark_context * uniform ctx,+                                               uniform struct memblock * uniform block,+                                               uniform int64_t size,+                                               uniform const char * uniform block_desc);++static uniform int memblock_alloc(uniform struct futhark_context * varying ctx,+                                  uniform struct memblock * varying block,+                                  varying int64_t size,+                                  uniform const char * uniform block_desc) {+  uniform int err = 0;++  foreach_active(i){+    err |= memblock_alloc(extract(ctx,i), extract(block,i), extract(size, i), block_desc);+  }++  return err;+}++static uniform int memblock_alloc(uniform struct futhark_context * uniform ctx,+                                  varying struct memblock * uniform block,+                                  uniform int64_t size,+                                  uniform const char * uniform block_desc) {+  uniform int err = 0;++  varying struct memblock _block = *block;+  uniform struct memblock aos[programCount];+  aos[programIndex] = _block;++  foreach_active(i){+    err |= memblock_alloc(ctx, &aos[i], size, block_desc);+  }+  *block = aos[programIndex];++  return err;+}++static uniform int memblock_alloc(uniform struct futhark_context * uniform ctx,+                                  varying struct memblock * uniform block,+                                  varying int64_t size,+                                  uniform const char * uniform block_desc) {+  uniform int err = 0;++  varying struct memblock _block = *block;+  uniform struct memblock aos[programCount];+  aos[programIndex] = _block;+  foreach_active(i){+    err |= memblock_alloc(ctx, &aos[i], extract(size, i), block_desc);+  }+  *block = aos[programIndex];++  return err;+}++extern "C" unmasked uniform int memblock_set(uniform struct futhark_context * uniform ctx,+                                             uniform struct memblock * uniform lhs,+                                             uniform struct memblock * uniform rhs,+                                             uniform const char * uniform lhs_desc);++static uniform int memblock_set (uniform struct futhark_context * uniform ctx,+                                 varying struct memblock * uniform lhs,+                                 varying struct memblock * uniform rhs,+                                 uniform const char * uniform lhs_desc) {+  uniform int err = 0;++  varying struct memblock _lhs = *lhs;+  varying struct memblock _rhs = *rhs;+  uniform struct memblock aos1[programCount];+  aos1[programIndex] = _lhs;++  uniform struct memblock aos2[programCount];+  aos2[programIndex] = _rhs;++  foreach_active(i) {+      err |= memblock_set(ctx,+      &aos1[i],+      &aos2[i],+      lhs_desc);+  }+  *lhs = aos1[programIndex];+  *rhs = aos2[programIndex];++  return err;+}++static uniform int memblock_set (uniform struct futhark_context * uniform ctx,+                                 varying struct memblock * uniform lhs,+                                 uniform struct memblock * uniform rhs,+                                 uniform const char * uniform lhs_desc) {+  uniform int err = 0;++  varying struct memblock _lhs = *lhs;+  uniform struct memblock aos1[programCount];+  aos1[programIndex] = _lhs;++  foreach_active(i) {+      err |= memblock_set(ctx,+      &aos1[i],+      rhs,+      lhs_desc);+  }+  *lhs = aos1[programIndex];++  return err;+}++// AOS <-> SOA memcpy functions+#define memmove_sized(dim)                                                                                      \+static inline void memmove_##dim(varying uint8 * uniform dst, uniform uint8 * varying src, uniform int64_t n) { \+    uniform uint##dim * varying srcp = (uniform uint##dim * varying) src;                                       \+    varying uint##dim * uniform dstp = (varying uint##dim * uniform) dst;                                       \+    for (uniform int64_t i = 0; i < n / (dim / 8); i++) {                                                       \+        dstp[i] = srcp[i];                                                                                      \+    }                                                                                                           \+}                                                                                                               \+static inline void memmove_##dim(uniform uint8 * varying dst, varying uint8 * uniform src, uniform int64_t n) { \+    varying uint##dim * uniform srcp = (varying uint##dim * uniform) src;                                       \+    uniform uint##dim * varying dstp = (uniform uint##dim * varying) dst;                                       \+    for (uniform int64_t i = 0; i < n / (dim / 8); i++) {                                                       \+        dstp[i] = srcp[i];                                                                                      \+    }                                                                                                           \+}                                                                                                               \+static inline void memmove_##dim(varying uint8 * uniform dst, varying uint8 * uniform src, uniform int64_t n) { \+    varying uint##dim * uniform srcp = (varying uint##dim * uniform) src;                                       \+    varying uint##dim * uniform dstp = (varying uint##dim * uniform) dst;                                       \+    for (uniform int64_t i = 0; i < n / (dim / 8); i++) {                                                       \+        dstp[i] = srcp[i];                                                                                      \+    }                                                                                                           \+}                                                                                                               \+static inline void memmove_##dim(varying uint8 * varying dst, uniform uint8 * varying src, uniform int64_t n) { \+    foreach_unique (ptr in dst) {                                                                               \+        memmove_##dim(ptr, src, n);                                                                             \+    }                                                                                                           \+}                                                                                                               \+static inline void memmove_##dim(uniform uint8 * varying dst, varying uint8 * varying src, uniform int64_t n) { \+    foreach_unique (ptr in src) {                                                                               \+        memmove_##dim(dst, ptr, n);                                                                             \+    }                                                                                                           \+}                                                                                                               \+static inline void memmove_##dim(varying uint8 * varying dst, varying uint8 * uniform src, uniform int64_t n) { \+    foreach_unique (ptr in dst) {                                                                               \+        memmove_##dim(ptr, src, n);                                                                             \+    }                                                                                                           \+}                                                                                                               \+static inline void memmove_##dim(varying uint8 * varying dst, varying uint8 * varying src, uniform int64_t n) { \+    if (reduce_equal((varying int64_t)dst)) {                                                                   \+        foreach_unique (ptr in src) {                                                                           \+            memmove_##dim(dst, ptr, n);                                                                         \+        }                                                                                                       \+    } else {                                                                                                    \+        foreach_unique (ptr in dst) {                                                                           \+            memmove_##dim(ptr, src, n);                                                                         \+        }                                                                                                       \+    }                                                                                                           \+}+memmove_sized(8)+memmove_sized(16)+memmove_sized(32)+memmove_sized(64)++// End of ispc_util.h.
rts/c/scalar.h view
@@ -65,1705 +65,2929 @@   return x * y; } -static inline uint8_t udiv8(uint8_t x, uint8_t y) {-  return x / y;-}--static inline uint16_t udiv16(uint16_t x, uint16_t y) {-  return x / y;-}--static inline uint32_t udiv32(uint32_t x, uint32_t y) {-  return x / y;-}--static inline uint64_t udiv64(uint64_t x, uint64_t y) {-  return x / y;-}--static inline uint8_t udiv_up8(uint8_t x, uint8_t y) {-  return (x + y - 1) / y;-}--static inline uint16_t udiv_up16(uint16_t x, uint16_t y) {-  return (x + y - 1) / y;-}--static inline uint32_t udiv_up32(uint32_t x, uint32_t y) {-  return (x + y - 1) / y;-}--static inline uint64_t udiv_up64(uint64_t x, uint64_t y) {-  return (x + y - 1) / y;-}--static inline uint8_t umod8(uint8_t x, uint8_t y) {-  return x % y;-}--static inline uint16_t umod16(uint16_t x, uint16_t y) {-  return x % y;-}--static inline uint32_t umod32(uint32_t x, uint32_t y) {-  return x % y;-}--static inline uint64_t umod64(uint64_t x, uint64_t y) {-  return x % y;-}--static inline uint8_t udiv_safe8(uint8_t x, uint8_t y) {-  return y == 0 ? 0 : x / y;-}--static inline uint16_t udiv_safe16(uint16_t x, uint16_t y) {-  return y == 0 ? 0 : x / y;-}--static inline uint32_t udiv_safe32(uint32_t x, uint32_t y) {-  return y == 0 ? 0 : x / y;-}--static inline uint64_t udiv_safe64(uint64_t x, uint64_t y) {-  return y == 0 ? 0 : x / y;-}--static inline uint8_t udiv_up_safe8(uint8_t x, uint8_t y) {-  return y == 0 ? 0 : (x + y - 1) / y;-}--static inline uint16_t udiv_up_safe16(uint16_t x, uint16_t y) {-  return y == 0 ? 0 : (x + y - 1) / y;-}--static inline uint32_t udiv_up_safe32(uint32_t x, uint32_t y) {-  return y == 0 ? 0 : (x + y - 1) / y;-}--static inline uint64_t udiv_up_safe64(uint64_t x, uint64_t y) {-  return y == 0 ? 0 : (x + y - 1) / y;-}--static inline uint8_t umod_safe8(uint8_t x, uint8_t y) {-  return y == 0 ? 0 : x % y;-}--static inline uint16_t umod_safe16(uint16_t x, uint16_t y) {-  return y == 0 ? 0 : x % y;-}--static inline uint32_t umod_safe32(uint32_t x, uint32_t y) {-  return y == 0 ? 0 : x % y;-}--static inline uint64_t umod_safe64(uint64_t x, uint64_t y) {-  return y == 0 ? 0 : x % y;-}--static inline int8_t sdiv8(int8_t x, int8_t y) {-  int8_t q = x / y;-  int8_t r = x % y;--  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int16_t sdiv16(int16_t x, int16_t y) {-  int16_t q = x / y;-  int16_t r = x % y;--  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int32_t sdiv32(int32_t x, int32_t y) {-  int32_t q = x / y;-  int32_t r = x % y;--  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int64_t sdiv64(int64_t x, int64_t y) {-  int64_t q = x / y;-  int64_t r = x % y;--  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);-}--static inline int8_t sdiv_up8(int8_t x, int8_t y) {-  return sdiv8(x + y - 1, y);-}--static inline int16_t sdiv_up16(int16_t x, int16_t y) {-  return sdiv16(x + y - 1, y);-}--static inline int32_t sdiv_up32(int32_t x, int32_t y) {-  return sdiv32(x + y - 1, y);-}--static inline int64_t sdiv_up64(int64_t x, int64_t y) {-  return sdiv64(x + y - 1, y);-}--static inline int8_t smod8(int8_t x, int8_t y) {-  int8_t r = x % y;--  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int16_t smod16(int16_t x, int16_t y) {-  int16_t r = x % y;--  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int32_t smod32(int32_t x, int32_t y) {-  int32_t r = x % y;--  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int64_t smod64(int64_t x, int64_t y) {-  int64_t r = x % y;--  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);-}--static inline int8_t sdiv_safe8(int8_t x, int8_t y) {-  return y == 0 ? 0 : sdiv8(x, y);-}--static inline int16_t sdiv_safe16(int16_t x, int16_t y) {-  return y == 0 ? 0 : sdiv16(x, y);-}--static inline int32_t sdiv_safe32(int32_t x, int32_t y) {-  return y == 0 ? 0 : sdiv32(x, y);-}--static inline int64_t sdiv_safe64(int64_t x, int64_t y) {-  return y == 0 ? 0 : sdiv64(x, y);-}--static inline int8_t sdiv_up_safe8(int8_t x, int8_t y) {-  return sdiv_safe8(x + y - 1, y);-}--static inline int16_t sdiv_up_safe16(int16_t x, int16_t y) {-  return sdiv_safe16(x + y - 1, y);-}--static inline int32_t sdiv_up_safe32(int32_t x, int32_t y) {-  return sdiv_safe32(x + y - 1, y);-}--static inline int64_t sdiv_up_safe64(int64_t x, int64_t y) {-  return sdiv_safe64(x + y - 1, y);-}--static inline int8_t smod_safe8(int8_t x, int8_t y) {-  return y == 0 ? 0 : smod8(x, y);-}--static inline int16_t smod_safe16(int16_t x, int16_t y) {-  return y == 0 ? 0 : smod16(x, y);-}--static inline int32_t smod_safe32(int32_t x, int32_t y) {-  return y == 0 ? 0 : smod32(x, y);-}--static inline int64_t smod_safe64(int64_t x, int64_t y) {-  return y == 0 ? 0 : smod64(x, y);-}--static inline int8_t squot8(int8_t x, int8_t y) {-  return x / y;-}--static inline int16_t squot16(int16_t x, int16_t y) {-  return x / y;-}--static inline int32_t squot32(int32_t x, int32_t y) {-  return x / y;-}--static inline int64_t squot64(int64_t x, int64_t y) {-  return x / y;-}--static inline int8_t srem8(int8_t x, int8_t y) {-  return x % y;-}--static inline int16_t srem16(int16_t x, int16_t y) {-  return x % y;-}--static inline int32_t srem32(int32_t x, int32_t y) {-  return x % y;-}--static inline int64_t srem64(int64_t x, int64_t y) {-  return x % y;-}--static inline int8_t squot_safe8(int8_t x, int8_t y) {-  return y == 0 ? 0 : x / y;-}--static inline int16_t squot_safe16(int16_t x, int16_t y) {-  return y == 0 ? 0 : x / y;-}--static inline int32_t squot_safe32(int32_t x, int32_t y) {-  return y == 0 ? 0 : x / y;-}--static inline int64_t squot_safe64(int64_t x, int64_t y) {-  return y == 0 ? 0 : x / y;-}--static inline int8_t srem_safe8(int8_t x, int8_t y) {-  return y == 0 ? 0 : x % y;-}--static inline int16_t srem_safe16(int16_t x, int16_t y) {-  return y == 0 ? 0 : x % y;-}--static inline int32_t srem_safe32(int32_t x, int32_t y) {-  return y == 0 ? 0 : x % y;-}--static inline int64_t srem_safe64(int64_t x, int64_t y) {-  return y == 0 ? 0 : x % y;-}--static inline int8_t smin8(int8_t x, int8_t y) {-  return x < y ? x : y;-}--static inline int16_t smin16(int16_t x, int16_t y) {-  return x < y ? x : y;-}--static inline int32_t smin32(int32_t x, int32_t y) {-  return x < y ? x : y;-}--static inline int64_t smin64(int64_t x, int64_t y) {-  return x < y ? x : y;-}--static inline uint8_t umin8(uint8_t x, uint8_t y) {-  return x < y ? x : y;-}--static inline uint16_t umin16(uint16_t x, uint16_t y) {-  return x < y ? x : y;-}--static inline uint32_t umin32(uint32_t x, uint32_t y) {-  return x < y ? x : y;-}--static inline uint64_t umin64(uint64_t x, uint64_t y) {-  return x < y ? x : y;-}--static inline int8_t smax8(int8_t x, int8_t y) {-  return x < y ? y : x;-}--static inline int16_t smax16(int16_t x, int16_t y) {-  return x < y ? y : x;-}--static inline int32_t smax32(int32_t x, int32_t y) {-  return x < y ? y : x;-}--static inline int64_t smax64(int64_t x, int64_t y) {-  return x < y ? y : x;-}--static inline uint8_t umax8(uint8_t x, uint8_t y) {-  return x < y ? y : x;-}--static inline uint16_t umax16(uint16_t x, uint16_t y) {-  return x < y ? y : x;-}--static inline uint32_t umax32(uint32_t x, uint32_t y) {-  return x < y ? y : x;-}--static inline uint64_t umax64(uint64_t x, uint64_t y) {-  return x < y ? y : x;-}--static inline uint8_t shl8(uint8_t x, uint8_t y) {-  return (uint8_t)(x << y);-}--static inline uint16_t shl16(uint16_t x, uint16_t y) {-  return (uint16_t)(x << y);-}--static inline uint32_t shl32(uint32_t x, uint32_t y) {-  return x << y;-}--static inline uint64_t shl64(uint64_t x, uint64_t y) {-  return x << y;-}--static inline uint8_t lshr8(uint8_t x, uint8_t y) {-  return x >> y;-}--static inline uint16_t lshr16(uint16_t x, uint16_t y) {-  return x >> y;-}--static inline uint32_t lshr32(uint32_t x, uint32_t y) {-  return x >> y;-}--static inline uint64_t lshr64(uint64_t x, uint64_t y) {-  return x >> y;-}--static inline int8_t ashr8(int8_t x, int8_t y) {-  return x >> y;-}--static inline int16_t ashr16(int16_t x, int16_t y) {-  return x >> y;-}--static inline int32_t ashr32(int32_t x, int32_t y) {-  return x >> y;-}--static inline int64_t ashr64(int64_t x, int64_t y) {-  return x >> y;-}--static inline uint8_t and8(uint8_t x, uint8_t y) {-  return x & y;-}--static inline uint16_t and16(uint16_t x, uint16_t y) {-  return x & y;-}--static inline uint32_t and32(uint32_t x, uint32_t y) {-  return x & y;-}--static inline uint64_t and64(uint64_t x, uint64_t y) {-  return x & y;-}--static inline uint8_t or8(uint8_t x, uint8_t y) {-  return x | y;-}--static inline uint16_t or16(uint16_t x, uint16_t y) {-  return x | y;-}--static inline uint32_t or32(uint32_t x, uint32_t y) {-  return x | y;-}--static inline uint64_t or64(uint64_t x, uint64_t y) {-  return x | y;-}--static inline uint8_t xor8(uint8_t x, uint8_t y) {-  return x ^ y;-}--static inline uint16_t xor16(uint16_t x, uint16_t y) {-  return x ^ y;-}--static inline uint32_t xor32(uint32_t x, uint32_t y) {-  return x ^ y;-}--static inline uint64_t xor64(uint64_t x, uint64_t y) {-  return x ^ y;-}--static inline bool ult8(uint8_t x, uint8_t y) {-  return x < y;-}--static inline bool ult16(uint16_t x, uint16_t y) {-  return x < y;-}--static inline bool ult32(uint32_t x, uint32_t y) {-  return x < y;-}--static inline bool ult64(uint64_t x, uint64_t y) {-  return x < y;-}--static inline bool ule8(uint8_t x, uint8_t y) {-  return x <= y;-}--static inline bool ule16(uint16_t x, uint16_t y) {-  return x <= y;-}--static inline bool ule32(uint32_t x, uint32_t y) {-  return x <= y;-}--static inline bool ule64(uint64_t x, uint64_t y) {-  return x <= y;-}--static inline bool slt8(int8_t x, int8_t y) {-  return x < y;-}--static inline bool slt16(int16_t x, int16_t y) {-  return x < y;-}--static inline bool slt32(int32_t x, int32_t y) {-  return x < y;-}--static inline bool slt64(int64_t x, int64_t y) {-  return x < y;-}--static inline bool sle8(int8_t x, int8_t y) {-  return x <= y;-}--static inline bool sle16(int16_t x, int16_t y) {-  return x <= y;-}--static inline bool sle32(int32_t x, int32_t y) {-  return x <= y;-}--static inline bool sle64(int64_t x, int64_t y) {-  return x <= y;-}--static inline uint8_t pow8(uint8_t x, uint8_t y) {-  uint8_t res = 1, rem = y;--  while (rem != 0) {-    if (rem & 1)-      res *= x;-    rem >>= 1;-    x *= x;-  }-  return res;-}--static inline uint16_t pow16(uint16_t x, uint16_t y) {-  uint16_t res = 1, rem = y;--  while (rem != 0) {-    if (rem & 1)-      res *= x;-    rem >>= 1;-    x *= x;-  }-  return res;-}--static inline uint32_t pow32(uint32_t x, uint32_t y) {-  uint32_t res = 1, rem = y;--  while (rem != 0) {-    if (rem & 1)-      res *= x;-    rem >>= 1;-    x *= x;-  }-  return res;-}--static inline uint64_t pow64(uint64_t x, uint64_t y) {-  uint64_t res = 1, rem = y;--  while (rem != 0) {-    if (rem & 1)-      res *= x;-    rem >>= 1;-    x *= x;-  }-  return res;-}--static inline bool itob_i8_bool(int8_t x) {-  return x;-}--static inline bool itob_i16_bool(int16_t x) {-  return x;-}--static inline bool itob_i32_bool(int32_t x) {-  return x;-}--static inline bool itob_i64_bool(int64_t x) {-  return x;-}--static inline int8_t btoi_bool_i8(bool x) {-  return x;-}--static inline int16_t btoi_bool_i16(bool x) {-  return x;-}--static inline int32_t btoi_bool_i32(bool x) {-  return x;-}--static inline int64_t btoi_bool_i64(bool x) {-  return x;-}--#define sext_i8_i8(x) ((int8_t) (int8_t) (x))-#define sext_i8_i16(x) ((int16_t) (int8_t) (x))-#define sext_i8_i32(x) ((int32_t) (int8_t) (x))-#define sext_i8_i64(x) ((int64_t) (int8_t) (x))-#define sext_i16_i8(x) ((int8_t) (int16_t) (x))-#define sext_i16_i16(x) ((int16_t) (int16_t) (x))-#define sext_i16_i32(x) ((int32_t) (int16_t) (x))-#define sext_i16_i64(x) ((int64_t) (int16_t) (x))-#define sext_i32_i8(x) ((int8_t) (int32_t) (x))-#define sext_i32_i16(x) ((int16_t) (int32_t) (x))-#define sext_i32_i32(x) ((int32_t) (int32_t) (x))-#define sext_i32_i64(x) ((int64_t) (int32_t) (x))-#define sext_i64_i8(x) ((int8_t) (int64_t) (x))-#define sext_i64_i16(x) ((int16_t) (int64_t) (x))-#define sext_i64_i32(x) ((int32_t) (int64_t) (x))-#define sext_i64_i64(x) ((int64_t) (int64_t) (x))-#define zext_i8_i8(x) ((int8_t) (uint8_t) (x))-#define zext_i8_i16(x) ((int16_t) (uint8_t) (x))-#define zext_i8_i32(x) ((int32_t) (uint8_t) (x))-#define zext_i8_i64(x) ((int64_t) (uint8_t) (x))-#define zext_i16_i8(x) ((int8_t) (uint16_t) (x))-#define zext_i16_i16(x) ((int16_t) (uint16_t) (x))-#define zext_i16_i32(x) ((int32_t) (uint16_t) (x))-#define zext_i16_i64(x) ((int64_t) (uint16_t) (x))-#define zext_i32_i8(x) ((int8_t) (uint32_t) (x))-#define zext_i32_i16(x) ((int16_t) (uint32_t) (x))-#define zext_i32_i32(x) ((int32_t) (uint32_t) (x))-#define zext_i32_i64(x) ((int64_t) (uint32_t) (x))-#define zext_i64_i8(x) ((int8_t) (uint64_t) (x))-#define zext_i64_i16(x) ((int16_t) (uint64_t) (x))-#define zext_i64_i32(x) ((int32_t) (uint64_t) (x))-#define zext_i64_i64(x) ((int64_t) (uint64_t) (x))--static int8_t abs8(int8_t x) {-  return (int8_t)abs(x);-}--static int16_t abs16(int16_t x) {-  return (int16_t)abs(x);-}--static int32_t abs32(int32_t x) {-  return abs(x);-}--static int64_t abs64(int64_t x) {-#if defined(__OPENCL_VERSION__)-  return abs(x);-#else-  return llabs(x);-#endif-}--#if defined(__OPENCL_VERSION__)-static int32_t futrts_popc8(int8_t x) {-  return popcount(x);-}--static int32_t futrts_popc16(int16_t x) {-  return popcount(x);-}--static int32_t futrts_popc32(int32_t x) {-  return popcount(x);-}--static int32_t futrts_popc64(int64_t x) {-  return popcount(x);-}-#elif defined(__CUDA_ARCH__)--static int32_t futrts_popc8(int8_t x) {-  return __popc(zext_i8_i32(x));-}--static int32_t futrts_popc16(int16_t x) {-  return __popc(zext_i16_i32(x));-}--static int32_t futrts_popc32(int32_t x) {-  return __popc(x);-}--static int32_t futrts_popc64(int64_t x) {-  return __popcll(x);-}--#else // Not OpenCL or CUDA, but plain C.--static int32_t futrts_popc8(uint8_t x) {-  int c = 0;-  for (; x; ++c) { x &= x - 1; }-  return c;-}--static int32_t futrts_popc16(uint16_t x) {-  int c = 0;-  for (; x; ++c) { x &= x - 1; }-  return c;-}--static int32_t futrts_popc32(uint32_t x) {-  int c = 0;-  for (; x; ++c) { x &= x - 1; }-  return c;-}--static int32_t futrts_popc64(uint64_t x) {-  int c = 0;-  for (; x; ++c) { x &= x - 1; }-  return c;-}-#endif--#if defined(__OPENCL_VERSION__)-static uint8_t futrts_mul_hi8(uint8_t a, uint8_t b) {-  return mul_hi(a, b);-}--static uint16_t futrts_mul_hi16(uint16_t a, uint16_t b) {-  return mul_hi(a, b);-}--static uint32_t futrts_mul_hi32(uint32_t a, uint32_t b) {-  return mul_hi(a, b);-}--static uint64_t futrts_mul_hi64(uint64_t a, uint64_t b) {-  return mul_hi(a, b);-}--#elif defined(__CUDA_ARCH__)--static uint8_t futrts_mul_hi8(uint8_t a, uint8_t b) {-  uint16_t aa = a;-  uint16_t bb = b;--  return aa * bb >> 8;-}--static uint16_t futrts_mul_hi16(uint16_t a, uint16_t b) {-  uint32_t aa = a;-  uint32_t bb = b;--  return aa * bb >> 16;-}--static uint32_t futrts_mul_hi32(uint32_t a, uint32_t b) {-  return mulhi(a, b);-}--static uint64_t futrts_mul_hi64(uint64_t a, uint64_t b) {-  return mul64hi(a, b);-}--#else // Not OpenCL or CUDA, but plain C.--static uint8_t futrts_mul_hi8(uint8_t a, uint8_t b) {-  uint16_t aa = a;-  uint16_t bb = b;--  return aa * bb >> 8;-}--static uint16_t futrts_mul_hi16(uint16_t a, uint16_t b) {-  uint32_t aa = a;-  uint32_t bb = b;--  return aa * bb >> 16;-}--static uint32_t futrts_mul_hi32(uint32_t a, uint32_t b) {-  uint64_t aa = a;-  uint64_t bb = b;--  return aa * bb >> 32;-}--static uint64_t futrts_mul_hi64(uint64_t a, uint64_t b) {-  __uint128_t aa = a;-  __uint128_t bb = b;--  return aa * bb >> 64;-}-#endif--#if defined(__OPENCL_VERSION__)-static uint8_t futrts_mad_hi8(uint8_t a, uint8_t b, uint8_t c) {-  return mad_hi(a, b, c);-}--static uint16_t futrts_mad_hi16(uint16_t a, uint16_t b, uint16_t c) {-  return mad_hi(a, b, c);-}--static uint32_t futrts_mad_hi32(uint32_t a, uint32_t b, uint32_t c) {-  return mad_hi(a, b, c);-}--static uint64_t futrts_mad_hi64(uint64_t a, uint64_t b, uint64_t c) {-  return mad_hi(a, b, c);-}--#else // Not OpenCL--static uint8_t futrts_mad_hi8(uint8_t a, uint8_t b, uint8_t c) {-  return futrts_mul_hi8(a, b) + c;-}--static uint16_t futrts_mad_hi16(uint16_t a, uint16_t b, uint16_t c) {-  return futrts_mul_hi16(a, b) + c;-}--static uint32_t futrts_mad_hi32(uint32_t a, uint32_t b, uint32_t c) {-  return futrts_mul_hi32(a, b) + c;-}--static uint64_t futrts_mad_hi64(uint64_t a, uint64_t b, uint64_t c) {-  return futrts_mul_hi64(a, b) + c;-}-#endif--#if defined(__OPENCL_VERSION__)-static int32_t futrts_clzz8(int8_t x) {-  return clz(x);-}--static int32_t futrts_clzz16(int16_t x) {-  return clz(x);-}--static int32_t futrts_clzz32(int32_t x) {-  return clz(x);-}--static int32_t futrts_clzz64(int64_t x) {-  return clz(x);-}--#elif defined(__CUDA_ARCH__)--static int32_t futrts_clzz8(int8_t x) {-  return __clz(zext_i8_i32(x)) - 24;-}--static int32_t futrts_clzz16(int16_t x) {-  return __clz(zext_i16_i32(x)) - 16;-}--static int32_t futrts_clzz32(int32_t x) {-  return __clz(x);-}--static int32_t futrts_clzz64(int64_t x) {-  return __clzll(x);-}--#else // Not OpenCL or CUDA, but plain C.--static int32_t futrts_clzz8(int8_t x) {-  return x == 0 ? 8 : __builtin_clz((uint32_t)zext_i8_i32(x)) - 24;-}--static int32_t futrts_clzz16(int16_t x) {-  return x == 0 ? 16 : __builtin_clz((uint32_t)zext_i16_i32(x)) - 16;-}--static int32_t futrts_clzz32(int32_t x) {-  return x == 0 ? 32 : __builtin_clz((uint32_t)x);-}--static int32_t futrts_clzz64(int64_t x) {-  return x == 0 ? 64 : __builtin_clzll((uint64_t)x);-}-#endif--#if defined(__OPENCL_VERSION__)-static int32_t futrts_ctzz8(int8_t x) {-  int i = 0;-  for (; i < 8 && (x & 1) == 0; i++, x >>= 1)-    ;-  return i;-}--static int32_t futrts_ctzz16(int16_t x) {-  int i = 0;-  for (; i < 16 && (x & 1) == 0; i++, x >>= 1)-    ;-  return i;-}--static int32_t futrts_ctzz32(int32_t x) {-  int i = 0;-  for (; i < 32 && (x & 1) == 0; i++, x >>= 1)-    ;-  return i;-}--static int32_t futrts_ctzz64(int64_t x) {-  int i = 0;-  for (; i < 64 && (x & 1) == 0; i++, x >>= 1)-    ;-  return i;-}--#elif defined(__CUDA_ARCH__)--static int32_t futrts_ctzz8(int8_t x) {-  int y = __ffs(x);-  return y == 0 ? 8 : y - 1;-}--static int32_t futrts_ctzz16(int16_t x) {-  int y = __ffs(x);-  return y == 0 ? 16 : y - 1;-}--static int32_t futrts_ctzz32(int32_t x) {-  int y = __ffs(x);-  return y == 0 ? 32 : y - 1;-}--static int32_t futrts_ctzz64(int64_t x) {-  int y = __ffsll(x);-  return y == 0 ? 64 : y - 1;-}--#else // Not OpenCL or CUDA, but plain C.--static int32_t futrts_ctzz8(int8_t x) {-  return x == 0 ? 8 : __builtin_ctz((uint32_t)x);-}--static int32_t futrts_ctzz16(int16_t x) {-  return x == 0 ? 16 : __builtin_ctz((uint32_t)x);-}--static int32_t futrts_ctzz32(int32_t x) {-  return x == 0 ? 32 : __builtin_ctz((uint32_t)x);-}--static int32_t futrts_ctzz64(int64_t x) {-  return x == 0 ? 64 : __builtin_ctzll((uint64_t)x);-}-#endif--static inline float fdiv32(float x, float y) {-  return x / y;-}--static inline float fadd32(float x, float y) {-  return x + y;-}--static inline float fsub32(float x, float y) {-  return x - y;-}--static inline float fmul32(float x, float y) {-  return x * y;-}--static inline bool cmplt32(float x, float y) {-  return x < y;-}--static inline bool cmple32(float x, float y) {-  return x <= y;-}--static inline float sitofp_i8_f32(int8_t x) {-  return (float) x;-}--static inline float sitofp_i16_f32(int16_t x) {-  return (float) x;-}--static inline float sitofp_i32_f32(int32_t x) {-  return (float) x;-}--static inline float sitofp_i64_f32(int64_t x) {-  return (float) x;-}--static inline float uitofp_i8_f32(uint8_t x) {-  return (float) x;-}--static inline float uitofp_i16_f32(uint16_t x) {-  return (float) x;-}--static inline float uitofp_i32_f32(uint32_t x) {-  return (float) x;-}--static inline float uitofp_i64_f32(uint64_t x) {-  return (float) x;-}--#ifdef __OPENCL_VERSION__-static inline float fabs32(float x) {-  return fabs(x);-}--static inline float fmax32(float x, float y) {-  return fmax(x, y);-}--static inline float fmin32(float x, float y) {-  return fmin(x, y);-}--static inline float fpow32(float x, float y) {-  return pow(x, y);-}--#else // Not OpenCL, but CUDA or plain C.--static inline float fabs32(float x) {-  return fabsf(x);-}--static inline float fmax32(float x, float y) {-  return fmaxf(x, y);-}--static inline float fmin32(float x, float y) {-  return fminf(x, y);-}--static inline float fpow32(float x, float y) {-  return powf(x, y);-}-#endif--static inline bool futrts_isnan32(float x) {-  return isnan(x);-}--static inline bool futrts_isinf32(float x) {-  return isinf(x);-}--static inline int8_t fptosi_f32_i8(float x) {-  if (futrts_isnan32(x) || futrts_isinf32(x)) {-    return 0;-  } else {-    return (int8_t) x;-  }-}--static inline int16_t fptosi_f32_i16(float x) {-  if (futrts_isnan32(x) || futrts_isinf32(x)) {-    return 0;-  } else {-    return (int16_t) x;-  }-}--static inline int32_t fptosi_f32_i32(float x) {-  if (futrts_isnan32(x) || futrts_isinf32(x)) {-    return 0;-  } else {-    return (int32_t) x;-  }-}--static inline int64_t fptosi_f32_i64(float x) {-  if (futrts_isnan32(x) || futrts_isinf32(x)) {-    return 0;-  } else {-    return (int64_t) x;-  };-}--static inline uint8_t fptoui_f32_i8(float x) {-  if (futrts_isnan32(x) || futrts_isinf32(x)) {-    return 0;-  } else {-    return (uint8_t) (int8_t) x;-  }-}--static inline uint16_t fptoui_f32_i16(float x) {-  if (futrts_isnan32(x) || futrts_isinf32(x)) {-    return 0;-  } else {-    return (uint16_t) (int16_t) x;-  }-}--static inline uint32_t fptoui_f32_i32(float x) {-  if (futrts_isnan32(x) || futrts_isinf32(x)) {-    return 0;-  } else {-    return (uint32_t) (int32_t) x;-  }-}--static inline uint64_t fptoui_f32_i64(float x) {-  if (futrts_isnan32(x) || futrts_isinf32(x)) {-    return 0;-  } else {-    return (uint64_t) (int64_t) x;-  }-}--static inline bool ftob_f32_bool(float x) {-  return x != 0;-}--static inline float btof_bool_f32(bool x) {-  return x ? 1 : 0;-}--#ifdef __OPENCL_VERSION__-static inline float futrts_log32(float x) {-  return log(x);-}--static inline float futrts_log2_32(float x) {-  return log2(x);-}--static inline float futrts_log10_32(float x) {-  return log10(x);-}--static inline float futrts_sqrt32(float x) {-  return sqrt(x);-}--static inline float futrts_cbrt32(float x) {-  return cbrt(x);-}--static inline float futrts_exp32(float x) {-  return exp(x);-}--static inline float futrts_cos32(float x) {-  return cos(x);-}--static inline float futrts_sin32(float x) {-  return sin(x);-}--static inline float futrts_tan32(float x) {-  return tan(x);-}--static inline float futrts_acos32(float x) {-  return acos(x);-}--static inline float futrts_asin32(float x) {-  return asin(x);-}--static inline float futrts_atan32(float x) {-  return atan(x);-}--static inline float futrts_cosh32(float x) {-  return cosh(x);-}--static inline float futrts_sinh32(float x) {-  return sinh(x);-}--static inline float futrts_tanh32(float x) {-  return tanh(x);-}--static inline float futrts_acosh32(float x) {-  return acosh(x);-}--static inline float futrts_asinh32(float x) {-  return asinh(x);-}--static inline float futrts_atanh32(float x) {-  return atanh(x);-}--static inline float futrts_atan2_32(float x, float y) {-  return atan2(x, y);-}--static inline float futrts_hypot32(float x, float y) {-  return hypot(x, y);-}--static inline float futrts_gamma32(float x) {-  return tgamma(x);-}--static inline float futrts_lgamma32(float x) {-  return lgamma(x);-}--static inline float futrts_erf32(float x) {-  return erf(x);-}--static inline float futrts_erfc32(float x) {-  return erfc(x);-}--static inline float fmod32(float x, float y) {-  return fmod(x, y);-}--static inline float futrts_round32(float x) {-  return rint(x);-}--static inline float futrts_floor32(float x) {-  return floor(x);-}--static inline float futrts_ceil32(float x) {-  return ceil(x);-}--static inline float futrts_lerp32(float v0, float v1, float t) {-  return mix(v0, v1, t);-}--static inline float futrts_mad32(float a, float b, float c) {-  return mad(a, b, c);-}--static inline float futrts_fma32(float a, float b, float c) {-  return fma(a, b, c);-}--#else // Not OpenCL, but CUDA or plain C.--static inline float futrts_log32(float x) {-  return logf(x);-}--static inline float futrts_log2_32(float x) {-  return log2f(x);-}--static inline float futrts_log10_32(float x) {-  return log10f(x);-}--static inline float futrts_sqrt32(float x) {-  return sqrtf(x);-}--static inline float futrts_cbrt32(float x) {-  return cbrtf(x);-}--static inline float futrts_exp32(float x) {-  return expf(x);-}--static inline float futrts_cos32(float x) {-  return cosf(x);-}--static inline float futrts_sin32(float x) {-  return sinf(x);-}--static inline float futrts_tan32(float x) {-  return tanf(x);-}--static inline float futrts_acos32(float x) {-  return acosf(x);-}--static inline float futrts_asin32(float x) {-  return asinf(x);-}--static inline float futrts_atan32(float x) {-  return atanf(x);-}--static inline float futrts_cosh32(float x) {-  return coshf(x);-}--static inline float futrts_sinh32(float x) {-  return sinhf(x);-}--static inline float futrts_tanh32(float x) {-  return tanhf(x);-}--static inline float futrts_acosh32(float x) {-  return acoshf(x);-}--static inline float futrts_asinh32(float x) {-  return asinhf(x);-}--static inline float futrts_atanh32(float x) {-  return atanhf(x);-}--static inline float futrts_atan2_32(float x, float y) {-  return atan2f(x, y);-}--static inline float futrts_hypot32(float x, float y) {-  return hypotf(x, y);-}--static inline float futrts_gamma32(float x) {-  return tgammaf(x);-}--static inline float futrts_lgamma32(float x) {-  return lgammaf(x);-}--static inline float futrts_erf32(float x) {-  return erff(x);-}--static inline float futrts_erfc32(float x) {-  return erfcf(x);-}--static inline float fmod32(float x, float y) {-  return fmodf(x, y);-}--static inline float futrts_round32(float x) {-  return rintf(x);-}--static inline float futrts_floor32(float x) {-  return floorf(x);-}--static inline float futrts_ceil32(float x) {-  return ceilf(x);-}--static inline float futrts_lerp32(float v0, float v1, float t) {-  return v0 + (v1 - v0) * t;-}--static inline float futrts_mad32(float a, float b, float c) {-  return a * b + c;-}--static inline float futrts_fma32(float a, float b, float c) {-  return fmaf(a, b, c);-}-#endif--static inline int32_t futrts_to_bits32(float x) {-  union {-    float f;-    int32_t t;-  } p;--  p.f = x;-  return p.t;-}--static inline float futrts_from_bits32(int32_t x) {-  union {-    int32_t f;-    float t;-  } p;--  p.f = x;-  return p.t;-}--static inline float fsignum32(float x) {-  return futrts_isnan32(x) ? x : (x > 0) - (x < 0);-}--#ifdef FUTHARK_F64_ENABLED--static inline double fdiv64(double x, double y) {-  return x / y;-}--static inline double fadd64(double x, double y) {-  return x + y;-}--static inline double fsub64(double x, double y) {-  return x - y;-}--static inline double fmul64(double x, double y) {-  return x * y;-}--static inline bool cmplt64(double x, double y) {-  return x < y;-}--static inline bool cmple64(double x, double y) {-  return x <= y;-}--static inline double sitofp_i8_f64(int8_t x) {-  return (double) x;-}--static inline double sitofp_i16_f64(int16_t x) {-  return (double) x;-}--static inline double sitofp_i32_f64(int32_t x) {-  return (double) x;-}--static inline double sitofp_i64_f64(int64_t x) {-  return (double) x;-}--static inline double uitofp_i8_f64(uint8_t x) {-  return (double) x;-}--static inline double uitofp_i16_f64(uint16_t x) {-  return (double) x;-}--static inline double uitofp_i32_f64(uint32_t x) {-  return (double) x;-}--static inline double uitofp_i64_f64(uint64_t x) {-  return (double) x;-}--static inline double fabs64(double x) {-  return fabs(x);-}--static inline double fmax64(double x, double y) {-  return fmax(x, y);-}--static inline double fmin64(double x, double y) {-  return fmin(x, y);-}--static inline double fpow64(double x, double y) {-  return pow(x, y);-}--static inline double futrts_log64(double x) {-  return log(x);-}--static inline double futrts_log2_64(double x) {-  return log2(x);-}--static inline double futrts_log10_64(double x) {-  return log10(x);-}--static inline double futrts_sqrt64(double x) {-  return sqrt(x);-}--static inline double futrts_cbrt64(double x) {-  return cbrt(x);-}--static inline double futrts_exp64(double x) {-  return exp(x);-}--static inline double futrts_cos64(double x) {-  return cos(x);-}--static inline double futrts_sin64(double x) {-  return sin(x);-}--static inline double futrts_tan64(double x) {-  return tan(x);-}--static inline double futrts_acos64(double x) {-  return acos(x);-}--static inline double futrts_asin64(double x) {-  return asin(x);-}--static inline double futrts_atan64(double x) {-  return atan(x);-}--static inline double futrts_cosh64(double x) {-  return cosh(x);-}--static inline double futrts_sinh64(double x) {-  return sinh(x);-}--static inline double futrts_tanh64(double x) {-  return tanh(x);-}--static inline double futrts_acosh64(double x) {-  return acosh(x);-}--static inline double futrts_asinh64(double x) {-  return asinh(x);-}--static inline double futrts_atanh64(double x) {-  return atanh(x);-}--static inline double futrts_atan2_64(double x, double y) {-  return atan2(x, y);-}--static inline double futrts_hypot64(double x, double y) {-  return hypot(x, y);-}--static inline double futrts_gamma64(double x) {-  return tgamma(x);-}--static inline double futrts_lgamma64(double x) {-  return lgamma(x);-}--static inline double futrts_erf64(double x) {-  return erf(x);-}--static inline double futrts_erfc64(double x) {-  return erfc(x);-}--static inline double futrts_fma64(double a, double b, double c) {-  return fma(a, b, c);-}--static inline double futrts_round64(double x) {-  return rint(x);-}--static inline double futrts_ceil64(double x) {-  return ceil(x);-}--static inline double futrts_floor64(double x) {-  return floor(x);-}--static inline bool futrts_isnan64(double x) {-  return isnan(x);-}--static inline bool futrts_isinf64(double x) {-  return isinf(x);-}--static inline int8_t fptosi_f64_i8(double x) {-  if (futrts_isnan64(x) || futrts_isinf64(x)) {-    return 0;-  } else {-    return (int8_t) x;-  }-}--static inline int16_t fptosi_f64_i16(double x) {-  if (futrts_isnan64(x) || futrts_isinf64(x)) {-    return 0;-  } else {-    return (int16_t) x;-  }-}--static inline int32_t fptosi_f64_i32(double x) {-  if (futrts_isnan64(x) || futrts_isinf64(x)) {-    return 0;-  } else {-    return (int32_t) x;-  }-}--static inline int64_t fptosi_f64_i64(double x) {-  if (futrts_isnan64(x) || futrts_isinf64(x)) {-    return 0;-  } else {-    return (int64_t) x;-  }-}--static inline uint8_t fptoui_f64_i8(double x) {-  if (futrts_isnan64(x) || futrts_isinf64(x)) {-    return 0;-  } else {-    return (uint8_t) (int8_t) x;-  }-}--static inline uint16_t fptoui_f64_i16(double x) {-  if (futrts_isnan64(x) || futrts_isinf64(x)) {-    return 0;-  } else {-    return (uint16_t) (int16_t) x;-  }-}--static inline uint32_t fptoui_f64_i32(double x) {-  if (futrts_isnan64(x) || futrts_isinf64(x)) {-    return 0;-  } else {-    return (uint32_t) (int32_t) x;-  }-}--static inline uint64_t fptoui_f64_i64(double x) {-  if (futrts_isnan64(x) || futrts_isinf64(x)) {-    return 0;-  } else {-    return (uint64_t) (int64_t) x;-  }-}--static inline bool ftob_f64_bool(double x) {-  return x != 0;-}--static inline double btof_bool_f64(bool x) {-  return x ? 1 : 0;-}--static inline int64_t futrts_to_bits64(double x) {-  union {-    double f;-    int64_t t;-  } p;--  p.f = x;-  return p.t;-}--static inline double futrts_from_bits64(int64_t x) {-  union {-    int64_t f;-    double t;-  } p;--  p.f = x;-  return p.t;-}--static inline double fmod64(double x, double y) {-  return fmod(x, y);-}--static inline double fsignum64(double x) {-  return futrts_isnan64(x) ? x : (x > 0) - (x < 0);-}--static inline double futrts_lerp64(double v0, double v1, double t) {-#ifdef __OPENCL_VERSION__-  return mix(v0, v1, t);-#else-  return v0 + (v1 - v0) * t;-#endif-}--static inline double futrts_mad64(double a, double b, double c) {-#ifdef __OPENCL_VERSION__-  return mad(a, b, c);-#else-  return a * b + c;-#endif-}--static inline float fpconv_f32_f32(float x) {-  return (float) x;-}--static inline double fpconv_f32_f64(float x) {-  return (double) x;-}--static inline float fpconv_f64_f32(double x) {-  return (float) x;-}--static inline double fpconv_f64_f64(double x) {-  return (double) x;-}+#if ISPC++static inline uint8_t udiv8(uint8_t x, uint8_t y) {+  // This strange pattern is used to prevent the ISPC compiler from+  // causing SIGFPEs and bogus results on divisions where inactive lanes+  // have 0-valued divisors. It ensures that any inactive lane instead+  // has a divisor of 1. https://github.com/ispc/ispc/issues/2292+  uint8_t ys = 1;+  foreach_active(i){+    ys = y;+  }++  return x / ys;+}++static inline uint16_t udiv16(uint16_t x, uint16_t y) {+  uint16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x / ys;+}++static inline uint32_t udiv32(uint32_t x, uint32_t y) {+  uint32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  ++  return x / ys;+}++static inline uint64_t udiv64(uint64_t x, uint64_t y) {+  uint64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  ++  return x / ys;+}++static inline uint8_t udiv_up8(uint8_t x, uint8_t y) {+  uint8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  ++  return (x + y - 1) / ys;+}++static inline uint16_t udiv_up16(uint16_t x, uint16_t y) {+  uint16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return (x + y - 1) / ys;+}++static inline uint32_t udiv_up32(uint32_t x, uint32_t y) {+  uint32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return (x + y - 1) / ys;+}++static inline uint64_t udiv_up64(uint64_t x, uint64_t y) {+  uint64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return (x + y - 1) / ys;+}++static inline uint8_t umod8(uint8_t x, uint8_t y) {+  uint8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x % ys;+}++static inline uint16_t umod16(uint16_t x, uint16_t y) {+  uint16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  ++  return x % ys;+}++static inline uint32_t umod32(uint32_t x, uint32_t y) {+  uint32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x % ys;+}++static inline uint64_t umod64(uint64_t x, uint64_t y) {+  uint64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x % ys;+}++static inline uint8_t udiv_safe8(uint8_t x, uint8_t y) {+  uint8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x / ys;+}++static inline uint16_t udiv_safe16(uint16_t x, uint16_t y) {+  uint16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x / ys;+}++static inline uint32_t udiv_safe32(uint32_t x, uint32_t y) {+  uint32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x / ys;+}++static inline uint64_t udiv_safe64(uint64_t x, uint64_t y) {+  uint64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x / ys;+}++static inline uint8_t udiv_up_safe8(uint8_t x, uint8_t y) {+  uint8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : (x + y - 1) / ys;+}++static inline uint16_t udiv_up_safe16(uint16_t x, uint16_t y) {+  uint16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : (x + y - 1) / ys;+}++static inline uint32_t udiv_up_safe32(uint32_t x, uint32_t y) {+  uint32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : (x + y - 1) / ys;+}++static inline uint64_t udiv_up_safe64(uint64_t x, uint64_t y) {+  uint64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : (x + y - 1) / ys;+}++static inline uint8_t umod_safe8(uint8_t x, uint8_t y) {+  uint8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x % ys;+}++static inline uint16_t umod_safe16(uint16_t x, uint16_t y) {+  uint16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x % ys;+}++static inline uint32_t umod_safe32(uint32_t x, uint32_t y) {+  uint32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x % ys;+}++static inline uint64_t umod_safe64(uint64_t x, uint64_t y) {+  uint64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x % ys;+}++static inline int8_t sdiv8(int8_t x, int8_t y) {+  int8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  int8_t q = x / ys;+  int8_t r = x % ys;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline int16_t sdiv16(int16_t x, int16_t y) {+  int16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  int16_t q = x / ys;+  int16_t r = x % ys;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline int32_t sdiv32(int32_t x, int32_t y) {+  int32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  int32_t q = x / ys;+  int32_t r = x % ys;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline int64_t sdiv64(int64_t x, int64_t y) {+  int64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  int64_t q = x / ys;+  int64_t r = x % ys;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline int8_t sdiv_up8(int8_t x, int8_t y) {+  return sdiv8(x + y - 1, y);+}++static inline int16_t sdiv_up16(int16_t x, int16_t y) {+  return sdiv16(x + y - 1, y);+}++static inline int32_t sdiv_up32(int32_t x, int32_t y) {+  return sdiv32(x + y - 1, y);+}++static inline int64_t sdiv_up64(int64_t x, int64_t y) {+  return sdiv64(x + y - 1, y);+}++static inline int8_t smod8(int8_t x, int8_t y) {+  int8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  int8_t r = x % ys;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline int16_t smod16(int16_t x, int16_t y) {+  int16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  int16_t r = x % ys;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline int32_t smod32(int32_t x, int32_t y) {+  int32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  int32_t r = x % ys;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline int64_t smod64(int64_t x, int64_t y) {+  int64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  int64_t r = x % ys;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline int8_t sdiv_safe8(int8_t x, int8_t y) {+  return y == 0 ? 0 : sdiv8(x, y);+}++static inline int16_t sdiv_safe16(int16_t x, int16_t y) {+  return y == 0 ? 0 : sdiv16(x, y);+}++static inline int32_t sdiv_safe32(int32_t x, int32_t y) {+  return y == 0 ? 0 : sdiv32(x, y);+}++static inline int64_t sdiv_safe64(int64_t x, int64_t y) {+  return y == 0 ? 0 : sdiv64(x, y);+}++static inline int8_t sdiv_up_safe8(int8_t x, int8_t y) {+  return sdiv_safe8(x + y - 1, y);+}++static inline int16_t sdiv_up_safe16(int16_t x, int16_t y) {+  return sdiv_safe16(x + y - 1, y);+}++static inline int32_t sdiv_up_safe32(int32_t x, int32_t y) {+  return sdiv_safe32(x + y - 1, y);+}++static inline int64_t sdiv_up_safe64(int64_t x, int64_t y) {+  return sdiv_safe64(x + y - 1, y);+}++static inline int8_t smod_safe8(int8_t x, int8_t y) {+  return y == 0 ? 0 : smod8(x, y);+}++static inline int16_t smod_safe16(int16_t x, int16_t y) {+  return y == 0 ? 0 : smod16(x, y);+}++static inline int32_t smod_safe32(int32_t x, int32_t y) {+  return y == 0 ? 0 : smod32(x, y);+}++static inline int64_t smod_safe64(int64_t x, int64_t y) {+  return y == 0 ? 0 : smod64(x, y);+}++static inline int8_t squot8(int8_t x, int8_t y) {+  int8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x / ys;+}++static inline int16_t squot16(int16_t x, int16_t y) {+  int16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x / ys;+}++static inline int32_t squot32(int32_t x, int32_t y) {+  int32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x / ys;+}++static inline int64_t squot64(int64_t x, int64_t y) {+  int64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x / ys;+}++static inline int8_t srem8(int8_t x, int8_t y) {+  int8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x % ys;+}++static inline int16_t srem16(int16_t x, int16_t y) {+  int16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x % ys;+}++static inline int32_t srem32(int32_t x, int32_t y) {+  int32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x % ys;+}++static inline int64_t srem64(int64_t x, int64_t y) {+  int8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return x % ys;+}++static inline int8_t squot_safe8(int8_t x, int8_t y) {+  int8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x / ys;+}++static inline int16_t squot_safe16(int16_t x, int16_t y) {+  int16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x / ys;+}++static inline int32_t squot_safe32(int32_t x, int32_t y) {+  int32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x / ys;+}++static inline int64_t squot_safe64(int64_t x, int64_t y) {+  int64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x / ys;+}++static inline int8_t srem_safe8(int8_t x, int8_t y) {+  int8_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x % ys;+}++static inline int16_t srem_safe16(int16_t x, int16_t y) {+  int16_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x % ys;+}++static inline int32_t srem_safe32(int32_t x, int32_t y) {+  int32_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x % ys;+}++static inline int64_t srem_safe64(int64_t x, int64_t y) {+  int64_t ys = 1;+  foreach_active(i){+    ys = y;+  }+  +  return y == 0 ? 0 : x % ys;+}++#else++static inline uint8_t udiv8(uint8_t x, uint8_t y) {+  return x / y;+}++static inline uint16_t udiv16(uint16_t x, uint16_t y) {+  return x / y;+}++static inline uint32_t udiv32(uint32_t x, uint32_t y) {+  return x / y;+}++static inline uint64_t udiv64(uint64_t x, uint64_t y) {+  return x / y;+}++static inline uint8_t udiv_up8(uint8_t x, uint8_t y) {+  return (x + y - 1) / y;+}++static inline uint16_t udiv_up16(uint16_t x, uint16_t y) {+  return (x + y - 1) / y;+}++static inline uint32_t udiv_up32(uint32_t x, uint32_t y) {+  return (x + y - 1) / y;+}++static inline uint64_t udiv_up64(uint64_t x, uint64_t y) {+  return (x + y - 1) / y;+}++static inline uint8_t umod8(uint8_t x, uint8_t y) {+  return x % y;+}++static inline uint16_t umod16(uint16_t x, uint16_t y) {+  return x % y;+}++static inline uint32_t umod32(uint32_t x, uint32_t y) {+  return x % y;+}++static inline uint64_t umod64(uint64_t x, uint64_t y) {+  return x % y;+}++static inline uint8_t udiv_safe8(uint8_t x, uint8_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uint16_t udiv_safe16(uint16_t x, uint16_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uint32_t udiv_safe32(uint32_t x, uint32_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uint64_t udiv_safe64(uint64_t x, uint64_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uint8_t udiv_up_safe8(uint8_t x, uint8_t y) {+  return y == 0 ? 0 : (x + y - 1) / y;+}++static inline uint16_t udiv_up_safe16(uint16_t x, uint16_t y) {+  return y == 0 ? 0 : (x + y - 1) / y;+}++static inline uint32_t udiv_up_safe32(uint32_t x, uint32_t y) {+  return y == 0 ? 0 : (x + y - 1) / y;+}++static inline uint64_t udiv_up_safe64(uint64_t x, uint64_t y) {+  return y == 0 ? 0 : (x + y - 1) / y;+}++static inline uint8_t umod_safe8(uint8_t x, uint8_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uint16_t umod_safe16(uint16_t x, uint16_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uint32_t umod_safe32(uint32_t x, uint32_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uint64_t umod_safe64(uint64_t x, uint64_t y) {+  return y == 0 ? 0 : x % y;+}++static inline int8_t sdiv8(int8_t x, int8_t y) {+  int8_t q = x / y;+  int8_t r = x % y;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline int16_t sdiv16(int16_t x, int16_t y) {+  int16_t q = x / y;+  int16_t r = x % y;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline int32_t sdiv32(int32_t x, int32_t y) {+  int32_t q = x / y;+  int32_t r = x % y;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline int64_t sdiv64(int64_t x, int64_t y) {+  int64_t q = x / y;+  int64_t r = x % y;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline int8_t sdiv_up8(int8_t x, int8_t y) {+  return sdiv8(x + y - 1, y);+}++static inline int16_t sdiv_up16(int16_t x, int16_t y) {+  return sdiv16(x + y - 1, y);+}++static inline int32_t sdiv_up32(int32_t x, int32_t y) {+  return sdiv32(x + y - 1, y);+}++static inline int64_t sdiv_up64(int64_t x, int64_t y) {+  return sdiv64(x + y - 1, y);+}++static inline int8_t smod8(int8_t x, int8_t y) {+  int8_t r = x % y;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline int16_t smod16(int16_t x, int16_t y) {+  int16_t r = x % y;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline int32_t smod32(int32_t x, int32_t y) {+  int32_t r = x % y;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline int64_t smod64(int64_t x, int64_t y) {+  int64_t r = x % y;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline int8_t sdiv_safe8(int8_t x, int8_t y) {+  return y == 0 ? 0 : sdiv8(x, y);+}++static inline int16_t sdiv_safe16(int16_t x, int16_t y) {+  return y == 0 ? 0 : sdiv16(x, y);+}++static inline int32_t sdiv_safe32(int32_t x, int32_t y) {+  return y == 0 ? 0 : sdiv32(x, y);+}++static inline int64_t sdiv_safe64(int64_t x, int64_t y) {+  return y == 0 ? 0 : sdiv64(x, y);+}++static inline int8_t sdiv_up_safe8(int8_t x, int8_t y) {+  return sdiv_safe8(x + y - 1, y);+}++static inline int16_t sdiv_up_safe16(int16_t x, int16_t y) {+  return sdiv_safe16(x + y - 1, y);+}++static inline int32_t sdiv_up_safe32(int32_t x, int32_t y) {+  return sdiv_safe32(x + y - 1, y);+}++static inline int64_t sdiv_up_safe64(int64_t x, int64_t y) {+  return sdiv_safe64(x + y - 1, y);+}++static inline int8_t smod_safe8(int8_t x, int8_t y) {+  return y == 0 ? 0 : smod8(x, y);+}++static inline int16_t smod_safe16(int16_t x, int16_t y) {+  return y == 0 ? 0 : smod16(x, y);+}++static inline int32_t smod_safe32(int32_t x, int32_t y) {+  return y == 0 ? 0 : smod32(x, y);+}++static inline int64_t smod_safe64(int64_t x, int64_t y) {+  return y == 0 ? 0 : smod64(x, y);+}++static inline int8_t squot8(int8_t x, int8_t y) {+  return x / y;+}++static inline int16_t squot16(int16_t x, int16_t y) {+  return x / y;+}++static inline int32_t squot32(int32_t x, int32_t y) {+  return x / y;+}++static inline int64_t squot64(int64_t x, int64_t y) {+  return x / y;+}++static inline int8_t srem8(int8_t x, int8_t y) {+  return x % y;+}++static inline int16_t srem16(int16_t x, int16_t y) {+  return x % y;+}++static inline int32_t srem32(int32_t x, int32_t y) {+  return x % y;+}++static inline int64_t srem64(int64_t x, int64_t y) {+  return x % y;+}++static inline int8_t squot_safe8(int8_t x, int8_t y) {+  return y == 0 ? 0 : x / y;+}++static inline int16_t squot_safe16(int16_t x, int16_t y) {+  return y == 0 ? 0 : x / y;+}++static inline int32_t squot_safe32(int32_t x, int32_t y) {+  return y == 0 ? 0 : x / y;+}++static inline int64_t squot_safe64(int64_t x, int64_t y) {+  return y == 0 ? 0 : x / y;+}++static inline int8_t srem_safe8(int8_t x, int8_t y) {+  return y == 0 ? 0 : x % y;+}++static inline int16_t srem_safe16(int16_t x, int16_t y) {+  return y == 0 ? 0 : x % y;+}++static inline int32_t srem_safe32(int32_t x, int32_t y) {+  return y == 0 ? 0 : x % y;+}++static inline int64_t srem_safe64(int64_t x, int64_t y) {+  return y == 0 ? 0 : x % y;+}++#endif++static inline int8_t smin8(int8_t x, int8_t y) {+  return x < y ? x : y;+}++static inline int16_t smin16(int16_t x, int16_t y) {+  return x < y ? x : y;+}++static inline int32_t smin32(int32_t x, int32_t y) {+  return x < y ? x : y;+}++static inline int64_t smin64(int64_t x, int64_t y) {+  return x < y ? x : y;+}++static inline uint8_t umin8(uint8_t x, uint8_t y) {+  return x < y ? x : y;+}++static inline uint16_t umin16(uint16_t x, uint16_t y) {+  return x < y ? x : y;+}++static inline uint32_t umin32(uint32_t x, uint32_t y) {+  return x < y ? x : y;+}++static inline uint64_t umin64(uint64_t x, uint64_t y) {+  return x < y ? x : y;+}++static inline int8_t smax8(int8_t x, int8_t y) {+  return x < y ? y : x;+}++static inline int16_t smax16(int16_t x, int16_t y) {+  return x < y ? y : x;+}++static inline int32_t smax32(int32_t x, int32_t y) {+  return x < y ? y : x;+}++static inline int64_t smax64(int64_t x, int64_t y) {+  return x < y ? y : x;+}++static inline uint8_t umax8(uint8_t x, uint8_t y) {+  return x < y ? y : x;+}++static inline uint16_t umax16(uint16_t x, uint16_t y) {+  return x < y ? y : x;+}++static inline uint32_t umax32(uint32_t x, uint32_t y) {+  return x < y ? y : x;+}++static inline uint64_t umax64(uint64_t x, uint64_t y) {+  return x < y ? y : x;+}++static inline uint8_t shl8(uint8_t x, uint8_t y) {+  return (uint8_t)(x << y);+}++static inline uint16_t shl16(uint16_t x, uint16_t y) {+  return (uint16_t)(x << y);+}++static inline uint32_t shl32(uint32_t x, uint32_t y) {+  return x << y;+}++static inline uint64_t shl64(uint64_t x, uint64_t y) {+  return x << y;+}++static inline uint8_t lshr8(uint8_t x, uint8_t y) {+  return x >> y;+}++static inline uint16_t lshr16(uint16_t x, uint16_t y) {+  return x >> y;+}++static inline uint32_t lshr32(uint32_t x, uint32_t y) {+  return x >> y;+}++static inline uint64_t lshr64(uint64_t x, uint64_t y) {+  return x >> y;+}++static inline int8_t ashr8(int8_t x, int8_t y) {+  return x >> y;+}++static inline int16_t ashr16(int16_t x, int16_t y) {+  return x >> y;+}++static inline int32_t ashr32(int32_t x, int32_t y) {+  return x >> y;+}++static inline int64_t ashr64(int64_t x, int64_t y) {+  return x >> y;+}++static inline uint8_t and8(uint8_t x, uint8_t y) {+  return x & y;+}++static inline uint16_t and16(uint16_t x, uint16_t y) {+  return x & y;+}++static inline uint32_t and32(uint32_t x, uint32_t y) {+  return x & y;+}++static inline uint64_t and64(uint64_t x, uint64_t y) {+  return x & y;+}++static inline uint8_t or8(uint8_t x, uint8_t y) {+  return x | y;+}++static inline uint16_t or16(uint16_t x, uint16_t y) {+  return x | y;+}++static inline uint32_t or32(uint32_t x, uint32_t y) {+  return x | y;+}++static inline uint64_t or64(uint64_t x, uint64_t y) {+  return x | y;+}++static inline uint8_t xor8(uint8_t x, uint8_t y) {+  return x ^ y;+}++static inline uint16_t xor16(uint16_t x, uint16_t y) {+  return x ^ y;+}++static inline uint32_t xor32(uint32_t x, uint32_t y) {+  return x ^ y;+}++static inline uint64_t xor64(uint64_t x, uint64_t y) {+  return x ^ y;+}++static inline bool ult8(uint8_t x, uint8_t y) {+  return x < y;+}++static inline bool ult16(uint16_t x, uint16_t y) {+  return x < y;+}++static inline bool ult32(uint32_t x, uint32_t y) {+  return x < y;+}++static inline bool ult64(uint64_t x, uint64_t y) {+  return x < y;+}++static inline bool ule8(uint8_t x, uint8_t y) {+  return x <= y;+}++static inline bool ule16(uint16_t x, uint16_t y) {+  return x <= y;+}++static inline bool ule32(uint32_t x, uint32_t y) {+  return x <= y;+}++static inline bool ule64(uint64_t x, uint64_t y) {+  return x <= y;+}++static inline bool slt8(int8_t x, int8_t y) {+  return x < y;+}++static inline bool slt16(int16_t x, int16_t y) {+  return x < y;+}++static inline bool slt32(int32_t x, int32_t y) {+  return x < y;+}++static inline bool slt64(int64_t x, int64_t y) {+  return x < y;+}++static inline bool sle8(int8_t x, int8_t y) {+  return x <= y;+}++static inline bool sle16(int16_t x, int16_t y) {+  return x <= y;+}++static inline bool sle32(int32_t x, int32_t y) {+  return x <= y;+}++static inline bool sle64(int64_t x, int64_t y) {+  return x <= y;+}++static inline uint8_t pow8(uint8_t x, uint8_t y) {+  uint8_t res = 1, rem = y;++  while (rem != 0) {+    if (rem & 1)+      res *= x;+    rem >>= 1;+    x *= x;+  }+  return res;+}++static inline uint16_t pow16(uint16_t x, uint16_t y) {+  uint16_t res = 1, rem = y;++  while (rem != 0) {+    if (rem & 1)+      res *= x;+    rem >>= 1;+    x *= x;+  }+  return res;+}++static inline uint32_t pow32(uint32_t x, uint32_t y) {+  uint32_t res = 1, rem = y;++  while (rem != 0) {+    if (rem & 1)+      res *= x;+    rem >>= 1;+    x *= x;+  }+  return res;+}++static inline uint64_t pow64(uint64_t x, uint64_t y) {+  uint64_t res = 1, rem = y;++  while (rem != 0) {+    if (rem & 1)+      res *= x;+    rem >>= 1;+    x *= x;+  }+  return res;+}++static inline bool itob_i8_bool(int8_t x) {+  return x != 0;+}++static inline bool itob_i16_bool(int16_t x) {+  return x != 0;+}++static inline bool itob_i32_bool(int32_t x) {+  return x != 0;+}++static inline bool itob_i64_bool(int64_t x) {+  return x != 0;+}++static inline int8_t btoi_bool_i8(bool x) {+  return x;+}++static inline int16_t btoi_bool_i16(bool x) {+  return x;+}++static inline int32_t btoi_bool_i32(bool x) {+  return x;+}++static inline int64_t btoi_bool_i64(bool x) {+  return x;+}++#define sext_i8_i8(x) ((int8_t) (int8_t) (x))+#define sext_i8_i16(x) ((int16_t) (int8_t) (x))+#define sext_i8_i32(x) ((int32_t) (int8_t) (x))+#define sext_i8_i64(x) ((int64_t) (int8_t) (x))+#define sext_i16_i8(x) ((int8_t) (int16_t) (x))+#define sext_i16_i16(x) ((int16_t) (int16_t) (x))+#define sext_i16_i32(x) ((int32_t) (int16_t) (x))+#define sext_i16_i64(x) ((int64_t) (int16_t) (x))+#define sext_i32_i8(x) ((int8_t) (int32_t) (x))+#define sext_i32_i16(x) ((int16_t) (int32_t) (x))+#define sext_i32_i32(x) ((int32_t) (int32_t) (x))+#define sext_i32_i64(x) ((int64_t) (int32_t) (x))+#define sext_i64_i8(x) ((int8_t) (int64_t) (x))+#define sext_i64_i16(x) ((int16_t) (int64_t) (x))+#define sext_i64_i32(x) ((int32_t) (int64_t) (x))+#define sext_i64_i64(x) ((int64_t) (int64_t) (x))+#define zext_i8_i8(x) ((int8_t) (uint8_t) (x))+#define zext_i8_i16(x) ((int16_t) (uint8_t) (x))+#define zext_i8_i32(x) ((int32_t) (uint8_t) (x))+#define zext_i8_i64(x) ((int64_t) (uint8_t) (x))+#define zext_i16_i8(x) ((int8_t) (uint16_t) (x))+#define zext_i16_i16(x) ((int16_t) (uint16_t) (x))+#define zext_i16_i32(x) ((int32_t) (uint16_t) (x))+#define zext_i16_i64(x) ((int64_t) (uint16_t) (x))+#define zext_i32_i8(x) ((int8_t) (uint32_t) (x))+#define zext_i32_i16(x) ((int16_t) (uint32_t) (x))+#define zext_i32_i32(x) ((int32_t) (uint32_t) (x))+#define zext_i32_i64(x) ((int64_t) (uint32_t) (x))+#define zext_i64_i8(x) ((int8_t) (uint64_t) (x))+#define zext_i64_i16(x) ((int16_t) (uint64_t) (x))+#define zext_i64_i32(x) ((int32_t) (uint64_t) (x))+#define zext_i64_i64(x) ((int64_t) (uint64_t) (x))++static int8_t abs8(int8_t x) {+  return (int8_t)abs(x);+}++static int16_t abs16(int16_t x) {+  return (int16_t)abs(x);+}++static int32_t abs32(int32_t x) {+  return abs(x);+}++static int64_t abs64(int64_t x) {+#if defined(__OPENCL_VERSION__) || defined(ISPC)+  return abs(x);+#else+  return llabs(x);+#endif+}++#if defined(__OPENCL_VERSION__)+static int32_t futrts_popc8(int8_t x) {+  return popcount(x);+}++static int32_t futrts_popc16(int16_t x) {+  return popcount(x);+}++static int32_t futrts_popc32(int32_t x) {+  return popcount(x);+}++static int32_t futrts_popc64(int64_t x) {+  return popcount(x);+}+#elif defined(__CUDA_ARCH__)++static int32_t futrts_popc8(int8_t x) {+  return __popc(zext_i8_i32(x));+}++static int32_t futrts_popc16(int16_t x) {+  return __popc(zext_i16_i32(x));+}++static int32_t futrts_popc32(int32_t x) {+  return __popc(x);+}++static int32_t futrts_popc64(int64_t x) {+  return __popcll(x);+}++#else // Not OpenCL or CUDA, but plain C.++static int32_t futrts_popc8(uint8_t x) {+  int c = 0;+  for (; x; ++c) { x &= x - 1; }+  return c;+}++static int32_t futrts_popc16(uint16_t x) {+  int c = 0;+  for (; x; ++c) { x &= x - 1; }+  return c;+}++static int32_t futrts_popc32(uint32_t x) {+  int c = 0;+  for (; x; ++c) { x &= x - 1; }+  return c;+}++static int32_t futrts_popc64(uint64_t x) {+  int c = 0;+  for (; x; ++c) { x &= x - 1; }+  return c;+}+#endif++#if defined(__OPENCL_VERSION__)+static uint8_t futrts_mul_hi8(uint8_t a, uint8_t b) {+  return mul_hi(a, b);+}++static uint16_t futrts_mul_hi16(uint16_t a, uint16_t b) {+  return mul_hi(a, b);+}++static uint32_t futrts_mul_hi32(uint32_t a, uint32_t b) {+  return mul_hi(a, b);+}++static uint64_t futrts_mul_hi64(uint64_t a, uint64_t b) {+  return mul_hi(a, b);+}++#elif defined(__CUDA_ARCH__)++static uint8_t futrts_mul_hi8(uint8_t a, uint8_t b) {+  uint16_t aa = a;+  uint16_t bb = b;++  return aa * bb >> 8;+}++static uint16_t futrts_mul_hi16(uint16_t a, uint16_t b) {+  uint32_t aa = a;+  uint32_t bb = b;++  return aa * bb >> 16;+}++static uint32_t futrts_mul_hi32(uint32_t a, uint32_t b) {+  return mulhi(a, b);+}++static uint64_t futrts_mul_hi64(uint64_t a, uint64_t b) {+  return mul64hi(a, b);+}++#elif ISPC++static uint8_t futrts_mul_hi8(uint8_t a, uint8_t b) {+  uint16_t aa = a;+  uint16_t bb = b;++  return aa * bb >> 8;+}++static uint16_t futrts_mul_hi16(uint16_t a, uint16_t b) {+  uint32_t aa = a;+  uint32_t bb = b;++  return aa * bb >> 16;+}++static uint32_t futrts_mul_hi32(uint32_t a, uint32_t b) {+  uint64_t aa = a;+  uint64_t bb = b;++  return aa * bb >> 32;+}++static uint64_t futrts_mul_hi64(uint64_t a, uint64_t b) {+  uint64_t ah = a >> 32;+  uint64_t al = a & 0xffffffff;+  uint64_t bh = b >> 32;+  uint64_t bl = b & 0xffffffff;++  uint64_t p1 = al * bl;+  uint64_t p2 = al * bh;+  uint64_t p3 = ah * bl;+  uint64_t p4 = ah * bh;++  uint64_t p1h = p1 >> 32;+  uint64_t p2h = p2 >> 32;+  uint64_t p3h = p3 >> 32;+  uint64_t p2l = p2 & 0xffffffff;+  uint64_t p3l = p3 & 0xffffffff;++  uint64_t l = p1h + p2l  + p3l;+  uint64_t m = (p2 >> 32) + (p3 >> 32);+  uint64_t h = (l >> 32) + m + p4;++  return h;+}++#else // Not OpenCL, ISPC, or CUDA, but plain C.++static uint8_t futrts_mul_hi8(uint8_t a, uint8_t b) {+  uint16_t aa = a;+  uint16_t bb = b;++  return aa * bb >> 8;+}++static uint16_t futrts_mul_hi16(uint16_t a, uint16_t b) {+  uint32_t aa = a;+  uint32_t bb = b;++  return aa * bb >> 16;+}++static uint32_t futrts_mul_hi32(uint32_t a, uint32_t b) {+  uint64_t aa = a;+  uint64_t bb = b;++  return aa * bb >> 32;+}++static uint64_t futrts_mul_hi64(uint64_t a, uint64_t b) {+  __uint128_t aa = a;+  __uint128_t bb = b;++  return aa * bb >> 64;+}+#endif++#if defined(__OPENCL_VERSION__)+static uint8_t futrts_mad_hi8(uint8_t a, uint8_t b, uint8_t c) {+  return mad_hi(a, b, c);+}++static uint16_t futrts_mad_hi16(uint16_t a, uint16_t b, uint16_t c) {+  return mad_hi(a, b, c);+}++static uint32_t futrts_mad_hi32(uint32_t a, uint32_t b, uint32_t c) {+  return mad_hi(a, b, c);+}++static uint64_t futrts_mad_hi64(uint64_t a, uint64_t b, uint64_t c) {+  return mad_hi(a, b, c);+}++#else // Not OpenCL++static uint8_t futrts_mad_hi8(uint8_t a, uint8_t b, uint8_t c) {+  return futrts_mul_hi8(a, b) + c;+}++static uint16_t futrts_mad_hi16(uint16_t a, uint16_t b, uint16_t c) {+  return futrts_mul_hi16(a, b) + c;+}++static uint32_t futrts_mad_hi32(uint32_t a, uint32_t b, uint32_t c) {+  return futrts_mul_hi32(a, b) + c;+}++static uint64_t futrts_mad_hi64(uint64_t a, uint64_t b, uint64_t c) {+  return futrts_mul_hi64(a, b) + c;+}+#endif++#if defined(__OPENCL_VERSION__)+static int32_t futrts_clzz8(int8_t x) {+  return clz(x);+}++static int32_t futrts_clzz16(int16_t x) {+  return clz(x);+}++static int32_t futrts_clzz32(int32_t x) {+  return clz(x);+}++static int32_t futrts_clzz64(int64_t x) {+  return clz(x);+}++#elif defined(__CUDA_ARCH__)++static int32_t futrts_clzz8(int8_t x) {+  return __clz(zext_i8_i32(x)) - 24;+}++static int32_t futrts_clzz16(int16_t x) {+  return __clz(zext_i16_i32(x)) - 16;+}++static int32_t futrts_clzz32(int32_t x) {+  return __clz(x);+}++static int32_t futrts_clzz64(int64_t x) {+  return __clzll(x);+}++#elif ISPC++static int32_t futrts_clzz8(int8_t x) {+  return count_leading_zeros((int32_t)(uint8_t)x)-24;+}++static int32_t futrts_clzz16(int16_t x) {+  return count_leading_zeros((int32_t)(uint16_t)x)-16;+}++static int32_t futrts_clzz32(int32_t x) {+  return count_leading_zeros(x);+}++static int32_t futrts_clzz64(int64_t x) {+  return count_leading_zeros(x);+}++#else // Not OpenCL, ISPC or CUDA, but plain C.++static int32_t futrts_clzz8(int8_t x) {+  return x == 0 ? 8 : __builtin_clz((uint32_t)zext_i8_i32(x)) - 24;+}++static int32_t futrts_clzz16(int16_t x) {+  return x == 0 ? 16 : __builtin_clz((uint32_t)zext_i16_i32(x)) - 16;+}++static int32_t futrts_clzz32(int32_t x) {+  return x == 0 ? 32 : __builtin_clz((uint32_t)x);+}++static int32_t futrts_clzz64(int64_t x) {+  return x == 0 ? 64 : __builtin_clzll((uint64_t)x);+}+#endif++#if defined(__OPENCL_VERSION__)+static int32_t futrts_ctzz8(int8_t x) {+  int i = 0;+  for (; i < 8 && (x & 1) == 0; i++, x >>= 1)+    ;+  return i;+}++static int32_t futrts_ctzz16(int16_t x) {+  int i = 0;+  for (; i < 16 && (x & 1) == 0; i++, x >>= 1)+    ;+  return i;+}++static int32_t futrts_ctzz32(int32_t x) {+  int i = 0;+  for (; i < 32 && (x & 1) == 0; i++, x >>= 1)+    ;+  return i;+}++static int32_t futrts_ctzz64(int64_t x) {+  int i = 0;+  for (; i < 64 && (x & 1) == 0; i++, x >>= 1)+    ;+  return i;+}++#elif defined(__CUDA_ARCH__)++static int32_t futrts_ctzz8(int8_t x) {+  int y = __ffs(x);+  return y == 0 ? 8 : y - 1;+}++static int32_t futrts_ctzz16(int16_t x) {+  int y = __ffs(x);+  return y == 0 ? 16 : y - 1;+}++static int32_t futrts_ctzz32(int32_t x) {+  int y = __ffs(x);+  return y == 0 ? 32 : y - 1;+}++static int32_t futrts_ctzz64(int64_t x) {+  int y = __ffsll(x);+  return y == 0 ? 64 : y - 1;+}++#elif ISPC++static int32_t futrts_ctzz8(int8_t x) {+  return x == 0 ? 8 : count_trailing_zeros((int32_t)x);+}++static int32_t futrts_ctzz16(int16_t x) {+  return x == 0 ? 16 : count_trailing_zeros((int32_t)x);+}++static int32_t futrts_ctzz32(int32_t x) {+  return count_trailing_zeros(x);+}++static int32_t futrts_ctzz64(int64_t x) {+  return count_trailing_zeros(x);+}++#else // Not OpenCL or CUDA, but plain C.++static int32_t futrts_ctzz8(int8_t x) {+  return x == 0 ? 8 : __builtin_ctz((uint32_t)x);+}++static int32_t futrts_ctzz16(int16_t x) {+  return x == 0 ? 16 : __builtin_ctz((uint32_t)x);+}++static int32_t futrts_ctzz32(int32_t x) {+  return x == 0 ? 32 : __builtin_ctz((uint32_t)x);+}++static int32_t futrts_ctzz64(int64_t x) {+  return x == 0 ? 64 : __builtin_ctzll((uint64_t)x);+}+#endif++static inline float fdiv32(float x, float y) {+  return x / y;+}++static inline float fadd32(float x, float y) {+  return x + y;+}++static inline float fsub32(float x, float y) {+  return x - y;+}++static inline float fmul32(float x, float y) {+  return x * y;+}++static inline bool cmplt32(float x, float y) {+  return x < y;+}++static inline bool cmple32(float x, float y) {+  return x <= y;+}++static inline float sitofp_i8_f32(int8_t x) {+  return (float) x;+}++static inline float sitofp_i16_f32(int16_t x) {+  return (float) x;+}++static inline float sitofp_i32_f32(int32_t x) {+  return (float) x;+}++static inline float sitofp_i64_f32(int64_t x) {+  return (float) x;+}++static inline float uitofp_i8_f32(uint8_t x) {+  return (float) x;+}++static inline float uitofp_i16_f32(uint16_t x) {+  return (float) x;+}++static inline float uitofp_i32_f32(uint32_t x) {+  return (float) x;+}++static inline float uitofp_i64_f32(uint64_t x) {+  return (float) x;+}++#ifdef __OPENCL_VERSION__+static inline float fabs32(float x) {+  return fabs(x);+}++static inline float fmax32(float x, float y) {+  return fmax(x, y);+}++static inline float fmin32(float x, float y) {+  return fmin(x, y);+}++static inline float fpow32(float x, float y) {+  return pow(x, y);+}++#elif ISPC++static inline float fabs32(float x) {+  return abs(x);+}++static inline float fmax32(float x, float y) {+  return isnan(x) ? y : isnan(y) ? x : max(x, y);+}++static inline float fmin32(float x, float y) {+  return isnan(x) ? y : isnan(y) ? x : min(x, y);+}++static inline float fpow32(float a, float b) {+  float ret;+  foreach_active (i) {+      uniform float r = __stdlib_powf(extract(a, i), extract(b, i));+      ret = insert(ret, i, r);+  }+  return ret;+}++#else // Not OpenCL, but CUDA or plain C.++static inline float fabs32(float x) {+  return fabsf(x);+}++static inline float fmax32(float x, float y) {+  return fmaxf(x, y);+}++static inline float fmin32(float x, float y) {+  return fminf(x, y);+}++static inline float fpow32(float x, float y) {+  return powf(x, y);+}+#endif++static inline bool futrts_isnan32(float x) {+  return isnan(x);+}++#if ISPC++static inline bool futrts_isinf32(float x) {+  return !isnan(x) && isnan(x - x);+}++static inline bool futrts_isfinite32(float x) {+  return !isnan(x) && !futrts_isinf32(x);+}++#else++static inline bool futrts_isinf32(float x) {+  return isinf(x);+}++#endif++static inline int8_t fptosi_f32_i8(float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (int8_t) x;+  }+}++static inline int16_t fptosi_f32_i16(float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (int16_t) x;+  }+}++static inline int32_t fptosi_f32_i32(float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (int32_t) x;+  }+}++static inline int64_t fptosi_f32_i64(float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (int64_t) x;+  };+}++static inline uint8_t fptoui_f32_i8(float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uint8_t) (int8_t) x;+  }+}++static inline uint16_t fptoui_f32_i16(float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uint16_t) (int16_t) x;+  }+}++static inline uint32_t fptoui_f32_i32(float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uint32_t) (int32_t) x;+  }+}++static inline uint64_t fptoui_f32_i64(float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uint64_t) (int64_t) x;+  }+}++static inline bool ftob_f32_bool(float x) {+  return x != 0;+}++static inline float btof_bool_f32(bool x) {+  return x ? 1 : 0;+}++#ifdef __OPENCL_VERSION__+static inline float futrts_log32(float x) {+  return log(x);+}++static inline float futrts_log2_32(float x) {+  return log2(x);+}++static inline float futrts_log10_32(float x) {+  return log10(x);+}++static inline float futrts_sqrt32(float x) {+  return sqrt(x);+}++static inline float futrts_cbrt32(float x) {+  return cbrt(x);+}++static inline float futrts_exp32(float x) {+  return exp(x);+}++static inline float futrts_cos32(float x) {+  return cos(x);+}++static inline float futrts_sin32(float x) {+  return sin(x);+}++static inline float futrts_tan32(float x) {+  return tan(x);+}++static inline float futrts_acos32(float x) {+  return acos(x);+}++static inline float futrts_asin32(float x) {+  return asin(x);+}++static inline float futrts_atan32(float x) {+  return atan(x);+}++static inline float futrts_cosh32(float x) {+  return cosh(x);+}++static inline float futrts_sinh32(float x) {+  return sinh(x);+}++static inline float futrts_tanh32(float x) {+  return tanh(x);+}++static inline float futrts_acosh32(float x) {+  return acosh(x);+}++static inline float futrts_asinh32(float x) {+  return asinh(x);+}++static inline float futrts_atanh32(float x) {+  return atanh(x);+}++static inline float futrts_atan2_32(float x, float y) {+  return atan2(x, y);+}++static inline float futrts_hypot32(float x, float y) {+  return hypot(x, y);+}++static inline float futrts_gamma32(float x) {+  return tgamma(x);+}++static inline float futrts_lgamma32(float x) {+  return lgamma(x);+}++static inline float futrts_erf32(float x) {+  return erf(x);+}++static inline float futrts_erfc32(float x) {+  return erfc(x);+}++static inline float fmod32(float x, float y) {+  return fmod(x, y);+}++static inline float futrts_round32(float x) {+  return rint(x);+}++static inline float futrts_floor32(float x) {+  return floor(x);+}++static inline float futrts_ceil32(float x) {+  return ceil(x);+}++static inline float futrts_lerp32(float v0, float v1, float t) {+  return mix(v0, v1, t);+}++static inline float futrts_mad32(float a, float b, float c) {+  return mad(a, b, c);+}++static inline float futrts_fma32(float a, float b, float c) {+  return fma(a, b, c);+}++#elif ISPC++static inline float futrts_log32(float x) {+  return futrts_isfinite32(x) || (futrts_isinf32(x) && x < 0)? log(x) : x;+}++static inline float futrts_log2_32(float x) {+  return futrts_log32(x) / log(2.0f);+}++static inline float futrts_log10_32(float x) {+  return futrts_log32(x) / log(10.0f);+}++static inline float futrts_sqrt32(float x) {+  return sqrt(x);+}++extern "C" unmasked uniform float cbrtf(uniform float);+static inline float futrts_cbrt32(float x) {+  float res;+  foreach_active (i) {+    uniform float r = cbrtf(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++static inline float futrts_exp32(float x) {+  return exp(x);+}++static inline float futrts_cos32(float x) {+  return cos(x);+}++static inline float futrts_sin32(float x) {+  return sin(x);+}++static inline float futrts_tan32(float x) {+  return tan(x);+}++static inline float futrts_acos32(float x) {+  return acos(x);+}++static inline float futrts_asin32(float x) {+  return asin(x);+}++static inline float futrts_atan32(float x) {+  return atan(x);+}++static inline float futrts_cosh32(float x) {+  return (exp(x)+exp(-x)) / 2.0f;+}++static inline float futrts_sinh32(float x) {+  return (exp(x)-exp(-x)) / 2.0f;+}++static inline float futrts_tanh32(float x) {+  return futrts_sinh32(x)/futrts_cosh32(x);+}++static inline float futrts_acosh32(float x) {+  float f = x+sqrt(x*x-1);+  if(futrts_isfinite32(f)) return log(f);+  return f;+}++static inline float futrts_asinh32(float x) {+  float f = x+sqrt(x*x+1);+  if(futrts_isfinite32(f)) return log(f);+  return f;++}++static inline float futrts_atanh32(float x) {+  float f = (1+x)/(1-x);+  if(futrts_isfinite32(f)) return log(f)/2.0f;+  return f;++}++static inline float futrts_atan2_32(float x, float y) {+  return (x == 0.0f && y == 0.0f) ? 0.0f : atan2(x, y);+}++static inline float futrts_hypot32(float x, float y) {+  if (futrts_isfinite32(x) && futrts_isfinite32(y)) {+    x = abs(x);+    y = abs(y);+    float a;+    float b;+    if (x >= y){+        a = x;+        b = y;+    } else {+        a = y;+        b = x;+    }+    if(b == 0){+      return a;+    }++    int e;+    float an;+    float bn;+    an = frexp (a, &e);+    bn = ldexp (b, - e);+    float cn;+    cn = sqrt (an * an + bn * bn);+    return ldexp (cn, e);+  } else {+    if (futrts_isinf32(x) || futrts_isinf32(y)) return INFINITY;+    else return x + y;+  }++}++extern "C" unmasked uniform float tgammaf(uniform float x);+static inline float futrts_gamma32(float x) {+  float res;+  foreach_active (i) {+    uniform float r = tgammaf(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++extern "C" unmasked uniform float lgammaf(uniform float x);+static inline float futrts_lgamma32(float x) {+  float res;+  foreach_active (i) {+    uniform float r = lgammaf(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++extern "C" unmasked uniform float erff(uniform float x);+static inline float futrts_erf32(float x) {+  float res;+  foreach_active (i) {+    uniform float r = erff(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++extern "C" unmasked uniform float erfcf(uniform float x);+static inline float futrts_erfc32(float x) {+  float res;+  foreach_active (i) {+    uniform float r = erfcf(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++static inline float fmod32(float x, float y) {+  return x - y * trunc(x/y);+}++static inline float futrts_round32(float x) {+  return round(x);+}++static inline float futrts_floor32(float x) {+  return floor(x);+}++static inline float futrts_ceil32(float x) {+  return ceil(x);+}++static inline float futrts_lerp32(float v0, float v1, float t) {+  return v0 + (v1 - v0) * t;+}++static inline float futrts_mad32(float a, float b, float c) {+  return a * b + c;+}++static inline float futrts_fma32(float a, float b, float c) {+  return a * b + c;+}++#else // Not OpenCL or ISPC, but CUDA or plain C.++static inline float futrts_log32(float x) {+  return logf(x);+}++static inline float futrts_log2_32(float x) {+  return log2f(x);+}++static inline float futrts_log10_32(float x) {+  return log10f(x);+}++static inline float futrts_sqrt32(float x) {+  return sqrtf(x);+}++static inline float futrts_cbrt32(float x) {+  return cbrtf(x);+}++static inline float futrts_exp32(float x) {+  return expf(x);+}++static inline float futrts_cos32(float x) {+  return cosf(x);+}++static inline float futrts_sin32(float x) {+  return sinf(x);+}++static inline float futrts_tan32(float x) {+  return tanf(x);+}++static inline float futrts_acos32(float x) {+  return acosf(x);+}++static inline float futrts_asin32(float x) {+  return asinf(x);+}++static inline float futrts_atan32(float x) {+  return atanf(x);+}++static inline float futrts_cosh32(float x) {+  return coshf(x);+}++static inline float futrts_sinh32(float x) {+  return sinhf(x);+}++static inline float futrts_tanh32(float x) {+  return tanhf(x);+}++static inline float futrts_acosh32(float x) {+  return acoshf(x);+}++static inline float futrts_asinh32(float x) {+  return asinhf(x);+}++static inline float futrts_atanh32(float x) {+  return atanhf(x);+}++static inline float futrts_atan2_32(float x, float y) {+  return atan2f(x, y);+}++static inline float futrts_hypot32(float x, float y) {+  return hypotf(x, y);+}++static inline float futrts_gamma32(float x) {+  return tgammaf(x);+}++static inline float futrts_lgamma32(float x) {+  return lgammaf(x);+}++static inline float futrts_erf32(float x) {+  return erff(x);+}++static inline float futrts_erfc32(float x) {+  return erfcf(x);+}++static inline float fmod32(float x, float y) {+  return fmodf(x, y);+}++static inline float futrts_round32(float x) {+  return rintf(x);+}++static inline float futrts_floor32(float x) {+  return floorf(x);+}++static inline float futrts_ceil32(float x) {+  return ceilf(x);+}++static inline float futrts_lerp32(float v0, float v1, float t) {+  return v0 + (v1 - v0) * t;+}++static inline float futrts_mad32(float a, float b, float c) {+  return a * b + c;+}++static inline float futrts_fma32(float a, float b, float c) {+  return fmaf(a, b, c);+}+#endif++#if ISPC+static inline int32_t futrts_to_bits32(float x) {+  return intbits(x);+}++static inline float futrts_from_bits32(int32_t x) {+  return floatbits(x);+}+#else+static inline int32_t futrts_to_bits32(float x) {+  union {+    float f;+    int32_t t;+  } p;++  p.f = x;+  return p.t;+}++static inline float futrts_from_bits32(int32_t x) {+  union {+    int32_t f;+    float t;+  } p;++  p.f = x;+  return p.t;+}+#endif++static inline float fsignum32(float x) {+  return futrts_isnan32(x) ? x : (x > 0 ? 1 : 0) - (x < 0 ? 1 : 0);+}++#ifdef FUTHARK_F64_ENABLED++#if ISPC+static inline bool futrts_isinf64(float x) {+  return !isnan(x) && isnan(x - x);+}++static inline bool futrts_isfinite64(float x) {+  return !isnan(x) && !futrts_isinf64(x);+}++static inline double fdiv64(double x, double y) {+  return x / y;+}++static inline double fadd64(double x, double y) {+  return x + y;+}++static inline double fsub64(double x, double y) {+  return x - y;+}++static inline double fmul64(double x, double y) {+  return x * y;+}++static inline bool cmplt64(double x, double y) {+  return x < y;+}++static inline bool cmple64(double x, double y) {+  return x <= y;+}++static inline double sitofp_i8_f64(int8_t x) {+  return (double) x;+}++static inline double sitofp_i16_f64(int16_t x) {+  return (double) x;+}++static inline double sitofp_i32_f64(int32_t x) {+  return (double) x;+}++static inline double sitofp_i64_f64(int64_t x) {+  return (double) x;+}++static inline double uitofp_i8_f64(uint8_t x) {+  return (double) x;+}++static inline double uitofp_i16_f64(uint16_t x) {+  return (double) x;+}++static inline double uitofp_i32_f64(uint32_t x) {+  return (double) x;+}++static inline double uitofp_i64_f64(uint64_t x) {+  return (double) x;+}++static inline double fabs64(double x) {+  return abs(x);+}++static inline double fmax64(double x, double y) {+  return isnan(x) ? y : isnan(y) ? x : max(x, y);+}++static inline double fmin64(double x, double y) {+  return isnan(x) ? y : isnan(y) ? x : min(x, y);+}++static inline double fpow64(double a, double b) {+  float ret;+  foreach_active (i) {+      uniform float r = __stdlib_powf(extract(a, i), extract(b, i));+      ret = insert(ret, i, r);+  }+  return ret;+}++static inline double futrts_log64(double x) {+  return futrts_isfinite64(x) || (futrts_isinf64(x) && x < 0)? log(x) : x;+}++static inline double futrts_log2_64(double x) {+  return futrts_log64(x)/log(2.0d);+}++static inline double futrts_log10_64(double x) {+  return futrts_log64(x)/log(10.0d);+}++static inline double futrts_sqrt64(double x) {+  return sqrt(x);+}++extern "C" unmasked uniform double cbrt(uniform double);+static inline double futrts_cbrt64(double x) {+  double res;+  foreach_active (i) {+    uniform double r = cbrtf(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++static inline double futrts_exp64(double x) {+  return exp(x);+}++static inline double futrts_cos64(double x) {+  return cos(x);+}++static inline double futrts_sin64(double x) {+  return sin(x);+}++static inline double futrts_tan64(double x) {+  return tan(x);+}++static inline double futrts_acos64(double x) {+  return acos(x);+}++static inline double futrts_asin64(double x) {+  return asin(x);+}++static inline double futrts_atan64(double x) {+  return atan(x);+}++static inline double futrts_cosh64(double x) {+  return (exp(x)+exp(-x)) / 2.0d;+}++static inline double futrts_sinh64(double x) {+  return (exp(x)-exp(-x)) / 2.0d;+}++static inline double futrts_tanh64(double x) {+  return futrts_sinh64(x)/futrts_cosh64(x);+}++static inline double futrts_acosh64(double x) {+  double f = x+sqrt(x*x-1.0d);+  if(futrts_isfinite64(f)) return log(f);+  return f;+}++static inline double futrts_asinh64(double x) {+  double f = x+sqrt(x*x+1.0d);+  if(futrts_isfinite64(f)) return log(f);+  return f;+}++static inline double futrts_atanh64(double x) {+  double f = (1.0d+x)/(1.0d-x);+  if(futrts_isfinite64(f)) return log(f)/2.0d;+  return f;++}++static inline double futrts_atan2_64(double x, double y) {+  return atan2(x, y);+}++extern "C" unmasked uniform double hypot(uniform double x, uniform double y);+static inline double futrts_hypot64(double x, double y) {+  double res;+  foreach_active (i) {+    uniform double r = hypot(extract(x, i), extract(y, i));+    res = insert(res, i, r);+  }+  return res;+}++extern "C" unmasked uniform double tgamma(uniform double x);+static inline double futrts_gamma64(double x) {+  double res;+  foreach_active (i) {+    uniform double r = tgamma(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++extern "C" unmasked uniform double lgamma(uniform double x);+static inline double futrts_lgamma64(double x) {+  double res;+  foreach_active (i) {+    uniform double r = lgamma(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++extern "C" unmasked uniform double erf(uniform double x);+static inline double futrts_erf64(double x) {+  double res;+  foreach_active (i) {+    uniform double r = erf(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++extern "C" unmasked uniform double erfc(uniform double x);+static inline double futrts_erfc64(double x) {+  double res;+  foreach_active (i) {+    uniform double r = erfc(extract(x, i));+    res = insert(res, i, r);+  }+  return res;+}++static inline double futrts_fma64(double a, double b, double c) {+  return a * b + c;+}++static inline double futrts_round64(double x) {+  return round(x);+}++static inline double futrts_ceil64(double x) {+  return ceil(x);+}++static inline double futrts_floor64(double x) {+  return floor(x);+}++static inline bool futrts_isnan64(double x) {+  return isnan(x);+}++static inline int8_t fptosi_f64_i8(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (int8_t) x;+  }+}++static inline int16_t fptosi_f64_i16(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (int16_t) x;+  }+}++static inline int32_t fptosi_f64_i32(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (int32_t) x;+  }+}++static inline int64_t fptosi_f64_i64(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (int64_t) x;+  }+}++static inline uint8_t fptoui_f64_i8(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uint8_t) (int8_t) x;+  }+}++static inline uint16_t fptoui_f64_i16(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uint16_t) (int16_t) x;+  }+}++static inline uint32_t fptoui_f64_i32(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uint32_t) (int32_t) x;+  }+}++static inline uint64_t fptoui_f64_i64(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uint64_t) (int64_t) x;+  }+}++static inline bool ftob_f64_bool(double x) {+  return x != 0.0;+}++static inline double btof_bool_f64(bool x) {+  return x ? 1.0 : 0.0;+}++static inline int64_t futrts_to_bits64(double x) {+  int64_t res;+  foreach_active (i) {+    uniform double tmp = extract(x, i);+    uniform int64_t r = *((uniform int64_t* uniform)&tmp);+    res = insert(res, i, r);+  }+  return res;+}++static inline double futrts_from_bits64(int64_t x) {+  double res;+  foreach_active (i) {+    uniform int64_t tmp = extract(x, i);+    uniform double r = *((uniform double* uniform)&tmp);+    res = insert(res, i, r);+  }+  return res;+}++static inline double fmod64(double x, double y) {+  return x - y * trunc(x/y);+}++static inline double fsignum64(double x) {+  return futrts_isnan64(x) ? x : (x > 0 ? 1.0d : 0.0d) - (x < 0 ? 1.0d : 0.0d);+}++static inline double futrts_lerp64(double v0, double v1, double t) {+  return v0 + (v1 - v0) * t;+}++static inline double futrts_mad64(double a, double b, double c) {+  return a * b + c;+}++static inline float fpconv_f32_f32(float x) {+  return (float) x;+}++static inline double fpconv_f32_f64(float x) {+  return (double) x;+}++static inline float fpconv_f64_f32(double x) {+  return (float) x;+}++static inline double fpconv_f64_f64(double x) {+  return (double) x;+}++#else++static inline double fdiv64(double x, double y) {+  return x / y;+}++static inline double fadd64(double x, double y) {+  return x + y;+}++static inline double fsub64(double x, double y) {+  return x - y;+}++static inline double fmul64(double x, double y) {+  return x * y;+}++static inline bool cmplt64(double x, double y) {+  return x < y;+}++static inline bool cmple64(double x, double y) {+  return x <= y;+}++static inline double sitofp_i8_f64(int8_t x) {+  return (double) x;+}++static inline double sitofp_i16_f64(int16_t x) {+  return (double) x;+}++static inline double sitofp_i32_f64(int32_t x) {+  return (double) x;+}++static inline double sitofp_i64_f64(int64_t x) {+  return (double) x;+}++static inline double uitofp_i8_f64(uint8_t x) {+  return (double) x;+}++static inline double uitofp_i16_f64(uint16_t x) {+  return (double) x;+}++static inline double uitofp_i32_f64(uint32_t x) {+  return (double) x;+}++static inline double uitofp_i64_f64(uint64_t x) {+  return (double) x;+}++static inline double fabs64(double x) {+  return fabs(x);+}++static inline double fmax64(double x, double y) {+  return fmax(x, y);+}++static inline double fmin64(double x, double y) {+  return fmin(x, y);+}++static inline double fpow64(double x, double y) {+  return pow(x, y);+}++static inline double futrts_log64(double x) {+  return log(x);+}++static inline double futrts_log2_64(double x) {+  return log2(x);+}++static inline double futrts_log10_64(double x) {+  return log10(x);+}++static inline double futrts_sqrt64(double x) {+  return sqrt(x);+}++static inline double futrts_cbrt64(double x) {+  return cbrt(x);+}++static inline double futrts_exp64(double x) {+  return exp(x);+}++static inline double futrts_cos64(double x) {+  return cos(x);+}++static inline double futrts_sin64(double x) {+  return sin(x);+}++static inline double futrts_tan64(double x) {+  return tan(x);+}++static inline double futrts_acos64(double x) {+  return acos(x);+}++static inline double futrts_asin64(double x) {+  return asin(x);+}++static inline double futrts_atan64(double x) {+  return atan(x);+}++static inline double futrts_cosh64(double x) {+  return cosh(x);+}++static inline double futrts_sinh64(double x) {+  return sinh(x);+}++static inline double futrts_tanh64(double x) {+  return tanh(x);+}++static inline double futrts_acosh64(double x) {+  return acosh(x);+}++static inline double futrts_asinh64(double x) {+  return asinh(x);+}++static inline double futrts_atanh64(double x) {+  return atanh(x);+}++static inline double futrts_atan2_64(double x, double y) {+  return atan2(x, y);+}++static inline double futrts_hypot64(double x, double y) {+  return hypot(x, y);+}++static inline double futrts_gamma64(double x) {+  return tgamma(x);+}++static inline double futrts_lgamma64(double x) {+  return lgamma(x);+}++static inline double futrts_erf64(double x) {+  return erf(x);+}++static inline double futrts_erfc64(double x) {+  return erfc(x);+}++static inline double futrts_fma64(double a, double b, double c) {+  return fma(a, b, c);+}++static inline double futrts_round64(double x) {+  return rint(x);+}++static inline double futrts_ceil64(double x) {+  return ceil(x);+}++static inline double futrts_floor64(double x) {+  return floor(x);+}++static inline bool futrts_isnan64(double x) {+  return isnan(x);+}++static inline bool futrts_isinf64(double x) {+  return isinf(x);+}++static inline int8_t fptosi_f64_i8(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (int8_t) x;+  }+}++static inline int16_t fptosi_f64_i16(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (int16_t) x;+  }+}++static inline int32_t fptosi_f64_i32(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (int32_t) x;+  }+}++static inline int64_t fptosi_f64_i64(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (int64_t) x;+  }+}++static inline uint8_t fptoui_f64_i8(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uint8_t) (int8_t) x;+  }+}++static inline uint16_t fptoui_f64_i16(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uint16_t) (int16_t) x;+  }+}++static inline uint32_t fptoui_f64_i32(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uint32_t) (int32_t) x;+  }+}++static inline uint64_t fptoui_f64_i64(double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uint64_t) (int64_t) x;+  }+}++static inline bool ftob_f64_bool(double x) {+  return x != 0;+}++static inline double btof_bool_f64(bool x) {+  return x ? 1 : 0;+}++static inline int64_t futrts_to_bits64(double x) {+  union {+    double f;+    int64_t t;+  } p;++  p.f = x;+  return p.t;+}++static inline double futrts_from_bits64(int64_t x) {+  union {+    int64_t f;+    double t;+  } p;++  p.f = x;+  return p.t;+}++static inline double fmod64(double x, double y) {+  return fmod(x, y);+}++static inline double fsignum64(double x) {+  return futrts_isnan64(x) ? x : (x > 0) - (x < 0);+}++static inline double futrts_lerp64(double v0, double v1, double t) {+#ifdef __OPENCL_VERSION__+  return mix(v0, v1, t);+#else+  return v0 + (v1 - v0) * t;+#endif+}++static inline double futrts_mad64(double a, double b, double c) {+#ifdef __OPENCL_VERSION__+  return mad(a, b, c);+#else+  return a * b + c;+#endif+}++static inline float fpconv_f32_f32(float x) {+  return (float) x;+}++static inline double fpconv_f32_f64(float x) {+  return (double) x;+}++static inline float fpconv_f64_f32(double x) {+  return (float) x;+}++static inline double fpconv_f64_f64(double x) {+  return (double) x;+}++#endif  #endif 
rts/c/scalar_f16.h view
@@ -9,7 +9,7 @@ // under emulation, so the compiler will have to be careful when // generating reads or writes. -#if !defined(cl_khr_fp16) && !(defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 600)+#if !defined(cl_khr_fp16) && !(defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 600) && !(defined(ISPC)) #define EMULATE_F16 #endif @@ -23,6 +23,9 @@ // compiler will have to be real careful! typedef float f16; +#elif ISPC+typedef float16 f16;+ #else  #ifdef __CUDA_ARCH__@@ -129,8 +132,12 @@ }  #ifndef EMULATE_F16+static inline bool futrts_isnan16(f16 x) {+  return isnan((float)x);+}  #ifdef __OPENCL_VERSION__+ static inline f16 fabs16(f16 x) {   return fabs(x); }@@ -147,6 +154,22 @@   return pow(x, y); } +#elif ISPC+static inline f16 fabs16(f16 x) {+  return abs(x);+}++static inline f16 fmax16(f16 x, f16 y) {+  return futrts_isnan16(x) ? y : futrts_isnan16(y) ? x : max(x, y);+}++static inline f16 fmin16(f16 x, f16 y) {+  return futrts_isnan16(x) ? y : futrts_isnan16(y) ? x : min(x, y);+}++static inline f16 fpow16(f16 x, f16 y) {+  return pow(x, y);+} #else // Assuming CUDA.  static inline f16 fabs16(f16 x) {@@ -166,13 +189,20 @@ } #endif -static inline bool futrts_isnan16(f16 x) {-  return isnan((float)x);+#if ISPC+static inline bool futrts_isinf16(float x) {+  return !futrts_isnan16(x) && futrts_isnan16(x - x); }+static inline bool futrts_isfinite16(float x) {+  return !futrts_isnan16(x) && !futrts_isinf16(x);+} +#else+ static inline bool futrts_isinf16(f16 x) {   return isinf((float)x); }+#endif  #ifdef __OPENCL_VERSION__ static inline f16 futrts_log16(f16 x) {@@ -298,7 +328,153 @@ static inline f16 futrts_fma16(f16 a, f16 b, f16 c) {   return fma(a, b, c); }+#elif ISPC +static inline f16 futrts_log16(f16 x) {+  return futrts_isfinite16(x) || (futrts_isinf16(x) && x < 0) ? log(x) : x;+}++static inline f16 futrts_log2_16(f16 x) {+  return futrts_log16(x) / log(2.0f16);+}++static inline f16 futrts_log10_16(f16 x) {+  return futrts_log16(x) / log(10.0f16);+}++static inline f16 futrts_sqrt16(f16 x) {+  return (float16)sqrt((float)x);+}++static inline f16 futrts_exp16(f16 x) {+  return exp(x);+}++static inline f16 futrts_cos16(f16 x) {+  return (float16)cos((float)x);+}++static inline f16 futrts_sin16(f16 x) {+  return (float16)sin((float)x);+}++static inline f16 futrts_tan16(f16 x) {+  return (float16)tan((float)x);+}++static inline f16 futrts_acos16(f16 x) {+  return (float16)acos((float)x);+}++static inline f16 futrts_asin16(f16 x) {+  return (float16)asin((float)x);+}++static inline f16 futrts_atan16(f16 x) {+  return (float16)atan((float)x);+}++static inline f16 futrts_cosh16(f16 x) {+  return (exp(x)+exp(-x)) / 2.0f16;+}++static inline f16 futrts_sinh16(f16 x) {+  return (exp(x)-exp(-x)) / 2.0f16;+}++static inline f16 futrts_tanh16(f16 x) {+  return futrts_sinh16(x)/futrts_cosh16(x);+}++static inline f16 futrts_acosh16(f16 x) {+  float16 f = x+(float16)sqrt((float)(x*x-1));+  if(futrts_isfinite16(f)) return log(f);+  return f;+}++static inline f16 futrts_asinh16(f16 x) {+  float16 f = x+(float16)sqrt((float)(x*x+1));+  if(futrts_isfinite16(f)) return log(f);+  return f;+}++static inline f16 futrts_atanh16(f16 x) {+  float16 f = (1+x)/(1-x);+  if(futrts_isfinite16(f)) return log(f)/2.0f16;+  return f;+}++static inline f16 futrts_atan2_16(f16 x, f16 y) {+  return (float16)atan2((float)x, (float)y);+}++static inline f16 futrts_hypot16(f16 x, f16 y) {+  return (float16)futrts_hypot32((float)x, (float)y);+}++extern "C" unmasked uniform float tgammaf(uniform float x);+static inline f16 futrts_gamma16(f16 x) {+  f16 res;+  foreach_active (i) {+    uniform f16 r = (f16)tgammaf(extract((float)x, i));+    res = insert(res, i, r);+  }+  return res;+}++extern "C" unmasked uniform float lgammaf(uniform float x);+static inline f16 futrts_lgamma16(f16 x) {+  f16 res;+  foreach_active (i) {+    uniform f16 r = (f16)lgammaf(extract((float)x, i));+    res = insert(res, i, r);+  }+  return res;+}++static inline f16 futrts_cbrt16(f16 x) {+  f16 res = (f16)futrts_cbrt32((float)x);+  return res;+}++static inline f16 futrts_erf16(f16 x) {+  f16 res = (f16)futrts_erf32((float)x);+  return res;+}++static inline f16 futrts_erfc16(f16 x) {+  f16 res = (f16)futrts_erfc32((float)x);+  return res;+}++static inline f16 fmod16(f16 x, f16 y) {+  return x - y * (float16)trunc((float) (x/y));+}++static inline f16 futrts_round16(f16 x) {+  return (float16)round((float)x);+}++static inline f16 futrts_floor16(f16 x) {+  return (float16)floor((float)x);+}++static inline f16 futrts_ceil16(f16 x) {+  return (float16)ceil((float)x);+}++static inline f16 futrts_lerp16(f16 v0, f16 v1, f16 t) {+  return v0 + (v1 - v0) * t;+}++static inline f16 futrts_mad16(f16 a, f16 b, f16 c) {+  return a * b + c;+}++static inline f16 futrts_fma16(f16 a, f16 b, f16 c) {+  return a * b + c;+}+ #else // Assume CUDA.  static inline f16 futrts_log16(f16 x) {@@ -436,6 +612,17 @@ static inline f16 futrts_from_bits16(int16_t x) {   return __ushort_as_half(x); }+#elif ISPC++static inline int16_t futrts_to_bits16(f16 x) {+  varying int16_t y = *((varying int16_t * uniform)&x);+  return y;+}++static inline f16 futrts_from_bits16(int16_t x) {+  varying f16 y = *((varying f16 * uniform)&x);+  return y;+} #else static inline int16_t futrts_to_bits16(f16 x) {   union {@@ -636,7 +823,7 @@ }  static inline f16 fsignum16(f16 x) {-  return futrts_isnan16(x) ? x : (x > 0) - (x < 0);+  return futrts_isnan16(x) ? x : (x > 0 ? 1 : 0) - (x < 0 ? 1 : 0); }  #endif@@ -652,7 +839,7 @@ }  static inline f16 fpconv_f32_f16(float x) {-  return x;+  return (f16) x; }  #ifdef FUTHARK_F64_ENABLED@@ -661,10 +848,15 @@   return (double) x; } +#if ISPC static inline f16 fpconv_f64_f16(double x) {+  return (f16) ((float)x);+}+#else+static inline f16 fpconv_f64_f16(double x) {   return (f16) x; }-+#endif #endif  
rts/c/scheduler.h view
@@ -495,7 +495,9 @@ struct scheduler {   struct worker *workers;   int num_threads;+  int minimum_chunk_size; +   // If there is work to steal => active_work > 0   volatile int active_work; @@ -534,12 +536,11 @@   return i; } --static inline int64_t compute_chunk_size(double kappa, struct subtask* subtask)+static inline int64_t compute_chunk_size(int64_t minimum_chunk_size, double kappa, struct subtask* subtask) {   double C = (double)*subtask->task_time / (double)*subtask->task_iter;   if (C == 0.0F) C += DBL_EPSILON;-  return smax64((int64_t)(kappa / C), 1);+  return smax64((int64_t)(kappa / C), minimum_chunk_size); }  /* Takes a chunk from subtask and enqueues the remaining iterations onto the worker's queue */@@ -549,7 +550,9 @@   if (subtask->chunkable) {     // Do we have information from previous runs avaliable     if (*subtask->task_iter > 0) {-      subtask->chunk_size = compute_chunk_size(worker->scheduler->kappa, subtask);+      subtask->chunk_size = compute_chunk_size(worker->scheduler->minimum_chunk_size,+                                               worker->scheduler->kappa,+                                               subtask);       assert(subtask->chunk_size > 0);     }     int64_t remaining_iter = subtask->end - subtask->start;@@ -790,7 +793,7 @@   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+  int64_t chunk_size = scheduler->minimum_chunk_size; // The initial chunk size when no info is avaliable     if (info.wake_up_threads || sched == DYNAMIC)@@ -1076,6 +1079,13 @@ static int scheduler_init(struct scheduler *scheduler,                           int num_workers,                           double kappa) {+#ifdef FUTHARK_BACKEND_ispc+  int64_t get_gang_size();+  scheduler->minimum_chunk_size = get_gang_size();+#else+  scheduler->minimum_chunk_size = 1;+#endif+   assert(num_workers > 0);    scheduler->kappa = kappa;
rts/c/server.h view
@@ -14,13 +14,28 @@ typedef int (*restore_fn)(const void*, FILE *, struct futhark_context*, void*); typedef void (*store_fn)(const void*, FILE *, struct futhark_context*, void*); typedef int (*free_fn)(const void*, struct futhark_context*, void*);+typedef int (*project_fn)(struct futhark_context*, void*, const void*);+typedef int (*new_fn)(struct futhark_context*, void**, const void*[]); +struct field {+  const char *name;+  const struct type *type;+  project_fn project;+};++struct record {+  int num_fields;+  const struct field* fields;+  new_fn new;+};+ struct type {   const char *name;   restore_fn restore;   store_fn store;   free_fn free;   const void *aux;+  const struct record *record; };  int free_scalar(const void *aux, struct futhark_context *ctx, void *p) {@@ -31,27 +46,27 @@   return 0; } -#define DEF_SCALAR_TYPE(T)                                              \-  int restore_##T(const void *aux, FILE *f,                             \-                  struct futhark_context *ctx, void *p) {               \-    (void)aux;                                                          \-    (void)ctx;                                                          \-    return read_scalar(f, &T##_info, p);                                \-  }                                                                     \-                                                                        \-  void store_##T(const void *aux, FILE *f,                              \-                 struct futhark_context *ctx, void *p) {                \-    (void)aux;                                                          \-    (void)ctx;                                                          \-    write_scalar(f, 1, &T##_info, p);                                   \-  }                                                                     \-                                                                        \-  struct type type_##T =                                                \-    { .name = #T,                                                       \-      .restore = restore_##T,                                           \-      .store = store_##T,                                               \-      .free = free_scalar                                               \-    }                                                                   \+#define DEF_SCALAR_TYPE(T)                                      \+  int restore_##T(const void *aux, FILE *f,                     \+                  struct futhark_context *ctx, void *p) {       \+    (void)aux;                                                  \+    (void)ctx;                                                  \+    return read_scalar(f, &T##_info, p);                        \+  }                                                             \+                                                                \+  void store_##T(const void *aux, FILE *f,                      \+                 struct futhark_context *ctx, void *p) {        \+    (void)aux;                                                  \+    (void)ctx;                                                  \+    write_scalar(f, 1, &T##_info, p);                           \+  }                                                             \+                                                                \+  struct type type_##T =                                        \+    { .name = #T,                                               \+      .restore = restore_##T,                                   \+      .store = store_##T,                                       \+      .free = free_scalar                                       \+    }                                                           \  DEF_SCALAR_TYPE(i8); DEF_SCALAR_TYPE(i16);@@ -67,7 +82,7 @@ DEF_SCALAR_TYPE(bool);  struct value {-  struct type *type;+  const struct type *type;   union {     void *v_ptr;     int8_t  v_i8;@@ -139,9 +154,9 @@ struct entry_point {   const char *name;   entry_point_fn f;-  struct type **out_types;+  const struct type **out_types;   bool *out_unique;-  struct type **in_types;+  const struct type **in_types;   bool *in_unique; }; @@ -165,7 +180,7 @@   // Last entry point identified by NULL name.   struct entry_point *entry_points;   // Last type identified by NULL name.-  struct type **types;+  const struct type **types; };  struct server_state {@@ -190,7 +205,7 @@  struct variable* create_variable(struct server_state *s,                                  const char *name,-                                 struct type *type) {+                                 const struct type *type) {   int found = -1;   for (int i = 0; i < s->variables_capacity; i++) {     if (found == -1 && s->variables[i].name == NULL) {@@ -240,7 +255,7 @@   return args[i]; } -struct type* get_type(struct server_state *s, const char *name) {+const struct type* get_type(struct server_state *s, const char *name) {   for (int i = 0; s->prog.types[i]; i++) {     if (strcmp(s->prog.types[i]->name, name) == 0) {       return s->prog.types[i];@@ -364,7 +379,7 @@       const char *vname = get_arg(args, i);       const char *type = get_arg(args, i+1); -      struct type *t = get_type(s, type);+      const struct type *t = get_type(s, type);       struct variable *v = create_variable(s, vname, t);        if (v == NULL) {@@ -414,7 +429,7 @@         return;       } -      struct type *t = v->value.type;+      const struct type *t = v->value.type;       t->store(t->aux, f, s->ctx, value_ptr(&v->value));     }     fclose(f);@@ -432,7 +447,7 @@       return;     } -    struct type *t = v->value.type;+    const struct type *t = v->value.type;      int err = t->free(t->aux, s->ctx, value_ptr(&v->value));     error_check(s, err);@@ -544,6 +559,138 @@   } } +void cmd_fields(struct server_state *s, const char *args[]) {+  const char *type = get_arg(args, 0);+  const struct type *t = get_type(s, type);+  const struct record *r = t->record;++  if (r == NULL) {+    failure();+    printf("Not a record type\n");+    return;+  }++  for (int i = 0; i < r->num_fields; i++) {+    const struct field f = r->fields[i];+    printf("%s %s\n", f.name, f.type->name);+  }+}++void cmd_project(struct server_state *s, const char *args[]) {+  const char *to_name = get_arg(args, 0);+  const char *from_name = get_arg(args, 1);+  const char *field_name = get_arg(args, 2);++  struct variable *from = get_variable(s, from_name);++  if (from == NULL) {+    failure();+    printf("Unknown variable: %s\n", from_name);+    return;+  }++  const struct type *from_type = from->value.type;+  const struct record *r = from_type->record;++  if (r == NULL) {+    failure();+    printf("Not a record type\n");+    return;+  }++  const struct field *field = NULL;+  for (int i = 0; i < r->num_fields; i++) {+    if (strcmp(r->fields[i].name, field_name) == 0) {+      field = &r->fields[i];+      break;+    }+  }++  if (field == NULL) {+    failure();+    printf("No such field\n");+  }++  struct variable *to = create_variable(s, to_name, field->type);++  if (to == NULL) {+    failure();+    printf("Variable already exists: %s\n", to_name);+    return;+  }++  field->project(s->ctx, value_ptr(&to->value), from->value.value.v_ptr);+}++void cmd_new(struct server_state *s, const char *args[]) {+  const char *to_name = get_arg(args, 0);+  const char *type_name = get_arg(args, 1);+  const struct type *type = get_type(s, type_name);+  struct variable *to = create_variable(s, to_name, type);++  if (to == NULL) {+    failure();+    printf("Variable already exists: %s\n", to_name);+    return;+  }++  const struct record* r = type->record;++  if (r == NULL) {+    failure();+    printf("Not a record type\n");+    return;+  }++  int num_args = 0;+  for (int i = 2; arg_exists(args, i); i++) {+    num_args++;+  }++  if (num_args != r->num_fields) {+    failure();+    printf("%d fields expected byt %d values provided.\n", num_args, r->num_fields);+    return;+  }++  const void** value_ptrs = alloca(num_args * sizeof(void*));++  for (int i = 0; i < num_args; i++) {+    struct variable* v = get_variable(s, args[2+i]);++    if (v == NULL) {+      failure();+      printf("Unknown variable: %s\n", args[2+i]);+      return;+    }++    if (strcmp(v->value.type->name, r->fields[i].type->name) != 0) {+      failure();+      printf("Field %s mismatch: expected type %s, got %s\n",+             r->fields[i].name, r->fields[i].type->name, v->value.type->name);+      return;+    }++    value_ptrs[i] = value_ptr(&v->value);+  }++  r->new(s->ctx, value_ptr(&to->value), value_ptrs);+}++void cmd_entry_points(struct server_state *s, const char *args[]) {+  (void)args;+  for (int i = 0; s->prog.entry_points[i].name; i++) {+    puts(s->prog.entry_points[i].name);+  }+}++void cmd_types(struct server_state *s, const char *args[]) {+  (void)args;+  for (int i = 0; s->prog.types[i] != NULL; i++) {+    puts(s->prog.types[i]->name);+  }+}+ char *next_word(char **line) {   char *p = *line; @@ -630,6 +777,16 @@     cmd_report(s, tokens+1);   } else if (strcmp(command, "set_tuning_param") == 0) {     cmd_set_tuning_param(s, tokens+1);+  } else if (strcmp(command, "fields") == 0) {+    cmd_fields(s, tokens+1);+  } else if (strcmp(command, "new") == 0) {+    cmd_new(s, tokens+1);+  } else if (strcmp(command, "project") == 0) {+    cmd_project(s, tokens+1);+  } else if (strcmp(command, "entry_points") == 0) {+    cmd_entry_points(s, tokens+1);+  } else if (strcmp(command, "types") == 0) {+    cmd_types(s, tokens+1);   } else {     futhark_panic(1, "Unknown command: %s\n", command);   }@@ -695,6 +852,7 @@   if (arr == NULL) {     return 1;   }+  assert(futhark_context_sync(ctx) == 0);    *(void**)p = arr;   free(data);@@ -717,7 +875,7 @@ }  int free_array(const struct array_aux *aux,-                struct futhark_context *ctx, void *p) {+               struct futhark_context *ctx, void *p) {   void *arr = *(void**)p;   return aux->free(ctx, arr); }@@ -769,7 +927,7 @@ }  int free_opaque(const struct opaque_aux *aux,-                 struct futhark_context *ctx, void *p) {+                struct futhark_context *ctx, void *p) {   void *obj = *(void**)p;   return aux->free(ctx, obj); }
+ rts/c/uniform.h view
@@ -0,0 +1,1708 @@++// Start of uniform.h++// Uniform versions of all library functions as to+// improve performance in ISPC when in an uniform context.++#if ISPC++static inline uniform uint8_t add8(uniform uint8_t x, uniform uint8_t y) {+  return x + y;+}++static inline uniform uint16_t add16(uniform uint16_t x, uniform uint16_t y) {+  return x + y;+}++static inline uniform uint32_t add32(uniform uint32_t x, uniform uint32_t y) {+  return x + y;+}++static inline uniform uint64_t add64(uniform uint64_t x, uniform uint64_t y) {+  return x + y;+}++static inline uniform uint8_t sub8(uniform uint8_t x, uniform uint8_t y) {+  return x - y;+}++static inline uniform uint16_t sub16(uniform uint16_t x, uniform uint16_t y) {+  return x - y;+}++static inline uniform uint32_t sub32(uniform uint32_t x, uniform uint32_t y) {+  return x - y;+}++static inline uniform uint64_t sub64(uniform uint64_t x, uniform uint64_t y) {+  return x - y;+}++static inline uniform uint8_t mul8(uniform uint8_t x, uniform uint8_t y) {+  return x * y;+}++static inline uniform uint16_t mul16(uniform uint16_t x, uniform uint16_t y) {+  return x * y;+}++static inline uniform uint32_t mul32(uniform uint32_t x, uniform uint32_t y) {+  return x * y;+}++static inline uniform uint64_t mul64(uniform uint64_t x, uniform uint64_t y) {+  return x * y;+}++static inline uniform uint8_t udiv8(uniform uint8_t x, uniform uint8_t y) {+  return x / y;+}++static inline uniform uint16_t udiv16(uniform uint16_t x, uniform uint16_t y) {+  return x / y;+}++static inline uniform uint32_t udiv32(uniform uint32_t x, uniform uint32_t y) {+  return x / y;+}++static inline uniform uint64_t udiv64(uniform uint64_t x, uniform uint64_t y) {+  return x / y;+}++static inline uniform uint8_t udiv_up8(uniform uint8_t x, uniform uint8_t y) {+  return (x + y - 1) / y;+}++static inline uniform uint16_t udiv_up16(uniform uint16_t x, uniform uint16_t y) {+  return (x + y - 1) / y;+}++static inline uniform uint32_t udiv_up32(uniform uint32_t x, uniform uint32_t y) {+  return (x + y - 1) / y;+}++static inline uniform uint64_t udiv_up64(uniform uint64_t x, uniform uint64_t y) {+  return (x + y - 1) / y;+}++static inline uniform uint8_t umod8(uniform uint8_t x, uniform uint8_t y) {+  return x % y;+}++static inline uniform uint16_t umod16(uniform uint16_t x, uniform uint16_t y) {+  return x % y;+}++static inline uniform uint32_t umod32(uniform uint32_t x, uniform uint32_t y) {+  return x % y;+}++static inline uniform uint64_t umod64(uniform uint64_t x, uniform uint64_t y) {+  return x % y;+}++static inline uniform uint8_t udiv_safe8(uniform uint8_t x, uniform uint8_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uniform uint16_t udiv_safe16(uniform uint16_t x, uniform uint16_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uniform uint32_t udiv_safe32(uniform uint32_t x, uniform uint32_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uniform uint64_t udiv_safe64(uniform uint64_t x, uniform uint64_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uniform uint8_t udiv_up_safe8(uniform uint8_t x, uniform uint8_t y) {+  return y == 0 ? 0 : (x + y - 1) / y;+}++static inline uniform uint16_t udiv_up_safe16(uniform uint16_t x, uniform uint16_t y) {+  return y == 0 ? 0 : (x + y - 1) / y;+}++static inline uniform uint32_t udiv_up_safe32(uniform uint32_t x, uniform uint32_t y) {+  return y == 0 ? 0 : (x + y - 1) / y;+}++static inline uniform uint64_t udiv_up_safe64(uniform uint64_t x, uniform uint64_t y) {+  return y == 0 ? 0 : (x + y - 1) / y;+}++static inline uniform uint8_t umod_safe8(uniform uint8_t x, uniform uint8_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uniform uint16_t umod_safe16(uniform uint16_t x, uniform uint16_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uniform uint32_t umod_safe32(uniform uint32_t x, uniform uint32_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uniform uint64_t umod_safe64(uniform uint64_t x, uniform uint64_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uniform int8_t sdiv8(uniform int8_t x, uniform int8_t y) {+  uniform int8_t q = x / y;+  uniform int8_t r = x % y;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline uniform int16_t sdiv16(uniform int16_t x, uniform int16_t y) {+  uniform int16_t q = x / y;+  uniform int16_t r = x % y;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline uniform int32_t sdiv32(uniform int32_t x, uniform int32_t y) {+  uniform int32_t q = x / y;+  uniform int32_t r = x % y;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline uniform int64_t sdiv64(uniform int64_t x, uniform int64_t y) {+  uniform int64_t q = x / y;+  uniform int64_t r = x % y;++  return q - ((r != 0 && r < 0 != y < 0) ? 1 : 0);+}++static inline uniform int8_t sdiv_up8(uniform int8_t x, uniform int8_t y) {+  return sdiv8(x + y - 1, y);+}++static inline uniform int16_t sdiv_up16(uniform int16_t x, uniform int16_t y) {+  return sdiv16(x + y - 1, y);+}++static inline uniform int32_t sdiv_up32(uniform int32_t x, uniform int32_t y) {+  return sdiv32(x + y - 1, y);+}++static inline uniform int64_t sdiv_up64(uniform int64_t x, uniform int64_t y) {+  return sdiv64(x + y - 1, y);+}++static inline uniform int8_t smod8(uniform int8_t x, uniform int8_t y) {+  uniform int8_t r = x % y;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline uniform int16_t smod16(uniform int16_t x, uniform int16_t y) {+  uniform int16_t r = x % y;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline uniform int32_t smod32(uniform int32_t x, uniform int32_t y) {+  uniform int32_t r = x % y;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline uniform int64_t smod64(uniform int64_t x, uniform int64_t y) {+  uniform int64_t r = x % y;++  return r + (r == 0 || (x > 0 && y > 0) || (x < 0 && y < 0) ? 0 : y);+}++static inline uniform int8_t sdiv_safe8(uniform int8_t x, uniform int8_t y) {+  return y == 0 ? 0 : sdiv8(x, y);+}++static inline uniform int16_t sdiv_safe16(uniform int16_t x, uniform int16_t y) {+  return y == 0 ? 0 : sdiv16(x, y);+}++static inline uniform int32_t sdiv_safe32(uniform int32_t x, uniform int32_t y) {+  return y == 0 ? 0 : sdiv32(x, y);+}++static inline uniform int64_t sdiv_safe64(uniform int64_t x, uniform int64_t y) {+  return y == 0 ? 0 : sdiv64(x, y);+}++static inline uniform int8_t sdiv_up_safe8(uniform int8_t x, uniform int8_t y) {+  return sdiv_safe8(x + y - 1, y);+}++static inline uniform int16_t sdiv_up_safe16(uniform int16_t x, uniform int16_t y) {+  return sdiv_safe16(x + y - 1, y);+}++static inline uniform int32_t sdiv_up_safe32(uniform int32_t x, uniform int32_t y) {+  return sdiv_safe32(x + y - 1, y);+}++static inline uniform int64_t sdiv_up_safe64(uniform int64_t x, uniform int64_t y) {+  return sdiv_safe64(x + y - 1, y);+}++static inline uniform int8_t smod_safe8(uniform int8_t x, uniform int8_t y) {+  return y == 0 ? 0 : smod8(x, y);+}++static inline uniform int16_t smod_safe16(uniform int16_t x, uniform int16_t y) {+  return y == 0 ? 0 : smod16(x, y);+}++static inline uniform int32_t smod_safe32(uniform int32_t x, uniform int32_t y) {+  return y == 0 ? 0 : smod32(x, y);+}++static inline uniform int64_t smod_safe64(uniform int64_t x, uniform int64_t y) {+  return y == 0 ? 0 : smod64(x, y);+}++static inline uniform int8_t squot8(uniform int8_t x, uniform int8_t y) {+  return x / y;+}++static inline uniform int16_t squot16(uniform int16_t x, uniform int16_t y) {+  return x / y;+}++static inline uniform int32_t squot32(uniform int32_t x, uniform int32_t y) {+  return x / y;+}++static inline uniform int64_t squot64(uniform int64_t x, uniform int64_t y) {+  return x / y;+}++static inline uniform int8_t srem8(uniform int8_t x, uniform int8_t y) {+  return x % y;+}++static inline uniform int16_t srem16(uniform int16_t x, uniform int16_t y) {+  return x % y;+}++static inline uniform int32_t srem32(uniform int32_t x, uniform int32_t y) {+  return x % y;+}++static inline uniform int64_t srem64(uniform int64_t x, uniform int64_t y) {+  return x % y;+}++static inline uniform int8_t squot_safe8(uniform int8_t x, uniform int8_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uniform int16_t squot_safe16(uniform int16_t x, uniform int16_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uniform int32_t squot_safe32(uniform int32_t x, uniform int32_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uniform int64_t squot_safe64(uniform int64_t x, uniform int64_t y) {+  return y == 0 ? 0 : x / y;+}++static inline uniform int8_t srem_safe8(uniform int8_t x, uniform int8_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uniform int16_t srem_safe16(uniform int16_t x, uniform int16_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uniform int32_t srem_safe32(uniform int32_t x, uniform int32_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uniform int64_t srem_safe64(uniform int64_t x, uniform int64_t y) {+  return y == 0 ? 0 : x % y;+}++static inline uniform int8_t smin8(uniform int8_t x, uniform int8_t y) {+  return x < y ? x : y;+}++static inline uniform int16_t smin16(uniform int16_t x, uniform int16_t y) {+  return x < y ? x : y;+}++static inline uniform int32_t smin32(uniform int32_t x, uniform int32_t y) {+  return x < y ? x : y;+}++static inline uniform int64_t smin64(uniform int64_t x, uniform int64_t y) {+  return x < y ? x : y;+}++static inline uniform uint8_t umin8(uniform uint8_t x, uniform uint8_t y) {+  return x < y ? x : y;+}++static inline uniform uint16_t umin16(uniform uint16_t x, uniform uint16_t y) {+  return x < y ? x : y;+}++static inline uniform uint32_t umin32(uniform uint32_t x, uniform uint32_t y) {+  return x < y ? x : y;+}++static inline uniform uint64_t umin64(uniform uint64_t x, uniform uint64_t y) {+  return x < y ? x : y;+}++static inline uniform int8_t smax8(uniform int8_t x, uniform int8_t y) {+  return x < y ? y : x;+}++static inline uniform int16_t smax16(uniform int16_t x, uniform int16_t y) {+  return x < y ? y : x;+}++static inline uniform int32_t smax32(uniform int32_t x, uniform int32_t y) {+  return x < y ? y : x;+}++static inline uniform int64_t smax64(uniform int64_t x, uniform int64_t y) {+  return x < y ? y : x;+}++static inline uniform uint8_t umax8(uniform uint8_t x, uniform uint8_t y) {+  return x < y ? y : x;+}++static inline uniform uint16_t umax16(uniform uint16_t x, uniform uint16_t y) {+  return x < y ? y : x;+}++static inline uniform uint32_t umax32(uniform uint32_t x, uniform uint32_t y) {+  return x < y ? y : x;+}++static inline uniform uint64_t umax64(uniform uint64_t x, uniform uint64_t y) {+  return x < y ? y : x;+}++static inline uniform uint8_t shl8(uniform uint8_t x, uniform uint8_t y) {+  return (uniform uint8_t)(x << y);+}++static inline uniform uint16_t shl16(uniform uint16_t x, uniform uint16_t y) {+  return (uniform uint16_t)(x << y);+}++static inline uniform uint32_t shl32(uniform uint32_t x, uniform uint32_t y) {+  return x << y;+}++static inline uniform uint64_t shl64(uniform uint64_t x, uniform uint64_t y) {+  return x << y;+}++static inline uniform uint8_t lshr8(uniform uint8_t x, uniform uint8_t y) {+  return x >> y;+}++static inline uniform uint16_t lshr16(uniform uint16_t x, uniform uint16_t y) {+  return x >> y;+}++static inline uniform uint32_t lshr32(uniform uint32_t x, uniform uint32_t y) {+  return x >> y;+}++static inline uniform uint64_t lshr64(uniform uint64_t x, uniform uint64_t y) {+  return x >> y;+}++static inline uniform int8_t ashr8(uniform int8_t x, uniform int8_t y) {+  return x >> y;+}++static inline uniform int16_t ashr16(uniform int16_t x, uniform int16_t y) {+  return x >> y;+}++static inline uniform int32_t ashr32(uniform int32_t x, uniform int32_t y) {+  return x >> y;+}++static inline uniform int64_t ashr64(uniform int64_t x, uniform int64_t y) {+  return x >> y;+}++static inline uniform uint8_t and8(uniform uint8_t x, uniform uint8_t y) {+  return x & y;+}++static inline uniform uint16_t and16(uniform uint16_t x, uniform uint16_t y) {+  return x & y;+}++static inline uniform uint32_t and32(uniform uint32_t x, uniform uint32_t y) {+  return x & y;+}++static inline uniform uint64_t and64(uniform uint64_t x, uniform uint64_t y) {+  return x & y;+}++static inline uniform uint8_t or8(uniform uint8_t x, uniform uint8_t y) {+  return x | y;+}++static inline uniform uint16_t or16(uniform uint16_t x, uniform uint16_t y) {+  return x | y;+}++static inline uniform uint32_t or32(uniform uint32_t x, uniform uint32_t y) {+  return x | y;+}++static inline uniform uint64_t or64(uniform uint64_t x, uniform uint64_t y) {+  return x | y;+}++static inline uniform uint8_t xor8(uniform uint8_t x, uniform uint8_t y) {+  return x ^ y;+}++static inline uniform uint16_t xor16(uniform uint16_t x, uniform uint16_t y) {+  return x ^ y;+}++static inline uniform uint32_t xor32(uniform uint32_t x, uniform uint32_t y) {+  return x ^ y;+}++static inline uniform uint64_t xor64(uniform uint64_t x, uniform uint64_t y) {+  return x ^ y;+}++static inline uniform bool ult8(uniform uint8_t x, uniform uint8_t y) {+  return x < y;+}++static inline uniform bool ult16(uniform uint16_t x, uniform uint16_t y) {+  return x < y;+}++static inline uniform bool ult32(uniform uint32_t x, uniform uint32_t y) {+  return x < y;+}++static inline uniform bool ult64(uniform uint64_t x, uniform uint64_t y) {+  return x < y;+}++static inline uniform bool ule8(uniform uint8_t x, uniform uint8_t y) {+  return x <= y;+}++static inline uniform bool ule16(uniform uint16_t x, uniform uint16_t y) {+  return x <= y;+}++static inline uniform bool ule32(uniform uint32_t x, uniform uint32_t y) {+  return x <= y;+}++static inline uniform bool ule64(uniform uint64_t x, uniform uint64_t y) {+  return x <= y;+}++static inline uniform bool slt8(uniform int8_t x, uniform int8_t y) {+  return x < y;+}++static inline uniform bool slt16(uniform int16_t x, uniform int16_t y) {+  return x < y;+}++static inline uniform bool slt32(uniform int32_t x, uniform int32_t y) {+  return x < y;+}++static inline uniform bool slt64(uniform int64_t x, uniform int64_t y) {+  return x < y;+}++static inline uniform bool sle8(uniform int8_t x, uniform int8_t y) {+  return x <= y;+}++static inline uniform bool sle16(uniform int16_t x, uniform int16_t y) {+  return x <= y;+}++static inline uniform bool sle32(uniform int32_t x, uniform int32_t y) {+  return x <= y;+}++static inline uniform bool sle64(uniform int64_t x, uniform int64_t y) {+  return x <= y;+}++static inline uniform uint8_t pow8(uniform uint8_t x, uniform uint8_t y) {+  uniform uint8_t res = 1, rem = y;++  while (rem != 0) {+    if (rem & 1)+      res *= x;+    rem >>= 1;+    x *= x;+  }+  return res;+}++static inline uniform uint16_t pow16(uniform uint16_t x, uniform uint16_t y) {+  uniform uint16_t res = 1, rem = y;++  while (rem != 0) {+    if (rem & 1)+      res *= x;+    rem >>= 1;+    x *= x;+  }+  return res;+}++static inline uniform uint32_t pow32(uniform uint32_t x, uniform uint32_t y) {+  uniform uint32_t res = 1, rem = y;++  while (rem != 0) {+    if (rem & 1)+      res *= x;+    rem >>= 1;+    x *= x;+  }+  return res;+}++static inline uniform uint64_t pow64(uniform uint64_t x, uniform uint64_t y) {+  uniform uint64_t res = 1, rem = y;++  while (rem != 0) {+    if (rem & 1)+      res *= x;+    rem >>= 1;+    x *= x;+  }+  return res;+}++static inline uniform bool itob_i8_bool(uniform int8_t x) {+  return x != 0;+}++static inline uniform bool itob_i16_bool(uniform int16_t x) {+  return x != 0;+}++static inline uniform bool itob_i32_bool(uniform int32_t x) {+  return x != 0;+}++static inline uniform bool itob_i64_bool(uniform int64_t x) {+  return x != 0;+}++static inline uniform int8_t btoi_bool_i8(uniform bool x) {+  return x;+}++static inline uniform int16_t btoi_bool_i16(uniform bool x) {+  return x;+}++static inline uniform int32_t btoi_bool_i32(uniform bool x) {+  return x;+}++static inline uniform int64_t btoi_bool_i64(uniform bool x) {+  return x;+}+++static uniform int8_t abs8(uniform int8_t x) {+  return (uniform int8_t)abs(x);+}++static uniform int16_t abs16(uniform int16_t x) {+  return (uniform int16_t)abs(x);+}++static uniform int32_t abs32(uniform int32_t x) {+  return abs(x);+}++static uniform int64_t abs64(uniform int64_t x) {+  return abs(x);+}++static uniform int32_t futrts_popc8(uniform uint8_t x) {+  uniform int c = 0;+  for (; x; ++c) { x &= x - 1; }+  return c;+}++static uniform int32_t futrts_popc16(uniform uint16_t x) {+  uniform int c = 0;+  for (; x; ++c) { x &= x - 1; }+  return c;+}++static uniform int32_t futrts_popc32(uniform uint32_t x) {+  uniform int c = 0;+  for (; x; ++c) { x &= x - 1; }+  return c;+}++static uniform int32_t futrts_popc64(uniform uint64_t x) {+  uniform int c = 0;+  for (; x; ++c) { x &= x - 1; }+  return c;+}++static uniform uint8_t futrts_mul_hi8(uniform uint8_t a, uniform uint8_t b) {+  uniform uint16_t aa = a;+  uniform uint16_t bb = b;++  return aa * bb >> 8;+}++static uniform uint16_t futrts_mul_hi16(uniform uint16_t a, uniform uint16_t b) {+  uniform uint32_t aa = a;+  uniform uint32_t bb = b;++  return aa * bb >> 16;+}++static uniform uint32_t futrts_mul_hi32(uniform uint32_t a, uniform uint32_t b) {+  uniform uint64_t aa = a;+  uniform uint64_t bb = b;++  return aa * bb >> 32;+}++static uniform uint64_t futrts_mul_hi64(uniform uint64_t a, uniform uint64_t b) {+  uniform uint64_t ah = a >> 32;+  uniform uint64_t al = a & 0xffffffff;+  uniform uint64_t bh = b >> 32;+  uniform uint64_t bl = b & 0xffffffff;++  uniform uint64_t p1 = al * bl;+  uniform uint64_t p2 = al * bh;+  uniform uint64_t p3 = ah * bl;+  uniform uint64_t p4 = ah * bh;++  uniform uint64_t p1h = p1 >> 32;+  uniform uint64_t p2h = p2 >> 32;+  uniform uint64_t p3h = p3 >> 32;+  uniform uint64_t p2l = p2 & 0xffffffff;+  uniform uint64_t p3l = p3 & 0xffffffff;++  uniform uint64_t l = p1h + p2l  + p3l;+  uniform uint64_t m = (p2 >> 32) + (p3 >> 32);+  uniform uint64_t h = (l >> 32) + m + p4;++  return h;+}++static uniform uint8_t futrts_mad_hi8(uniform uint8_t a, uniform uint8_t b, uniform uint8_t c) {+  return futrts_mul_hi8(a, b) + c;+}++static uniform uint16_t futrts_mad_hi16(uniform uint16_t a, uniform uint16_t b, uniform uint16_t c) {+  return futrts_mul_hi16(a, b) + c;+}++static uniform uint32_t futrts_mad_hi32(uniform uint32_t a, uniform uint32_t b, uniform uint32_t c) {+  return futrts_mul_hi32(a, b) + c;+}++static uniform uint64_t futrts_mad_hi64(uniform uint64_t a, uniform uint64_t b, uniform uint64_t c) {+  return futrts_mul_hi64(a, b) + c;+}++static uniform int32_t futrts_clzz8(uniform int8_t x) {+  return count_leading_zeros((uniform int32_t)(uniform uint8_t)x)-24;+}++static uniform int32_t futrts_clzz16(uniform int16_t x) {+  return count_leading_zeros((uniform int32_t)(uniform uint16_t)x)-16;+}++static uniform int32_t futrts_clzz32(uniform int32_t x) {+  return count_leading_zeros(x);+}++static uniform int32_t futrts_clzz64(uniform int64_t x) {+  return count_leading_zeros(x);+}++static uniform int32_t futrts_ctzz8(uniform int8_t x) {+  return x == 0 ? 8 : count_trailing_zeros((uniform int32_t)x);+}++static uniform int32_t futrts_ctzz16(uniform int16_t x) {+  return x == 0 ? 16 : count_trailing_zeros((uniform int32_t)x);+}++static uniform int32_t futrts_ctzz32(uniform int32_t x) {+  return count_trailing_zeros(x);+}++static uniform int32_t futrts_ctzz64(uniform int64_t x) {+  return count_trailing_zeros(x);+}+++static inline uniform float fdiv32(uniform float x, uniform float y) {+  return x / y;+}++static inline uniform float fadd32(uniform float x, uniform float y) {+  return x + y;+}++static inline uniform float fsub32(uniform float x, uniform float y) {+  return x - y;+}++static inline uniform float fmul32(uniform float x, uniform float y) {+  return x * y;+}++static inline uniform bool cmplt32(uniform float x, uniform float y) {+  return x < y;+}++static inline uniform bool cmple32(uniform float x, uniform float y) {+  return x <= y;+}++static inline uniform float sitofp_i8_f32(uniform int8_t x) {+  return (uniform float) x;+}++static inline uniform float sitofp_i16_f32(uniform int16_t x) {+  return (uniform float) x;+}++static inline uniform float sitofp_i32_f32(uniform int32_t x) {+  return (uniform float) x;+}++static inline uniform float sitofp_i64_f32(uniform int64_t x) {+  return (uniform float) x;+}++static inline uniform float uitofp_i8_f32(uniform uint8_t x) {+  return (uniform float) x;+}++static inline uniform float uitofp_i16_f32(uniform uint16_t x) {+  return (uniform float) x;+}++static inline uniform float uitofp_i32_f32(uniform uint32_t x) {+  return (uniform float) x;+}++static inline uniform float uitofp_i64_f32(uniform uint64_t x) {+  return (uniform float) x;+}+++static inline uniform float fabs32(uniform float x) {+  return abs(x);+}++static inline uniform float fmax32(uniform float x, uniform float y) {+  return isnan(x) ? y : isnan(y) ? x : max(x, y);+}++static inline uniform float fmin32(uniform float x, uniform float y) {+  return isnan(x) ? y : isnan(y) ? x : min(x, y);+}++static inline uniform float fpow32(uniform float x, uniform float y) {+  return __stdlib_powf(x, y);+}++static inline uniform bool futrts_isnan32(uniform float x) {+  return isnan(x);+}++static inline uniform bool futrts_isinf32(uniform float x) {+  return !isnan(x) && isnan(x - x);+}+static inline uniform bool futrts_isfinite32(uniform float x) {+  return !isnan(x) && !futrts_isinf32(x);+}+++static inline uniform int8_t fptosi_f32_i8(uniform float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uniform int8_t) x;+  }+}++static inline uniform int16_t fptosi_f32_i16(uniform float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uniform int16_t) x;+  }+}++static inline uniform int32_t fptosi_f32_i32(uniform float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uniform int32_t) x;+  }+}++static inline uniform int64_t fptosi_f32_i64(uniform float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uniform int64_t) x;+  };+}++static inline uniform uint8_t fptoui_f32_i8(uniform float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uniform uint8_t) (uniform int8_t) x;+  }+}++static inline uniform uint16_t fptoui_f32_i16(uniform float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uniform uint16_t) (uniform int16_t) x;+  }+}++static inline uniform uint32_t fptoui_f32_i32(uniform float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uniform uint32_t) (uniform int32_t) x;+  }+}++static inline uniform uint64_t fptoui_f32_i64(uniform float x) {+  if (futrts_isnan32(x) || futrts_isinf32(x)) {+    return 0;+  } else {+    return (uniform uint64_t) (uniform int64_t) x;+  }+}+++static inline uniform float futrts_log32(uniform float x) {+  return futrts_isfinite32(x) || (futrts_isinf32(x) && x < 0)? log(x) : x;+}++static inline uniform float futrts_log2_32(uniform float x) {+  return futrts_log32(x) / log(2.0f);+}++static inline uniform float futrts_log10_32(uniform float x) {+  return futrts_log32(x) / log(10.0f);+}++static inline uniform float futrts_sqrt32(uniform float x) {+  return sqrt(x);+}++extern "C" unmasked uniform float cbrtf(uniform float);+static inline uniform float futrts_cbrt32(uniform float x) {+  return cbrtf(x);+}++static inline uniform float futrts_exp32(uniform float x) {+  return exp(x);+}++static inline uniform float futrts_cos32(uniform float x) {+  return cos(x);+}++static inline uniform float futrts_sin32(uniform float x) {+  return sin(x);+}++static inline uniform float futrts_tan32(uniform float x) {+  return tan(x);+}++static inline uniform float futrts_acos32(uniform float x) {+  return acos(x);+}++static inline uniform float futrts_asin32(uniform float x) {+  return asin(x);+}++static inline uniform float futrts_atan32(uniform float x) {+  return atan(x);+}++static inline uniform float futrts_cosh32(uniform float x) {+  return (exp(x)+exp(-x)) / 2.0f;+}++static inline uniform float futrts_sinh32(uniform float x) {+  return (exp(x)-exp(-x)) / 2.0f;+}++static inline uniform float futrts_tanh32(uniform float x) {+  return futrts_sinh32(x)/futrts_cosh32(x);+}++static inline uniform float futrts_acosh32(uniform float x) {+  uniform float f = x+sqrt(x*x-1);+  if(futrts_isfinite32(f)) return log(f);+  return f;+}++static inline uniform float futrts_asinh32(uniform float x) {+  uniform float f = x+sqrt(x*x+1);+  if(futrts_isfinite32(f)) return log(f);+  return f;++}++static inline uniform float futrts_atanh32(uniform float x) {+  uniform float f = (1+x)/(1-x);+  if(futrts_isfinite32(f)) return log(f)/2.0f;+  return f;++}++static inline uniform float futrts_atan2_32(uniform float x, uniform float y) {+  return (x == 0.0f && y == 0.0f) ? 0.0f : atan2(x, y);+}++static inline uniform float futrts_hypot32(uniform float x, uniform float y) {+  if (futrts_isfinite32(x) && futrts_isfinite32(y)) {+    x = abs(x);+    y = abs(y);+    uniform float a;+    uniform float b;+    if (x >= y){+        a = x;+        b = y;+    } else {+        a = y;+        b = x;+    }+    if(b == 0){+      return a;+    }++    uniform int e;+    uniform float an;+    uniform float bn;+    an = frexp (a, &e);+    bn = ldexp (b, - e);+    uniform float cn;+    cn = sqrt (an * an + bn * bn);+    return ldexp (cn, e);+  } else {+    if (futrts_isinf32(x) || futrts_isinf32(y)) return INFINITY;+    else return x + y;+  }++}++extern "C" unmasked uniform float tgammaf(uniform float x);+static inline uniform float futrts_gamma32(uniform float x) {+  return tgammaf(x);+}++extern "C" unmasked uniform float tgammaf(uniform float x);+static inline uniform float futrts_lgamma32(uniform float x) {+  return lgammaf(x);+}++extern "C" unmasked uniform float erff(uniform float);+static inline uniform float futrts_erf32(uniform float x) {+  return erff(x);+}++extern "C" unmasked uniform float erfcf(uniform float);+static inline uniform float futrts_erfc32(uniform float x) {+  return erfcf(x);+}++static inline uniform float fmod32(uniform float x, uniform float y) {+  return x - y * trunc(x/y);+}++static inline uniform float futrts_round32(uniform float x) {+  return round(x);+}++static inline uniform float futrts_floor32(uniform float x) {+  return floor(x);+}++static inline uniform float futrts_ceil32(uniform float x) {+  return ceil(x);+}++static inline uniform float futrts_lerp32(uniform float v0, uniform float v1, uniform float t) {+  return v0 + (v1 - v0) * t;+}++static inline uniform float futrts_mad32(uniform float a, uniform float b, uniform float c) {+  return a * b + c;+}++static inline uniform float futrts_fma32(uniform float a, uniform float b, uniform float c) {+  return a * b + c;+}++static inline uniform int32_t futrts_to_bits32(uniform float x) {+  return intbits(x);+}++static inline uniform float futrts_from_bits32(uniform int32_t x) {+  return floatbits(x);+}++static inline uniform float fsignum32(uniform float x) {+  return futrts_isnan32(x) ? x : (x > 0 ? 1 : 0) - (x < 0 ? 1 : 0);+}++#ifdef FUTHARK_F64_ENABLED++static inline uniform bool futrts_isinf64(uniform float x) {+  return !isnan(x) && isnan(x - x);+}+static inline uniform bool futrts_isfinite64(uniform float x) {+  return !isnan(x) && !futrts_isinf64(x);+}++static inline uniform double fdiv64(uniform double x, uniform double y) {+  return x / y;+}++static inline uniform double fadd64(uniform double x, uniform double y) {+  return x + y;+}++static inline uniform double fsub64(uniform double x, uniform double y) {+  return x - y;+}++static inline uniform double fmul64(uniform double x, uniform double y) {+  return x * y;+}++static inline uniform bool cmplt64(uniform double x, uniform double y) {+  return x < y;+}++static inline uniform bool cmple64(uniform double x, uniform double y) {+  return x <= y;+}++static inline uniform double sitofp_i8_f64(uniform int8_t x) {+  return (uniform double) x;+}++static inline uniform double sitofp_i16_f64(uniform int16_t x) {+  return (uniform double) x;+}++static inline uniform double sitofp_i32_f64(uniform int32_t x) {+  return (uniform double) x;+}++static inline uniform double sitofp_i64_f64(uniform int64_t x) {+  return (uniform double) x;+}++static inline uniform double uitofp_i8_f64(uniform uint8_t x) {+  return (uniform double) x;+}++static inline uniform double uitofp_i16_f64(uniform uint16_t x) {+  return (uniform double) x;+}++static inline uniform double uitofp_i32_f64(uniform uint32_t x) {+  return (uniform double) x;+}++static inline uniform double uitofp_i64_f64(uniform uint64_t x) {+  return (uniform double) x;+}++static inline uniform double fabs64(uniform double x) {+  return abs(x);+}++static inline uniform double fmax64(uniform double x, uniform double y) {+  return isnan(x) ? y : isnan(y) ? x : max(x, y);+}++static inline uniform double fmin64(uniform double x, uniform double y) {+  return isnan(x) ? y : isnan(y) ? x : min(x, y);+}++static inline uniform double fpow64(uniform double x, uniform double y) {+  return __stdlib_powf(x, y);+}++static inline uniform double futrts_log64(uniform double x) {+  return futrts_isfinite64(x) || (futrts_isinf64(x) && x < 0)? log(x) : x;+}++static inline uniform double futrts_log2_64(uniform double x) {+  return futrts_log64(x)/log(2.0d);+}++static inline uniform double futrts_log10_64(uniform double x) {+  return futrts_log64(x)/log(10.0d);+}++static inline uniform double futrts_sqrt64(uniform double x) {+  return sqrt(x);+}++extern "C" unmasked uniform double cbrt(uniform double);+static inline uniform double futrts_cbrt64(uniform double x) {+  return cbrt(x);+}++static inline uniform double futrts_exp64(uniform double x) {+  return exp(x);+}++static inline uniform double futrts_cos64(uniform double x) {+  return cos(x);+}++static inline uniform double futrts_sin64(uniform double x) {+  return sin(x);+}++static inline uniform double futrts_tan64(uniform double x) {+  return tan(x);+}++static inline uniform double futrts_acos64(uniform double x) {+  return acos(x);+}++static inline uniform double futrts_asin64(uniform double x) {+  return asin(x);+}++static inline uniform double futrts_atan64(uniform double x) {+  return atan(x);+}++static inline uniform double futrts_cosh64(uniform double x) {+  return (exp(x)+exp(-x)) / 2.0d;+}++static inline uniform double futrts_sinh64(uniform double x) {+  return (exp(x)-exp(-x)) / 2.0d;+}++static inline uniform double futrts_tanh64(uniform double x) {+  return futrts_sinh64(x)/futrts_cosh64(x);+}++static inline uniform double futrts_acosh64(uniform double x) {+  uniform double f = x+sqrt(x*x-1.0d);+  if(futrts_isfinite64(f)) return log(f);+  return f;+}++static inline uniform double futrts_asinh64(uniform double x) {+  uniform double f = x+sqrt(x*x+1.0d);+  if(futrts_isfinite64(f)) return log(f);+  return f;+}++static inline uniform double futrts_atanh64(uniform double x) {+  uniform double f = (1.0d+x)/(1.0d-x);+  if(futrts_isfinite64(f)) return log(f)/2.0d;+  return f;++}++static inline uniform double futrts_atan2_64(uniform double x, uniform double y) {+  return atan2(x, y);+}++extern "C" unmasked uniform double hypot(uniform double x, uniform double y);+static inline uniform double futrts_hypot64(uniform double x, uniform double y) {+  return hypot(x, y);+}++extern "C" unmasked uniform double tgamma(uniform double x);+static inline uniform double futrts_gamma64(uniform double x) {+  return tgamma(x);+}++extern "C" unmasked uniform double lgamma(uniform double x);+static inline uniform double futrts_lgamma64(uniform double x) {+  return lgamma(x);+}++extern "C" unmasked uniform double erf(uniform double);+static inline uniform double futrts_erf64(uniform double x) {+  return erf(x);+}++extern "C" unmasked uniform double erfc(uniform double);+static inline uniform double futrts_erfc64(uniform double x) {+  return erfc(x);+}++static inline uniform double futrts_fma64(uniform double a, uniform double b, uniform double c) {+  return a * b + c;+}++static inline uniform double futrts_round64(uniform double x) {+  return round(x);+}++static inline uniform double futrts_ceil64(uniform double x) {+  return ceil(x);+}++static inline uniform double futrts_floor64(uniform double x) {+  return floor(x);+}++static inline uniform bool futrts_isnan64(uniform double x) {+  return isnan(x);+}++static inline uniform int8_t fptosi_f64_i8(uniform double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uniform int8_t) x;+  }+}++static inline uniform int16_t fptosi_f64_i16(uniform double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uniform int16_t) x;+  }+}++static inline uniform int32_t fptosi_f64_i32(uniform double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uniform int32_t) x;+  }+}++static inline uniform int64_t fptosi_f64_i64(uniform double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uniform int64_t) x;+  }+}++static inline uniform uint8_t fptoui_f64_i8(uniform double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uniform uint8_t) (uniform int8_t) x;+  }+}++static inline uniform uint16_t fptoui_f64_i16(uniform double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uniform uint16_t) (uniform int16_t) x;+  }+}++static inline uniform uint32_t fptoui_f64_i32(uniform double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uniform uint32_t) (uniform int32_t) x;+  }+}++static inline uniform uint64_t fptoui_f64_i64(uniform double x) {+  if (futrts_isnan64(x) || futrts_isinf64(x)) {+    return 0;+  } else {+    return (uniform uint64_t) (uniform int64_t) x;+  }+}++static inline uniform bool ftob_f64_bool(uniform double x) {+  return x != 0.0;+}++static inline uniform double btof_bool_f64(uniform bool x) {+  return x ? 1.0 : 0.0;+}++static inline uniform bool ftob_f32_bool(uniform float x) {+  return x != 0;+}++static inline uniform float btof_bool_f32(uniform bool x) {+  return x ? 1 : 0;+}++static inline uniform int64_t futrts_to_bits64(uniform double x) {+  return *((uniform int64_t* uniform)&x);+}++static inline uniform double futrts_from_bits64(uniform int64_t x) {+  return *((uniform double* uniform)&x);+}++static inline uniform double fmod64(uniform double x, uniform double y) {+  return x - y * trunc(x/y);+}++static inline uniform double fsignum64(uniform double x) {+  return futrts_isnan64(x) ? x : (x > 0 ? 1.0d : 0.0d) - (x < 0 ? 1.0d : 0.0d);+}++static inline uniform double futrts_lerp64(uniform double v0, uniform double v1, uniform double t) {+  return v0 + (v1 - v0) * t;+}++static inline uniform double futrts_mad64(uniform double a, uniform double b, uniform double c) {+  return a * b + c;+}++static inline uniform float fpconv_f32_f32(uniform float x) {+  return (uniform float) x;+}++static inline uniform double fpconv_f32_f64(uniform float x) {+  return (uniform double) x;+}++static inline uniform float fpconv_f64_f32(uniform double x) {+  return (uniform float) x;+}++static inline uniform double fpconv_f64_f64(uniform double x) {+  return (uniform double) x;+}++static inline uniform double fpconv_f16_f64(uniform f16 x) {+  return (uniform double) x;+}++static inline uniform f16 fpconv_f64_f16(uniform double x) {+  return (uniform f16) ((uniform float)x); +}++#endif+++static inline uniform f16 fadd16(uniform f16 x, uniform f16 y) {+  return x + y;+}++static inline uniform f16 fsub16(uniform f16 x, uniform f16 y) {+  return x - y;+}++static inline uniform f16 fmul16(uniform f16 x, uniform f16 y) {+  return x * y;+}++static inline uniform bool cmplt16(uniform f16 x, uniform f16 y) {+  return x < y;+}++static inline uniform bool cmple16(uniform f16 x, uniform f16 y) {+  return x <= y;+}++static inline uniform f16 sitofp_i8_f16(uniform int8_t x) {+  return (uniform f16) x;+}++static inline uniform f16 sitofp_i16_f16(uniform int16_t x) {+  return (uniform f16) x;+}++static inline uniform f16 sitofp_i32_f16(uniform int32_t x) {+  return (uniform f16) x;+}++static inline uniform f16 sitofp_i64_f16(uniform int64_t x) {+  return (uniform f16) x;+}++static inline uniform f16 uitofp_i8_f16(uniform uint8_t x) {+  return (uniform f16) x;+}++static inline uniform f16 uitofp_i16_f16(uniform uint16_t x) {+  return (uniform f16) x;+}++static inline uniform f16 uitofp_i32_f16(uniform uint32_t x) {+  return (uniform f16) x;+}++static inline uniform f16 uitofp_i64_f16(uniform uint64_t x) {+  return (uniform f16) x;+}++static inline uniform int8_t fptosi_f16_i8(uniform f16 x) {+  return (uniform int8_t) (uniform float) x;+}++static inline uniform int16_t fptosi_f16_i16(uniform f16 x) {+  return (uniform int16_t) x;+}++static inline uniform int32_t fptosi_f16_i32(uniform f16 x) {+  return (uniform int32_t) x;+}++static inline uniform int64_t fptosi_f16_i64(uniform f16 x) {+  return (uniform int64_t) x;+}++static inline uniform uint8_t fptoui_f16_i8(uniform f16 x) {+  return (uniform uint8_t) (uniform float) x;+}++static inline uniform uint16_t fptoui_f16_i16(uniform f16 x) {+  return (uniform uint16_t) x;+}++static inline uniform uint32_t fptoui_f16_i32(uniform f16 x) {+  return (uniform uint32_t) x;+}++static inline uniform uint64_t fptoui_f16_i64(uniform f16 x) {+  return (uniform uint64_t) x;+}++static inline uniform f16 fabs16(uniform f16 x) {+  return abs(x);+}++static inline uniform bool futrts_isnan16(uniform f16 x) {+  return isnan((uniform float)x);+}++static inline uniform f16 fmax16(uniform f16 x, uniform f16 y) {+  return futrts_isnan16(x) ? y : futrts_isnan16(y) ? x : max(x, y);+}++static inline uniform f16 fmin16(uniform f16 x, uniform f16 y) {+  return min(x, y);+}++static inline uniform f16 fpow16(uniform f16 x, uniform f16 y) {+  return pow(x, y);+}++static inline uniform bool futrts_isinf16(uniform float x) {+  return !futrts_isnan16(x) && futrts_isnan16(x - x);+}+static inline uniform bool futrts_isfinite16(uniform float x) {+  return !futrts_isnan16(x) && !futrts_isinf16(x);+}+++static inline uniform f16 futrts_log16(uniform f16 x) {+  return futrts_isfinite16(x) || (futrts_isinf16(x) && x < 0)? log(x) : x;+}++static inline uniform f16 futrts_log2_16(uniform f16 x) {+  return futrts_log16(x) / log(2.0f16);+}++static inline uniform f16 futrts_log10_16(uniform f16 x) {+  return futrts_log16(x) / log(10.0f16);+}++static inline uniform f16 futrts_sqrt16(uniform f16 x) {+  return (uniform f16)sqrt((uniform float)x);+}++extern "C" unmasked uniform float cbrtf(uniform float);+static inline uniform f16 futrts_cbrt16(uniform f16 x) {+  return (uniform f16)cbrtf((uniform float)x);+}++static inline uniform f16 futrts_exp16(uniform f16 x) {+  return exp(x);+}++static inline uniform f16 futrts_cos16(uniform f16 x) {+  return (uniform f16)cos((uniform float)x);+}++static inline uniform f16 futrts_sin16(uniform f16 x) {+  return (uniform f16)sin((uniform float)x);+}++static inline uniform f16 futrts_tan16(uniform f16 x) {+  return (uniform f16)tan((uniform float)x);+}++static inline uniform f16 futrts_acos16(uniform f16 x) {+  return (uniform f16)acos((uniform float)x);+}++static inline uniform f16 futrts_asin16(uniform f16 x) {+  return (uniform f16)asin((uniform float)x);+}++static inline uniform f16 futrts_atan16(uniform f16 x) {+  return (uniform f16)atan((uniform float)x);+}++static inline uniform f16 futrts_cosh16(uniform f16 x) {+  return (exp(x)+exp(-x)) / 2.0f16;+}++static inline uniform f16 futrts_sinh16(uniform f16 x) {+  return (exp(x)-exp(-x)) / 2.0f16;+}++static inline uniform f16 futrts_tanh16(uniform f16 x) {+  return futrts_sinh16(x)/futrts_cosh16(x);+}++static inline uniform f16 futrts_acosh16(uniform f16 x) {+  uniform f16 f = x+(uniform f16)sqrt((uniform float)(x*x-1));+  if(futrts_isfinite16(f)) return log(f);+  return f;+}++static inline uniform f16 futrts_asinh16(uniform f16 x) {+  uniform f16 f = x+(uniform f16)sqrt((uniform float)(x*x+1));+  if(futrts_isfinite16(f)) return log(f);+  return f;+}++static inline uniform f16 futrts_atanh16(uniform f16 x) {+  uniform f16 f = (1+x)/(1-x);+  if(futrts_isfinite16(f)) return log(f)/2.0f16;+  return f;+}++static inline uniform f16 futrts_atan2_16(uniform f16 x, uniform f16 y) {+  return (uniform f16)atan2((uniform float)x, (uniform float)y);+}++static inline uniform f16 futrts_hypot16(uniform f16 x, uniform f16 y) {+  return (uniform f16)futrts_hypot32((uniform float)x, (uniform float)y);+}++extern "C" unmasked uniform float tgammaf(uniform float x);+static inline uniform f16 futrts_gamma16(uniform f16 x) {+  return (uniform f16)tgammaf((uniform float)x);+}++extern "C" unmasked uniform float lgammaf(uniform float x);+static inline uniform f16 futrts_lgamma16(uniform f16 x) {+  return (uniform f16)lgammaf((uniform float)x);+}++extern "C" unmasked uniform float erff(uniform float);+static inline uniform f16 futrts_erf32(uniform f16 x) {+  return (uniform f16)erff((uniform float)x);+}++extern "C" unmasked uniform float erfcf(uniform float);+static inline uniform f16 futrts_erfc32(uniform f16 x) {+  return (uniform f16)erfcf((uniform float)x);+}++static inline uniform f16 fmod16(uniform f16 x, uniform f16 y) {+  return x - y * (uniform f16)trunc((uniform float) (x/y));+}++static inline uniform f16 futrts_round16(uniform f16 x) {+  return (uniform f16)round((uniform float)x);+}++static inline uniform f16 futrts_floor16(uniform f16 x) {+  return (uniform f16)floor((uniform float)x);+}++static inline uniform f16 futrts_ceil16(uniform f16 x) {+  return (uniform f16)ceil((uniform float)x);+}++static inline uniform f16 futrts_lerp16(uniform f16 v0, uniform f16 v1, uniform f16 t) {+  return v0 + (v1 - v0) * t;+}++static inline uniform f16 futrts_mad16(uniform f16 a, uniform f16 b, uniform f16 c) {+  return a * b + c;+}++static inline uniform f16 futrts_fma16(uniform f16 a, uniform f16 b, uniform f16 c) {+  return a * b + c;+}++static inline uniform int16_t futrts_to_bits16(uniform f16 x) {+  return *((uniform int16_t *)&x);+}++static inline uniform f16 futrts_from_bits16(uniform int16_t x) {+  return *((uniform f16 *)&x);+}++static inline uniform float fpconv_f16_f16(uniform f16 x) {+  return x;+}++static inline uniform float fpconv_f16_f32(uniform f16 x) {+  return x;+}++static inline uniform f16 fpconv_f32_f16(uniform float x) {+  return (uniform f16) x;+}+#endif++// End of uniform.h.
rts/c/util.h view
@@ -135,6 +135,11 @@   b->used += needed; } +char * lexical_realloc_error(size_t new_size) {+  return msgprintf("Failed to allocate memory.\nAttempted allocation: %12lld bytes\n",+                       (long long) new_size);+}+ static int lexical_realloc(char **error, unsigned char **ptr, int64_t *old_size, int64_t new_size) {   unsigned char *new = realloc(*ptr, (size_t)new_size);   if (new == NULL) {
rts/python/server.py view
@@ -151,6 +151,14 @@             if reader.get_char() != b'':                 raise self.Failure('Expected EOF after reading values') +    def _cmd_types(self, args):+        for k in self._ctx.opaques.keys():+            print(k)++    def _cmd_entry_points(self, args):+        for k in self._ctx.entry_points.keys():+            print(k)+     _commands = { 'inputs': _cmd_inputs,                   'outputs': _cmd_outputs,                   'call': _cmd_call,@@ -161,7 +169,9 @@                   'clear': _cmd_dummy,                   'pause_profiling': _cmd_dummy,                   'unpause_profiling': _cmd_dummy,-                  'report': _cmd_dummy+                  'report': _cmd_dummy,+                  'types': _cmd_types,+                  'entry_points': _cmd_entry_points,                  }      def _process_line(self, line):
src/Futhark/AD/Derivatives.hs view
@@ -10,7 +10,7 @@  import Data.Bifunctor (bimap) import Futhark.Analysis.PrimExp.Convert-import Futhark.IR.Syntax.Core+import Futhark.IR.Syntax.Core (Name, VName) import Futhark.Util.IntegralExp import Prelude hiding (quot) 
src/Futhark/AD/Fwd.hs view
@@ -277,8 +277,8 @@  zeroFromSubExp :: SubExp -> ADM VName zeroFromSubExp (Constant c) =-  letExp "zero" $-    BasicOp $ SubExp $ Constant $ blankPrimValue $ primValueType c+  letExp "zero" . BasicOp . SubExp . Constant $+    blankPrimValue (primValueType c) zeroFromSubExp (Var v) = do   t <- lookupType v   letExp "zero" $ zeroExp t@@ -432,16 +432,16 @@   val_pats' <- bundleNew val_pats   pat' <- bundleNew pat   body' <--    localScope (scopeOfFParams (map fst val_pats) <> scopeOf loop) $-      slocal' $ fwdBody body+    localScope (scopeOfFParams (map fst val_pats) <> scopeOf loop) . slocal' $+      fwdBody body   addStm $ Let pat' aux $ DoLoop val_pats' (WhileLoop v) body' fwdStm (Let pat aux (DoLoop val_pats loop@(ForLoop i it bound loop_vars) body)) = do   pat' <- bundleNew pat   val_pats' <- bundleNew val_pats   loop_vars' <- bundleNew loop_vars   body' <--    localScope (scopeOfFParams (map fst val_pats) <> scopeOf loop) $-      slocal' $ fwdBody body+    localScope (scopeOfFParams (map fst val_pats) <> scopeOf loop) . slocal' $+      fwdBody body   addStm $ Let pat' aux $ DoLoop val_pats' (ForLoop i it bound loop_vars') body' fwdStm (Let pat aux (WithAcc inputs lam)) = do   inputs' <- forM inputs $ \(shape, arrs, op) -> do
src/Futhark/AD/Rev.hs view
@@ -135,15 +135,15 @@       returnSweepCode $ do         arr_dims <- arrayDims <$> lookupType arr         void $-          updateAdj arr <=< letExp "adj_reshape" $-            BasicOp $ Reshape (map DimNew arr_dims) pat_adj+          updateAdj arr <=< letExp "adj_reshape" . BasicOp $+            Reshape (map DimNew arr_dims) pat_adj     --     Rearrange perm arr -> do       (_pat_v, pat_adj) <- commonBasicOp pat aux e m       returnSweepCode $         void $-          updateAdj arr <=< letExp "adj_rearrange" $-            BasicOp $ Rearrange (rearrangeInverse perm) pat_adj+          updateAdj arr <=< letExp "adj_rearrange" . BasicOp $+            Rearrange (rearrangeInverse perm) pat_adj     --     Rotate rots arr -> do       (_pat_v, pat_adj) <- commonBasicOp pat aux e m@@ -151,8 +151,8 @@         let neg = BasicOp . BinOp (Sub Int64 OverflowWrap) (intConst Int64 0)         rots' <- mapM (letSubExp "rot_neg" . neg) rots         void $-          updateAdj arr <=< letExp "adj_rotate" $-            BasicOp $ Rotate rots' pat_adj+          updateAdj arr <=< letExp "adj_rotate" . BasicOp $+            Rotate rots' pat_adj     --     Replicate (Shape ns) x -> do       (_pat_v, pat_adj) <- commonBasicOp pat aux e m@@ -162,8 +162,8 @@         ne <- letSubExp "zero" $ zeroExp x_t         n <- letSubExp "rep_size" =<< foldBinOp (Mul Int64 OverflowUndef) (intConst Int64 1) ns         pat_adj_flat <--          letExp (baseString pat_adj <> "_flat") $-            BasicOp $ Reshape (map DimNew $ n : arrayDims x_t) pat_adj+          letExp (baseString pat_adj <> "_flat") . BasicOp $+            Reshape (map DimNew $ n : arrayDims x_t) pat_adj         reduce <- reduceSOAC [Reduce Commutative lam [ne]]         updateSubExpAdj x           =<< letExp "rep_contrib" (Op $ Screma n [pat_adj_flat] reduce)@@ -178,7 +178,8 @@                   slice = DimSlice start w (intConst Int64 1)               pat_adj_slice <-                 letExp (baseString pat_adj <> "_slice") $-                  BasicOp $ Index pat_adj (sliceAt v_t d [slice])+                  BasicOp $+                    Index pat_adj (sliceAt v_t d [slice])               start' <- letSubExp "start" $ BasicOp $ BinOp (Add Int64 OverflowUndef) start w               slices <- sliceAdj start' vs               pure $ pat_adj_slice : slices
src/Futhark/AD/Rev/Loop.hs view
@@ -71,8 +71,8 @@     let indexify (x_param, xs) = do           xs_t <- lookupType xs           x' <--            letExp (baseString $ paramName x_param) $-              BasicOp $ Index xs $ fullSlice xs_t [DimFix (Var i)]+            letExp (baseString $ paramName x_param) . BasicOp . Index xs $+              fullSlice xs_t [DimFix (Var i)]           pure (paramName x_param, x')     (substs_list, subst_stms) <- collectStms $ mapM indexify loop_vars     let Body aux' stms' res' = substituteNames (M.fromList substs_list) body@@ -136,25 +136,24 @@                     loop_inits' = map (Var . paramName) loop_params                     val_pats'' = zip loop_params' loop_inits'                 outer_body <--                  buildBody_ $-                    do-                      offset' <--                        letSubExp "offset" $-                          BasicOp $ BinOp (Mul it OverflowUndef) offset (Var i)+                  buildBody_ $ do+                    offset' <-+                      letSubExp "offset" . BasicOp $+                        BinOp (Mul it OverflowUndef) offset (Var i) -                      inner_body <- insertStmsM $ do-                        i_inner <--                          letExp "i_inner" $-                            BasicOp $ BinOp (Add it OverflowUndef) offset' (Var i')-                        pure $ substituteNames (M.singleton i' i_inner) body'+                    inner_body <- insertStmsM $ do+                      i_inner <-+                        letExp "i_inner" . BasicOp $+                          BinOp (Add it OverflowUndef) offset' (Var i')+                      pure $ substituteNames (M.singleton i' i_inner) body' -                      inner_loop <--                        letTupExp "inner_loop"-                          =<< nestifyLoop'-                            offset'-                            (n - 1)-                            (DoLoop val_pats'' (ForLoop i' it' bound_se loop_vars') inner_body)-                      pure $ varsRes inner_loop+                    inner_loop <-+                      letTupExp "inner_loop"+                        =<< nestifyLoop'+                          offset'+                          (n - 1)+                          (DoLoop val_pats'' (ForLoop i' it' bound_se loop_vars') inner_body)+                    pure $ varsRes inner_loop                 pure $                   DoLoop val_pats (ForLoop i it bound_se loop_vars) outer_body           | n == 1 =@@ -174,8 +173,8 @@     bound' <- letSubExp "bound" $ BasicOp $ BinOp (FPow Float64) bound_float n_root     bound_int <- letSubExp "bound_int" $ BasicOp $ ConvOp (FPToUI Float64 it) bound'     total_iters <--      letSubExp "total_iters" $-        BasicOp $ BinOp (Pow it) bound_int (Constant $ IntValue $ intValue it n)+      letSubExp "total_iters" . BasicOp $+        BinOp (Pow it) bound_int (Constant $ IntValue $ intValue it n)     remain_iters <-       letSubExp "remain_iters" $ BasicOp $ BinOp (Sub it OverflowUndef) bound total_iters     mined_loop <- nestifyLoop bound_int n loop@@ -183,8 +182,8 @@     renameForLoop loop $ \_loop' val_pats' _form' i' it' _bound' loop_vars' body' -> do       remain_body <- insertStmsM $ do         i_remain <--          letExp "i_remain" $-            BasicOp $ BinOp (Add it OverflowUndef) total_iters (Var i')+          letExp "i_remain" . BasicOp $+            BinOp (Add it OverflowUndef) total_iters (Var i')         pure $ substituteNames (M.singleton i' i_remain) body'       let loop_params_rem = map fst val_pats'           loop_inits_rem = map (Var . patElemName) $ patElems pat'@@ -246,12 +245,15 @@               let saved_param = Param mempty saved_param_v $ arrayOf t (Shape [bound64]) Unique                   saved_pat = PatElem saved_pat_v $ arrayOf t (Shape [bound64]) NoUniqueness               saved_update <--                localScope (scopeOfFParams [saved_param]) $-                  letInPlace+                localScope (scopeOfFParams [saved_param])+                  $ letInPlace                     (baseString v <> "_saved_update")                     saved_param_v                     (fullSlice (fromDecl $ paramDec saved_param) [DimFix i_i64])-                    $ substituteNames copy_substs $ BasicOp $ SubExp $ Var v+                  $ substituteNames copy_substs+                  $ BasicOp+                  $ SubExp+                  $ Var v               pure (saved_update, (saved_pat, saved_param))           pure (bodyResult body <> varsRes saved_updates, unzip saved_pats_params) @@ -286,18 +288,17 @@         forM (map snd loop_vars) $ \xs -> do           xs_t <- lookupType xs           xs_rev <--            letExp "reverse" $-              BasicOp $-                Index xs $-                  fullSlice-                    xs_t-                    [DimSlice bound_minus_one bound (Constant (IntValue (Int64Value (-1))))]+            letExp "reverse" . BasicOp . Index xs $+              fullSlice+                xs_t+                [DimSlice bound_minus_one bound (Constant (IntValue (Int64Value (-1))))]           pure (xs, xs_rev)      (i_rev, i_stms) <- collectStms $       inScopeOf form $ do         letExp (baseString i <> "_rev") $-          BasicOp $ BinOp (Sub it OverflowWrap) bound_minus_one (Var i)+          BasicOp $+            BinOp (Sub it OverflowWrap) bound_minus_one (Var i)      pure (var_arrays_substs, M.singleton i i_rev, i_stms) 
src/Futhark/AD/Rev/Map.hs view
@@ -104,8 +104,8 @@           inBounds res_i adj_i adj_v = subAD . buildRenamedBody $ do             forM_ (zip (lambdaParams map_lam) as) $ \(p, a) -> do               a_t <- lookupType a-              letBindNames [paramName p] $-                BasicOp $ Index a $ fullSlice a_t [DimFix adj_i]+              letBindNames [paramName p] . BasicOp . Index a $+                fullSlice a_t [DimFix adj_i]             adj_elems <-               fmap (map resSubExp) . bodyBind . lambdaBody                 =<< vjpLambda ops (oneHot res_i (AdjVal adj_v)) adjs_for map_lam@@ -228,6 +228,6 @@           zero <- letSubExp "zero" $ zeroExp t           reduce <- reduceSOAC [Reduce Commutative lam [zero]]           contrib_sum <--            letExp (baseString v <> "_contrib_sum") $-              Op $ Screma w [contribs] reduce+            letExp (baseString v <> "_contrib_sum") . Op $+              Screma w [contribs] reduce           void $ updateAdj v contrib_sum
src/Futhark/AD/Rev/Monad.hs view
@@ -29,7 +29,6 @@     updateAdjIndex,     setAdj,     insAdj,-    insSubExpAdj,     adjsReps,     --     copyConsumedArrsInStm,@@ -138,7 +137,8 @@   | otherwise = do       zero <- letSubExp "zero" $ zeroExp t       attributing (oneAttr "sequential") $-        letExp "zeroes_" $ BasicOp $ Replicate shape zero+        letExp "zeroes_" . BasicOp $+          Replicate shape zero  sparseArray :: (MonadBuilder m, Rep m ~ SOACS) => Sparse -> m VName sparseArray (Sparse shape t ivs) = do@@ -390,8 +390,8 @@           dims <- arrayDims <$> lookupType d           ~[v_adj'] <-             tabNest (length dims) [d, v_adj] $ \is [d', v_adj'] ->-              letTupExp "acc" $-                BasicOp $ UpdateAcc v_adj' (map Var is) [Var d']+              letTupExp "acc" . BasicOp $+                UpdateAcc v_adj' (map Var is) [Var d']           insAdj v v_adj'         _ -> do           v_adj' <- letExp (baseString v <> "_adj") =<< addExp v_adj d@@ -411,7 +411,8 @@         tabNest (length dims) [d, v_adj] $ \is [d', v_adj'] -> do           slice' <-             traverse (toSubExp "index") $-              fixSlice (fmap pe64 slice) $ map le64 is+              fixSlice (fmap pe64 slice) $+                map le64 is           letTupExp (baseString v_adj') . BasicOp $             UpdateAcc v_adj' slice' [Var d']       pure v_adj'@@ -427,10 +428,6 @@ updateSubExpAdj Constant {} _ = pure () updateSubExpAdj (Var v) d = void $ updateAdj v d -insSubExpAdj :: SubExp -> VName -> ADM ()-insSubExpAdj Constant {} _ = pure ()-insSubExpAdj (Var v) d = void $ insAdj v d- -- The index may be negative, in which case the update has no effect. updateAdjIndex :: VName -> (InBounds, SubExp) -> SubExp -> ADM () updateAdjIndex v (check, i) se = do@@ -457,15 +454,18 @@                 dims <- arrayDims <$> lookupType se_v                 ~[v_adj'] <-                   tabNest (length dims) [se_v, v_adj] $ \is [se_v', v_adj'] ->-                    letTupExp "acc" $-                      BasicOp $ UpdateAcc v_adj' (i : map Var is) [Var se_v']+                    letTupExp "acc" . BasicOp $+                      UpdateAcc v_adj' (i : map Var is) [Var se_v']                 pure v_adj'           _ -> do             let stms s = do-                  v_adj_i <- letExp (baseString v_adj <> "_i") $ BasicOp $ Index v_adj $ fullSlice v_adj_t [DimFix i]+                  v_adj_i <-+                    letExp (baseString v_adj <> "_i") . BasicOp $+                      Index v_adj $+                        fullSlice v_adj_t [DimFix i]                   se_update <- letSubExp "updated_adj_i" =<< addExp se_v v_adj_i-                  letExp (baseString v_adj) $-                    BasicOp $ Update s v_adj (fullSlice v_adj_t [DimFix i]) se_update+                  letExp (baseString v_adj) . BasicOp $+                    Update s v_adj (fullSlice v_adj_t [DimFix i]) se_update             case check of               CheckBounds _ -> stms Safe               AssumeBounds -> stms Unsafe
src/Futhark/AD/Rev/Reduce.hs view
@@ -23,8 +23,8 @@   arr_t <- lookupType arr   let w = arraySize 0 arr_t   start <--    letSubExp "rev_start" $-      BasicOp $ BinOp (Sub Int64 OverflowUndef) w (intConst Int64 1)+    letSubExp "rev_start" . BasicOp $+      BinOp (Sub Int64 OverflowUndef) w (intConst Int64 1)   let stride = intConst Int64 (-1)       slice = fullSlice arr_t [DimSlice start w stride]   letExp (baseString arr <> "_rev") $ BasicOp $ Index arr slice@@ -91,7 +91,9 @@     isAdd op = do       adj_rep <-         letExp (baseString adj <> "_rep") $-          BasicOp $ Replicate (Shape [w]) $ Var adj+          BasicOp $+            Replicate (Shape [w]) $+              Var adj       void $ updateAdj a adj_rep   where     isAdd FAdd {} = True@@ -190,7 +192,8 @@    red_iota <-     letExp "red_iota" $-      BasicOp $ Iota w (intConst Int64 0) (intConst Int64 1) Int64+      BasicOp $+        Iota w (intConst Int64 0) (intConst Int64 1) Int64   form <- reduceSOAC [Reduce Commutative red_lam [ne, intConst Int64 (-1)]]   x_ind <- newVName (baseString x <> "_ind")   auxing aux $ letBindNames [x, x_ind] $ Op $ Screma w [as, red_iota] form
src/Futhark/AD/Rev/Scan.hs view
@@ -82,7 +82,9 @@   nm1 <- letSubExp "nm1" =<< toExp (pe64 w - 1)   y_adj_last <-     letExp (baseString y_adj ++ "_last") $-      BasicOp $ Index y_adj $ fullSlice arr_tp [DimFix nm1]+      BasicOp $+        Index y_adj $+          fullSlice arr_tp [DimFix nm1]    par_i <- newParam "i" $ Prim int64   lam <- mkLambda [par_i] $ do
src/Futhark/AD/Rev/Scatter.hs view
@@ -113,7 +113,8 @@     -- creating xs_adj     zeros <-       replicateM (length val_as) . letExp "zeros" $-        zeroExp $ xs_t `setOuterSize` w+        zeroExp $+          xs_t `setOuterSize` w     let f_tps = replicate (rank * num_vals) (Prim int64) ++ replicate num_vals val_t     f <- mkIdentityLambda f_tps     xs_adj <-
src/Futhark/Actions.hs view
@@ -19,6 +19,7 @@     compileOpenCLAction,     compileCUDAAction,     compileMulticoreAction,+    compileMulticoreToISPCAction,     compileMulticoreToWASMAction,     compilePythonAction,     compilePyOpenCLAction,@@ -40,6 +41,7 @@ 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.MulticoreISPC as MulticoreISPC import qualified Futhark.CodeGen.Backends.MulticoreWASM as MulticoreWASM import qualified Futhark.CodeGen.Backends.PyOpenCL as PyOpenCL import qualified Futhark.CodeGen.Backends.SequentialC as SequentialC@@ -149,7 +151,7 @@   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 ImpGenMulticore.AllowDynamicScheduling+      actionProcedure = liftIO . putStrLn . pretty . snd <=< ImpGenMulticore.compileProg     }  -- Lines that we prepend (in comments) to generated code.@@ -174,6 +176,9 @@ cmdCFLAGS :: [String] -> [String] cmdCFLAGS def = maybe def words $ lookup "CFLAGS" unixEnvironment +cmdISPCFLAGS :: [String] -> [String]+cmdISPCFLAGS def = maybe def words $ lookup "ISPCFLAGS" unixEnvironment+ runCC :: String -> String -> [String] -> [String] -> FutharkM () runCC cpath outpath cflags_def ldflags = do   ret <-@@ -192,13 +197,58 @@       externalErrorS $ "Failed to run " ++ cmdCC ++ ": " ++ show err     Right (ExitFailure code, _, gccerr) ->       externalErrorS $-        cmdCC ++ " failed with code "+        cmdCC+          ++ " failed with code "           ++ show code           ++ ":\n"           ++ gccerr     Right (ExitSuccess, _, _) ->       pure () +runISPC :: String -> String -> String -> String -> [String] -> [String] -> [String] -> FutharkM ()+runISPC ispcpath outpath cpath ispcextension ispc_flags cflags_def ldflags = do+  ret_ispc <-+    liftIO $+      runProgramWithExitCode+        "ispc"+        ( [ispcpath, "-o", ispcbase `addExtension` "o"]+            ++ ["--addressing=64", "--pic"]+            ++ cmdISPCFLAGS ispc_flags -- These flags are always needed+        )+        mempty+  ret <-+    liftIO $+      runProgramWithExitCode+        cmdCC+        ( [ispcbase `addExtension` "o"]+            ++ [cpath, "-o", outpath]+            ++ cmdCFLAGS cflags_def+            +++            -- The default LDFLAGS are always added.+            ldflags+        )+        mempty+  case ret_ispc of+    Left err ->+      externalErrorS $ "Failed to run " ++ cmdCC ++ ": " ++ show err+    Right (ExitFailure code, _, gccerr) -> throwError code gccerr+    Right (ExitSuccess, _, _) ->+      case ret of+        Left err ->+          externalErrorS $ "Failed to run ispc: " ++ show err+        Right (ExitFailure code, _, gccerr) -> throwError code gccerr+        Right (ExitSuccess, _, _) ->+          pure ()+  where+    ispcbase = outpath <> ispcextension+    throwError code gccerr =+      externalErrorS $+        cmdCC+          ++ " failed with code "+          ++ show code+          ++ ":\n"+          ++ gccerr+ -- | The @futhark c@ action. compileCAction :: FutharkConfig -> CompilerMode -> FilePath -> Action SeqMem compileCAction fcfg mode outpath =@@ -321,6 +371,38 @@         ToServer -> do           liftIO $ T.writeFile cpath $ cPrependHeader $ MulticoreC.asServer cprog           runCC cpath outpath ["-O3", "-std=c99"] ["-lm", "-pthread"]++-- | The @futhark ispc@ action.+compileMulticoreToISPCAction :: FutharkConfig -> CompilerMode -> FilePath -> Action MCMem+compileMulticoreToISPCAction fcfg mode outpath =+  Action+    { actionName = "Compile to multicore ISPC",+      actionDescription = "Compile to multicore ISPC",+      actionProcedure = helper+    }+  where+    helper prog = do+      let cpath = outpath `addExtension` "c"+          hpath = outpath `addExtension` "h"+          jsonpath = outpath `addExtension` "json"+          ispcpath = outpath `addExtension` "kernels.ispc"+          ispcextension = "_ispc"+      (cprog, ispc) <- handleWarnings fcfg $ MulticoreISPC.compileProg (T.pack versionString) prog+      case mode of+        ToLibrary -> do+          let (header, impl, manifest) = MulticoreC.asLibrary cprog+          liftIO $ T.writeFile hpath $ cPrependHeader header+          liftIO $ T.writeFile cpath $ cPrependHeader impl+          liftIO $ T.writeFile ispcpath ispc+          liftIO $ T.writeFile jsonpath manifest+        ToExecutable -> do+          liftIO $ T.writeFile cpath $ cPrependHeader $ MulticoreC.asExecutable cprog+          liftIO $ T.writeFile ispcpath ispc+          runISPC ispcpath outpath cpath ispcextension ["-O3", "--woff"] ["-O3", "-std=c99"] ["-lm", "-pthread"]+        ToServer -> do+          liftIO $ T.writeFile cpath $ cPrependHeader $ MulticoreC.asServer cprog+          liftIO $ T.writeFile ispcpath ispc+          runISPC ispcpath outpath cpath ispcextension ["-O3", "--woff"] ["-O3", "-std=c99"] ["-lm", "-pthread"]  pythonCommon ::   (CompilerMode -> String -> prog -> FutharkM (Warnings, T.Text)) ->
src/Futhark/Analysis/Alias.hs view
@@ -29,8 +29,11 @@   (ASTRep rep, CanBeAliased (Op rep)) =>   Prog rep ->   Prog (Aliases rep)-aliasAnalysis (Prog consts funs) =-  Prog (fst (analyseStms mempty consts)) (map analyseFun funs)+aliasAnalysis prog =+  prog+    { progConsts = fst (analyseStms mempty (progConsts prog)),+      progFuns = map analyseFun (progFuns prog)+    }  -- | Perform alias analysis on function. analyseFun ::@@ -95,7 +98,8 @@         any (`nameIn` unAliases cons) $           v : namesToList (M.findWithDefault mempty v aliases)       notConsumed =-        AliasDec . namesFromList+        AliasDec+          . namesFromList           . filter (not . isConsumed)           . namesToList           . unAliases
src/Futhark/Analysis/CallGraph.hs view
@@ -10,7 +10,6 @@     calledByConsts,     allCalledBy,     numOccurences,-    findNoninlined,   ) where @@ -141,39 +140,6 @@             pure body         } --- | The set of all functions that are called noinline somewhere, or--- have a noinline attribute on their definition.-findNoninlined :: Prog SOACS -> S.Set Name-findNoninlined prog =-  foldMap noinlineDef (progFuns prog)-    <> foldMap onStm (foldMap (bodyStms . funDefBody) (progFuns prog) <> progConsts prog)-  where-    onStm :: Stm SOACS -> S.Set Name-    onStm (Let _ aux (Apply fname _ _ _))-      | "noinline" `inAttrs` stmAuxAttrs aux =-          S.singleton fname-    onStm (Let _ _ e) = execWriter $ mapExpM folder e-      where-        folder =-          identityMapper-            { mapOnBody = \_ body -> do-                tell $ foldMap onStm $ bodyStms body-                pure body,-              mapOnOp =-                mapSOACM-                  identitySOACMapper-                    { mapOnSOACLambda = \lam -> do-                        tell $ foldMap onStm $ bodyStms $ lambdaBody lam-                        pure lam-                    }-            }--    noinlineDef fd-      | "noinline" `inAttrs` funDefAttrs fd =-          S.singleton $ funDefName fd-      | otherwise =-          mempty- instance Pretty FunCalls where   ppr = stack . map f . M.toList . fcMap     where@@ -186,5 +152,6 @@         ppFunCalls ("called at top level", cg) : map ppFunCalls (M.toList fg)     where       ppFunCalls (f, fcalls) =-        ppr f </> text (map (const '=') (nameToString f))+        ppr f+          </> text (map (const '=') (nameToString f))           </> indent 2 (ppr fcalls)
src/Futhark/Analysis/HORep/MapNest.hs view
@@ -153,7 +153,8 @@   let nparams = zipWith (Param mempty) npnames $ map SOAC.inputRowType inps   body <- runBodyBuilder $     localScope (scopeOfLParams nparams) $ do-      letBindNames nres =<< SOAC.toExp+      letBindNames nres+        =<< SOAC.toExp         =<< toSOAC (MapNest nw lam ns $ map (SOAC.identInput . paramIdent) nparams)       pure $ resultBody $ map Var nres   let outerlam =
src/Futhark/Analysis/HORep/SOAC.hs view
@@ -41,6 +41,7 @@     -- * SOAC inputs     Input (..),     varInput,+    inputTransforms,     identInput,     isVarInput,     isVarishInput,@@ -52,6 +53,7 @@     inputRowType,     transformRows,     transposeInput,+    applyTransforms,      -- ** Input transformations     ArrayTransforms,@@ -286,38 +288,46 @@ addInitialTransforms :: ArrayTransforms -> Input -> Input addInitialTransforms ts (Input ots a t) = Input (ts <> ots) a t +applyTransform :: MonadBuilder m => ArrayTransform -> VName -> m VName+applyTransform (Replicate cs n) ia =+  certifying cs . letExp "repeat" . BasicOp $+    Futhark.Replicate n (Futhark.Var ia)+applyTransform (Rearrange cs perm) ia = do+  r <- arrayRank <$> lookupType ia+  certifying cs . letExp "rearrange" . BasicOp $+    Futhark.Rearrange (perm ++ [length perm .. r - 1]) ia+applyTransform (Reshape cs shape) ia =+  certifying cs . letExp "reshape" . BasicOp $+    Futhark.Reshape shape ia+applyTransform (ReshapeOuter cs shape) ia = do+  shape' <- reshapeOuter shape 1 . arrayShape <$> lookupType ia+  certifying cs . letExp "reshape_outer" . BasicOp $+    Futhark.Reshape shape' ia+applyTransform (ReshapeInner cs shape) ia = do+  shape' <- reshapeInner shape 1 . arrayShape <$> lookupType ia+  certifying cs . letExp "reshape_inner" . BasicOp $+    Futhark.Reshape shape' ia++applyTransforms :: MonadBuilder m => ArrayTransforms -> VName -> m VName+applyTransforms (ArrayTransforms ts) a = foldlM (flip applyTransform) a ts+ -- | Convert SOAC inputs to the corresponding expressions. inputsToSubExps ::   (MonadBuilder m) =>   [Input] ->   m [VName]-inputsToSubExps = mapM inputToExp'+inputsToSubExps = mapM f   where-    inputToExp' (Input (ArrayTransforms ts) a _) =-      foldlM transform a ts--    transform ia (Replicate cs n) =-      certifying cs $-        letExp "repeat" $ BasicOp $ Futhark.Replicate n (Futhark.Var ia)-    transform ia (Rearrange cs perm) =-      certifying cs $-        letExp "rearrange" $ BasicOp $ Futhark.Rearrange perm ia-    transform ia (Reshape cs shape) =-      certifying cs $-        letExp "reshape" $ BasicOp $ Futhark.Reshape shape ia-    transform ia (ReshapeOuter cs shape) = do-      shape' <- reshapeOuter shape 1 . arrayShape <$> lookupType ia-      certifying cs $-        letExp "reshape_outer" $ BasicOp $ Futhark.Reshape shape' ia-    transform ia (ReshapeInner cs shape) = do-      shape' <- reshapeInner shape 1 . arrayShape <$> lookupType ia-      certifying cs $-        letExp "reshape_inner" $ BasicOp $ Futhark.Reshape shape' ia+    f (Input ts a _) = applyTransforms ts a  -- | Return the array name of the input. inputArray :: Input -> VName inputArray (Input _ v _) = v +-- | The transformations applied to an input.+inputTransforms :: Input -> ArrayTransforms+inputTransforms (Input ts _ _) = ts+ -- | Return the type of an input. inputType :: Input -> Type inputType (Input (ArrayTransforms ts) _ at) =@@ -398,7 +408,8 @@ instance PrettyRep rep => PP.Pretty (SOAC rep) where   ppr (Screma w form arrs) = Futhark.ppScrema w arrs form   ppr (Hist len ops bucket_fun imgs) = Futhark.ppHist len imgs ops bucket_fun-  ppr soac = text $ show soac+  ppr (Stream w form lam nes arrs) = Futhark.ppStream w arrs form nes lam+  ppr (Scatter w lam arrs dests) = Futhark.ppScatter w arrs lam dests  -- | Returns the inputs used in a SOAC. inputs :: SOAC rep -> [Input]@@ -606,14 +617,16 @@                   lastel_tmp_ids                   scan0_ids               lelstm =-                mkLet lastel_ids $-                  If+                mkLet lastel_ids+                  $ If                     (Futhark.Var $ identName empty_arr)                     (mkBody mempty $ subExpsRes nes)                     ( mkBody (stmsFromList leltmpstms) $-                        varsRes $ map identName lastel_tmp_ids+                        varsRes $+                          map identName lastel_tmp_ids                     )-                    $ ifCommon $ map identType lastel_tmp_ids+                  $ ifCommon+                  $ map identType lastel_tmp_ids           -- 4. let strm_resids = map (acc `+`,nes, scan0_ids)           maplam <- mkMapPlusAccLam (map (Futhark.Var . paramName) inpacc_ids) scan_lam           let mapstm =
src/Futhark/Analysis/Interference.hs view
@@ -282,10 +282,11 @@     memSizesExp :: LocalScope GPUMem m => Exp GPUMem -> m (Map VName Int)     memSizesExp (Op (Inner (SegOp segop))) =       let body = segBody segop-       in inScopeOf (kernelBodyStms body) $-            fmap mconcat+       in inScopeOf (kernelBodyStms body)+            $ fmap mconcat               <$> mapM memSizesStm-              $ stmsToList $ kernelBodyStms body+            $ stmsToList+            $ kernelBodyStms body     memSizesExp (If _ then_body else_body _) = do       then_res <- memSizes $ bodyStms then_body       else_res <- memSizes $ bodyStms else_body@@ -333,7 +334,8 @@         pure (res1 <> res2)     helper stm@Let {stmExp = DoLoop merge _ body} =       fmap (analyseLoopParams merge) . inScopeOf stm $-        analyseGPU' lumap $ bodyStms body+        analyseGPU' lumap $+          bodyStms body     helper stm =       inScopeOf stm $ pure mempty 
src/Futhark/Analysis/LastUse.hs view
@@ -5,7 +5,14 @@ {-# LANGUAGE TypeFamilies #-}  -- | Provides last-use analysis for Futhark programs.-module Futhark.Analysis.LastUse (LastUseMap, Used, analyseGPUMem, analyseSeqMem) where+module Futhark.Analysis.LastUse+  ( LastUseMap,+    LastUse,+    Used,+    analyseGPUMem,+    analyseSeqMem,+  )+where  import Control.Monad.Reader import Data.Bifunctor (first)@@ -19,17 +26,17 @@ import Futhark.IR.GPUMem import Futhark.IR.SeqMem --- | `LastUseMap` tells which names were last used in a given statement.--- Statements are uniquely identified by the `VName` of the first value--- parameter in the statement pattern. `Names` is the set of names last used.+-- | 'LastUseMap' tells which names were last used in a given statement.+-- Statements are uniquely identified by the 'VName' of the first value+-- parameter in the statement pattern. 'Names' is the set of names last used. type LastUseMap = Map VName Names --- | `LastUse` is a mapping from a `VName` to the statement identifying it's--- last use. `LastUseMap` is the inverse of `LastUse`.+-- | 'LastUse' is a mapping from a 'VName' to the statement identifying it's+-- last use. 'LastUseMap' is the inverse of 'LastUse'. type LastUse = Map VName VName --- | `Used` is the set of `VName` that were used somewhere in a statement, body--- or otherwise.+-- | 'Used' is the set of 'VName' that were used somewhere in a+-- statement, body or otherwise. type Used = Names  type LastUseOp rep =@@ -189,7 +196,10 @@ analyseHistOp (lumap, used) (HistOp width race dest neutral shp lambda) = do   (lumap', used') <- analyseLambda (lumap, used) lambda   let nms =-        ( freeIn width <> freeIn race <> freeIn dest <> freeIn neutral+        ( freeIn width+            <> freeIn race+            <> freeIn dest+            <> freeIn neutral             <> freeIn shp         )           `namesSubtract` used'
src/Futhark/Analysis/MemAlias.hs view
@@ -1,10 +1,10 @@ {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-}  module Futhark.Analysis.MemAlias   ( analyzeSeqMem,     analyzeGPUMem,-    canBeSameMemory,     aliasesOf,     MemAliases,   )@@ -45,7 +45,9 @@   mempty = MemAliases mempty  instance Pretty MemAliases where-  ppr (MemAliases m) = ppr m+  ppr (MemAliases m) = stack $ map f $ M.toList m+    where+      f (v, vs) = ppr v <+> "aliases:" </> indent 2 (oneLine $ ppr vs)  addAlias :: VName -> VName -> MemAliases -> MemAliases addAlias v1 v2 m =@@ -54,15 +56,6 @@ singleton :: VName -> Names -> MemAliases singleton v ns = MemAliases $ M.singleton v ns -canBeSameMemory :: MemAliases -> VName -> VName -> Bool-canBeSameMemory (MemAliases m) v1 v2 =-  case fmap (v2 `nameIn`) (M.lookup v1 m) of-    Just True -> True-    Just False -> case fmap (v1 `nameIn`) (M.lookup v2 m) of-      Just b -> b-      Nothing -> error $ "VName not found in MemAliases: " <> pretty v2-    Nothing -> error $ "VName not found in MemAliases: " <> pretty v1- aliasesOf :: MemAliases -> VName -> Names aliasesOf (MemAliases m) v = fromMaybe mempty $ M.lookup v m @@ -82,7 +75,9 @@   analyzeStms (kernelBodyStms kbody) m analyzeHostOp m (SegOp (SegHist _ _ _ _ kbody)) =   analyzeStms (kernelBodyStms kbody) m-analyzeHostOp _ _ = pure mempty+analyzeHostOp m SizeOp {} = pure m+analyzeHostOp m GPUBody {} = pure m+analyzeHostOp m (OtherOp ()) = pure m  analyzeStm :: (Mem rep inner, LetDec rep ~ LetDecMem) => MemAliases -> Stm rep -> MemAliasesM inner MemAliases analyzeStm m (Let (Pat [PatElem vname _]) _ (Op (Alloc _ _))) =
src/Futhark/Analysis/PrimExp.hs view
@@ -27,7 +27,7 @@     constFoldPrimExp,      -- * Construction-    module Futhark.IR.Primitive,+    module Language.Futhark.Primitive,     NumExp (..),     IntExp (..),     FloatExp (..),@@ -75,10 +75,10 @@ import qualified Data.Map as M import qualified Data.Set as S import Data.Traversable-import Futhark.IR.Primitive import Futhark.IR.Prop.Names import Futhark.Util.IntegralExp import Futhark.Util.Pretty+import Language.Futhark.Primitive import Prelude hiding (id, (.))  -- | A primitive expression parametrised over the representation of
src/Futhark/Analysis/PrimExp/Convert.hs view
@@ -45,7 +45,9 @@   toExp (ValueExp v) =     pure $ BasicOp $ SubExp $ Constant v   toExp (FunExp h args t) =-    Apply (nameFromString h) <$> args' <*> pure [primRetType t]+    Apply (nameFromString h)+      <$> args'+      <*> pure [primRetType t]       <*> pure (Safe, mempty, [])     where       args' = zip <$> mapM (toSubExp "apply_arg") args <*> pure (repeat Observe)
src/Futhark/Analysis/PrimExp/Parse.hs view
@@ -15,8 +15,8 @@ import qualified Data.Text as T import Data.Void import Futhark.Analysis.PrimExp-import Futhark.IR.Primitive.Parse import Futhark.Util.Pretty (prettyText)+import Language.Futhark.Primitive.Parse import Text.Megaparsec  pBinOp :: Parsec Void T.Text BinOp
src/Futhark/Analysis/Rephrase.hs view
@@ -35,10 +35,10 @@  -- | Rephrase an entire program. rephraseProg :: Monad m => Rephraser m from to -> Prog from -> m (Prog to)-rephraseProg rephraser (Prog consts funs) =-  Prog-    <$> mapM (rephraseStm rephraser) consts-    <*> mapM (rephraseFunDef rephraser) funs+rephraseProg rephraser prog = do+  consts <- mapM (rephraseStm rephraser) (progConsts prog)+  funs <- mapM (rephraseFunDef rephraser) (progFuns prog)+  pure $ prog {progConsts = consts, progFuns = funs}  -- | Rephrase a function definition. rephraseFunDef :: Monad m => Rephraser m from to -> FunDef from -> m (FunDef to)
src/Futhark/Analysis/SymbolTable.hs view
@@ -422,7 +422,8 @@    in vtable         { bindings =             adjustSeveral isSize dims $-              M.insert name entry' $ bindings vtable+              M.insert name entry' $+                bindings vtable         }  insertEntries ::
src/Futhark/Analysis/UsageTable.hs view
@@ -66,8 +66,10 @@ expand look (UsageTable m) = UsageTable $ foldl' grow m $ IM.toList m   where     grow m' (k, v) =-      foldl' (grow'' $ v `withoutU` presentU) m' $-        namesIntMap $ look $ VName (nameFromString "") k+      foldl'+        (grow'' $ v `withoutU` presentU)+        m'+        (namesIntMap $ look $ VName (nameFromString "") k)     grow'' v m'' k = IM.insertWith (<>) (baseTag k) v m''  is :: Usages -> VName -> UsageTable -> Bool@@ -171,9 +173,7 @@ usageInExp :: Aliased rep => Exp rep -> UsageTable usageInExp (Apply _ args _ _) =   mconcat-    [ mconcat $-        map consumedUsage $-          namesToList $ subExpAliases arg+    [ mconcat $ map consumedUsage $ namesToList $ subExpAliases arg       | (arg, d) <- args,         d == Consume     ]
src/Futhark/Bench.hs view
@@ -373,7 +373,9 @@     Left err ->       pure $         Left-          ( "Reference output generation for " ++ program ++ " failed:\n"+          ( "Reference output generation for "+              ++ program+              ++ " failed:\n"               ++ unlines (map T.unpack err),             Nothing           )
src/Futhark/Builder.hs view
@@ -105,7 +105,13 @@   lookupType name = do     t <- BuilderT $ gets $ M.lookup name . snd     case t of-      Nothing -> error $ "BuilderT.lookupType: unknown variable " ++ pretty name+      Nothing -> do+        known <- BuilderT $ gets $ M.keys . snd+        error . unlines $+          [ "BuilderT.lookupType: unknown variable " ++ pretty name,+            "Known variables: ",+            unwords $ map pretty known+          ]       Just t' -> pure $ typeOf t'   askScope = BuilderT $ gets snd 
src/Futhark/CLI/Autotune.hs view
@@ -99,10 +99,10 @@  serverOptions :: AutotuneOptions -> [String] serverOptions opts =-  "--default-threshold" :-  show (optDefaultThreshold opts) :-  "-L" :-  optExtraOptions opts+  "--default-threshold"+    : show (optDefaultThreshold opts)+    : "-L"+    : optExtraOptions opts  setTuningParam :: Server -> String -> Int -> IO () setTuningParam server name val =@@ -177,7 +177,7 @@           ropts = runOptions timeout opts        when (optVerbose opts > 1) $-        putStrLn $ "Trying path: " ++ show path+        putStrLn ("Trying path: " ++ show path)        -- Setting the tuning parameters is a stateful action, so we       -- must be careful to restore the defaults below.  This is@@ -235,7 +235,8 @@   let root (v, _) = ((v, False), [])   pure $     unfoldForest (unfold thresholds) $-      map root $ filter (null . snd) thresholds+      map root $+        filter (null . snd) thresholds   where     getThresholds = mapMaybe findThreshold . lines     regex = makeRegex ("(.*) \\(threshold\\(([^ ]+,)(.*)\\)\\)" :: String)@@ -245,14 +246,14 @@       [grp1, _, grp2] <- regexGroups regex l       pure         ( grp1,-          filter (not . null . fst) $-            map+          filter (not . null . fst)+            $ map               ( \x ->                   if "!" `isPrefixOf` x                     then (drop 1 x, False)                     else (x, True)               )-              $ words grp2+            $ words grp2         )      unfold thresholds ((parent, parent_cmp), ancestors) =@@ -294,7 +295,8 @@       if not $ isPrefixOf (T.unpack entry_point ++ ".") v         then do           when (optVerbose opts > 0) $-            putStrLn $ unwords [v, "is irrelevant for", T.unpack entry_point]+            putStrLn $+              unwords [v, "is irrelevant for", T.unpack entry_point]           pure (thresholds, best_runtimes)         else do           putStrLn $@@ -340,7 +342,8 @@                         pure Nothing                when (optVerbose opts > 1) $-                putStrLn $ unwords ("Got ePars: " : map show ePars)+                putStrLn $+                  unwords ("Got ePars: " : map show ePars)                (best_t, newMax) <- binarySearch runner (t, tMax) ePars               let newMinIdx = do@@ -417,7 +420,8 @@               pure (best_t, best_e_par)         (_, _) -> do           when (optVerbose opts > 0) $-            putStrLn $ unwords ["Trying e_pars", show xs]+            putStrLn $+              unwords ["Trying e_pars", show xs]           candidates <-             catMaybes . zipWith (fmap . flip (,)) xs               <$> mapM (runner $ timeout best_t) xs@@ -434,7 +438,10 @@    forest <- thresholdForest prog   when (optVerbose opts > 0) $-    putStrLn $ ("Threshold forest:\n" ++) $ drawForest $ map (fmap show) forest+    putStrLn $+      ("Threshold forest:\n" ++) $+        drawForest $+          map (fmap show) forest    let progbin = "." </> dropExtension prog   putStrLn $ "Running with options: " ++ unwords (serverOptions opts)
src/Futhark/CLI/Bench.hs view
@@ -115,7 +115,8 @@       <> show (optMinTime opts)       <> ")."   when (optConvergencePhase opts) . putStrLn $-    "More runs automatically performed for up to " <> show (optConvergenceMaxTime opts)+    "More runs automatically performed for up to "+      <> show (optConvergenceMaxTime opts)       <> " to ensure accurate measurement."    futhark <- FutharkExe . compFuthark <$> compileOptions opts@@ -266,7 +267,8 @@  interimResult :: Int -> Int -> Double -> T.Text interimResult us_sum runs elapsed =-  T.pack (printf "%10.0fμs " avg) <> progress elapsed+  T.pack (printf "%10.0fμs " avg)+    <> progress elapsed     <> (" " <> prettyText runs <> " runs")   where     avg :: Double
src/Futhark/CLI/Check.hs view
@@ -30,5 +30,7 @@     [file] -> Just $ do       (warnings, _, _) <- readProgramOrDie file       when (checkWarn cfg && anyWarnings warnings) $-        liftIO $ hPutStrLn stderr $ pretty warnings+        liftIO $+          hPutStrLn stderr $+            pretty warnings     _ -> Nothing
src/Futhark/CLI/Dataset.hs view
@@ -200,8 +200,8 @@   V.ValueType ds t' <- toValueType t   pure $ V.ValueType (d' : ds) t'   where-    constantDim (DimExpConst k _) = Right k-    constantDim _ = Left "Array has non-constant dimension declaration."+    constantDim (SizeExpConst k _) = Right k+    constantDim _ = Left "Array has non-constant size." toValueType (TEVar (QualName [] v) _)   | Just t <- lookup v m = Right $ V.ValueType [] t   where
src/Futhark/CLI/Dev.hs view
@@ -37,6 +37,7 @@ import Futhark.Optimise.InPlaceLowering import Futhark.Optimise.InliningDeadFun import qualified Futhark.Optimise.MemoryBlockMerging as MemoryBlockMerging+import Futhark.Optimise.ReduceDeviceSyncs (reduceDeviceSyncs) import Futhark.Optimise.Sink import Futhark.Optimise.TileLoops import Futhark.Optimise.Unstream@@ -198,7 +199,8 @@   pure prog kernelsMemProg name rep =   externalErrorS $-    "Pass " ++ name+    "Pass "+      ++ name       ++ " expects GPUMem representation, but got "       ++ representation rep @@ -207,7 +209,8 @@   pure prog soacsProg name rep =   externalErrorS $-    "Pass " ++ name+    "Pass "+      ++ name       ++ " expects SOACS representation, but got "       ++ representation rep @@ -348,7 +351,9 @@           repf <$> runPipeline pipeline config prog         Nothing ->           externalErrorS $-            "Expected " ++ repdesc ++ " representation, but got "+            "Expected "+              ++ repdesc+              ++ " representation, but got "               ++ representation rep  soacsPipelineOption ::@@ -388,7 +393,9 @@       []       ["no-check"]       ( NoArg $-          Right $ changeFutharkConfig $ \opts -> opts {futharkTypeCheck = False}+          Right $+            changeFutharkConfig $+              \opts -> opts {futharkTypeCheck = False}       )       "Disable type-checking.",     Option@@ -411,6 +418,7 @@                 "cuda" -> Right $ GPUMemAction compileCUDAAction                 "wasm" -> Right $ SeqMemAction compileCtoWASMAction                 "wasm-multicore" -> Right $ MCMemAction compileMulticoreToWASMAction+                "ispc" -> Right $ MCMemAction compileMulticoreToISPCAction                 "python" -> Right $ SeqMemAction compilePythonAction                 "pyopencl" -> Right $ GPUMemAction compilePyOpenCLAction                 _ -> Left $ error $ "Invalid backend: " <> arg@@ -558,6 +566,7 @@     kernelsPassOption histAccsGPU [],     kernelsPassOption unstreamGPU [],     kernelsPassOption sinkGPU [],+    kernelsPassOption reduceDeviceSyncs [],     typedPassOption soacsProg GPU extractKernels [],     typedPassOption soacsProg MC extractMulticore [],     iplOption [],@@ -632,7 +641,9 @@       Just $ do         res <-           runFutharkM (m file config) $-            fst $ futharkVerbose $ futharkConfig config+            fst $+              futharkVerbose $+                futharkConfig config         case res of           Left err -> do             dumpError (futharkConfig config) err
src/Futhark/CLI/Doc.hs view
@@ -72,7 +72,8 @@     write (name, content) = do       let file = dir </> makeRelative "/" name       when (docVerbose cfg) $-        hPutStrLn stderr $ "Writing " <> file+        hPutStrLn stderr $+          "Writing " <> file       createDirectoryIfMissing True $ takeDirectory file       T.writeFile file content 
src/Futhark/CLI/LSP.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE ExplicitNamespaces #-}-{-# LANGUAGE OverloadedStrings #-}  -- | @futhark lsp@ module Futhark.CLI.LSP (main) where@@ -9,7 +8,6 @@ import Data.IORef (newIORef) import Futhark.LSP.Handlers (handlers) import Futhark.LSP.State (emptyState)-import Futhark.Util (debug) import Language.LSP.Server import Language.LSP.Types   ( SaveOptions (SaveOptions),@@ -17,14 +15,11 @@     TextDocumentSyncOptions (..),     type (|?) (InR),   )-import System.Log.Logger (Priority (DEBUG))  -- | Run @futhark lsp@ main :: String -> [String] -> IO () main _prog _args = do   state_mvar <- newIORef emptyState-  debug "Init with emptyState"-  setupLogger Nothing ["futhark"] DEBUG   _ <-     runServer $       ServerDefinition
src/Futhark/CLI/Literate.hs view
@@ -114,7 +114,8 @@ pprDirective _ (DirectiveCovert f) =   pprDirective False f pprDirective _ (DirectiveImg e params) =-  "> :img " <> PP.align (PP.ppr e)+  "> :img "+    <> PP.align (PP.ppr e)     <> if null params' then mempty else PP.stack $ ";" : params'   where     params' =@@ -133,14 +134,15 @@   "> :plot2d " <> PP.align (PP.ppr e) pprDirective True (DirectiveGnuplot e script) =   PP.stack $-    "> :gnuplot " <> PP.align (PP.ppr e) <> ";" :-    map PP.strictText (T.lines script)+    "> :gnuplot " <> PP.align (PP.ppr e) <> ";"+      : map PP.strictText (T.lines script) pprDirective False (DirectiveGnuplot e _) =   "> :gnuplot " <> PP.align (PP.ppr e) pprDirective False (DirectiveVideo e _) =   "> :video " <> PP.align (PP.ppr e) pprDirective True (DirectiveVideo e params) =-  "> :video " <> PP.ppr e+  "> :video "+    <> PP.ppr e     <> if null params' then mempty else PP.stack $ ";" : params'   where     params' =@@ -210,9 +212,13 @@ parsePlotParams :: Parser (Maybe (Int, Int)) parsePlotParams =   optional $-    ";" *> hspace *> eol *> token "-- size:"+    ";"+      *> hspace+      *> eol+      *> token "-- size:"       *> token "("-      *> ((,) <$> parseInt <* token "," <*> parseInt) <* token ")"+      *> ((,) <$> parseInt <* token "," <*> parseInt)+      <* token ")"  withPredicate :: (a -> Bool) -> String -> Parser a -> Parser a withPredicate f msg p = do@@ -229,7 +235,8 @@ parseImgParams :: Parser ImgParams parseImgParams =   fmap (fromMaybe defaultImgParams) $-    optional $ ";" *> hspace *> eol *> "-- " *> parseParams defaultImgParams+    optional $+      ";" *> hspace *> eol *> "-- " *> parseParams defaultImgParams   where     parseParams params =       choice@@ -246,7 +253,8 @@ parseVideoParams :: Parser VideoParams parseVideoParams =   fmap (fromMaybe defaultVideoParams) $-    optional $ ";" *> hspace *> eol *> "-- " *> parseParams defaultVideoParams+    optional $+      ";" *> hspace *> eol *> "-- " *> parseParams defaultVideoParams   where     parseParams params =       choice@@ -293,22 +301,31 @@     parseDirective =       choice         [ DirectiveRes <$> parseExp postlexeme <* afterExp,-          directiveName "covert" $> DirectiveCovert+          directiveName "covert"+            $> DirectiveCovert             <*> parseDirective,-          directiveName "brief" $> DirectiveBrief+          directiveName "brief"+            $> DirectiveBrief             <*> parseDirective,-          directiveName "img" $> DirectiveImg+          directiveName "img"+            $> DirectiveImg             <*> parseExp postlexeme-            <*> parseImgParams <* eol,-          directiveName "plot2d" $> DirectivePlot+            <*> parseImgParams+            <* eol,+          directiveName "plot2d"+            $> DirectivePlot             <*> parseExp postlexeme-            <*> parsePlotParams <* eol,-          directiveName "gnuplot" $> DirectiveGnuplot+            <*> parsePlotParams+            <* eol,+          directiveName "gnuplot"+            $> DirectiveGnuplot             <*> parseExp postlexeme             <*> (";" *> hspace *> eol *> parseBlockComment),-          (directiveName "video" <|> directiveName "video") $> DirectiveVideo+          (directiveName "video" <|> directiveName "video")+            $> DirectiveVideo             <*> parseExp postlexeme-            <*> parseVideoParams <* eol+            <*> parseVideoParams+            <* eol         ]     directiveName s = try $ token (":" <> s) @@ -437,7 +454,8 @@       pure $ T.pack stdout_t     Right (ExitFailure code', _, stderr_t) ->       throwError $-        prog' <> " failed with exit code "+        prog'+          <> " failed with exit code "           <> T.pack (show code')           <> " and stderr:\n"           <> T.pack stderr_t@@ -594,10 +612,14 @@   exists <- liftIO $ doesFileExist fname   liftIO $ createDirectoryIfMissing True $ envImgDir env   when (exists && scriptVerbose (envOpts env) > 0) $-    liftIO $ T.hPutStrLn stderr $ "Using existing file: " <> T.pack fname+    liftIO $+      T.hPutStrLn stderr $+        "Using existing file: " <> T.pack fname   unless exists $ do     when (scriptVerbose (envOpts env) > 0) $-      liftIO $ T.hPutStrLn stderr $ "Generating new file: " <> T.pack fname+      liftIO $+        T.hPutStrLn stderr $+          "Generating new file: " <> T.pack fname     m fname   modify $ \s -> s {stateFiles = S.insert fname $ stateFiles s}   pure (fname, fname_rel)@@ -718,7 +740,8 @@ -- processDirective env (DirectiveVideo e params) = do   when (format `notElem` ["webm", "gif"]) $-    throwError $ "Unknown video format: " <> format+    throwError $+      "Unknown video format: " <> format    let file = (videoFile params, "video" <.> T.unpack format)   fmap (videoBlock params) . newFile env file $ \videofile -> do@@ -737,7 +760,6 @@               onWebM videofile =<< bmpsToVideo dir       ValueTuple [stepfun, initial, num_frames]         | ValueAtom (SFun stepfun' _ [_, _] closure) <- stepfun,-          ValueAtom (SValue _ _) <- initial,           ValueAtom (SValue "i64" _) <- num_frames -> do             Just (ValueAtom num_frames') <-               mapM getValue <$> getExpValue (envServer env) num_frames@@ -878,7 +900,8 @@       | otherwise = throwError e     toRemove f = do       when (scriptVerbose (envOpts env) > 0) $-        T.hPutStrLn stderr $ "Deleting unused file: " <> T.pack f+        T.hPutStrLn stderr $+          "Deleting unused file: " <> T.pack f       removePathForcibly f  processScript :: Env -> [Block] -> IO (Failure, T.Text)@@ -962,13 +985,16 @@       unless (scriptSkipCompilation opts) $ do         let entryOpt v = "--entry-point=" ++ T.unpack v             compile_options =-              "--server" :-              map entryOpt (S.toList (varsInScripts script))+              "--server"+                : map entryOpt (S.toList (varsInScripts script))                 ++ scriptCompilerOptions opts         when (scriptVerbose opts > 0) $-          T.hPutStrLn stderr $ "Compiling " <> T.pack prog <> "..."+          T.hPutStrLn stderr $+            "Compiling " <> T.pack prog <> "..."         when (scriptVerbose opts > 1) $-          T.hPutStrLn stderr $ T.pack $ unwords compile_options+          T.hPutStrLn stderr $+            T.pack $+              unwords compile_options          let onError err = do               mapM_ (T.hPutStrLn stderr) err
src/Futhark/CLI/Main.hs view
@@ -22,6 +22,7 @@ import qualified Futhark.CLI.Literate as Literate import qualified Futhark.CLI.Misc as Misc import qualified Futhark.CLI.Multicore as Multicore+import qualified Futhark.CLI.MulticoreISPC as MulticoreISPC import qualified Futhark.CLI.MulticoreWASM as MulticoreWASM import qualified Futhark.CLI.OpenCL as OpenCL import qualified Futhark.CLI.Pkg as Pkg@@ -59,6 +60,7 @@       ("pyopencl", (PyOpenCL.main, "Compile to Python calling PyOpenCL.")),       ("wasm", (WASM.main, "Compile to WASM with sequential C")),       ("wasm-multicore", (MulticoreWASM.main, "Compile to WASM with multicore C")),+      ("ispc", (MulticoreISPC.main, "Compile to multicore ISPC")),       ("test", (Test.main, "Test Futhark programs.")),       ("bench", (Bench.main, "Benchmark Futhark programs.")),       ("dataset", (Dataset.main, "Generate random test data.")),@@ -75,7 +77,8 @@       ("query", (Query.main, "Query semantic information about program.")),       ("literate", (Literate.main, "Process a literate Futhark program.")),       ("lsp", (LSP.main, "Run LSP server.")),-      ("thanks", (Misc.mainThanks, "Express gratitude."))+      ("thanks", (Misc.mainThanks, "Express gratitude.")),+      ("tokens", (Misc.mainTokens, "Express gratitude."))     ]  msg :: String@@ -131,6 +134,7 @@           exitWith $ ExitFailure 1       | otherwise = throw e +-- | The @futhark@ executable. main :: IO () main = reportingIOErrors $ do   hSetEncoding stdout utf8
src/Futhark/CLI/Misc.hs view
@@ -7,6 +7,7 @@     mainDataget,     mainCheckSyntax,     mainThanks,+    mainTokens,   ) where @@ -14,12 +15,14 @@ import qualified Data.ByteString.Lazy as BS import Data.Function (on) import Data.List (isInfixOf, nubBy)+import Data.Loc (L (..), startPos) import qualified Data.Text.IO as T import Futhark.Compiler import Futhark.Test-import Futhark.Util (hashText)+import Futhark.Util (hashText, interactWithFileSafely) import Futhark.Util.Options import Futhark.Util.Pretty (prettyTextOneLine)+import Language.Futhark.Parser.Lexer (scanTokens) import Language.Futhark.Prop (isBuiltin) import System.Environment (getExecutablePath) import System.Exit@@ -105,3 +108,26 @@         "Likewise!",         "And thank you in return for trying the language!"       ]++-- | @futhark tokens@+mainTokens :: String -> [String] -> IO ()+mainTokens = mainWithOptions () [] "program" $ \args () ->+  case args of+    [file] -> Just $ do+      res <- interactWithFileSafely (scanTokens (startPos file) <$> BS.readFile file)+      case res of+        Nothing -> do+          hPutStrLn stderr $ file <> ": file not found."+          exitWith $ ExitFailure 2+        Just (Left e) -> do+          hPrint stderr e+          exitWith $ ExitFailure 2+        Just (Right (Left e)) -> do+          hPrint stderr e+          exitWith $ ExitFailure 2+        Just (Right (Right (tokens, _))) ->+          mapM_ printToken tokens+    _ -> Nothing+  where+    printToken (L _ token) =+      print token
+ src/Futhark/CLI/MulticoreISPC.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE FlexibleContexts #-}++-- | @futhark multicore@+module Futhark.CLI.MulticoreISPC (main) where++import Futhark.Actions (compileMulticoreToISPCAction)+import Futhark.Compiler.CLI+import Futhark.Passes (multicorePipeline)++-- | Run @futhark multicore@.+main :: String -> [String] -> IO ()+main = compilerMain+  ()+  []+  "Compile to multicore ISPC"+  "Generate multicore ISPC code from optimised Futhark program."+  multicorePipeline+  $ \fcfg () mode outpath prog ->+    actionProcedure (compileMulticoreToISPCAction fcfg mode outpath) prog
src/Futhark/CLI/Pkg.hs view
@@ -49,7 +49,9 @@             -- matter the host OS.             when (".." `elem` Posix.splitPath (Zip.eRelativePath entry)) $               fail $-                "Zip archive for " <> pdir <> " contains suspicious path: "+                "Zip archive for "+                  <> pdir+                  <> " contains suspicious path: "                   <> Zip.eRelativePath entry             let f = pdir </> makeRelative from_dir (Zip.eRelativePath entry)             createDirectoryIfMissing True $ takeDirectory f@@ -68,7 +70,9 @@     -- package files.     let noPkgDir =           fail $-            "futhark.pkg for " ++ T.unpack p ++ "-"+            "futhark.pkg for "+              ++ T.unpack p+              ++ "-"               ++ T.unpack (prettySemVer v)               ++ " does not define a package path."     from_dir <- maybe noPkgDir (pure . (pkgRevZipballDir info <>)) $ pkgDir m@@ -89,7 +93,8 @@      when (null written) $       fail $-        "Zip archive for package " ++ T.unpack p+        "Zip archive for package "+          ++ T.unpack p           ++ " does not contain any files in "           ++ from_dir @@ -311,7 +316,9 @@           | otherwise ->               liftIO $                 T.putStrLn $-                  "Replaced " <> p <> " "+                  "Replaced "+                    <> p+                    <> " "                     <> prettySemVer (requiredPkgRev prev_r')                     <> " => "                     <> prettySemVer v@@ -385,7 +392,9 @@       when (v /= requiredPkgRev req) $         liftIO $           T.putStrLn $-            "Upgraded " <> requiredPkg req <> " "+            "Upgraded "+              <> requiredPkg req+              <> " "               <> prettySemVer (requiredPkgRev req)               <> " => "               <> prettySemVer v
src/Futhark/CLI/REPL.hs view
@@ -409,7 +409,8 @@  typeCommand :: Command typeCommand = genTypeCommand parseExp T.checkExp $ \(ps, e) ->-  pretty e <> concatMap ((" " <>) . pretty) ps+  pretty e+    <> concatMap ((" " <>) . pretty) ps     <> " : "     <> pretty (typeOf e) 
src/Futhark/CLI/Run.hs view
@@ -122,7 +122,9 @@               pure (externalErrorS (show err))         )   when (interpreterPrintWarnings cfg) $-    liftIO $ hPutStr stderr $ pretty ws+    liftIO $+      hPutStr stderr $+        pretty ws    let imp = T.mkInitialImport "."   ienv1 <-@@ -137,7 +139,9 @@     badOnLeft pretty $       snd $         T.checkDec imports src' tenv1 imp $-          mkOpen $ toPOSIX $ dropExtension file+          mkOpen $+            toPOSIX $+              dropExtension file   ienv2 <- badOnLeft show =<< runInterpreter' (I.interpretDec ienv1 d1)   ienv3 <- badOnLeft show =<< runInterpreter' (I.interpretDec ienv2 d2)   pure (tenv2, ienv3)
src/Futhark/CLI/Test.hs view
@@ -97,7 +97,9 @@         "Running " <> T.pack (unwords $ binpath : extra_options)    context prog_ctx $-    pureTestResults $ liftIO $ withServer (futharkServerCfg to_run to_run_args) f+    pureTestResults $+      liftIO $+        withServer (futharkServerCfg to_run to_run_args) f  data TestMode   = -- | Only type check.@@ -175,12 +177,18 @@         Nothing           | expected_occurences > 0 ->               throwError $-                name <> maybePipeline pipeline <> " should have occurred " <> T.pack (show expected_occurences)+                name+                  <> maybePipeline pipeline+                  <> " should have occurred "+                  <> T.pack (show expected_occurences)                   <> " times, but did not occur at all in optimised program."         Just actual_occurences           | expected_occurences /= actual_occurences ->               throwError $-                name <> maybePipeline pipeline <> " should have occurred " <> T.pack (show expected_occurences)+                name+                  <> maybePipeline pipeline+                  <> " should have occurred "+                  <> T.pack (show expected_occurences)                   <> " times, but occurred "                   <> T.pack (show actual_occurences)                   <> " times."@@ -192,7 +200,8 @@     testWarning (ExpectedWarning regex_s regex)       | not (match regex $ T.unpack $ T.decodeUtf8 futerr) =           throwError $-            "Expected warning:\n  " <> regex_s+            "Expected warning:\n  "+              <> regex_s               <> "\nGot warnings:\n  "               <> T.decodeUtf8 futerr       | otherwise = pure ()@@ -278,7 +287,8 @@        when (mode == Interpreted) $         context "Interpreting" $-          accErrors_ $ map (runInterpretedEntry (FutharkExe futhark) program) ios+          accErrors_ $+            map (runInterpretedEntry (FutharkExe futhark) program) ios  liftCommand ::   (MonadError T.Text m, MonadIO m) =>@@ -308,7 +318,9 @@     runCompiledCase input_types outs ins run = runExceptT $ do       let TestRun _ input_spec _ index _ = run           case_ctx =-            "Entry point: " <> entry <> "; dataset: "+            "Entry point: "+              <> entry+              <> "; dataset: "               <> T.pack (runDescription run)        context1 case_ctx $ do@@ -325,7 +337,7 @@           Right _ ->             SuccessResult               <$> readResults server outs-                <* liftCommand (cmdFree server outs)+              <* liftCommand (cmdFree server outs)          compareResult entry index program expected res @@ -333,7 +345,8 @@ checkError (ThisError regex_s regex) err   | not (match regex $ T.unpack err) =       E.throwError $-        "Expected error:\n  " <> regex_s+        "Expected error:\n  "+          <> regex_s           <> "\nGot error:\n"           <> T.unlines (map ("  " <>) (T.lines err)) checkError _ _ =@@ -487,7 +500,9 @@ reportText :: TestStatus -> IO () reportText ts =   putStr $-    "(" ++ show (testStatusFail ts) ++ " failed, "+    "("+      ++ show (testStatusFail ts)+      ++ " failed, "       ++ show (testStatusPass ts)       ++ " passed, "       ++ show num_remain@@ -539,7 +554,8 @@             case msg of               TestStarted test -> do                 unless fancy $-                  putStr $ "Started testing " <> testCaseProgram test <> " "+                  putStr $+                    "Started testing " <> testCaseProgram test <> " "                 getResults $ ts {testStatusRun = test : testStatusRun ts}               TestDone test res -> do                 let ts' =@@ -558,7 +574,8 @@                                 testStatusRunPass ts' + numTestCases test                             }                     unless fancy $-                      putStr $ "Finished testing " <> testCaseProgram test <> " "+                      putStr $+                        "Finished testing " <> testCaseProgram test <> " "                     getResults $ ts'' {testStatusPass = testStatusPass ts + 1}                   Failure s -> do                     when fancy moveCursorToTableTop@@ -570,7 +587,8 @@                         { testStatusFail = testStatusFail ts' + 1,                           testStatusRunPass =                             testStatusRunPass ts'-                              + numTestCases test - length s,+                              + numTestCases test+                              - length s,                           testStatusRunFail =                             testStatusRunFail ts'                               + length s@@ -766,8 +784,8 @@ excludeBackend config =   config     { configExclude =-        "no_" <> T.pack (configBackend (configPrograms config)) :-        configExclude config+        "no_" <> T.pack (configBackend (configPrograms config))+          : configExclude config     }  -- | Run @futhark test@.
src/Futhark/CodeGen/Backends/CCUDA.hs view
@@ -59,7 +59,7 @@       operations       extra       cuda_includes-      [Space "device", DefaultSpace]+      (Space "device", [Space "device", DefaultSpace])       cliOptions       prog'   where@@ -213,26 +213,28 @@   error $ "Cannot deallocate in '" ++ space ++ "' memory space."  copyCUDAMemory :: GC.Copy OpenCL ()-copyCUDAMemory dstmem dstidx dstSpace srcmem srcidx srcSpace nbytes = do-  let (fn, prof) = memcpyFun dstSpace srcSpace+copyCUDAMemory b dstmem dstidx dstSpace srcmem srcidx srcSpace nbytes = do+  let (copy, prof) = memcpyFun b dstSpace srcSpace       (bef, aft) = profilingEnclosure prof   GC.item-    [C.citem|{-                $items:bef-                CUDA_SUCCEED_OR_RETURN(-                  $id:fn($exp:dstmem + $exp:dstidx,-                         $exp:srcmem + $exp:srcidx,-                         $exp:nbytes));-                $items:aft-                }-                |]+    [C.citem|{$items:bef CUDA_SUCCEED_OR_RETURN($exp:copy); $items:aft}|]   where-    memcpyFun DefaultSpace (Space "device") = ("cuMemcpyDtoH" :: String, copyDevToHost)-    memcpyFun (Space "device") DefaultSpace = ("cuMemcpyHtoD", copyHostToDev)-    memcpyFun (Space "device") (Space "device") = ("cuMemcpy", copyDevToDev)-    memcpyFun _ _ =+    dst = [C.cexp|$exp:dstmem + $exp:dstidx|]+    src = [C.cexp|$exp:srcmem + $exp:srcidx|]+    memcpyFun GC.CopyBarrier DefaultSpace (Space "device") =+      ([C.cexp|cuMemcpyDtoH($exp:dst, $exp:src, $exp:nbytes)|], copyDevToHost)+    memcpyFun GC.CopyBarrier (Space "device") DefaultSpace =+      ([C.cexp|cuMemcpyHtoD($exp:dst, $exp:src, $exp:nbytes)|], copyHostToDev)+    memcpyFun _ (Space "device") (Space "device") =+      ([C.cexp|cuMemcpy($exp:dst, $exp:src, $exp:nbytes)|], copyDevToDev)+    memcpyFun GC.CopyNoBarrier DefaultSpace (Space "device") =+      ([C.cexp|cuMemcpyDtoHAsync($exp:dst, $exp:src, $exp:nbytes, 0)|], copyDevToHost)+    memcpyFun GC.CopyNoBarrier (Space "device") DefaultSpace =+      ([C.cexp|cuMemcpyHtoDAsync($exp:dst, $exp:src, $exp:nbytes, 0)|], copyHostToDev)+    memcpyFun _ _ _ =       error $-        "Cannot copy to '" ++ show dstSpace+        "Cannot copy to '"+          ++ show dstSpace           ++ "' from '"           ++ show srcSpace           ++ "'."@@ -270,7 +272,8 @@   GC.item [C.citem|struct memblock_device $id:name = ctx->$id:name;|] staticCUDAArray _ space _ _ =   error $-    "CUDA backend cannot create static array in '" ++ space+    "CUDA backend cannot create static array in '"+      ++ space       ++ "' memory space"  cudaMemoryType :: GC.MemoryType OpenCL ()
src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs view
@@ -317,8 +317,8 @@                                      &ctx->$id:name,                                      ctx->cuda.module,                                      $string:(pretty (C.toIdent name mempty))));|]-        ) :-        forCostCentre name+        )+          : forCostCentre name        (kernel_fields, init_kernel_fields) =         unzip $
src/Futhark/CodeGen/Backends/COpenCL.hs view
@@ -68,7 +68,7 @@           failures       )       include_opencl_h-      [Space "device", DefaultSpace]+      (Space "device", [Space "device", DefaultSpace])       cliOptions       prog'   where@@ -226,36 +226,42 @@ deallocateOpenCLBuffer _ _ space =   error $ "Cannot deallocate in '" ++ space ++ "' space" +syncArg :: GC.CopyBarrier -> C.Exp+syncArg GC.CopyBarrier = [C.cexp|CL_TRUE|]+syncArg GC.CopyNoBarrier = [C.cexp|CL_FALSE|]+ copyOpenCLMemory :: GC.Copy OpenCL () -- The read/write/copy-buffer functions fail if the given offset is -- out of bounds, even if asked to read zero bytes.  We protect with a -- branch to avoid this.-copyOpenCLMemory destmem destidx DefaultSpace srcmem srcidx (Space "device") nbytes =+copyOpenCLMemory b destmem destidx DefaultSpace srcmem srcidx (Space "device") nbytes =   GC.stm     [C.cstm|     if ($exp:nbytes > 0) {+      typename cl_bool sync_call = $exp:(syncArg b);       OPENCL_SUCCEED_OR_RETURN(         clEnqueueReadBuffer(ctx->opencl.queue, $exp:srcmem,-                            ctx->failure_is_an_option ? CL_FALSE : CL_TRUE,+                            ctx->failure_is_an_option ? CL_FALSE : sync_call,                             (size_t)$exp:srcidx, (size_t)$exp:nbytes,                             $exp:destmem + $exp:destidx,                             0, NULL, $exp:(profilingEvent copyHostToDev)));-      if (ctx->failure_is_an_option &&+      if (sync_call &&+          ctx->failure_is_an_option &&           futhark_context_sync(ctx) != 0) { return 1; }    }   |]-copyOpenCLMemory destmem destidx (Space "device") srcmem srcidx DefaultSpace nbytes =+copyOpenCLMemory b destmem destidx (Space "device") srcmem srcidx DefaultSpace nbytes =   GC.stm     [C.cstm|     if ($exp:nbytes > 0) {       OPENCL_SUCCEED_OR_RETURN(-        clEnqueueWriteBuffer(ctx->opencl.queue, $exp:destmem, CL_TRUE,+        clEnqueueWriteBuffer(ctx->opencl.queue, $exp:destmem, $exp:(syncArg b),                              (size_t)$exp:destidx, (size_t)$exp:nbytes,                              $exp:srcmem + $exp:srcidx,                              0, NULL, $exp:(profilingEvent copyDevToHost)));     }   |]-copyOpenCLMemory destmem destidx (Space "device") srcmem srcidx (Space "device") nbytes =+copyOpenCLMemory _ destmem destidx (Space "device") srcmem srcidx (Space "device") nbytes =   -- Be aware that OpenCL swaps the usual order of operands for   -- memcpy()-like functions.  The order below is not a typo.   GC.stm@@ -272,9 +278,9 @@       }     }   }|]-copyOpenCLMemory destmem destidx DefaultSpace srcmem srcidx DefaultSpace nbytes =+copyOpenCLMemory _ destmem destidx DefaultSpace srcmem srcidx DefaultSpace nbytes =   GC.copyMemoryDefaultSpace destmem destidx srcmem srcidx nbytes-copyOpenCLMemory _ _ destspace _ _ srcspace _ =+copyOpenCLMemory _ _ _ destspace _ _ srcspace _ =   error $ "Cannot copy to " ++ show destspace ++ " from " ++ show srcspace  openclMemoryType :: GC.MemoryType OpenCL ()@@ -443,8 +449,8 @@           ++ " and local work size "           ++ dims           ++ "; local memory: %d bytes.\n",-        [C.cexp|$string:(pretty kernel_name)|] :-        map (kernelDim global_work_size) [0 .. kernel_rank - 1]+        [C.cexp|$string:(pretty kernel_name)|]+          : map (kernelDim global_work_size) [0 .. kernel_rank - 1]           ++ map (kernelDim local_work_size) [0 .. kernel_rank - 1]           ++ [[C.cexp|(int)$exp:local_bytes|]]       )
src/Futhark/CodeGen/Backends/GenericC.hs view
@@ -8,6 +8,7 @@ -- | C code generator framework. module Futhark.CodeGen.Backends.GenericC   ( compileProg,+    compileProg',     CParts (..),     asLibrary,     asExecutable,@@ -27,12 +28,14 @@     readScalarPointerWithQuals,     Allocate,     Deallocate,+    CopyBarrier (..),     Copy,     StaticArray,      -- * Monadic compiler interface     CompilerM,-    CompilerState (compUserState, compNameSrc),+    CompilerState (compUserState, compNameSrc, compDeclaredMem),+    CompilerEnv (envCachedMem),     getUserState,     modifyUserState,     contextContents,@@ -77,6 +80,12 @@     primTypeToCType,     intTypeToCType,     copyMemoryDefaultSpace,+    linearCode,+    derefPointer,+    fatMemAlloc,+    fatMemSet,+    fatMemUnRef,+    errorMsgString,   ) where @@ -84,7 +93,7 @@ import Control.Monad.Reader import Control.Monad.State import Data.Bifunctor (first)-import Data.Char (isAlpha, isAlphaNum)+import Data.Char (isAlpha, isAlphaNum, isDigit) import qualified Data.DList as DL import Data.List (unzip4) import Data.Loc@@ -100,7 +109,7 @@ import Futhark.IR.Prop (isBuiltInFunction) import qualified Futhark.Manifest as Manifest import Futhark.MonadFreshNames-import Futhark.Util (zEncodeString)+import Futhark.Util (chunks, mapAccumLM, zEncodeString) import Futhark.Util.Pretty (prettyText) import qualified Language.C.Quote.OpenCL as C import qualified Language.C.Syntax as C@@ -112,11 +121,10 @@ data Publicness = Private | Public   deriving (Eq, Ord, Show) -type ArrayType = (Space, Signedness, PrimType, Int)+type ArrayType = (Signedness, PrimType, Int)  data CompilerState s = CompilerState   { compArrayTypes :: M.Map ArrayType Publicness,-    compOpaqueTypes :: M.Map String [ValueDesc],     compEarlyDecls :: DL.DList C.Definition,     compInit :: [C.Stm],     compNameSrc :: VNameSource,@@ -134,7 +142,6 @@ newCompilerState src s =   CompilerState     { compArrayTypes = mempty,-      compOpaqueTypes = mempty,       compEarlyDecls = mempty,       compInit = [],       compNameSrc = src,@@ -152,6 +159,7 @@ -- to ensure that the header file remains structured and readable. data HeaderSection   = ArrayDecl String+  | OpaqueTypeDecl String   | OpaqueDecl String   | EntryDecl   | MiscDecl@@ -198,8 +206,20 @@ -- | Create a static array of values - initialised at load time. type StaticArray op s = VName -> SpaceId -> PrimType -> ArrayContents -> CompilerM op s () +-- | Whether a copying operation should implicitly function as a+-- barrier regarding further operations on the source.  This is a+-- rather subtle detail and is mostly useful for letting some+-- device/GPU copies be asynchronous (#1664).+data CopyBarrier+  = CopyBarrier+  | -- | Explicit context synchronisation should be done+    -- before the source or target is used.+    CopyNoBarrier+  deriving (Eq, Show)+ -- | Copy from one memory block to another. type Copy op s =+  CopyBarrier ->   C.Exp ->   C.Exp ->   Space ->@@ -264,7 +284,8 @@   (formatstr, formatargs) <- errorMsgString msg   let formatstr' = "Error: " <> formatstr <> "\n\nBacktrace:\n%s"   items-    [C.citems|ctx->error = msgprintf($string:formatstr', $args:formatargs, $string:stacktrace);+    [C.citems|if (ctx->error == NULL)+                ctx->error = msgprintf($string:formatstr', $args:formatargs, $string:stacktrace);               err = FUTHARK_PROGRAM_ERROR;               goto cleanup;|] @@ -309,9 +330,9 @@       error "Cannot allocate in non-default memory space"     defDeallocate _ _ =       error "Cannot deallocate in non-default memory space"-    defCopy destmem destoffset DefaultSpace srcmem srcoffset DefaultSpace size =+    defCopy _ destmem destoffset DefaultSpace srcmem srcoffset DefaultSpace size =       copyMemoryDefaultSpace destmem destoffset srcmem srcoffset size-    defCopy _ _ _ _ _ _ _ =+    defCopy _ _ _ _ _ _ _ _ =       error "Cannot copy to or from non-default memory space"     defStaticArray _ _ _ _ =       error "Cannot create static array in non-default memory space"@@ -367,12 +388,16 @@     . M.toList     . compHeaderDecls -initDecls, arrayDecls, opaqueDecls, entryDecls, miscDecls :: CompilerState s -> T.Text+initDecls, arrayDecls, opaqueDecls, opaqueTypeDecls, entryDecls, miscDecls :: CompilerState s -> T.Text initDecls = declsCode (== InitDecl) arrayDecls = declsCode isArrayDecl   where     isArrayDecl ArrayDecl {} = True     isArrayDecl _ = False+opaqueTypeDecls = declsCode isOpaqueTypeDecl+  where+    isOpaqueTypeDecl OpaqueTypeDecl {} = True+    isOpaqueTypeDecl _ = False opaqueDecls = declsCode isOpaqueDecl   where     isOpaqueDecl OpaqueDecl {} = True@@ -613,7 +638,8 @@ allocRawMem dest size space desc = case space of   Space sid ->     join $-      asks envAllocate <*> pure [C.cexp|$exp:dest|]+      asks envAllocate+        <*> pure [C.cexp|$exp:dest|]         <*> pure [C.cexp|$exp:size|]         <*> pure [C.cexp|$exp:desc|]         <*> pure sid@@ -651,7 +677,7 @@   free <- collect $ freeRawMem [C.cexp|block->mem|] space [C.cexp|desc|]   ctx_ty <- contextType   let unrefdef =-        [C.cedecl|static int $id:(fatMemUnRef space) ($ty:ctx_ty *ctx, $ty:mty *block, const char *desc) {+        [C.cedecl|int $id:(fatMemUnRef space) ($ty:ctx_ty *ctx, $ty:mty *block, const char *desc) {   if (block->references != NULL) {     *(block->references) -= 1;     if (ctx->detail_memory) {@@ -677,7 +703,7 @@     collect $       allocRawMem [C.cexp|block->mem|] [C.cexp|size|] space [C.cexp|desc|]   let allocdef =-        [C.cedecl|static int $id:(fatMemAlloc space) ($ty:ctx_ty *ctx, $ty:mty *block, typename int64_t size, const char *desc) {+        [C.cedecl|int $id:(fatMemAlloc space) ($ty:ctx_ty *ctx, $ty:mty *block, typename int64_t size, const char *desc) {   if (size < 0) {     futhark_panic(1, "Negative allocation of %lld bytes attempted for %s in %s.\n",           (long long)size, desc, $string:spacedesc, ctx->$id:usagename);@@ -731,7 +757,7 @@   -- Memory setting - unreference the destination and increase the   -- count of the source by one.   let setdef =-        [C.cedecl|static int $id:(fatMemSet space) ($ty:ctx_ty *ctx, $ty:mty *lhs, $ty:mty *rhs, const char *lhs_desc) {+        [C.cedecl|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);   if (rhs->references != NULL) {     (*(rhs->references))++;@@ -915,6 +941,7 @@   new_body <- collect $ do     prepare_new     copy+      CopyNoBarrier       [C.cexp|arr->mem.mem|]       [C.cexp|0|]       space@@ -926,6 +953,7 @@   new_raw_body <- collect $ do     prepare_new     copy+      CopyNoBarrier       [C.cexp|arr->mem.mem|]       [C.cexp|0|]       space@@ -939,6 +967,7 @@   values_body <-     collect $       copy+        CopyNoBarrier         [C.cexp|data|]         [C.cexp|0|]         DefaultSpace@@ -1023,23 +1052,216 @@         Manifest.arrayNew = T.pack new_array       } +lookupOpaqueType :: String -> OpaqueTypes -> OpaqueType+lookupOpaqueType v (OpaqueTypes types) =+  case lookup v types of+    Just t -> t+    Nothing -> error $ "Unknown opaque type: " ++ show v++opaquePayload :: OpaqueTypes -> OpaqueType -> [ValueType]+opaquePayload _ (OpaqueType ts) = ts+opaquePayload types (OpaqueRecord fs) = concatMap f fs+  where+    f (_, TypeOpaque s) = opaquePayload types $ lookupOpaqueType s types+    f (_, TypeTransparent v) = [v]++opaqueToCType :: String -> CompilerM op s C.Type+opaqueToCType desc = do+  name <- publicName $ opaqueName desc+  pure [C.cty|struct $id:name|]++valueTypeToCType :: Publicness -> ValueType -> CompilerM op s C.Type+valueTypeToCType _ (ValueType signed (Rank 0) pt) =+  pure $ primAPIType signed pt+valueTypeToCType pub (ValueType signed (Rank rank) pt) = do+  name <- publicName $ arrayName pt signed rank+  let add = M.insertWith max (signed, pt, rank) pub+  modify $ \s -> s {compArrayTypes = add $ compArrayTypes s}+  pure [C.cty|struct $id:name|]++entryPointTypeToCType :: Publicness -> EntryPointType -> CompilerM op s C.Type+entryPointTypeToCType _ (TypeOpaque desc) = opaqueToCType desc+entryPointTypeToCType pub (TypeTransparent vt) = valueTypeToCType pub vt++entryTypeName :: EntryPointType -> Manifest.TypeName+entryTypeName (TypeOpaque desc) = T.pack desc+entryTypeName (TypeTransparent vt) = prettyText vt++-- | Figure out which of the members of an opaque type corresponds to+-- which fields.+recordFieldPayloads :: OpaqueTypes -> [EntryPointType] -> [a] -> [[a]]+recordFieldPayloads types = chunks . map typeLength+  where+    typeLength (TypeTransparent _) = 1+    typeLength (TypeOpaque desc) =+      length $ opaquePayload types $ lookupOpaqueType desc types++opaqueProjectFunctions ::+  OpaqueTypes ->+  String ->+  [(Name, EntryPointType)] ->+  [ValueType] ->+  CompilerM op s [Manifest.RecordField]+opaqueProjectFunctions types desc fs vds = do+  opaque_type <- opaqueToCType desc+  ctx_ty <- contextType+  ops <- asks envOperations+  let mkProject (TypeTransparent (ValueType sign (Rank 0) pt)) [(i, _)] = do+        pure+          ( primAPIType sign pt,+            [C.citems|v = obj->$id:(tupleField i);|]+          )+      mkProject (TypeTransparent vt) [(i, _)] = do+        ct <- valueTypeToCType Public vt+        pure+          ( [C.cty|$ty:ct *|],+            criticalSection+              ops+              [C.citems|v = malloc(sizeof($ty:ct));+                        memcpy(v, obj->$id:(tupleField i), sizeof($ty:ct));+                        (void)(*(v->mem.references))++;|]+          )+      mkProject (TypeTransparent _) rep =+        error $ "mkProject: invalid representation of transparent type: " ++ show rep+      mkProject (TypeOpaque f_desc) components = do+        ct <- opaqueToCType f_desc+        let setField j (i, ValueType _ (Rank r) _) =+              if r == 0+                then [C.citems|v->$id:(tupleField j) = obj->$id:(tupleField i);|]+                else+                  [C.citems|v->$id:(tupleField j) = malloc(sizeof(*v->$id:(tupleField j)));+                            *v->$id:(tupleField j) = *obj->$id:(tupleField i);+                            (void)(*(v->$id:(tupleField j)->mem.references))++;|]+        pure+          ( [C.cty|$ty:ct *|],+            criticalSection+              ops+              [C.citems|v = malloc(sizeof($ty:ct));+                        $items:(concat (zipWith setField [0..] components))|]+          )+  let onField ((f, et), elems) = do+        project <- publicName $ "project_" ++ opaqueName desc ++ "_" ++ nameToString f+        (et_ty, project_items) <- mkProject et elems+        headerDecl+          (OpaqueDecl desc)+          [C.cedecl|int $id:project($ty:ctx_ty *ctx, $ty:et_ty *out, const $ty:opaque_type *obj);|]+        libDecl+          [C.cedecl|int $id:project($ty:ctx_ty *ctx, $ty:et_ty *out, const $ty:opaque_type *obj) {+                      (void)ctx;+                      $ty:et_ty v;+                      $items:project_items+                      *out = v;+                      return 0;+                    }|]+        pure $ Manifest.RecordField (nameToText f) (entryTypeName et) (T.pack project)++  mapM onField . zip fs . recordFieldPayloads types (map snd fs) $+    zip [0 ..] vds++opaqueNewFunctions ::+  OpaqueTypes ->+  String ->+  [(Name, EntryPointType)] ->+  [ValueType] ->+  CompilerM op s Manifest.CFuncName+opaqueNewFunctions types desc fs vds = do+  opaque_type <- opaqueToCType desc+  ctx_ty <- contextType+  ops <- asks envOperations+  new <- publicName $ "new_" ++ opaqueName desc++  (params, new_stms) <-+    fmap (unzip . snd)+      . mapAccumLM onField 0+      . zip fs+      . recordFieldPayloads types (map snd fs)+      $ vds++  headerDecl+    (OpaqueDecl desc)+    [C.cedecl|int $id:new($ty:ctx_ty *ctx, $ty:opaque_type** out, $params:params);|]+  libDecl+    [C.cedecl|int $id:new($ty:ctx_ty *ctx, $ty:opaque_type** out, $params:params) {+                $ty:opaque_type* v = malloc(sizeof($ty:opaque_type));+                $items:(criticalSection ops new_stms)+                *out = v;+                return 0;+              }|]+  pure $ T.pack new+  where+    onField offset ((f, et), f_vts) = do+      let param_name =+            if all isDigit (nameToString f)+              then C.toIdent ("v" <> f) mempty+              else C.toIdent f mempty+      case et of+        TypeTransparent (ValueType sign (Rank 0) pt) -> do+          let ct = primAPIType sign pt+          pure+            ( offset + 1,+              ( [C.cparam|const $ty:ct $id:param_name|],+                [C.citem|v->$id:(tupleField offset) = $id:param_name;|]+              )+            )+        TypeTransparent vt -> do+          ct <- valueTypeToCType Public vt+          pure+            ( offset + 1,+              ( [C.cparam|const $ty:ct* $id:param_name|],+                [C.citem|{v->$id:(tupleField offset) = malloc(sizeof($ty:ct));+                          *v->$id:(tupleField offset) = *$id:param_name;+                          (void)(*(v->$id:(tupleField offset)->mem.references))++;}|]+              )+            )+        TypeOpaque f_desc -> do+          ct <- opaqueToCType f_desc+          let param_fields = do+                i <- [0 ..]+                pure [C.cexp|$id:param_name->$id:(tupleField i)|]+          pure+            ( offset + length f_vts,+              ( [C.cparam|const $ty:ct* $id:param_name|],+                [C.citem|{$stms:(zipWith3 setFieldField [offset ..] param_fields f_vts)}|]+              )+            )++    setFieldField i e (ValueType _ (Rank r) _)+      | r == 0 =+          [C.cstm|v->$id:(tupleField i) = $exp:e;|]+      | otherwise =+          [C.cstm|{v->$id:(tupleField i) = malloc(sizeof(*$exp:e));+                   *v->$id:(tupleField i) = *$exp:e;+                   (void)(*(v->$id:(tupleField i)->mem.references))++;}|]++processOpaqueRecord ::+  OpaqueTypes ->+  String ->+  OpaqueType ->+  [ValueType] ->+  CompilerM op s (Maybe Manifest.RecordOps)+processOpaqueRecord _ _ (OpaqueType _) _ = pure Nothing+processOpaqueRecord types desc (OpaqueRecord fs) vds =+  Just+    <$> ( Manifest.RecordOps+            <$> opaqueProjectFunctions types desc fs vds+            <*> opaqueNewFunctions types desc fs vds+        )+ opaqueLibraryFunctions ::+  OpaqueTypes ->   String ->-  [ValueDesc] ->-  CompilerM op s Manifest.OpaqueOps-opaqueLibraryFunctions desc vds = do-  name <- publicName $ opaqueName desc vds-  free_opaque <- publicName $ "free_" ++ opaqueName desc vds-  store_opaque <- publicName $ "store_" ++ opaqueName desc vds-  restore_opaque <- publicName $ "restore_" ++ opaqueName desc vds+  OpaqueType ->+  CompilerM op s (Manifest.OpaqueOps, Maybe Manifest.RecordOps)+opaqueLibraryFunctions types desc ot = do+  name <- publicName $ opaqueName desc+  free_opaque <- publicName $ "free_" ++ opaqueName desc+  store_opaque <- publicName $ "store_" ++ opaqueName desc+  restore_opaque <- publicName $ "restore_" ++ opaqueName desc    let opaque_type = [C.cty|struct $id:name|] -      freeComponent _ ScalarValue {} =-        pure ()-      freeComponent i (ArrayValue _ _ pt signed shape) = do-        let rank = length shape-            field = tupleField i+      freeComponent i (ValueType signed (Rank rank) pt) = unless (rank == 0) $ do+        let field = tupleField i         free_array <- publicName $ "free_" ++ arrayName pt signed rank         -- Protect against NULL here, because we also want to use this         -- to free partially loaded opaques.@@ -1048,16 +1270,15 @@                 ret = tmp;              }|] -      storeComponent i (ScalarValue pt sign _) =+      storeComponent i (ValueType sign (Rank 0) pt) =         let field = tupleField i          in ( storageSize pt 0 [C.cexp|NULL|],               storeValueHeader sign pt 0 [C.cexp|NULL|] [C.cexp|out|]                 ++ [C.cstms|memcpy(out, &obj->$id:field, sizeof(obj->$id:field));                             out += sizeof(obj->$id:field);|]             )-      storeComponent i (ArrayValue _ _ pt sign shape) =-        let rank = length shape-            arr_name = arrayName pt sign rank+      storeComponent i (ValueType sign (Rank rank) pt) =+        let arr_name = arrayName pt sign rank             field = tupleField i             shape_array = "futhark_shape_" ++ arr_name             values_array = "futhark_values_" ++ arr_name@@ -1071,6 +1292,7 @@    ctx_ty <- contextType +  let vds = opaquePayload types ot   free_body <- collect $ zipWithM_ freeComponent [0 ..] vds    store_body <- collect $ do@@ -1083,16 +1305,15 @@     stm [C.cstm|if (p != NULL && *p == NULL) { *p = malloc(*n); }|]     stm [C.cstm|if (p != NULL) { unsigned char *out = *p; $stms:(concat stores) }|] -  let restoreComponent i (ScalarValue pt sign _) = do+  let restoreComponent i (ValueType sign (Rank 0) pt) = do         let field = tupleField i             dataptr = "data_" ++ show i         stms $ loadValueHeader sign pt 0 [C.cexp|NULL|] [C.cexp|src|]         item [C.citem|const void* $id:dataptr = src;|]         stm [C.cstm|src += sizeof(obj->$id:field);|]         pure [C.cstms|memcpy(&obj->$id:field, $id:dataptr, sizeof(obj->$id:field));|]-      restoreComponent i (ArrayValue _ _ pt sign shape) = do+      restoreComponent i (ValueType sign (Rank rank) pt) = do         let field = tupleField i-            rank = length shape             arr_name = arrayName pt sign rank             new_array = "futhark_new_" ++ arr_name             dataptr = "data_" ++ show i@@ -1110,14 +1331,14 @@              if (obj->$id:field == NULL) { err = 1; }|]    load_body <- collect $ do-    loads <- concat <$> zipWithM restoreComponent [0 ..] vds+    loads <- concat <$> zipWithM restoreComponent [0 ..] (opaquePayload types ot)     stm       [C.cstm|if (err == 0) {                 $stms:loads               }|]    headerDecl-    (OpaqueDecl desc)+    (OpaqueTypeDecl desc)     [C.cedecl|struct $id:name;|]   headerDecl     (OpaqueDecl desc)@@ -1129,13 +1350,17 @@     (OpaqueDecl desc)     [C.cedecl|$ty:opaque_type* $id:restore_opaque($ty:ctx_ty *ctx, const void *p);|] -  -- We do not need to enclose the body in a critical section, because-  -- when we operate on the components of the opaque, we are calling-  -- public API functions that do their own locking.+  record <- processOpaqueRecord types desc ot vds++  -- We do not need to enclose most bodies in a critical section,+  -- because when we operate on the components of the opaque, we are+  -- calling public API functions that do their own locking.  The+  -- exception is projection, where we fiddle with reference counts.   mapM_     libDecl     [C.cunit|           int $id:free_opaque($ty:ctx_ty *ctx, $ty:opaque_type *obj) {+            (void)ctx;             int ret = 0, tmp;             $items:free_body             free(obj);@@ -1144,6 +1369,7 @@            int $id:store_opaque($ty:ctx_ty *ctx,                                const $ty:opaque_type *obj, void **p, size_t *n) {+            (void)ctx;             int ret = 0;             $items:store_body             return ret;@@ -1165,70 +1391,77 @@           }     |] -  pure $-    Manifest.OpaqueOps-      { Manifest.opaqueFree = T.pack free_opaque,-        Manifest.opaqueStore = T.pack store_opaque,-        Manifest.opaqueRestore = T.pack restore_opaque-      }+  pure+    ( Manifest.OpaqueOps+        { Manifest.opaqueFree = T.pack free_opaque,+          Manifest.opaqueStore = T.pack store_opaque,+          Manifest.opaqueRestore = T.pack restore_opaque+        },+      record+    ) -valueDescToCType :: Publicness -> ValueDesc -> CompilerM op s C.Type-valueDescToCType _ (ScalarValue pt signed _) =-  pure $ primAPIType signed pt-valueDescToCType pub (ArrayValue _ space pt signed shape) = do-  let rank = length shape+valueDescToType :: ValueDesc -> ValueType+valueDescToType (ScalarValue pt signed _) =+  ValueType signed (Rank 0) pt+valueDescToType (ArrayValue _ _ pt signed shape) =+  ValueType signed (Rank (length shape)) pt++generateArray ::+  Space ->+  ((Signedness, PrimType, Int), Publicness) ->+  CompilerM op s (Maybe (T.Text, Manifest.Type))+generateArray space ((signed, pt, rank), pub) = do   name <- publicName $ arrayName pt signed rank-  let add = M.insertWith max (space, signed, pt, rank) pub-  modify $ \s -> s {compArrayTypes = add $ compArrayTypes s}-  pure [C.cty|struct $id:name|]+  let memty = fatMemType space+  libDecl [C.cedecl|struct $id:name { $ty:memty mem; typename int64_t shape[$int:rank]; };|]+  ops <- arrayLibraryFunctions pub space pt signed rank+  let pt_name = T.pack $ prettySigned (signed == Unsigned) pt+      pretty_name = mconcat (replicate rank "[]") <> pt_name+      arr_type = [C.cty|struct $id:name*|]+  case pub of+    Public ->+      pure $+        Just+          ( pretty_name,+            Manifest.TypeArray (prettyText arr_type) pt_name rank ops+          )+    Private ->+      pure Nothing -opaqueToCType :: String -> [ValueDesc] -> CompilerM op s C.Type-opaqueToCType desc vds = do-  name <- publicName $ opaqueName desc vds-  let add = M.insert desc vds-  modify $ \s -> s {compOpaqueTypes = add $ compOpaqueTypes s}-  -- Now ensure that the constituent array types will exist.-  mapM_ (valueDescToCType Private) vds-  pure [C.cty|struct $id:name|]+generateOpaque ::+  OpaqueTypes ->+  (String, OpaqueType) ->+  CompilerM op s (T.Text, Manifest.Type)+generateOpaque types (desc, ot) = do+  name <- publicName $ opaqueName desc+  members <- zipWithM field (opaquePayload types ot) [(0 :: Int) ..]+  libDecl [C.cedecl|struct $id:name { $sdecls:members };|]+  (ops, record) <- opaqueLibraryFunctions types desc ot+  let opaque_type = [C.cty|struct $id:name*|]+  pure (T.pack desc, Manifest.TypeOpaque (prettyText opaque_type) ops record)+  where+    field vt@(ValueType _ (Rank r) _) i = do+      ct <- valueTypeToCType Private vt+      pure $+        if r == 0+          then [C.csdecl|$ty:ct $id:(tupleField i);|]+          else [C.csdecl|$ty:ct *$id:(tupleField i);|] -generateAPITypes :: CompilerM op s (M.Map T.Text Manifest.Type)-generateAPITypes = do-  array_ts <- mapM generateArray . M.toList =<< gets compArrayTypes-  opaque_ts <- mapM generateOpaque . M.toList =<< gets compOpaqueTypes+generateAPITypes :: Space -> OpaqueTypes -> CompilerM op s (M.Map T.Text Manifest.Type)+generateAPITypes arr_space types@(OpaqueTypes opaques) = do+  mapM_ (findNecessaryArrays . snd) opaques+  array_ts <- mapM (generateArray arr_space) . M.toList =<< gets compArrayTypes+  opaque_ts <- mapM (generateOpaque types) opaques   pure $ M.fromList $ catMaybes array_ts <> opaque_ts   where-    generateArray ((space, signed, pt, rank), pub) = do-      name <- publicName $ arrayName pt signed rank-      let memty = fatMemType space-      libDecl [C.cedecl|struct $id:name { $ty:memty mem; typename int64_t shape[$int:rank]; };|]-      ops <- arrayLibraryFunctions pub space pt signed rank-      let pt_name = T.pack $ prettySigned (signed == TypeUnsigned) pt-          pretty_name = mconcat (replicate rank "[]") <> pt_name-          arr_type = [C.cty|struct $id:name*|]-      case pub of-        Public ->-          pure $-            Just-              ( pretty_name,-                Manifest.TypeArray (prettyText arr_type) pt_name rank ops-              )-        Private ->-          pure Nothing--    generateOpaque (desc, vds) = do-      name <- publicName $ opaqueName desc vds-      members <- zipWithM field vds [(0 :: Int) ..]-      libDecl [C.cedecl|struct $id:name { $sdecls:members };|]-      ops <- opaqueLibraryFunctions desc vds-      let opaque_type = [C.cty|struct $id:name*|]-      pure (T.pack desc, Manifest.TypeOpaque (prettyText opaque_type) ops)--    field vd@ScalarValue {} i = do-      ct <- valueDescToCType Private vd-      pure [C.csdecl|$ty:ct $id:(tupleField i);|]-    field vd i = do-      ct <- valueDescToCType Private vd-      pure [C.csdecl|$ty:ct *$id:(tupleField i);|]+    -- Ensure that array types will be generated before the opaque+    -- records that allow projection of them.  This is because the+    -- projection functions somewhat uglily directly poke around in+    -- the innards to increment reference counts.+    findNecessaryArrays (OpaqueType _) =+      pure ()+    findNecessaryArrays (OpaqueRecord fs) =+      mapM_ (entryPointTypeToCType Public . snd) fs  allTrue :: [C.Exp] -> C.Exp allTrue [] = [C.cexp|true|]@@ -1241,20 +1474,20 @@ prepareEntryInputs args = collect' $ zipWithM prepare [(0 :: Int) ..] args   where     arg_names = namesFromList $ concatMap evNames args-    evNames (OpaqueValue _ _ vds) = map vdName vds-    evNames (TransparentValue _ vd) = [vdName vd]+    evNames (OpaqueValue _ vds) = map vdName vds+    evNames (TransparentValue vd) = [vdName vd]     vdName (ArrayValue v _ _ _ _) = v     vdName (ScalarValue _ _ v) = v -    prepare pno (TransparentValue _ vd) = do+    prepare pno (TransparentValue vd) = do       let pname = "in" ++ show pno       (ty, check) <- prepareValue Public [C.cexp|$id:pname|] vd       pure         ( [C.cparam|const $ty:ty $id:pname|],           if null check then Nothing else Just $ allTrue check         )-    prepare pno (OpaqueValue _ desc vds) = do-      ty <- opaqueToCType desc vds+    prepare pno (OpaqueValue desc vds) = do+      ty <- opaqueToCType desc       let pname = "in" ++ show pno           field i ScalarValue {} = [C.cexp|$id:pname->$id:(tupleField i)|]           field i ArrayValue {} = [C.cexp|$id:pname->$id:(tupleField i)|]@@ -1272,13 +1505,13 @@       stm [C.cstm|$id:name = $exp:src';|]       pure (pt', [])     prepareValue pub src vd@(ArrayValue mem _ _ _ shape) = do-      ty <- valueDescToCType pub vd+      ty <- valueTypeToCType pub $ valueDescToType vd        stm [C.cstm|$exp:mem = $exp:src->mem;|]        let rank = length shape           maybeCopyDim (Var d) i-            | not $ d `nameIn` arg_names =+            | d `notNameIn` arg_names =                 ( Just [C.cstm|$id:d = $exp:src->shape[$int:i];|],                   [C.cexp|$id:d == $exp:src->shape[$int:i]|]                 )@@ -1296,9 +1529,9 @@ prepareEntryOutputs :: [ExternalValue] -> CompilerM op s ([C.Param], [C.BlockItem]) prepareEntryOutputs = collect' . zipWithM prepare [(0 :: Int) ..]   where-    prepare pno (TransparentValue _ vd) = do+    prepare pno (TransparentValue vd) = do       let pname = "out" ++ show pno-      ty <- valueDescToCType Public vd+      ty <- valueTypeToCType Public $ valueDescToType vd        case vd of         ArrayValue {} -> do@@ -1308,18 +1541,19 @@         ScalarValue {} -> do           prepareValue [C.cexp|*$id:pname|] vd           pure [C.cparam|$ty:ty *$id:pname|]-    prepare pno (OpaqueValue _ desc vds) = do+    prepare pno (OpaqueValue desc vds) = do       let pname = "out" ++ show pno-      ty <- opaqueToCType desc vds-      vd_ts <- mapM (valueDescToCType Private) vds+      ty <- opaqueToCType desc+      vd_ts <- mapM (valueTypeToCType Private . valueDescToType) vds        stm [C.cstm|assert((*$id:pname = ($ty:ty*) malloc(sizeof($ty:ty))) != NULL);|]        forM_ (zip3 [0 ..] vd_ts vds) $ \(i, ct, vd) -> do-        let field = [C.cexp|(*$id:pname)->$id:(tupleField i)|]+        let field = [C.cexp|((*$id:pname)->$id:(tupleField i))|]         case vd of           ScalarValue {} -> pure ()-          _ -> stm [C.cstm|assert(($exp:field = ($ty:ct*) malloc(sizeof($ty:ct))) != NULL);|]+          ArrayValue {} -> do+            stm [C.cstm|assert(($exp:field = ($ty:ct*) malloc(sizeof($ty:ct))) != NULL);|]         prepareValue field vd        pure [C.cparam|$ty:ty **$id:pname|]@@ -1354,8 +1588,8 @@   Name ->   Function op ->   CompilerM op s (Maybe (C.Definition, (T.Text, Manifest.EntryPoint)))-onEntryPoint _ _ (Function Nothing _ _ _ _ _) = pure Nothing-onEntryPoint get_consts fname (Function (Just ename) outputs inputs _ results args) = inNewFunction $ do+onEntryPoint _ _ (Function Nothing _ _ _) = pure Nothing+onEntryPoint get_consts fname (Function (Just (EntryPoint ename results args)) outputs inputs _) = inNewFunction $ do   let out_args = map (\p -> [C.cexp|&$id:(paramName p)|]) outputs       in_args = map (\p -> [C.cexp|$id:(paramName p)|]) inputs @@ -1369,7 +1603,7 @@   let (entry_point_input_params, entry_point_input_checks) = unzip inputs'    (entry_point_output_params, pack_entry_outputs) <--    prepareEntryOutputs results+    prepareEntryOutputs $ map snd results    ctx_ty <- contextType @@ -1444,32 +1678,26 @@       let ty' = primTypeToCType ty       decl [C.cdecl|$ty:ty' $id:name;|] -    vdTypeAndUnique (TransparentValue _ (ScalarValue pt signed _)) =-      ( T.pack $ prettySigned (signed == TypeUnsigned) pt,-        False-      )-    vdTypeAndUnique (TransparentValue u (ArrayValue _ _ pt signed shape)) =-      ( T.pack $-          mconcat (replicate (length shape) "[]")-            <> prettySigned (signed == TypeUnsigned) pt,-        u == Unique-      )-    vdTypeAndUnique (OpaqueValue u name _) =-      (T.pack name, u == Unique)+    vdType (TransparentValue (ScalarValue pt signed _)) =+      T.pack $ prettySigned (signed == Unsigned) pt+    vdType (TransparentValue (ArrayValue _ _ pt signed shape)) =+      T.pack $+        mconcat (replicate (length shape) "[]")+          <> prettySigned (signed == Unsigned) pt+    vdType (OpaqueValue name _) =+      T.pack name -    outputManifest vd =-      let (t, u) = vdTypeAndUnique vd-       in Manifest.Output-            { Manifest.outputType = t,-              Manifest.outputUnique = u-            }-    inputManifest (v, vd) =-      let (t, u) = vdTypeAndUnique vd-       in Manifest.Input-            { Manifest.inputName = nameToText v,-              Manifest.inputType = t,-              Manifest.inputUnique = u-            }+    outputManifest (u, vd) =+      Manifest.Output+        { Manifest.outputType = vdType vd,+          Manifest.outputUnique = u == Unique+        }+    inputManifest ((v, u), vd) =+      Manifest.Input+        { Manifest.inputName = nameToText v,+          Manifest.inputType = vdType vd,+          Manifest.inputUnique = u == Unique+        }  -- | The result of compilation to C is multiple parts, which can be -- put together in various ways.  The obvious way is to concatenate@@ -1539,26 +1767,26 @@ asServer parts =   gnuSource <> disableWarnings <> cHeader parts <> cUtils parts <> cServer parts <> cLib parts --- | Compile imperative program to a C program.  Always uses the--- function named "main" as entry point, so make sure it is defined.-compileProg ::+compileProg' ::   MonadFreshNames m =>   T.Text ->   T.Text ->-  Operations op () ->-  CompilerM op () () ->+  Operations op s ->+  s ->+  CompilerM op s () ->   T.Text ->-  [Space] ->+  (Space, [Space]) ->   [Option] ->   Definitions op ->-  m CParts-compileProg backend version ops extra header_extra spaces options prog = do+  m (CParts, CompilerState s)+compileProg' backend version ops def extra header_extra (arr_space, spaces) options prog = do   src <- getNameSource   let ((prototypes, definitions, entry_point_decls, manifest), endstate) =-        runCompilerM ops src () compileProg'+        runCompilerM ops src def compileProgAction       initdecls = initDecls endstate       entrydecls = entryDecls endstate       arraydecls = arrayDecls endstate+      opaquetypedecls = opaqueTypeDecls endstate       opaquedecls = opaqueDecls endstate       miscdecls = miscDecls endstate @@ -1582,6 +1810,7 @@ $arraydecls  // Opaque values+$opaquetypedecls $opaquedecls  // Entry points@@ -1651,18 +1880,20 @@   |]    pure-    CParts-      { cHeader = headerdefs,-        cUtils = utildefs,-        cCLI = clidefs,-        cServer = serverdefs,-        cLib = libdefs,-        cJsonManifest = Manifest.manifestToJSON manifest-      }+    ( CParts+        { cHeader = headerdefs,+          cUtils = utildefs,+          cCLI = clidefs,+          cServer = serverdefs,+          cLib = libdefs,+          cJsonManifest = Manifest.manifestToJSON manifest+        },+      endstate+    )   where-    Definitions consts (Functions funs) = prog+    Definitions types consts (Functions funs) = prog -    compileProg' = do+    compileProgAction = do       (memstructs, memfuns, memreport) <- unzip3 <$> mapM defineMemorySpace spaces        get_consts <- compileConstants consts@@ -1680,13 +1911,14 @@        mapM_ earlyDecl $ concat memfuns -      types <- commonLibFuns memreport+      type_funs <- generateAPITypes arr_space types+      generateCommonLibFuns memreport        pure         ( T.unlines $ map prettyText prototypes,           T.unlines $ map (prettyText . funcToDef) functions,           T.unlines $ map prettyText entry_points,-          Manifest.Manifest (M.fromList entry_points_manifest) types backend version+          Manifest.Manifest (M.fromList entry_points_manifest) type_funs backend version         )      funcToDef func = C.FuncDef func loc@@ -1695,9 +1927,24 @@           C.OldFunc _ _ _ _ _ _ l -> l           C.Func _ _ _ _ _ l -> l -commonLibFuns :: [C.BlockItem] -> CompilerM op s (M.Map T.Text Manifest.Type)-commonLibFuns memreport = do-  types <- generateAPITypes+-- | Compile imperative program to a C program.  Always uses the+-- function named "main" as entry point, so make sure it is defined.+compileProg ::+  MonadFreshNames m =>+  T.Text ->+  T.Text ->+  Operations op () ->+  CompilerM op () () ->+  T.Text ->+  (Space, [Space]) ->+  [Option] ->+  Definitions op ->+  m CParts+compileProg backend version ops extra header_extra (arr_space, spaces) options prog =+  fst <$> compileProg' backend version ops () extra header_extra (arr_space, spaces) options prog++generateCommonLibFuns :: [C.BlockItem] -> CompilerM op s ()+generateCommonLibFuns memreport = do   ctx <- contextType   cfg <- configType   ops <- asks envOperations@@ -1788,8 +2035,6 @@                        }|]     ) -  pure types- compileConstants :: Constants op -> CompilerM op s [C.BlockItem] compileConstants (Constants ps init_consts) = do   ctx_ty <- contextType@@ -1897,7 +2142,7 @@   local lexMem $ f (concatMap declCached cached') (map freeCached cached')  compileFun :: [C.BlockItem] -> [C.Param] -> (Name, Function op) -> CompilerM op s (C.Definition, C.Func)-compileFun get_constants extra (fname, func@(Function _ outputs inputs body _ _)) = inNewFunction $ do+compileFun get_constants extra (fname, func@(Function _ outputs inputs body)) = inNewFunction $ do   (outparams, out_ptrs) <- unzip <$> mapM compileOutput outputs   inparams <- mapM compileInput inputs @@ -2164,7 +2409,7 @@ compileCode (Copy _ dest (Count destoffset) destspace src (Count srcoffset) srcspace (Count size)) = do   copy <- asks envCopy   join $-    copy+    copy CopyBarrier       <$> rawMem dest       <*> compileExp (untyped destoffset)       <*> pure destspace
src/Futhark/CodeGen/Backends/GenericC/CLI.hs view
@@ -190,7 +190,7 @@             [C.cstm|;|],             [C.cexp|$id:dest|]           )-    Just (TypeOpaque desc _) ->+    Just (TypeOpaque desc _ _) ->       ( [C.citems|futhark_panic(1, "Cannot read input #%d of type %s\n", $int:i, $string:(T.unpack desc));|],         [C.cstm|;|],         [C.cstm|;|],@@ -256,7 +256,7 @@             [C.cexp|$id:result|],             [C.cstm|assert($id:(arrayFree ops)(ctx, $id:result) == 0);|]           )-        Just (TypeOpaque t ops) ->+        Just (TypeOpaque t ops _) ->           ( [C.citem|typename $id:t $id:result;|],             [C.cexp|$id:result|],             [C.cstm|assert($id:(opaqueFree ops)(ctx, $id:result) == 0);|]@@ -269,7 +269,7 @@     Nothing ->       let info = tname <> "_info"        in [C.cstm|write_scalar(stdout, binary_output, &$id:info, &$exp:e);|]-    Just (TypeOpaque desc _) ->+    Just (TypeOpaque desc _ _) ->       [C.cstm|printf("#<opaque %s>", $string:(T.unpack desc));|]     Just (TypeArray _ et rank ops) ->       let et' = uncurry primAPIType $ scalarToPrim et@@ -409,7 +409,8 @@       (cli_entry_point_decls, entry_point_inits) =         unzip $           map (uncurry (cliEntryPoint manifest)) $-            M.toList $ manifestEntryPoints manifest+            M.toList $+              manifestEntryPoints manifest    in prettyText         [C.cunit| $esc:("#include <getopt.h>")
src/Futhark/CodeGen/Backends/GenericC/Options.hs view
@@ -136,8 +136,8 @@     optionStringChunk option = do       short <- optionShortName option       pure $-        short :-        case optionArgument option of-          NoArgument -> ""-          RequiredArgument _ -> ":"-          OptionalArgument -> "::"+        short+          : case optionArgument option of+            NoArgument -> ""+            RequiredArgument _ -> ":"+            OptionalArgument -> "::"
src/Futhark/CodeGen/Backends/GenericC/Server.hs view
@@ -113,21 +113,31 @@ typeStructName :: T.Text -> String typeStructName tname = "type_" <> zEncodeString (T.unpack tname) -typeBoilerplate :: (T.Text, Type) -> (C.Initializer, [C.Definition])-typeBoilerplate (tname, TypeArray _ et rank ops) =+cType :: Manifest -> TypeName -> C.Type+cType manifest tname =+  case M.lookup tname $ manifestTypes manifest of+    Just (TypeArray ctype _ _ _) -> [C.cty|typename $id:(T.unpack ctype)|]+    Just (TypeOpaque ctype _ _) -> [C.cty|typename $id:(T.unpack ctype)|]+    Nothing -> uncurry primAPIType $ scalarToPrim tname++-- First component is forward declaration so we don't have to worry+-- about ordering.+typeBoilerplate :: Manifest -> (T.Text, Type) -> (C.Definition, C.Initializer, [C.Definition])+typeBoilerplate _ (tname, TypeArray _ et rank ops) =   let type_name = typeStructName tname       aux_name = type_name ++ "_aux"       info_name = T.unpack et ++ "_info"       shape_args = [[C.cexp|shape[$int:i]|] | i <- [0 .. rank - 1]]       array_new_wrap = arrayNew ops <> "_wrap"-   in ( [C.cinit|&$id:type_name|],+   in ( [C.cedecl|const struct type $id:type_name;|],+        [C.cinit|&$id:type_name|],         [C.cunit|               void* $id:array_new_wrap(struct futhark_context *ctx,                                        const void* p,                                        const typename int64_t* shape) {                 return $id:(arrayNew ops)(ctx, p, $args:shape_args);               }-              struct array_aux $id:aux_name = {+              const struct array_aux $id:aux_name = {                 .name = $string:(T.unpack tname),                 .rank = $int:rank,                 .info = &$id:info_name,@@ -136,7 +146,7 @@                 .shape = (typename array_shape_fn)$id:(arrayShape ops),                 .values = (typename array_values_fn)$id:(arrayValues ops)               };-              struct type $id:type_name = {+              const struct type $id:type_name = {                 .name = $string:(T.unpack tname),                 .restore = (typename restore_fn)restore_array,                 .store = (typename store_fn)store_array,@@ -144,28 +154,67 @@                 .aux = &$id:aux_name               };|]       )-typeBoilerplate (tname, TypeOpaque _ ops) =+typeBoilerplate manifest (tname, TypeOpaque c_type_name ops record) =   let type_name = typeStructName tname-      aux_name = type_name ++ "_aux"-   in ( [C.cinit|&$id:type_name|],-        [C.cunit|-              struct opaque_aux $id:aux_name = {+      aux_name = type_name <> "_aux"+      (record_edecls, record_init) = recordDefs type_name record+   in ( [C.cedecl|const struct type $id:type_name;|],+        [C.cinit|&$id:type_name|],+        record_edecls+          ++ [C.cunit|+              const struct opaque_aux $id:aux_name = {                 .store = (typename opaque_store_fn)$id:(opaqueStore ops),                 .restore = (typename opaque_restore_fn)$id:(opaqueRestore ops),                 .free = (typename opaque_free_fn)$id:(opaqueFree ops)               };-              struct type $id:type_name = {+              const struct type $id:type_name = {                 .name = $string:(T.unpack tname),                 .restore = (typename restore_fn)restore_opaque,                 .store = (typename store_fn)store_opaque,                 .free = (typename free_fn)free_opaque,-                .aux = &$id:aux_name+                .aux = &$id:aux_name,+                .record = $init:record_init               };|]       )+  where+    recordDefs _ Nothing = ([], [C.cinit|NULL|])+    recordDefs type_name (Just (RecordOps fields new)) =+      let new_wrap = new <> "_wrap"+          record_name = type_name <> "_record"+          fields_name = type_name <> "_fields"+          onField i (RecordField name field_tname project) =+            let field_c_type = cType manifest field_tname+                field_v = "v" <> show (i :: Int)+             in ( [C.cinit|{.name = $string:(T.unpack name),+                            .type = &$id:(typeStructName field_tname),+                            .project = (typename project_fn)$id:project+                           }|],+                  [C.citem|const $ty:field_c_type $id:field_v =+                            *(const $ty:field_c_type*)fields[$int:i];|],+                  [C.cexp|$id:field_v|]+                )+          (field_inits, get_fields, field_args) = unzip3 $ zipWith onField [0 ..] fields+       in ( [C.cunit|+             const struct field $id:fields_name[] = {+               $inits:field_inits+             };+             int $id:new_wrap(struct futhark_context* ctx, void** outp, const void* fields[]) {+               typename $id:c_type_name *out = (typename $id:c_type_name*) outp;+               $items:get_fields+               return $id:new(ctx, out, $args:field_args);+             }+             const struct record $id:record_name = {+               .num_fields = $int:(length fields),+               .fields = $id:fields_name,+               .new = $id:new_wrap+             };|],+            [C.cinit|&$id:record_name|]+          ) -entryTypeBoilerplate :: Manifest -> ([C.Initializer], [C.Definition])-entryTypeBoilerplate =-  second concat . unzip . map typeBoilerplate . M.toList . manifestTypes+entryTypeBoilerplate :: Manifest -> ([C.Definition], [C.Initializer], [C.Definition])+entryTypeBoilerplate manifest =+  second concat . unzip3 . map (typeBoilerplate manifest) . M.toList . manifestTypes $+    manifest  oneEntryBoilerplate :: Manifest -> (T.Text, EntryPoint) -> ([C.Definition], C.Initializer) oneEntryBoilerplate manifest (name, EntryPoint cfun outputs inputs) =@@ -183,14 +232,14 @@         | null in_types = ([C.citems|(void)ins;|], mempty)         | otherwise = unzip $ zipWith loadIn [0 ..] in_types    in ( [C.cunit|-                struct type* $id:out_types_name[] = {+                const struct type* $id:out_types_name[] = {                   $inits:(map typeStructInit out_types),                   NULL                 };                 bool $id:out_unique_name[] = {                   $inits:(map outputUniqueInit outputs)                 };-                struct type* $id:in_types_name[] = {+                const struct type* $id:in_types_name[] = {                   $inits:(map typeStructInit in_types),                   NULL                 };@@ -219,20 +268,14 @@     uniqueInit True = [C.cinit|true|]     uniqueInit False = [C.cinit|false|] -    cType tname =-      case M.lookup tname $ manifestTypes manifest of-        Just (TypeArray ctype _ _ _) -> [C.cty|typename $id:(T.unpack ctype)|]-        Just (TypeOpaque ctype _) -> [C.cty|typename $id:(T.unpack ctype)|]-        Nothing -> uncurry primAPIType $ scalarToPrim tname-     loadOut i tname =       let v = "out" ++ show (i :: Int)-       in ( [C.citem|$ty:(cType tname) *$id:v = outs[$int:i];|],+       in ( [C.citem|$ty:(cType manifest tname) *$id:v = outs[$int:i];|],             [C.cexp|$id:v|]           )     loadIn i tname =       let v = "in" ++ show (i :: Int)-       in ( [C.citem|$ty:(cType tname) $id:v = *($ty:(cType tname)*)ins[$int:i];|],+       in ( [C.citem|$ty:(cType manifest tname) $id:v = *($ty:(cType manifest tname)*)ins[$int:i];|],             [C.cexp|$id:v|]           ) @@ -241,16 +284,17 @@   first concat $     unzip $       map (oneEntryBoilerplate manifest) $-        M.toList $ manifestEntryPoints manifest+        M.toList $+          manifestEntryPoints manifest  mkBoilerplate ::   Manifest ->   ([C.Definition], [C.Initializer], [C.Initializer]) mkBoilerplate manifest =-  let (type_inits, type_defs) = entryTypeBoilerplate manifest+  let (type_decls, type_inits, type_defs) = entryTypeBoilerplate manifest       (entry_defs, entry_inits) = entryBoilerplate manifest       scalar_type_inits = map scalarTypeInit scalar_types-   in (type_defs ++ entry_defs, scalar_type_inits ++ type_inits, entry_inits)+   in (type_decls ++ type_defs ++ entry_defs, scalar_type_inits ++ type_inits, entry_inits)   where     scalarTypeInit tname = [C.cinit|&$id:(typeStructName tname)|]     scalar_types =@@ -292,7 +336,7 @@  $edecls:boilerplate_defs -struct type* types[] = {+const struct type* types[] = {   $inits:type_inits,   NULL };
src/Futhark/CodeGen/Backends/GenericPython.hs view
@@ -56,12 +56,12 @@ import qualified Futhark.CodeGen.ImpCode as Imp import Futhark.CodeGen.RTS.Python import Futhark.Compiler.Config (CompilerMode (..))-import Futhark.IR.Primitive hiding (Bool) import Futhark.IR.Prop (isBuiltInFunction, subExpVars) import Futhark.IR.Syntax.Core (Space (..)) import Futhark.MonadFreshNames import Futhark.Util (zEncodeString) import Futhark.Util.Pretty (pretty, prettyText)+import Language.Futhark.Primitive hiding (Bool)  -- | A substitute expression compiler, tried before the main -- compilation function.@@ -331,17 +331,20 @@            }        ] -functionExternalValues :: Imp.Function a -> [Imp.ExternalValue]-functionExternalValues fun = Imp.functionResult fun ++ map snd (Imp.functionArgs fun)+functionExternalValues :: Imp.EntryPoint -> [Imp.ExternalValue]+functionExternalValues entry =+  map snd (Imp.entryPointResults entry) ++ map snd (Imp.entryPointArgs entry)  opaqueDefs :: Imp.Functions a -> M.Map String [PyExp] opaqueDefs (Imp.Functions funs) =-  mconcat . map evd . concatMap (functionExternalValues . snd) $-    filter (isJust . Imp.functionEntry . snd) funs+  mconcat+    . map evd+    . concatMap functionExternalValues+    . mapMaybe (Imp.functionEntry . snd)+    $ funs   where     evd Imp.TransparentValue {} = mempty-    evd (Imp.OpaqueValue _ name vds) =-      M.singleton name $ map (String . vd) vds+    evd (Imp.OpaqueValue name vds) = M.singleton name $ map (String . vd) vds     vd (Imp.ScalarValue pt s _) =       readTypeEnum pt s     vd (Imp.ArrayValue _ _ pt s dims) =@@ -390,7 +393,7 @@          ]       ++ prog'   where-    Imp.Definitions consts (Imp.Functions funs) = prog+    Imp.Definitions _types consts (Imp.Functions funs) = prog     compileProg' = withConstantSubsts consts $ do       compileConstants consts @@ -406,11 +409,11 @@           pure             [ ClassDef $                 Class class_name $-                  Assign (Var "entry_points") (Dict entry_point_types) :-                  Assign-                    (Var "opaques")-                    (Dict $ zip (map String opaque_names) (map Tuple opaque_payloads)) :-                  map FunDef (constructor' : definitions ++ entry_points)+                  Assign (Var "entry_points") (Dict entry_point_types)+                    : Assign+                      (Var "opaques")+                      (Dict $ zip (map String opaque_names) (map Tuple opaque_payloads))+                    : map FunDef (constructor' : definitions ++ entry_points)             ]         ToServer -> do           (entry_points, entry_point_types) <-@@ -419,11 +422,11 @@             parse_options_server               ++ [ ClassDef                      ( Class class_name $-                         Assign (Var "entry_points") (Dict entry_point_types) :-                         Assign-                           (Var "opaques")-                           (Dict $ zip (map String opaque_names) (map Tuple opaque_payloads)) :-                         map FunDef (constructor' : definitions ++ entry_points)+                         Assign (Var "entry_points") (Dict entry_point_types)+                           : Assign+                             (Var "opaques")+                             (Dict $ zip (map String opaque_names) (map Tuple opaque_payloads))+                           : map FunDef (constructor' : definitions ++ entry_points)                      ),                    Assign                      (Var "server")@@ -440,18 +443,18 @@                 ( Class class_name $                     map FunDef $                       constructor' : definitions-                ) :-            classinst :-            map FunDef entry_point_defs+                )+              : classinst+              : map FunDef entry_point_defs               ++ selectEntryPoint entry_point_names entry_points      parse_options_executable =-      Assign (Var "runtime_file") None :-      Assign (Var "do_warmup_run") (Bool False) :-      Assign (Var "num_runs") (Integer 1) :-      Assign (Var "entry_point") (String "main") :-      Assign (Var "binary_output") (Bool False) :-      generateOptionParser (executableOptions ++ options)+      Assign (Var "runtime_file") None+        : Assign (Var "do_warmup_run") (Bool False)+        : Assign (Var "num_runs") (Integer 1)+        : Assign (Var "entry_point") (String "main")+        : Assign (Var "binary_output") (Bool False)+        : generateOptionParser (executableOptions ++ options)      parse_options_server =       generateOptionParser (standardOptions ++ options)@@ -461,7 +464,8 @@      selectEntryPoint entry_point_names entry_points =       [ Assign (Var "entry_points") $-          Dict $ zip (map String entry_point_names) entry_points,+          Dict $+            zip (map String entry_point_names) entry_points,         Assign (Var "entry_point_fun") $           simpleCall "entry_points.get" [Var "entry_point"],         If@@ -492,7 +496,10 @@     constExp p =       M.singleton (Imp.paramName p) $         Index (Var "self.constants") $-          IdxExp $ String $ pretty $ Imp.paramName p+          IdxExp $+            String $+              pretty $+                Imp.paramName p  compileConstants :: Imp.Constants op -> CompilerM op s () compileConstants (Imp.Constants _ init_consts) = do@@ -500,7 +507,7 @@   mapM_ atInit =<< collect (compileCode init_consts)  compileFunc :: (Name, Imp.Function op) -> CompilerM op s PyFunDef-compileFunc (fname, Imp.Function _ outputs inputs body _ _) = do+compileFunc (fname, Imp.Function _ outputs inputs body) = do   body' <- collect $ compileCode body   let inputs' = map (compileName . Imp.paramName) inputs   let ret = Return $ tupleOrSingle $ compileOutput outputs@@ -545,18 +552,18 @@       ]  entryPointOutput :: Imp.ExternalValue -> CompilerM op s PyExp-entryPointOutput (Imp.OpaqueValue u desc vs) =+entryPointOutput (Imp.OpaqueValue desc vs) =   simpleCall "opaque" . (String (pretty desc) :)-    <$> mapM (entryPointOutput . Imp.TransparentValue u) vs-entryPointOutput (Imp.TransparentValue _ (Imp.ScalarValue bt ept name)) = do+    <$> mapM (entryPointOutput . Imp.TransparentValue) vs+entryPointOutput (Imp.TransparentValue (Imp.ScalarValue bt ept name)) = do   name' <- compileVar name   pure $ simpleCall tf [name']   where     tf = compilePrimToExtNp bt ept-entryPointOutput (Imp.TransparentValue _ (Imp.ArrayValue mem (Imp.Space sid) bt ept dims)) = do+entryPointOutput (Imp.TransparentValue (Imp.ArrayValue mem (Imp.Space sid) bt ept dims)) = do   pack_output <- asks envEntryOutput   pack_output mem sid bt ept dims-entryPointOutput (Imp.TransparentValue _ (Imp.ArrayValue mem _ bt ept dims)) = do+entryPointOutput (Imp.TransparentValue (Imp.ArrayValue mem _ bt ept dims)) = do   mem' <- Cast <$> compileVar mem <*> pure (compilePrimTypeExt bt ept)   dims' <- mapM compileDim dims   pure $ simpleCall "createArray" [mem', Tuple dims', Var $ compilePrimToExtNp bt ept]@@ -621,14 +628,14 @@ declEntryPointInputSizes :: [Imp.ExternalValue] -> CompilerM op s () declEntryPointInputSizes = mapM_ onSize . concatMap sizes   where-    sizes (Imp.TransparentValue _ v) = valueSizes v-    sizes (Imp.OpaqueValue _ _ vs) = concatMap valueSizes vs+    sizes (Imp.TransparentValue v) = valueSizes v+    sizes (Imp.OpaqueValue _ vs) = concatMap valueSizes vs     valueSizes (Imp.ArrayValue _ _ _ _ dims) = subExpVars dims     valueSizes Imp.ScalarValue {} = []     onSize v = stm $ Assign (Var (compileName v)) None  entryPointInput :: (Int, Imp.ExternalValue, PyExp) -> CompilerM op s ()-entryPointInput (i, Imp.OpaqueValue u desc vs, e) = do+entryPointInput (i, Imp.OpaqueValue desc vs, e) = do   let type_is_ok =         BinOp           "and"@@ -636,9 +643,9 @@           (BinOp "==" (Field e "desc") (String desc))   stm $ If (UnOp "not" type_is_ok) [badInput i e desc] []   mapM_ entryPointInput $-    zip3 (repeat i) (map (Imp.TransparentValue u) vs) $+    zip3 (repeat i) (map Imp.TransparentValue vs) $       map (Index (Field e "data") . IdxExp . Integer) [0 ..]-entryPointInput (i, Imp.TransparentValue _ (Imp.ScalarValue bt s name), e) = do+entryPointInput (i, Imp.TransparentValue (Imp.ScalarValue bt s name), e) = do   vname' <- compileVar name   let -- HACK: A Numpy int64 will signal an OverflowError if we pass       -- it a number bigger than 2**63.  This does not happen if we@@ -659,9 +666,9 @@       [Assign vname' npcall]       [ Catch           (Tuple [Var "TypeError", Var "AssertionError"])-          [badInput i e $ prettySigned (s == Imp.TypeUnsigned) bt]+          [badInput i e $ prettySigned (s == Imp.Unsigned) bt]       ]-entryPointInput (i, Imp.TransparentValue _ (Imp.ArrayValue mem (Imp.Space sid) bt ept dims), e) = do+entryPointInput (i, Imp.TransparentValue (Imp.ArrayValue mem (Imp.Space sid) bt ept dims), e) = do   unpack_input <- asks envEntryInput   mem' <- compileVar mem   unpack <- collect $ unpack_input mem' sid bt ept dims e@@ -672,10 +679,10 @@           (Tuple [Var "TypeError", Var "AssertionError"])           [ badInput i e $               concat (replicate (length dims) "[]")-                ++ prettySigned (ept == Imp.TypeUnsigned) bt+                ++ prettySigned (ept == Imp.Unsigned) bt           ]       ]-entryPointInput (i, Imp.TransparentValue _ (Imp.ArrayValue mem _ t s dims), e) = do+entryPointInput (i, Imp.TransparentValue (Imp.ArrayValue mem _ t s dims), e) = do   let type_is_wrong = UnOp "not" $ BinOp "in" (simpleCall "type" [e]) $ List [Var "np.ndarray"]   let dtype_is_wrong = UnOp "not" $ BinOp "==" (Field e "dtype") $ Var $ compilePrimToExtNp t s   let dim_is_wrong = UnOp "not" $ BinOp "==" (Field e "ndim") $ Integer $ toInteger $ length dims@@ -684,7 +691,7 @@       type_is_wrong       [ badInput i e $           concat (replicate (length dims) "[]")-            ++ prettySigned (s == Imp.TypeUnsigned) t+            ++ prettySigned (s == Imp.Unsigned) t       ]       []   stm $@@ -693,7 +700,7 @@       [ badInputType           i           e-          (concat (replicate (length dims) "[]") ++ prettySigned (s == Imp.TypeUnsigned) t)+          (concat (replicate (length dims) "[]") ++ prettySigned (s == Imp.Unsigned) t)           (simpleCall "np.dtype" [Var (compilePrimToExtNp t s)])           (Field e "dtype")       ]@@ -701,7 +708,7 @@   stm $     If       dim_is_wrong-      [badInputDim i e (prettySigned (s == Imp.TypeUnsigned) t) (length dims)]+      [badInputDim i e (prettySigned (s == Imp.Unsigned) t) (length dims)]       []    zipWithM_ (unpackDim e) dims [0 ..]@@ -711,9 +718,9 @@   stm $ Assign dest unwrap_call  extValueDescName :: Imp.ExternalValue -> String-extValueDescName (Imp.TransparentValue _ v) = extName $ valueDescName v-extValueDescName (Imp.OpaqueValue _ desc []) = extName $ zEncodeString desc-extValueDescName (Imp.OpaqueValue _ desc (v : _)) =+extValueDescName (Imp.TransparentValue v) = extName $ valueDescName v+extValueDescName (Imp.OpaqueValue desc []) = extName $ zEncodeString desc+extValueDescName (Imp.OpaqueValue desc (v : _)) =   extName $ zEncodeString desc ++ "_" ++ pretty (baseTag (valueDescVName v))  extName :: String -> String@@ -728,14 +735,14 @@  -- Key into the FUTHARK_PRIMTYPES dict. readTypeEnum :: PrimType -> Imp.Signedness -> String-readTypeEnum (IntType Int8) Imp.TypeUnsigned = "u8"-readTypeEnum (IntType Int16) Imp.TypeUnsigned = "u16"-readTypeEnum (IntType Int32) Imp.TypeUnsigned = "u32"-readTypeEnum (IntType Int64) Imp.TypeUnsigned = "u64"-readTypeEnum (IntType Int8) Imp.TypeDirect = "i8"-readTypeEnum (IntType Int16) Imp.TypeDirect = "i16"-readTypeEnum (IntType Int32) Imp.TypeDirect = "i32"-readTypeEnum (IntType Int64) Imp.TypeDirect = "i64"+readTypeEnum (IntType Int8) Imp.Unsigned = "u8"+readTypeEnum (IntType Int16) Imp.Unsigned = "u16"+readTypeEnum (IntType Int32) Imp.Unsigned = "u32"+readTypeEnum (IntType Int64) Imp.Unsigned = "u64"+readTypeEnum (IntType Int8) Imp.Signed = "i8"+readTypeEnum (IntType Int16) Imp.Signed = "i16"+readTypeEnum (IntType Int32) Imp.Signed = "i32"+readTypeEnum (IntType Int64) Imp.Signed = "i64" readTypeEnum (FloatType Float16) _ = "f16" readTypeEnum (FloatType Float32) _ = "f32" readTypeEnum (FloatType Float64) _ = "f64"@@ -743,15 +750,15 @@ readTypeEnum Unit _ = "bool"  readInput :: Imp.ExternalValue -> PyStmt-readInput (Imp.OpaqueValue _ desc _) =+readInput (Imp.OpaqueValue desc _) =   Raise $     simpleCall       "Exception"       [String $ "Cannot read argument of type " ++ desc ++ "."]-readInput decl@(Imp.TransparentValue _ (Imp.ScalarValue bt ept _)) =+readInput decl@(Imp.TransparentValue (Imp.ScalarValue bt ept _)) =   let type_name = readTypeEnum bt ept    in Assign (Var $ extValueDescName decl) $ simpleCall "read_value" [String type_name]-readInput decl@(Imp.TransparentValue _ (Imp.ArrayValue _ _ bt ept dims)) =+readInput decl@(Imp.TransparentValue (Imp.ArrayValue _ _ bt ept dims)) =   let type_name = readTypeEnum bt ept    in Assign (Var $ extValueDescName decl) $         simpleCall@@ -766,17 +773,17 @@     -- that returns an equivalent Numpy array.  This works for PyOpenCL,     -- but we will probably need yet another plugin mechanism here in     -- the future.-    printValue' (Imp.OpaqueValue _ desc _) _ =+    printValue' (Imp.OpaqueValue desc _) _ =       pure         [ Exp $             simpleCall               "sys.stdout.write"               [String $ "#<opaque " ++ desc ++ ">"]         ]-    printValue' (Imp.TransparentValue u (Imp.ArrayValue mem (Space _) bt ept shape)) e =-      printValue' (Imp.TransparentValue u (Imp.ArrayValue mem DefaultSpace bt ept shape)) $+    printValue' (Imp.TransparentValue (Imp.ArrayValue mem (Space _) bt ept shape)) e =+      printValue' (Imp.TransparentValue (Imp.ArrayValue mem DefaultSpace bt ept shape)) $         simpleCall (pretty e ++ ".get") []-    printValue' (Imp.TransparentValue _ _) e =+    printValue' (Imp.TransparentValue _) e =       pure         [ Exp $             Call@@ -788,6 +795,7 @@         ]  prepareEntry ::+  Imp.EntryPoint ->   (Name, Imp.Function op) ->   CompilerM     op@@ -798,7 +806,7 @@       [PyStmt],       [(Imp.ExternalValue, PyExp)]     )-prepareEntry (fname, Imp.Function _ outputs inputs _ results args) = do+prepareEntry (Imp.EntryPoint _ results args) (fname, Imp.Function _ outputs inputs _) = do   let output_paramNames = map (compileName . Imp.paramName) outputs       funTuple = tupleOrSingle $ fmap Var output_paramNames @@ -806,7 +814,7 @@     declEntryPointInputSizes $ map snd args     mapM_ entryPointInput . zip3 [0 ..] (map snd args) $       map (Var . extValueDescName . snd) args-  (res, prepareOut) <- collect' $ mapM entryPointOutput results+  (res, prepareOut) <- collect' $ mapM (entryPointOutput . snd) results    let argexps_lib = map (compileName . Imp.paramName) inputs       fname' = "self." ++ futharkFun (nameToString fname)@@ -827,7 +835,7 @@       prepareIn,       call argexps_lib,       prepareOut,-      zip results res+      zip (map snd results) res     )  copyMemoryDefaultSpace ::@@ -855,9 +863,10 @@   ReturnTiming ->   (Name, Imp.Function op) ->   CompilerM op s (Maybe (PyFunDef, (PyExp, PyExp)))-compileEntryFun sync timing entry-  | Just ename <- Imp.functionEntry $ snd entry = do-      (params, prepareIn, body_lib, prepareOut, res) <- prepareEntry entry+compileEntryFun sync timing fun+  | Just entry <- Imp.functionEntry $ snd fun = do+      let ename = Imp.entryPointName entry+      (params, prepareIn, body_lib, prepareOut, res) <- prepareEntry entry fun       let (maybe_sync, ret) =             case timing of               DoNotReturnTiming ->@@ -872,11 +881,12 @@                         tupleOrSingle $ map snd res                       ]                 )-          (pts, rts) = entryTypes $ snd entry+          (pts, rts) = entryTypes entry            do_run =-            Assign (Var "time_start") (simpleCall "time.time" []) :-            body_lib ++ maybe_sync+            Assign (Var "time_start") (simpleCall "time.time" [])+              : body_lib+              ++ maybe_sync               ++ [ Assign (Var "runtime") $                      BinOp                        "-"@@ -892,24 +902,24 @@           )   | otherwise = pure Nothing -entryTypes :: Imp.Function op -> ([String], [String])-entryTypes func =-  ( map (desc . snd) $ Imp.functionArgs func,-    map desc $ Imp.functionResult func-  )+entryTypes :: Imp.EntryPoint -> ([String], [String])+entryTypes (Imp.EntryPoint _ res args) =+  (map descArg args, map desc res)   where-    desc (Imp.OpaqueValue u d _) = pretty u <> d-    desc (Imp.TransparentValue u (Imp.ScalarValue pt s _)) = pretty u <> readTypeEnum pt s-    desc (Imp.TransparentValue u (Imp.ArrayValue _ _ pt s dims)) =+    descArg ((_, u), d) = desc (u, d)+    desc (u, Imp.OpaqueValue d _) = pretty u <> d+    desc (u, Imp.TransparentValue (Imp.ScalarValue pt s _)) = pretty u <> readTypeEnum pt s+    desc (u, Imp.TransparentValue (Imp.ArrayValue _ _ pt s dims)) =       pretty u <> concat (replicate (length dims) "[]") <> readTypeEnum pt s  callEntryFun ::   [PyStmt] ->   (Name, Imp.Function op) ->   CompilerM op s (Maybe (PyFunDef, String, PyExp))-callEntryFun _ (_, Imp.Function Nothing _ _ _ _ _) = pure Nothing-callEntryFun pre_timing entry@(fname, Imp.Function (Just ename) _ _ _ _ decl_args) = do-  (_, prepare_in, body_bin, _, res) <- prepareEntry entry+callEntryFun _ (_, Imp.Function Nothing _ _ _) = pure Nothing+callEntryFun pre_timing fun@(fname, Imp.Function (Just entry) _ _ _) = do+  let Imp.EntryPoint ename _ decl_args = entry+  (_, prepare_in, body_bin, _, res) <- prepareEntry entry fun    let str_input = map (readInput . snd) decl_args       end_of_input = [Exp $ simpleCall "end_of_input" [String $ pretty fname]]@@ -935,7 +945,9 @@   pure $     Just       ( Def fname' [] $-          str_input ++ end_of_input ++ prepare_in+          str_input+            ++ end_of_input+            ++ prepare_in             ++ [Try [do_warmup_run, do_num_runs] [except']]             ++ [close_runtime_file]             ++ str_output,@@ -1014,10 +1026,10 @@ compilePrimTypeExt :: PrimType -> Imp.Signedness -> String compilePrimTypeExt t ept =   case (t, ept) of-    (IntType Int8, Imp.TypeUnsigned) -> "ct.c_uint8"-    (IntType Int16, Imp.TypeUnsigned) -> "ct.c_uint16"-    (IntType Int32, Imp.TypeUnsigned) -> "ct.c_uint32"-    (IntType Int64, Imp.TypeUnsigned) -> "ct.c_uint64"+    (IntType Int8, Imp.Unsigned) -> "ct.c_uint8"+    (IntType Int16, Imp.Unsigned) -> "ct.c_uint16"+    (IntType Int32, Imp.Unsigned) -> "ct.c_uint32"+    (IntType Int64, Imp.Unsigned) -> "ct.c_uint64"     (IntType Int8, _) -> "ct.c_int8"     (IntType Int16, _) -> "ct.c_int16"     (IntType Int32, _) -> "ct.c_int32"@@ -1046,10 +1058,10 @@ compilePrimToExtNp :: Imp.PrimType -> Imp.Signedness -> String compilePrimToExtNp bt ept =   case (bt, ept) of-    (IntType Int8, Imp.TypeUnsigned) -> "np.uint8"-    (IntType Int16, Imp.TypeUnsigned) -> "np.uint16"-    (IntType Int32, Imp.TypeUnsigned) -> "np.uint32"-    (IntType Int64, Imp.TypeUnsigned) -> "np.uint64"+    (IntType Int8, Imp.Unsigned) -> "np.uint8"+    (IntType Int16, Imp.Unsigned) -> "np.uint16"+    (IntType Int32, Imp.Unsigned) -> "np.uint32"+    (IntType Int64, Imp.Unsigned) -> "np.uint64"     (IntType Int8, _) -> "np.int8"     (IntType Int16, _) -> "np.int16"     (IntType Int32, _) -> "np.int32"
src/Futhark/CodeGen/Backends/GenericPython/AST.hs view
@@ -131,18 +131,22 @@  instance Pretty PyStmt where   ppr (If cond [] []) =-    text "if" <+> ppr cond <> text ":"+    text "if"+      <+> ppr cond <> text ":"       </> indent 2 (text "pass")   ppr (If cond [] fbranch) =-    text "if" <+> ppr cond <> text ":"+    text "if"+      <+> ppr cond <> text ":"       </> indent 2 (text "pass")       </> text "else:"       </> indent 2 (stack $ map ppr fbranch)   ppr (If cond tbranch []) =-    text "if" <+> ppr cond <> text ":"+    text "if"+      <+> ppr cond <> text ":"       </> indent 2 (stack $ map ppr tbranch)   ppr (If cond tbranch fbranch) =-    text "if" <+> ppr cond <> text ":"+    text "if"+      <+> ppr cond <> text ":"       </> indent 2 (stack $ map ppr tbranch)       </> text "else:"       </> indent 2 (stack $ map ppr fbranch)@@ -151,13 +155,18 @@       </> indent 2 (stack $ map ppr pystms)       </> stack (map ppr pyexcepts)   ppr (While cond body) =-    text "while" <+> ppr cond <> text ":"+    text "while"+      <+> ppr cond <> text ":"       </> indent 2 (stack $ map ppr body)   ppr (For i what body) =-    text "for" <+> ppr i <+> text "in" <+> ppr what <> text ":"+    text "for"+      <+> ppr i+      <+> text "in"+      <+> ppr what <> text ":"       </> indent 2 (stack $ map ppr body)   ppr (With what body) =-    text "with" <+> ppr what <> text ":"+    text "with"+      <+> ppr what <> text ":"       </> indent 2 (stack $ map ppr body)   ppr (Assign e1 e2) = ppr e1 <+> text "=" <+> ppr e2   ppr (AssignOp op e1 e2) = ppr e1 <+> text (op ++ "=") <+> ppr e2@@ -177,17 +186,21 @@  instance Pretty PyFunDef where   ppr (Def fname params body) =-    text "def" <+> text fname <> parens (commasep $ map ppr params) <> text ":"+    text "def"+      <+> text fname <> parens (commasep $ map ppr params) <> text ":"       </> indent 2 (stack (map ppr body))  instance Pretty PyClassDef where   ppr (Class cname body) =-    text "class" <+> text cname <> text ":"+    text "class"+      <+> text cname <> text ":"       </> indent 2 (stack (map ppr body))  instance Pretty PyExcept where   ppr (Catch pyexp stms) =-    text "except" <+> ppr pyexp <+> text "as e:"+    text "except"+      <+> ppr pyexp+      <+> text "as e:"       </> indent 2 (stack $ map ppr stms)  instance Pretty PyProg where
src/Futhark/CodeGen/Backends/GenericPython/Options.hs view
@@ -83,7 +83,9 @@       For         "optarg"         ( Index (Var "parser_result") $-            IdxExp $ String $ fieldName option+            IdxExp $+              String $+                fieldName option         )         $ optionAction option 
src/Futhark/CodeGen/Backends/GenericWASM.hs view
@@ -22,26 +22,26 @@ import Futhark.CodeGen.Backends.SimpleRep (opaqueName) import qualified Futhark.CodeGen.ImpCode.Sequential as Imp import Futhark.CodeGen.RTS.JavaScript-import Futhark.IR.Primitive+import Language.Futhark.Primitive import NeatInterpolation (text)  extToString :: Imp.ExternalValue -> String-extToString (Imp.TransparentValue u (Imp.ArrayValue vn _ pt s dimSize)) =-  concat (replicate (length dimSize) "[]") ++ extToString (Imp.TransparentValue u (Imp.ScalarValue pt s vn))-extToString (Imp.TransparentValue _ (Imp.ScalarValue (FloatType Float16) _ _)) = "f16"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (FloatType Float32) _ _)) = "f32"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (FloatType Float64) _ _)) = "f64"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (IntType Int8) Imp.TypeDirect _)) = "i8"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (IntType Int16) Imp.TypeDirect _)) = "i16"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (IntType Int32) Imp.TypeDirect _)) = "i32"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (IntType Int64) Imp.TypeDirect _)) = "i64"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (IntType Int8) Imp.TypeUnsigned _)) = "u8"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (IntType Int16) Imp.TypeUnsigned _)) = "u16"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (IntType Int32) Imp.TypeUnsigned _)) = "u32"-extToString (Imp.TransparentValue _ (Imp.ScalarValue (IntType Int64) Imp.TypeUnsigned _)) = "u64"-extToString (Imp.TransparentValue _ (Imp.ScalarValue Bool _ _)) = "bool"-extToString (Imp.TransparentValue _ (Imp.ScalarValue Unit _ _)) = error "extToString: Unit"-extToString (Imp.OpaqueValue _ oname vds) = opaqueName oname vds+extToString (Imp.TransparentValue (Imp.ArrayValue vn _ pt s dimSize)) =+  concat (replicate (length dimSize) "[]") ++ extToString (Imp.TransparentValue (Imp.ScalarValue pt s vn))+extToString (Imp.TransparentValue (Imp.ScalarValue (FloatType Float16) _ _)) = "f16"+extToString (Imp.TransparentValue (Imp.ScalarValue (FloatType Float32) _ _)) = "f32"+extToString (Imp.TransparentValue (Imp.ScalarValue (FloatType Float64) _ _)) = "f64"+extToString (Imp.TransparentValue (Imp.ScalarValue (IntType Int8) Imp.Signed _)) = "i8"+extToString (Imp.TransparentValue (Imp.ScalarValue (IntType Int16) Imp.Signed _)) = "i16"+extToString (Imp.TransparentValue (Imp.ScalarValue (IntType Int32) Imp.Signed _)) = "i32"+extToString (Imp.TransparentValue (Imp.ScalarValue (IntType Int64) Imp.Signed _)) = "i64"+extToString (Imp.TransparentValue (Imp.ScalarValue (IntType Int8) Imp.Unsigned _)) = "u8"+extToString (Imp.TransparentValue (Imp.ScalarValue (IntType Int16) Imp.Unsigned _)) = "u16"+extToString (Imp.TransparentValue (Imp.ScalarValue (IntType Int32) Imp.Unsigned _)) = "u32"+extToString (Imp.TransparentValue (Imp.ScalarValue (IntType Int64) Imp.Unsigned _)) = "u64"+extToString (Imp.TransparentValue (Imp.ScalarValue Bool _ _)) = "bool"+extToString (Imp.TransparentValue (Imp.ScalarValue Unit _ _)) = error "extToString: Unit"+extToString (Imp.OpaqueValue oname _) = opaqueName oname  type EntryPointType = String @@ -204,7 +204,9 @@  makeResult :: Int -> String -> String makeResult i typ =-  "  var result" ++ show i ++ " = "+  "  var result"+    ++ show i+    ++ " = "     ++ if isArray typ       then "this.new_" ++ signature ++ "_from_ptr(" ++ readout ++ ");"       else
src/Futhark/CodeGen/Backends/MulticoreC.hs view
@@ -12,6 +12,20 @@     GC.asServer,     operations,     cliOptions,+    compileOp,+    ValueType (..),+    paramToCType,+    prepareTaskStruct,+    closureFreeStructField,+    generateParLoopFn,+    addTimingFields,+    functionTiming,+    functionIterations,+    multiCoreReport,+    multicoreDef,+    multicoreName,+    DefSpecifier,+    atomicOps,   ) where @@ -23,7 +37,7 @@ 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 Futhark.CodeGen.ImpCode.Multicore hiding (ValueType) import qualified Futhark.CodeGen.ImpGen.Multicore as ImpGen import Futhark.CodeGen.RTS.C (schedulerH) import Futhark.IR.MCMem (MCMem, Prog)@@ -42,10 +56,10 @@         operations         generateContext         ""-        [DefaultSpace]+        (DefaultSpace, [DefaultSpace])         cliOptions     )-    <=< ImpGen.compileProg ImpGen.AllowDynamicScheduling+    <=< ImpGen.compileProg  -- | Generate the multicore context definitions.  This is exported -- because the WASM backend needs it.@@ -304,7 +318,10 @@ compileSetRetvalStructValues struct vnames we = concat $ zipWith field vnames we   where     field name (ct, Prim _) =-      [C.cstms|$id:struct.$id:(closureRetvalStructField name)=(($ty:ct*)&$id:name);|]+      [C.cstms|$id:struct.$id:(closureRetvalStructField name)=(($ty:ct*)&$id:name);+               $escstm:("#if ISPC")+               $id:struct.$id:(closureRetvalStructField name)+= programIndex;+               $escstm:("#endif")|]     field name (_, MemBlock) =       [C.cstms|$id:struct.$id:(closureRetvalStructField name)=$id:name.mem;|]     field name (_, RawMem) =@@ -576,7 +593,7 @@    e' <- GC.compileExp e -  let lexical = lexicalMemoryUsageMC TraverseKernels $ Function Nothing [] params seq_code [] []+  let lexical = lexicalMemoryUsageMC TraverseKernels $ Function Nothing [] params seq_code    fstruct <-     prepareTaskStruct multicoreDef "task" free_args free_ctypes retval_args retval_ctypes@@ -601,7 +618,7 @@   -- Generate the nested segop function if available   fnpar_task <- case par_task of     Just (ParallelTask nested_code) -> do-      let lexical_nested = lexicalMemoryUsageMC TraverseKernels $ Function Nothing [] params nested_code [] []+      let lexical_nested = lexicalMemoryUsageMC TraverseKernels $ Function Nothing [] params nested_code       fnpar_task <- generateParLoopFn lexical_nested (name ++ "_nested_task") nested_code fstruct free retval       GC.stm [C.cstm|$id:ftask_name.nested_fn = $id:fnpar_task;|]       pure $ zip [fnpar_task] [True]@@ -627,7 +644,7 @@   free_ctypes <- mapM paramToCType free   let free_args = map paramName free -  let lexical = lexicalMemoryUsageMC TraverseKernels $ Function Nothing [] free body [] []+  let lexical = lexicalMemoryUsageMC TraverseKernels $ Function Nothing [] free body    fstruct <-     prepareTaskStruct multicoreDef (s' ++ "_parloop_struct") free_args free_ctypes mempty mempty@@ -686,6 +703,29 @@   mapM_ GC.profileReport $ multiCoreReport $ zip [ftask, ftask_total] [True, False] compileOp (Atomic aop) =   atomicOps aop (\ty _ -> pure [C.cty|$ty:ty*|])+compileOp (ISPCKernel body _) =+  scopedBlock body+compileOp (ForEach i from bound body) = do+  let i' = C.toIdent i+      t = primTypeToCType $ primExpType bound+  from' <- GC.compileExp from+  bound' <- GC.compileExp bound+  body' <- GC.collect $ GC.compileCode body+  GC.stm+    [C.cstm|for ($ty:t $id:i' = $exp:from'; $id:i' < $exp:bound'; $id:i'++) {+            $items:body'+          }|]+compileOp (ForEachActive i body) = do+  GC.decl [C.cdecl|typename int64_t $id:i = 0;|]+  scopedBlock body+compileOp (ExtractLane dest tar _) = do+  tar' <- GC.compileExp tar+  GC.stm [C.cstm|$id:dest = $exp:tar';|]++scopedBlock :: MCCode -> GC.CompilerM Multicore s ()+scopedBlock code = do+  inner <- GC.collect $ GC.compileCode code+  GC.stm [C.cstm|{$items:inner}|]  doAtomic ::   (C.ToIdent a1) =>
+ src/Futhark/CodeGen/Backends/MulticoreISPC.hs view
@@ -0,0 +1,1114 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++-- | C code generator.  This module can convert a correct ImpCode+-- program to an equivalent ISPC program.+module Futhark.CodeGen.Backends.MulticoreISPC+  ( compileProg,+    GC.CParts (..),+    GC.asLibrary,+    GC.asExecutable,+    GC.asServer,+    operations,+    ISPCState,+  )+where++import Control.Lens (each, over)+import Control.Monad+import Control.Monad.Reader+import Control.Monad.State+import Data.Bifunctor+import qualified Data.DList as DL+import Data.List (unzip4)+import Data.Loc (noLoc)+import qualified Data.Map as M+import Data.Maybe+import qualified Data.Text as T+import qualified Futhark.CodeGen.Backends.GenericC as GC+import qualified Futhark.CodeGen.Backends.MulticoreC as MC+import Futhark.CodeGen.Backends.SimpleRep+import Futhark.CodeGen.ImpCode.Multicore+import qualified Futhark.CodeGen.ImpGen.Multicore as ImpGen+import Futhark.CodeGen.RTS.C (errorsH, ispcUtilH, uniformH)+import Futhark.IR.MCMem (MCMem, Prog)+import Futhark.IR.Prop (isBuiltInFunction)+import Futhark.MonadFreshNames+import Futhark.Util.Pretty (prettyText)+import qualified Language.C.Quote.OpenCL as C+import qualified Language.C.Syntax as C+import NeatInterpolation (untrimming)++type ISPCCompilerM a = GC.CompilerM Multicore ISPCState a++-- | Transient state tracked by the ISPC backend.+data ISPCState = ISPCState+  { sDefs :: DL.DList C.Definition,+    sUniform :: Names+  }++uniform :: C.TypeQual+uniform = C.EscTypeQual "uniform" noLoc++unmasked :: C.TypeQual+unmasked = C.EscTypeQual "unmasked" noLoc++export :: C.TypeQual+export = C.EscTypeQual "export" noLoc++varying :: C.TypeQual+varying = C.EscTypeQual "varying" noLoc++-- | Compile the program to C and ISPC code using multicore operations.+compileProg ::+  MonadFreshNames m => T.Text -> Prog MCMem -> m (ImpGen.Warnings, (GC.CParts, T.Text))+compileProg version prog = do+  -- Dynamic scheduling seems completely broken currently, so we disable it.+  (ws, defs) <- ImpGen.compileProg prog+  let Functions funs = defFuns defs++  (ws', (cparts, endstate)) <-+    traverse+      ( GC.compileProg'+          "ispc"+          version+          operations+          (ISPCState mempty mempty)+          ( do+              GC.libDecl [C.cedecl|char** futhark_get_error_ref(struct futhark_context* ctx) { return &ctx->error; }|]+              MC.generateContext+              mapM_ compileBuiltinFun funs+          )+          mempty+          (DefaultSpace, [DefaultSpace])+          MC.cliOptions+      )+      (ws, defs)++  let ispc_decls = T.unlines $ map prettyText $ DL.toList $ sDefs $ GC.compUserState endstate++  -- The bool #define is a workaround around an ISPC bug, stdbool doesn't get included.+  let ispcdefs =+        [untrimming|+#define bool uint8+typedef int64 int64_t;+typedef int32 int32_t;+typedef int16 int16_t;+typedef int8 int8_t;+typedef int8 char;+typedef unsigned int64 uint64_t;+typedef unsigned int32 uint32_t;+typedef unsigned int16 uint16_t;+typedef unsigned int8 uint8_t;+#define volatile++$errorsH++#define INFINITY (floatbits((uniform int)0x7f800000))+#define NAN (floatbits((uniform int)0x7fc00000))+#define fabs(x) abs(x)+#define FUTHARK_F64_ENABLED+$cScalarDefs++$uniformH++$ispcUtilH++$ispc_decls|]++  pure (ws', (cparts, ispcdefs))++-- | Compiler operations specific to the ISPC multicore backend.+operations :: GC.Operations Multicore ISPCState+operations =+  MC.operations+    { GC.opsCompiler = compileOp+    }++ispcDecl :: C.Definition -> ISPCCompilerM ()+ispcDecl def =+  GC.modifyUserState (\s -> s {sDefs = sDefs s <> DL.singleton def})++ispcEarlyDecl :: C.Definition -> ISPCCompilerM ()+ispcEarlyDecl def =+  GC.modifyUserState (\s -> s {sDefs = DL.singleton def <> sDefs s})++ispcDef :: MC.DefSpecifier ISPCState+ispcDef s f = do+  s' <- MC.multicoreName s+  ispcDecl =<< f s'+  pure s'++-- | Expose a struct to both ISPC and C.+sharedDef :: MC.DefSpecifier ISPCState+sharedDef s f = do+  s' <- MC.multicoreName s+  ispcDecl =<< f s'+  GC.earlyDecl =<< f s'+  pure s'++-- | Copy memory where one of the operands is using an AoS layout.+copyMemoryAOS ::+  PrimType ->+  C.Exp ->+  C.Exp ->+  C.Exp ->+  C.Exp ->+  C.Exp ->+  GC.CompilerM op s ()+copyMemoryAOS pt destmem destidx srcmem srcidx nbytes =+  GC.stm+    [C.cstm|if ($exp:nbytes > 0) {+              $id:overload($exp:destmem + $exp:destidx,+                      $exp:srcmem + $exp:srcidx,+                      extract($exp:nbytes, 0));+            }|]+  where+    size = show (8 * primByteSize pt :: Integer)+    overload = "memmove_" <> size++-- | ISPC has no string literals, so this makes one in C and exposes it via an+-- external function, returning the name.+makeStringLiteral :: String -> ISPCCompilerM Name+makeStringLiteral str = do+  name <- MC.multicoreDef "strlit_shim" $ \s ->+    pure [C.cedecl|char* $id:s() { return $string:str; }|]+  ispcDecl+    [C.cedecl|extern "C" $tyqual:unmasked $tyqual:uniform char* $tyqual:uniform $id:name();|]+  pure name++-- | Set memory in ISPC+setMem :: (C.ToExp a, C.ToExp b) => a -> b -> Space -> ISPCCompilerM ()+setMem dest src space = do+  let src_s = pretty $ C.toExp src noLoc+  strlit <- makeStringLiteral src_s+  GC.stm+    [C.cstm|if ($id:(GC.fatMemSet space)(ctx, &$exp:dest, &$exp:src,+                                            $id:strlit()) != 0) {+                    $escstm:("unmasked { return 1; }")+                  }|]++-- | Unref memory in ISPC+unRefMem :: C.ToExp a => a -> Space -> ISPCCompilerM ()+unRefMem mem space = do+  cached <- isJust <$> GC.cacheMem mem+  let mem_s = pretty $ C.toExp mem noLoc+  strlit <- makeStringLiteral mem_s+  unless cached $+    GC.stm+      [C.cstm|if ($id:(GC.fatMemUnRef space)(ctx, &$exp:mem, $id:strlit()) != 0) {+                  $escstm:("unmasked { return 1; }")+                }|]++-- | Allocate memory in ISPC+allocMem ::+  (C.ToExp a, C.ToExp b) =>+  a ->+  b ->+  Space ->+  C.Stm ->+  ISPCCompilerM ()+allocMem mem size space on_failure = do+  let mem_s = pretty $ C.toExp mem noLoc+  strlit <- makeStringLiteral mem_s+  GC.stm+    [C.cstm|if ($id:(GC.fatMemAlloc space)(ctx, &$exp:mem, $exp:size,+                                              $id:strlit())) {+                    $stm:on_failure+                  }|]++-- | Free memory in ISPC+freeAllocatedMem :: ISPCCompilerM [C.BlockItem]+freeAllocatedMem = GC.collect $ mapM_ (uncurry unRefMem) =<< gets GC.compDeclaredMem++-- | Given a ImpCode function, generate all the required machinery for calling+-- it in ISPC, both in a varying or uniform context. This involves handling+-- for the fact that ISPC cannot pass structs by value to external functions.+compileBuiltinFun :: (Name, Function op) -> ISPCCompilerM ()+compileBuiltinFun (fname, func@(Function _ outputs inputs _))+  | isNothing $ functionEntry func = do+      let extra = [[C.cparam|$tyqual:uniform struct futhark_context * $tyqual:uniform ctx|]]+          extra_c = [[C.cparam|struct futhark_context * ctx|]]+          extra_exp = [[C.cexp|$id:p|] | C.Param (Just p) _ _ _ <- extra]++      (inparams_c, in_args_c) <- unzip <$> mapM (compileInputsExtern []) inputs+      (outparams_c, out_args_c) <- unzip <$> mapM (compileOutputsExtern []) outputs++      (inparams_extern, _) <- unzip <$> mapM (compileInputsExtern [C.ctyquals|$tyqual:uniform|]) inputs+      (outparams_extern, _) <- unzip <$> mapM (compileOutputsExtern [C.ctyquals|$tyqual:uniform|]) outputs++      (inparams_uni, in_args_noderef) <- unzip <$> mapM compileInputsUniform inputs+      (outparams_uni, out_args_noderef) <- unzip <$> mapM compileOutputsUniform outputs++      (inparams_varying, in_args_vary, prebody_in') <- unzip3 <$> mapM compileInputsVarying inputs+      (outparams_varying, out_args_vary, prebody_out', postbody_out') <- unzip4 <$> mapM compileOutputsVarying outputs+      let (prebody_in, prebody_out, postbody_out) = over each concat (prebody_in', prebody_out', postbody_out')++      GC.libDecl+        =<< pure+          [C.cedecl|int $id:((funName fname) ++ "_extern")($params:extra_c, $params:outparams_c, $params:inparams_c) {+                  return $id:(funName fname)($args:extra_exp, $args:out_args_c, $args:in_args_c);+                }|]++      let ispc_extern =+            [C.cedecl|extern "C" $tyqual:unmasked $tyqual:uniform int $id:((funName fname) ++ "_extern")+                      ($params:extra, $params:outparams_extern, $params:inparams_extern);|]++          ispc_uniform =+            [C.cedecl|$tyqual:uniform int $id:(funName fname)+                    ($params:extra, $params:outparams_uni, $params:inparams_uni) {+                      return $id:(funName $ fname<>"_extern")(+                        $args:extra_exp,+                        $args:out_args_noderef,+                        $args:in_args_noderef);+                    }|]++          ispc_varying =+            [C.cedecl|$tyqual:uniform int $id:(funName fname)+                    ($params:extra, $params:outparams_varying, $params:inparams_varying) {+                        $tyqual:uniform int err = 0;+                        $items:prebody_in+                        $items:prebody_out+                        $escstm:("foreach_active (i)")+                        {+                          err |= $id:(funName $ fname<>"_extern")(+                            $args:extra_exp,+                            $args:out_args_vary,+                            $args:in_args_vary);+                        }+                        $items:postbody_out+                        return err;+                    }|]++      mapM_ ispcEarlyDecl [ispc_varying, ispc_uniform, ispc_extern]+  | otherwise = pure ()+  where+    compileInputsExtern vari (ScalarParam name bt) = do+      let ctp = GC.primTypeToCType bt+      pure ([C.cparam|$tyquals:vari $ty:ctp $id:name|], [C.cexp|$id:name|])+    compileInputsExtern vari (MemParam name space) = do+      ty <- GC.memToCType name space+      pure ([C.cparam|$tyquals:vari $ty:ty * $tyquals:vari $id:name|], [C.cexp|*$id:name|])++    compileOutputsExtern vari (ScalarParam name bt) = do+      p_name <- newVName $ "out_" ++ baseString name+      let ctp = GC.primTypeToCType bt+      pure ([C.cparam|$tyquals:vari $ty:ctp * $tyquals:vari $id:p_name|], [C.cexp|$id:p_name|])+    compileOutputsExtern vari (MemParam name space) = do+      ty <- GC.memToCType name space+      p_name <- newVName $ baseString name ++ "_p"+      pure ([C.cparam|$tyquals:vari $ty:ty * $tyquals:vari $id:p_name|], [C.cexp|$id:p_name|])++    compileInputsUniform (ScalarParam name bt) = do+      let ctp = GC.primTypeToCType bt+          params = [C.cparam|$tyqual:uniform $ty:ctp $id:name|]+          args = [C.cexp|$id:name|]+      pure (params, args)+    compileInputsUniform (MemParam name space) = do+      ty <- GC.memToCType name space+      let params = [C.cparam|$tyqual:uniform $ty:ty $id:name|]+          args = [C.cexp|&$id:name|]+      pure (params, args)++    compileOutputsUniform (ScalarParam name bt) = do+      p_name <- newVName $ "out_" ++ baseString name+      let ctp = GC.primTypeToCType bt+          params = [C.cparam|$tyqual:uniform $ty:ctp *$tyqual:uniform $id:p_name|]+          args = [C.cexp|$id:p_name|]+      pure (params, args)+    compileOutputsUniform (MemParam name space) = do+      ty <- GC.memToCType name space+      p_name <- newVName $ baseString name ++ "_p"+      let params = [C.cparam|$tyqual:uniform $ty:ty $id:p_name|]+          args = [C.cexp|&$id:p_name|]+      pure (params, args)++    compileInputsVarying (ScalarParam name bt) = do+      let ctp = GC.primTypeToCType bt+          params = [C.cparam|$ty:ctp $id:name|]+          args = [C.cexp|extract($id:name,i)|]+          pre_body = []+      pure (params, args, pre_body)+    compileInputsVarying (MemParam name space) = do+      typ <- GC.memToCType name space+      newvn <- newVName $ "aos_" <> baseString name+      let params = [C.cparam|$ty:typ $id:name|]+          args = [C.cexp|&$id:(newvn)[i]|]+          pre_body =+            [C.citems|$tyqual:uniform $ty:typ $id:(newvn)[programCount];+                               $id:(newvn)[programIndex] = $id:name;|]+      pure (params, args, pre_body)++    compileOutputsVarying (ScalarParam name bt) = do+      p_name <- newVName $ "out_" ++ baseString name+      deref_name <- newVName $ "aos_" ++ baseString name+      vari_p_name <- newVName $ "convert_" ++ baseString name+      let ctp = GC.primTypeToCType bt+          pre_body =+            [C.citems|$tyqual:varying $ty:ctp $id:vari_p_name = *$id:p_name;+                                $tyqual:uniform $ty:ctp $id:deref_name[programCount];+                                $id:deref_name[programIndex] = $id:vari_p_name;|]+          post_body = [C.citems|*$id:p_name = $id:(deref_name)[programIndex];|]+          params = [C.cparam|$tyqual:varying $ty:ctp * $tyqual:uniform $id:p_name|]+          args = [C.cexp|&$id:(deref_name)[i]|]+      pure (params, args, pre_body, post_body)+    compileOutputsVarying (MemParam name space) = do+      typ <- GC.memToCType name space+      newvn <- newVName $ "aos_" <> baseString name+      let params = [C.cparam|$ty:typ $id:name|]+          args = [C.cexp|&$id:(newvn)[i]|]+          pre_body =+            [C.citems|$tyqual:uniform $ty:typ $id:(newvn)[programCount];+                       $id:(newvn)[programIndex] = $id:name;|]+      pure (params, args, pre_body, [])++-- | Handle logging an error message in ISPC.+handleError :: ErrorMsg Exp -> String -> ISPCCompilerM ()+handleError msg stacktrace = do+  -- Get format sting+  (formatstr, formatargs) <- GC.errorMsgString msg+  let formatstr' = "Error: " <> formatstr <> "\n\nBacktrace:\n%s"+  -- Get args types and names for shim+  let arg_types = errorMsgArgTypes msg+  arg_names <- mapM (newVName . const "arg") arg_types+  let params = zipWith (\ty name -> [C.cparam|$ty:(GC.primTypeToCType ty) $id:name|]) arg_types arg_names+  let params_uni = zipWith (\ty name -> [C.cparam|$tyqual:uniform $ty:(GC.primTypeToCType ty) $id:name|]) arg_types arg_names+  -- Make shim+  let formatargs' = mapArgNames msg formatargs arg_names+  shim <- MC.multicoreDef "assert_shim" $ \s -> do+    pure+      [C.cedecl|void $id:s(struct futhark_context* ctx, $params:params) {+        if (ctx->error == NULL)+          ctx->error = msgprintf($string:formatstr', $args:formatargs', $string:stacktrace);+      }|]+  ispcDecl+    [C.cedecl|extern "C" $tyqual:unmasked void $id:shim($tyqual:uniform struct futhark_context* $tyqual:uniform, $params:params_uni);|]+  -- Call the shim+  args <- getErrorValExps msg+  uni <- newVName "uni"+  let args' = map (\x -> [C.cexp|extract($exp:x, $id:uni)|]) args+  GC.items+    [C.citems|+      $escstm:("foreach_active(" <> pretty uni <> ")")+      {+        $id:shim(ctx, $args:args');+        err = FUTHARK_PROGRAM_ERROR;+      }+      $escstm:("unmasked { return err; }")|]+  where+    getErrorVal (ErrorString _) = Nothing+    getErrorVal (ErrorVal _ v) = Just v++    getErrorValExps (ErrorMsg m) = mapM compileExp $ mapMaybe getErrorVal m++    mapArgNames' (x : xs) (y : ys) (t : ts)+      | isJust $ getErrorVal x = [C.cexp|$id:t|] : mapArgNames' xs ys ts+      | otherwise = y : mapArgNames' xs ys (t : ts)+    mapArgNames' _ ys [] = ys+    mapArgNames' _ _ _ = []++    mapArgNames (ErrorMsg parts) = mapArgNames' parts++-- | Given the name and type of a parameter, return the C type used to+-- represent it. We use uniform pointers to varying values for lexical+-- memory blocks, as this generally results in less gathers/scatters.+getMemType :: VName -> PrimType -> ISPCCompilerM C.Type+getMemType dest elemtype = do+  cached <- isJust <$> GC.cacheMem dest+  if cached+    then pure [C.cty|$tyqual:varying $ty:(primStorageType elemtype)* uniform|]+    else pure [C.cty|$ty:(primStorageType elemtype)*|]++compileExp :: Exp -> ISPCCompilerM C.Exp+compileExp e@(ValueExp (FloatValue (Float64Value v))) =+  if isInfinite v || isNaN v+    then GC.compileExp e+    else pure [C.cexp|$esc:(pretty v <> "d")|]+compileExp e@(ValueExp (FloatValue (Float16Value v))) =+  if isInfinite v || isNaN v+    then GC.compileExp e+    else pure [C.cexp|$esc:(pretty v <> "f16")|]+compileExp (ValueExp val) =+  pure $ C.toExp val mempty+compileExp (LeafExp v _) =+  pure [C.cexp|$id:v|]+compileExp (UnOpExp Complement {} x) = do+  x' <- compileExp x+  pure [C.cexp|~$exp:x'|]+compileExp (UnOpExp Not {} x) = do+  x' <- compileExp x+  pure [C.cexp|!$exp:x'|]+compileExp (UnOpExp (FAbs Float32) x) = do+  x' <- compileExp x+  pure [C.cexp|(float)fabs($exp:x')|]+compileExp (UnOpExp (FAbs Float64) x) = do+  x' <- compileExp x+  pure [C.cexp|fabs($exp:x')|]+compileExp (UnOpExp SSignum {} x) = do+  x' <- compileExp x+  pure [C.cexp|($exp:x' > 0 ? 1 : 0) - ($exp:x' < 0 ? 1 : 0)|]+compileExp (UnOpExp USignum {} x) = do+  x' <- compileExp x+  pure [C.cexp|($exp:x' > 0 ? 1 : 0) - ($exp:x' < 0 ? 1 : 0) != 0|]+compileExp (UnOpExp op x) = do+  x' <- compileExp x+  pure [C.cexp|$id:(pretty op)($exp:x')|]+compileExp (CmpOpExp cmp x y) = do+  x' <- compileExp x+  y' <- compileExp y+  pure $ case cmp of+    CmpEq {} -> [C.cexp|$exp:x' == $exp:y'|]+    FCmpLt {} -> [C.cexp|$exp:x' < $exp:y'|]+    FCmpLe {} -> [C.cexp|$exp:x' <= $exp:y'|]+    CmpLlt {} -> [C.cexp|$exp:x' < $exp:y'|]+    CmpLle {} -> [C.cexp|$exp:x' <= $exp:y'|]+    _ -> [C.cexp|$id:(pretty cmp)($exp:x', $exp:y')|]+compileExp (ConvOpExp conv x) = do+  x' <- compileExp x+  pure [C.cexp|$id:(pretty conv)($exp:x')|]+compileExp (BinOpExp bop x y) = do+  x' <- compileExp x+  y' <- compileExp y+  pure $ case bop of+    Add _ OverflowUndef -> [C.cexp|$exp:x' + $exp:y'|]+    Sub _ OverflowUndef -> [C.cexp|$exp:x' - $exp:y'|]+    Mul _ OverflowUndef -> [C.cexp|$exp:x' * $exp:y'|]+    FAdd {} -> [C.cexp|$exp:x' + $exp:y'|]+    FSub {} -> [C.cexp|$exp:x' - $exp:y'|]+    FMul {} -> [C.cexp|$exp:x' * $exp:y'|]+    FDiv {} -> [C.cexp|$exp:x' / $exp:y'|]+    Xor {} -> [C.cexp|$exp:x' ^ $exp:y'|]+    And {} -> [C.cexp|$exp:x' & $exp:y'|]+    Or {} -> [C.cexp|$exp:x' | $exp:y'|]+    LogAnd {} -> [C.cexp|$exp:x' && $exp:y'|]+    LogOr {} -> [C.cexp|$exp:x' || $exp:y'|]+    _ -> [C.cexp|$id:(pretty bop)($exp:x', $exp:y')|]+compileExp (FunExp h args _) = do+  args' <- mapM compileExp args+  pure [C.cexp|$id:(funName (nameFromString h))($args:args')|]++-- | Compile a block of code with ISPC specific semantics, falling back+-- to generic C when this semantics is not needed.+-- All recursive constructors are duplicated here, since not doing so+-- would cause use to enter regular generic C codegen with no escape.+compileCode :: MCCode -> ISPCCompilerM ()+compileCode (Comment s code) = do+  xs <- GC.collect $ compileCode code+  let comment = "// " ++ s+  GC.stm+    [C.cstm|$comment:comment+              { $items:xs }+             |]+compileCode (DeclareScalar name _ t) = do+  let ct = GC.primTypeToCType t+  quals <- getVariabilityQuals name+  GC.decl [C.cdecl|$tyquals:quals $ty:ct $id:name;|]+compileCode (DeclareArray name DefaultSpace t vs) = do+  name_realtype <- newVName $ baseString name ++ "_realtype"+  let ct = GC.primTypeToCType t+  case vs of+    ArrayValues vs' -> do+      let vs'' = [[C.cinit|$exp:v|] | v <- vs']+      GC.earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:(length vs')] = {$inits:vs''};|]+    ArrayZeros n ->+      GC.earlyDecl [C.cedecl|static $ty:ct $id:name_realtype[$int:n];|]+  -- Fake a memory block.+  GC.contextField+    (C.toIdent name noLoc)+    [C.cty|struct memblock|]+    $ Just [C.cexp|(struct memblock){NULL, (char*)$id:name_realtype, 0}|]+  -- Make an exported C shim to access it+  shim <- MC.multicoreDef "get_static_array_shim" $ \f ->+    pure [C.cedecl|struct memblock* $id:f(struct futhark_context* ctx) { return &ctx->$id:name; }|]+  ispcDecl+    [C.cedecl|extern "C" $tyqual:unmasked $tyqual:uniform struct memblock * $tyqual:uniform+                        $id:shim($tyqual:uniform struct futhark_context* $tyqual:uniform ctx);|]+  -- Call it+  GC.item [C.citem|$tyqual:uniform struct memblock $id:name = *$id:shim(ctx);|]+compileCode (c1 :>>: c2) = go (GC.linearCode (c1 :>>: c2))+  where+    go (DeclareScalar name _ t : SetScalar dest e : code)+      | name == dest = do+          let ct = GC.primTypeToCType t+          e' <- compileExp e+          quals <- getVariabilityQuals name+          GC.item [C.citem|$tyquals:quals $ty:ct $id:name = $exp:e';|]+          go code+    go (x : xs) = compileCode x >> go xs+    go [] = pure ()+compileCode (Allocate name (Count (TPrimExp e)) space) = do+  size <- compileExp e+  cached <- GC.cacheMem name+  case cached of+    Just cur_size ->+      GC.stm+        [C.cstm|if ($exp:cur_size < $exp:size) {+                  err = lexical_realloc(futhark_get_error_ref(ctx), &$exp:name, &$exp:cur_size, $exp:size);+                  if (err != FUTHARK_SUCCESS) {+                    $escstm:("unmasked { return err; }")+                  }+                }|]+    _ ->+      allocMem name size space [C.cstm|$escstm:("unmasked { return 1; }")|]+compileCode (SetMem dest src space) =+  setMem dest src space+compileCode (Write dest (Count idx) elemtype DefaultSpace _ elemexp)+  | isConstExp (untyped idx) = do+      dest' <- GC.rawMem dest+      idxexp <- compileExp (untyped idx)+      varis <- mapM getVariability (namesToList $ freeIn idx)+      let quals = if all (== Uniform) varis then [C.ctyquals|$tyqual:uniform|] else []+      tmp <- newVName "tmp_idx"+      -- Disambiguate the variability of the constant index+      GC.decl [C.cdecl|$tyquals:quals typename int64_t $id:tmp = $exp:idxexp;|]+      deref <-+        GC.derefPointer dest' [C.cexp|$id:tmp|]+          <$> getMemType dest elemtype+      elemexp' <- toStorage elemtype <$> compileExp elemexp+      GC.stm [C.cstm|$exp:deref = $exp:elemexp';|]+  | otherwise = do+      dest' <- GC.rawMem dest+      deref <-+        GC.derefPointer dest'+          <$> compileExp (untyped idx)+          <*> getMemType dest elemtype+      elemexp' <- toStorage elemtype <$> compileExp elemexp+      GC.stm [C.cstm|$exp:deref = $exp:elemexp';|]+  where+    isConstExp = isSimple . constFoldPrimExp+    isSimple (ValueExp _) = True+    isSimple _ = False+compileCode (Read x src (Count iexp) restype DefaultSpace _) = do+  src' <- GC.rawMem src+  e <-+    fmap (fromStorage restype) $+      GC.derefPointer src'+        <$> compileExp (untyped iexp)+        <*> getMemType src restype+  GC.stm [C.cstm|$id:x = $exp:e;|]+compileCode code@(Copy pt dest (Count destoffset) DefaultSpace src (Count srcoffset) DefaultSpace (Count size)) = do+  dm <- isJust <$> GC.cacheMem dest+  sm <- isJust <$> GC.cacheMem src+  if dm || sm+    then+      join $+        copyMemoryAOS pt+          <$> GC.rawMem dest+          <*> compileExp (untyped destoffset)+          <*> GC.rawMem src+          <*> compileExp (untyped srcoffset)+          <*> compileExp (untyped size)+    else GC.compileCode code+compileCode (Free name space) = do+  cached <- isJust <$> GC.cacheMem name+  unless cached $ unRefMem name space+compileCode (For i bound body) = do+  let i' = C.toIdent i+      t = GC.primTypeToCType $ primExpType bound+  bound' <- compileExp bound+  body' <- GC.collect $ compileCode body+  quals <- getVariabilityQuals i+  GC.stm+    [C.cstm|for ($tyquals:quals $ty:t $id:i' = 0; $id:i' < $exp:bound'; $id:i'++) {+            $items:body'+          }|]+compileCode (While cond body) = do+  cond' <- compileExp $ untyped cond+  body' <- GC.collect $ compileCode body+  GC.stm+    [C.cstm|while ($exp:cond') {+            $items:body'+          }|]+compileCode (If cond tbranch fbranch) = do+  cond' <- compileExp $ untyped cond+  tbranch' <- GC.collect $ compileCode tbranch+  fbranch' <- GC.collect $ compileCode fbranch+  GC.stm $ case (tbranch', fbranch') of+    (_, []) ->+      [C.cstm|if ($exp:cond') { $items:tbranch' }|]+    ([], _) ->+      [C.cstm|if (!($exp:cond')) { $items:fbranch' }|]+    _ ->+      [C.cstm|if ($exp:cond') { $items:tbranch' } else { $items:fbranch' }|]+compileCode (Call dests fname args) =+  defCallIspc dests fname =<< mapM compileArg args+  where+    compileArg (MemArg m) = pure [C.cexp|$exp:m|]+    compileArg (ExpArg e) = compileExp e+    defCallIspc dests' fname' args' = do+      let out_args = [[C.cexp|&$id:d|] | d <- dests']+          args''+            | isBuiltInFunction fname' = args'+            | otherwise = [C.cexp|ctx|] : out_args ++ args'+      case dests' of+        [d]+          | isBuiltInFunction fname' ->+              GC.stm [C.cstm|$id:d = $id:(funName fname')($args:args'');|]+        _ ->+          GC.item+            [C.citem|+            if ($id:(funName fname')($args:args'') != 0) {+              $escstm:("unmasked { return 1; }")+            }|]+compileCode (Assert e msg (loc, locs)) = do+  e' <- compileExp e+  err <- GC.collect $ handleError msg stacktrace+  GC.stm [C.cstm|if (!$exp:e') { $items:err }|]+  where+    stacktrace = prettyStacktrace 0 $ map locStr $ loc : locs+compileCode code =+  GC.compileCode code++-- | Prepare a struct with memory allocted in the scope and populate+-- its fields with values+prepareMemStruct :: [(VName, VName)] -> [VName] -> ISPCCompilerM Name+prepareMemStruct lexmems fatmems = do+  let lex_defs = concatMap lexMemDef lexmems+  let fat_defs = map fatMemDef fatmems+  name <- ispcDef "mem_struct" $ \s -> do+    pure+      [C.cedecl|struct $id:s {+        $sdecls:lex_defs+        $sdecls:fat_defs+      };|]+  let name' = name <> "_"+  GC.decl [C.cdecl|$tyqual:uniform struct $id:name $id:name';|]+  forM_ (concatMap (\(a, b) -> [a, b]) lexmems) $ \m ->+    GC.stm [C.cstm|$id:name'.$id:m = $id:m;|]+  forM_ fatmems $ \m ->+    GC.stm [C.cstm|$id:name'.$id:m = &$id:m;|]+  pure name+  where+    lexMemDef (name, size) =+      [ [C.csdecl|$tyqual:varying unsigned char * $tyqual:uniform $id:name;|],+        [C.csdecl|$tyqual:varying size_t $id:size;|]+      ]+    fatMemDef name =+      [C.csdecl|$tyqual:varying struct memblock * $tyqual:uniform $id:name;|]++-- | Get memory from the memory struct into local variables+compileGetMemStructVals :: Name -> [(VName, VName)] -> [VName] -> ISPCCompilerM ()+compileGetMemStructVals struct lexmems fatmems = do+  forM_ fatmems $ \m ->+    GC.decl [C.cdecl|struct memblock $id:m = *$id:struct->$id:m;|]+  forM_ lexmems $ \(m, s) -> do+    GC.decl [C.cdecl|$tyqual:varying unsigned char * $tyqual:uniform $id:m = $id:struct->$id:m;|]+    GC.decl [C.cdecl|size_t $id:s = $id:struct->$id:s;|]++-- | Write back potentially changed memory addresses and sizes to the memory struct+compileWritebackMemStructVals :: Name -> [(VName, VName)] -> [VName] -> ISPCCompilerM ()+compileWritebackMemStructVals struct lexmems fatmems = do+  forM_ fatmems $ \m ->+    GC.stm [C.cstm|*$id:struct->$id:m = $id:m;|]+  forM_ lexmems $ \(m, s) -> do+    GC.stm [C.cstm|$id:struct->$id:m = $id:m;|]+    GC.stm [C.cstm|$id:struct->$id:s = $id:s;|]++-- | Read back potentially changed memory addresses and sizes to the memory struct into local variables+compileReadbackMemStructVals :: Name -> [(VName, VName)] -> [VName] -> ISPCCompilerM ()+compileReadbackMemStructVals struct lexmems fatmems = do+  forM_ fatmems $ \m ->+    GC.stm [C.cstm|$id:m = *$id:struct.$id:m;|]+  forM_ lexmems $ \(m, s) -> do+    GC.stm [C.cstm|$id:m = $id:struct.$id:m;|]+    GC.stm [C.cstm|$id:s = $id:struct.$id:s;|]++compileGetStructVals ::+  Name ->+  [VName] ->+  [(C.Type, MC.ValueType)] ->+  ISPCCompilerM [C.BlockItem]+compileGetStructVals struct a b = concat <$> zipWithM field a b+  where+    struct' = struct <> "_"+    field name (ty, MC.Prim pt) = do+      let inner = [C.cexp|$id:struct'->$id:(MC.closureFreeStructField name)|]+      pure [C.citems|$tyqual:uniform $ty:ty $id:name = $exp:(fromStorage pt inner);|]+    field name (_, _) = do+      strlit <- makeStringLiteral $ pretty name+      pure+        [C.citems|$tyqual:uniform struct memblock $id:name;+                     $id:name.desc = $id:strlit();+                     $id:name.mem = $id:struct'->$id:(MC.closureFreeStructField name);+                     $id:name.size = 0;+                     $id:name.references = NULL;|]++-- | Can the given code produce an error? If so, we can't use foreach+-- loops, since they don't allow for early-outs in error handling.+mayProduceError :: MCCode -> Bool+mayProduceError (x :>>: y) = mayProduceError x || mayProduceError y+mayProduceError (If _ x y) = mayProduceError x || mayProduceError y+mayProduceError (For _ _ x) = mayProduceError x+mayProduceError (While _ x) = mayProduceError x+mayProduceError (Comment _ x) = mayProduceError x+mayProduceError (Op (ForEachActive _ body)) = mayProduceError body+mayProduceError (Op (ForEach _ _ _ body)) = mayProduceError body+mayProduceError (Op SegOp {}) = True+mayProduceError Allocate {} = True+mayProduceError Assert {} = True+mayProduceError SetMem {} = True+mayProduceError Free {} = True+mayProduceError Call {} = True+mayProduceError _ = False++-- Generate a segop function for top_level and potentially nested SegOp code+compileOp :: GC.OpCompiler Multicore ISPCState+compileOp (SegOp name params seq_task par_task retvals (SchedulerInfo e sched)) = do+  let (ParallelTask seq_code) = seq_task+  free_ctypes <- mapM MC.paramToCType params+  retval_ctypes <- mapM MC.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' <- compileExp e++  let lexical = lexicalMemoryUsageMC OpaqueKernels $ Function Nothing [] params seq_code++  fstruct <-+    MC.prepareTaskStruct sharedDef "task" free_args free_ctypes retval_args retval_ctypes++  fpar_task <- MC.generateParLoopFn lexical (name ++ "_task") seq_code fstruct free retval+  MC.addTimingFields fpar_task++  let ftask_name = fstruct <> "_task"++  to_c <- GC.collect $ do+    GC.decl [C.cdecl|struct scheduler_segop $id:ftask_name;|]+    GC.stm [C.cstm|$id:ftask_name.args = args;|]+    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 = iterations;|]+    -- Create the timing fields for the task+    GC.stm [C.cstm|$id:ftask_name.task_time = &ctx->$id:(MC.functionTiming fpar_task);|]+    GC.stm [C.cstm|$id:ftask_name.task_iter = &ctx->$id:(MC.functionIterations fpar_task);|]++    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) -> do+        let lexical_nested = lexicalMemoryUsageMC OpaqueKernels $ Function Nothing [] params nested_code+        fnpar_task <- MC.generateParLoopFn lexical_nested (name ++ "_nested_task") nested_code fstruct free retval+        GC.stm [C.cstm|$id:ftask_name.nested_fn = $id:fnpar_task;|]+        pure $ zip [fnpar_task] [True]+      Nothing -> do+        GC.stm [C.cstm|$id:ftask_name.nested_fn=NULL;|]+        pure mempty++    GC.stm [C.cstm|return scheduler_prepare_task(&ctx->scheduler, &$id:ftask_name);|]++    -- Add profile fields for -P option+    mapM_ GC.profileReport $ MC.multiCoreReport $ (fpar_task, True) : fnpar_task++  schedn <- MC.multicoreDef "schedule_shim" $ \s ->+    pure+      [C.cedecl|int $id:s(struct futhark_context* ctx, void* args, typename int64_t iterations) {+        $items:to_c+    }|]++  ispcDecl+    [C.cedecl|extern "C" $tyqual:unmasked $tyqual:uniform int $id:schedn+                        (struct futhark_context $tyqual:uniform * $tyqual:uniform ctx,+                        struct $id:fstruct $tyqual:uniform * $tyqual:uniform args,+                        $tyqual:uniform int iterations);|]++  aos_name <- newVName "aos"+  GC.items+    [C.citems|+    $escstm:("#if ISPC")+    $tyqual:uniform struct $id:fstruct $id:aos_name[programCount];+    $id:aos_name[programIndex] = $id:(fstruct <> "_");+    $escstm:("foreach_active (i)")+    {+      if (err == 0) {+        err = $id:schedn(ctx, &$id:aos_name[i], extract($exp:e', i));+      }+    }+    if (err != 0) {+      $escstm:("unmasked { return err; }")+    }+    $escstm:("#else")+    err = $id:schedn(ctx, &$id:(fstruct <> "_"), $exp:e');+    if (err != 0) {+      goto cleanup;+    }+    $escstm:("#endif")|]+compileOp (ISPCKernel body free) = do+  free_ctypes <- mapM MC.paramToCType free+  let free_args = map paramName free++  let lexical = lexicalMemoryUsageMC OpaqueKernels $ Function Nothing [] free body+  -- Generate ISPC kernel+  fstruct <- MC.prepareTaskStruct sharedDef "param_struct" free_args free_ctypes [] []+  let fstruct' = fstruct <> "_"++  ispcShim <- ispcDef "loop_ispc" $ \s -> do+    mainBody <- GC.inNewFunction $+      analyzeVariability body $+        cachingMemory lexical $ \decl_cached free_cached lexmems ->+          GC.collect $ do+            GC.decl [C.cdecl|$tyqual:uniform struct futhark_context * $tyqual:uniform ctx = $id:fstruct'->ctx;|]+            GC.items =<< compileGetStructVals fstruct free_args free_ctypes+            body' <- GC.collect $ compileCode body+            mapM_ GC.item decl_cached+            mapM_ GC.item =<< GC.declAllocatedMem++            -- Make inner kernel for error handling, if needed+            if mayProduceError body+              then do+                fatmems <- gets (map fst . GC.compDeclaredMem)+                mstruct <- prepareMemStruct lexmems fatmems+                let mstruct' = mstruct <> "_"+                innerShim <- ispcDef "inner_ispc" $ \t -> do+                  innerBody <- GC.collect $ do+                    GC.decl [C.cdecl|$tyqual:uniform struct futhark_context * $tyqual:uniform ctx = $id:fstruct'->ctx;|]+                    GC.items =<< compileGetStructVals fstruct free_args free_ctypes+                    compileGetMemStructVals mstruct' lexmems fatmems+                    GC.decl [C.cdecl|$tyqual:uniform int err = 0;|]+                    mapM_ GC.item body'+                    compileWritebackMemStructVals mstruct' lexmems fatmems+                    GC.stm [C.cstm|return err;|]+                  pure+                    [C.cedecl|+                static $tyqual:unmasked inline $tyqual:uniform int $id:t(+                  $tyqual:uniform typename int64_t start,+                  $tyqual:uniform typename int64_t end,+                  struct $id:fstruct $tyqual:uniform * $tyqual:uniform $id:fstruct',+                  struct $id:mstruct $tyqual:uniform * $tyqual:uniform $id:mstruct') {+                  $items:innerBody+                }|]+                -- Call the kernel and read back potentially changed memory+                GC.decl [C.cdecl|$tyqual:uniform int err = $id:innerShim(start, end, $id:fstruct', &$id:mstruct');|]+                compileReadbackMemStructVals mstruct' lexmems fatmems+              else do+                GC.decl [C.cdecl|$tyqual:uniform int err = 0;|]+                mapM_ GC.item body'++            free_mem <- freeAllocatedMem+            GC.stm [C.cstm|cleanup: {$stms:free_cached $items:free_mem}|]+            GC.stm [C.cstm|return err;|]+    GC.earlyDecl+      [C.cedecl|int $id:s(typename int64_t start,+                                  typename int64_t end,+                                  struct $id:fstruct * $id:fstruct');|]+    pure+      [C.cedecl|+        $tyqual:export $tyqual:uniform int $id:s($tyqual:uniform typename int64_t start,+                                                 $tyqual:uniform typename int64_t end,+                                                 struct $id:fstruct $tyqual:uniform * $tyqual:uniform $id:fstruct' ) {+          $items:mainBody+        }|]++  -- Generate C code to call into ISPC kernel+  GC.items+    [C.citems|+    err = $id:ispcShim(start, end, & $id:fstruct');+    if (err != 0) {+      goto cleanup;+    }|]+compileOp (ForEach i from bound body) = do+  from' <- compileExp from+  bound' <- compileExp bound+  body' <- GC.collect $ compileCode body+  if mayProduceError body+    then+      GC.stms+        [C.cstms|+      for ($tyqual:uniform typename int64_t i = 0; i < (($exp:bound' - $exp:from') / programCount); i++) {+        typename int64_t $id:i = $exp:from' + programIndex + i * programCount;+        $items:body'+      }+      if (programIndex < (($exp:bound' - $exp:from') % programCount)) {+        typename int64_t $id:i = $exp:from' + programIndex + ((($exp:bound' - $exp:from') / programCount) * programCount);+        $items:body'+      }|]+    else+      GC.stms+        [C.cstms|+      $escstm:("foreach (" <> pretty i <> " = " <> pretty from' <> " ... " <> pretty bound' <> ")") {+        $items:body'+      }|]+compileOp (ForEachActive name body) = do+  body' <- GC.collect $ compileCode body+  GC.stms+    [C.cstms|+    for ($tyqual:uniform unsigned int $id:name = 0; $id:name < programCount; $id:name++) {+      if (programIndex == $id:name) {+        $items:body'+      }+    }|]+compileOp (ExtractLane dest tar lane) = do+  tar' <- compileExp tar+  lane' <- compileExp lane+  GC.stm [C.cstm|$id:dest = extract($exp:tar', $exp:lane');|]+compileOp (Atomic aop) =+  MC.atomicOps aop $ \ty arr -> do+    cached <- isJust <$> GC.cacheMem arr+    if cached+      then pure [C.cty|$tyqual:varying $ty:ty* $tyqual:uniform|]+      else pure [C.cty|$ty:ty*|]+compileOp op = MC.compileOp op++-- | Like @GenericC.cachingMemory@, but adapted for ISPC codegen.+cachingMemory ::+  M.Map VName Space ->+  ([C.BlockItem] -> [C.Stm] -> [(VName, VName)] -> GC.CompilerM op s a) ->+  GC.CompilerM op s a+cachingMemory lexical f = do+  let cached = M.keys $ M.filter (== DefaultSpace) lexical++  cached' <- forM cached $ \mem -> do+    size <- newVName $ pretty mem <> "_cached_size"+    pure (mem, size)++  let lexMem env =+        env+          { GC.envCachedMem =+              M.fromList (map (first (`C.toExp` noLoc)) cached')+                <> GC.envCachedMem env+          }++      declCached (mem, size) =+        [ [C.citem|size_t $id:size = 0;|],+          [C.citem|$tyqual:varying unsigned char * $tyqual:uniform $id:mem = NULL;|]+        ]++      freeCached (mem, _) =+        [C.cstm|free($id:mem);|]++  local lexMem $ f (concatMap declCached cached') (map freeCached cached') cached'++-- Variability analysis+type Dependencies = M.Map VName Names++data Variability = Uniform | Varying+  deriving (Eq, Ord, Show)++newtype VariabilityM a+  = VariabilityM (ReaderT Names (State Dependencies) a)+  deriving+    ( Functor,+      Applicative,+      Monad,+      MonadState Dependencies,+      MonadReader Names+    )++execVariabilityM :: VariabilityM a -> Dependencies+execVariabilityM (VariabilityM m) =+  execState (runReaderT m mempty) mempty++-- | Extend the set of dependencies with a new one+addDeps :: VName -> Names -> VariabilityM ()+addDeps v ns = do+  deps <- get+  env <- ask+  case M.lookup v deps of+    Nothing -> put $ M.insert v (ns <> env) deps+    Just ns' -> put $ M.insert v (ns <> ns') deps++-- | Find all the dependencies in a body of code+findDeps :: MCCode -> VariabilityM ()+findDeps (x :>>: y) = do+  findDeps x+  findDeps y+findDeps (If cond x y) =+  local (<> freeIn cond) $ do+    findDeps x+    findDeps y+findDeps (For idx bound x) = do+  addDeps idx free+  local (<> free) $ findDeps x+  where+    free = freeIn bound+findDeps (While cond x) = do+  local (<> freeIn cond) $ findDeps x+findDeps (Comment _ x) =+  findDeps x+findDeps (Op (SegOp _ free _ _ retvals _)) =+  mapM_+    ( \x ->+        addDeps (paramName x) $+          namesFromList $+            map paramName free+    )+    retvals+findDeps (Op (ForEach _ _ _ body)) =+  findDeps body+findDeps (Op (ForEachActive _ body)) =+  findDeps body+findDeps (SetScalar name e) =+  addDeps name $ freeIn e+findDeps (Call tars _ args) =+  mapM_ (\x -> addDeps x $ freeIn args) tars+findDeps (Read x arr (Count iexp) _ DefaultSpace _) = do+  addDeps x $ freeIn (untyped iexp)+  addDeps x $ oneName arr+findDeps (Op (GetLoopBounds x y)) = do+  addDeps x mempty+  addDeps y mempty+findDeps (Op (ExtractLane x _ _)) = do+  addDeps x mempty+findDeps (Op (Atomic (AtomicCmpXchg _ old arr ind res val))) = do+  addDeps res $ freeIn arr <> freeIn ind <> freeIn val+  addDeps old $ freeIn arr <> freeIn ind <> freeIn val+findDeps _ = pure ()++-- | Take a list of dependencies and iterate them to a fixed point.+depsFixedPoint :: Dependencies -> Dependencies+depsFixedPoint deps =+  if deps == deps'+    then deps+    else depsFixedPoint deps'+  where+    grow names =+      names <> foldMap (\n -> M.findWithDefault mempty n deps) (namesIntMap names)+    deps' = M.map grow deps++-- | Find roots of variance. These are memory blocks declared in+-- the current scope as well as loop indices of foreach loops.+findVarying :: MCCode -> [VName]+findVarying (x :>>: y) = findVarying x ++ findVarying y+findVarying (If _ x y) = findVarying x ++ findVarying y+findVarying (For _ _ x) = findVarying x+findVarying (While _ x) = findVarying x+findVarying (Comment _ x) = findVarying x+findVarying (Op (ForEachActive _ body)) = findVarying body+findVarying (Op (ForEach idx _ _ body)) = idx : findVarying body+findVarying (DeclareMem mem _) = [mem]+findVarying _ = []++-- | Analyze variability in a body of code and run an action with+-- info about that variability in the compiler state.+analyzeVariability :: MCCode -> ISPCCompilerM a -> ISPCCompilerM a+analyzeVariability code m = do+  let roots = findVarying code+  let deps = depsFixedPoint $ execVariabilityM $ findDeps code+  let safelist = M.filter (\b -> all (`notNameIn` b) roots) deps+  let safe = namesFromList $ M.keys safelist+  pre_state <- GC.getUserState+  GC.modifyUserState (\s -> s {sUniform = safe})+  a <- m+  GC.modifyUserState (\s -> s {sUniform = sUniform pre_state})+  pure a++-- | Get the variability of a variable+getVariability :: VName -> ISPCCompilerM Variability+getVariability name = do+  uniforms <- sUniform <$> GC.getUserState+  pure $+    if name `nameIn` uniforms+      then Uniform+      else Varying++-- | Get the variability qualifiers of a variable+getVariabilityQuals :: VName -> ISPCCompilerM [C.TypeQual]+getVariabilityQuals name = variQuals <$> getVariability name+  where+    variQuals Uniform = [C.ctyquals|$tyqual:uniform|]+    variQuals Varying = []
src/Futhark/CodeGen/Backends/MulticoreWASM.hs view
@@ -43,7 +43,7 @@   Prog MCMem ->   m (ImpGen.Warnings, (GC.CParts, T.Text, [String])) compileProg version prog = do-  (ws, prog') <- ImpGen.compileProg ImpGen.AllowDynamicScheduling prog+  (ws, prog') <- ImpGen.compileProg prog    prog'' <-     GC.compileProg@@ -52,7 +52,7 @@       MC.operations       MC.generateContext       ""-      [DefaultSpace]+      (DefaultSpace, [DefaultSpace])       MC.cliOptions       prog' @@ -67,12 +67,12 @@ fRepMyRep :: Imp.Definitions Imp.Multicore -> [JSEntryPoint] fRepMyRep prog =   let Imp.Functions fs = Imp.defFuns prog-      function (Imp.Function entry _ _ _ res args) = do-        n <- entry+      function (Imp.Function entry _ _ _) = do+        Imp.EntryPoint n res args <- entry         Just $           JSEntryPoint             { name = nameToString n,               parameters = map (extToString . snd) args,-              ret = map extToString res+              ret = map (extToString . snd) res             }    in mapMaybe (function . snd) fs
src/Futhark/CodeGen/Backends/PyOpenCL.hs view
@@ -43,15 +43,15 @@     ImpGen.compileProg prog   -- prepare the strings for assigning the kernels and set them as global   let assign =-        unlines $-          map+        unlines+          $ map             ( \x ->                 pretty $                   Assign                     (Var ("self." ++ zEncodeString (nameToString x) ++ "_var"))                     (Var $ "program." ++ zEncodeString (nameToString x))             )-            $ M.keys kernels+          $ M.keys kernels    let defines =         [ Assign (Var "synchronous") $ Bool False,@@ -206,7 +206,8 @@   v' <- Py.compileVar v   Py.stm $     Assign v' $-      Var $ "self.max_" ++ pretty size_class+      Var $+        "self.max_" ++ pretty size_class callKernel (Imp.LaunchKernel safety name args num_workgroups workgroup_size) = do   num_workgroups' <- mapM (fmap asLong . Py.compileExp) num_workgroups   workgroup_size' <- mapM (fmap asLong . Py.compileExp) workgroup_size@@ -408,7 +409,8 @@     -- Store the memory block for later reference.     Py.stm $       Assign (Field (Var "self") name') $-        Var $ Py.compileName static_mem+        Var $+          Py.compileName static_mem    Py.stm $ Assign (Var name') (Field (Var "self") name')   where
src/Futhark/CodeGen/Backends/PyOpenCL/Boilerplate.hs view
@@ -115,7 +115,8 @@         what' =           Lambda "device" $             runIdentity $-              Py.compilePrimExp onLeaf $ untyped what+              Py.compilePrimExp onLeaf $+                untyped what          onLeaf (DeviceInfo s) =           pure $
src/Futhark/CodeGen/Backends/SequentialC.hs view
@@ -25,7 +25,7 @@ compileProg :: MonadFreshNames m => T.Text -> Prog SeqMem -> m (ImpGen.Warnings, GC.CParts) compileProg version =   traverse-    (GC.compileProg "c" version operations generateBoilerplate mempty [DefaultSpace] [])+    (GC.compileProg "c" version operations generateBoilerplate mempty (DefaultSpace, [DefaultSpace]) [])     <=< ImpGen.compileProg   where     operations :: GC.Operations Imp.Sequential ()
src/Futhark/CodeGen/Backends/SequentialWASM.hs view
@@ -48,7 +48,7 @@       operations       generateBoilerplate       ""-      [DefaultSpace]+      (DefaultSpace, [DefaultSpace])       []       prog'   pure (ws, (prog'', javascriptWrapper (fRepMyRep prog'), emccExportNames (fRepMyRep prog')))@@ -62,12 +62,12 @@ fRepMyRep :: Imp.Program -> [JSEntryPoint] fRepMyRep prog =   let Imp.Functions fs = Imp.defFuns prog-      function (Imp.Function entry _ _ _ res args) = do-        n <- entry+      function (Imp.Function entry _ _ _) = do+        Imp.EntryPoint n res args <- entry         Just $           JSEntryPoint             { name = nameToString n,               parameters = map (extToString . snd) args,-              ret = map extToString res+              ret = map (extToString . snd) res             }    in mapMaybe (function . snd) fs
src/Futhark/CodeGen/Backends/SimpleRep.hs view
@@ -78,8 +78,8 @@ -- | The C API corresponding to a primitive type.  Integers are -- assumed to have the specified sign. primAPIType :: Signedness -> PrimType -> C.Type-primAPIType TypeUnsigned (IntType t) = uintTypeToCType t-primAPIType TypeDirect (IntType t) = intTypeToCType t+primAPIType Unsigned (IntType t) = uintTypeToCType t+primAPIType Signed (IntType t) = intTypeToCType t primAPIType _ t = primStorageType t  -- | Convert from scalar to storage representation for the given type.@@ -108,11 +108,12 @@ -- | The name of exposed array type structs. arrayName :: PrimType -> Signedness -> Int -> String arrayName pt signed rank =-  prettySigned (signed == TypeUnsigned) pt ++ "_" ++ show rank ++ "d"+  prettySigned (signed == Unsigned) pt ++ "_" ++ show rank ++ "d"  -- | The name of exposed opaque types.-opaqueName :: String -> [ValueDesc] -> String-opaqueName s _+opaqueName :: String -> String+opaqueName "()" = "opaque_unit" -- Hopefully this ad-hoc convenience won't bite us.+opaqueName s   | valid = "opaque_" ++ s   where     valid =@@ -120,18 +121,15 @@         && not (isDigit $ head s)         && all ok s     ok c = isAlphaNum c || c == '_'-opaqueName s vds = "opaque_" ++ hash (zipWith xor [0 ..] $ map ord (s ++ concatMap p vds))+opaqueName s = "opaque_" ++ hash (zipWith xor [0 ..] $ map ord s)   where-    p (ScalarValue pt signed _) =-      show (pt, signed)-    p (ArrayValue _ space pt signed dims) =-      show (space, pt, signed, length dims)-     -- FIXME: a stupid hash algorithm; may have collisions.     hash =-      printf "%x" . foldl xor 0+      printf "%x"+        . foldl xor 0         . map-          ( iter . (* 0x45d9f3b)+          ( iter+              . (* 0x45d9f3b)               . iter               . (* 0x45d9f3b)               . iter@@ -142,18 +140,18 @@ -- | The 'PrimType' (and sign) correspond to a human-readable scalar -- type name (e.g. @f64@).  Beware: partial! scalarToPrim :: T.Text -> (Signedness, PrimType)-scalarToPrim "bool" = (TypeDirect, Bool)-scalarToPrim "i8" = (TypeDirect, IntType Int8)-scalarToPrim "i16" = (TypeDirect, IntType Int16)-scalarToPrim "i32" = (TypeDirect, IntType Int32)-scalarToPrim "i64" = (TypeDirect, IntType Int64)-scalarToPrim "u8" = (TypeUnsigned, IntType Int8)-scalarToPrim "u16" = (TypeUnsigned, IntType Int16)-scalarToPrim "u32" = (TypeUnsigned, IntType Int32)-scalarToPrim "u64" = (TypeUnsigned, IntType Int64)-scalarToPrim "f16" = (TypeDirect, FloatType Float16)-scalarToPrim "f32" = (TypeDirect, FloatType Float32)-scalarToPrim "f64" = (TypeDirect, FloatType Float64)+scalarToPrim "bool" = (Signed, Bool)+scalarToPrim "i8" = (Signed, IntType Int8)+scalarToPrim "i16" = (Signed, IntType Int16)+scalarToPrim "i32" = (Signed, IntType Int32)+scalarToPrim "i64" = (Signed, IntType Int64)+scalarToPrim "u8" = (Unsigned, IntType Int8)+scalarToPrim "u16" = (Unsigned, IntType Int16)+scalarToPrim "u32" = (Unsigned, IntType Int32)+scalarToPrim "u64" = (Unsigned, IntType Int64)+scalarToPrim "f16" = (Signed, FloatType Float16)+scalarToPrim "f32" = (Signed, FloatType Float32)+scalarToPrim "f64" = (Signed, FloatType Float64) scalarToPrim tname = error $ "scalarToPrim: " <> T.unpack tname  -- | Return an expression multiplying together the given expressions.@@ -251,14 +249,14 @@     (_, FloatType Float16) -> " f16"     (_, FloatType Float32) -> " f32"     (_, FloatType Float64) -> " f64"-    (TypeDirect, IntType Int8) -> "  i8"-    (TypeDirect, IntType Int16) -> " i16"-    (TypeDirect, IntType Int32) -> " i32"-    (TypeDirect, IntType Int64) -> " i64"-    (TypeUnsigned, IntType Int8) -> "  u8"-    (TypeUnsigned, IntType Int16) -> " u16"-    (TypeUnsigned, IntType Int32) -> " u32"-    (TypeUnsigned, IntType Int64) -> " u64"+    (Signed, IntType Int8) -> "  i8"+    (Signed, IntType Int16) -> " i16"+    (Signed, IntType Int32) -> " i32"+    (Signed, IntType Int64) -> " i64"+    (Unsigned, IntType Int8) -> "  u8"+    (Unsigned, IntType Int16) -> " u16"+    (Unsigned, IntType Int32) -> " u32"+    (Unsigned, IntType Int64) -> " u64"  -- | Produce code for storing the header (everything besides the -- actual payload) for a value of this type.
src/Futhark/CodeGen/ImpCode.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE Strict #-} {-# LANGUAGE TupleSections #-} @@ -57,17 +58,14 @@     Functions (..),     Function,     FunctionT (..),+    EntryPoint (..),     Constants (..),     ValueDesc (..),-    Signedness (..),     ExternalValue (..),     Param (..),     paramName,-    SubExp (..),     MemSize,     DimSize,-    Space (..),-    SpaceId,     Code (..),     PrimValue (..),     Exp,@@ -75,9 +73,6 @@     Volatility (..),     Arg (..),     var,-    ErrorMsg (..),-    ErrorMsgPart (..),-    errorMsgArgTypes,     ArrayContents (..),     declaredIn,     lexicalMemoryUsage,@@ -92,8 +87,9 @@      -- * Re-exports from other modules.     pretty,+    module Futhark.IR.Syntax.Core,     module Language.Futhark.Core,-    module Futhark.IR.Primitive,+    module Language.Futhark.Primitive,     module Futhark.Analysis.PrimExp,     module Futhark.Analysis.PrimExp.Convert,     module Futhark.IR.GPU.Sizes,@@ -109,18 +105,24 @@ import Futhark.Analysis.PrimExp.Convert import Futhark.IR.GPU.Sizes (Count (..)) import Futhark.IR.Pretty ()-import Futhark.IR.Primitive import Futhark.IR.Prop.Names import Futhark.IR.Syntax.Core-  ( ErrorMsg (..),+  ( EntryPointType (..),+    ErrorMsg (..),     ErrorMsgPart (..),+    OpaqueType (..),+    OpaqueTypes (..),+    Rank (..),+    Signedness (..),     Space (..),     SpaceId,     SubExp (..),+    ValueType (..),     errorMsgArgTypes,   ) import Futhark.Util.Pretty hiding (space) import Language.Futhark.Core+import Language.Futhark.Primitive  -- | The size of a memory block. type MemSize = SubExp@@ -141,13 +143,15 @@  -- | A collection of imperative functions and constants. data Definitions a = Definitions-  { defConsts :: Constants a,+  { defTypes :: OpaqueTypes,+    defConsts :: Constants a,     defFuns :: Functions a   }   deriving (Show)  instance Functor Definitions where-  fmap f (Definitions consts funs) = Definitions (fmap f consts) (fmap f funs)+  fmap f (Definitions types consts funs) =+    Definitions types (fmap f consts) (fmap f funs)  -- | A collection of imperative functions. newtype Functions a = Functions [(Name, Function a)]@@ -172,15 +176,6 @@ instance Functor Constants where   fmap f (Constants params code) = Constants params (fmap f code) --- | Since the core language does not care for signedness, but the--- source language does, entry point input/output information has--- metadata for integer types (and arrays containing these) that--- indicate whether they are really unsigned integers.-data Signedness-  = TypeUnsigned-  | TypeDirect-  deriving (Eq, Ord, Show)- -- | A description of an externally meaningful value. data ValueDesc   = -- | An array with memory block memory space, element type,@@ -197,22 +192,27 @@ data ExternalValue   = -- | The string is a human-readable description with no other     -- semantics.-    -- not matter.-    OpaqueValue Uniqueness String [ValueDesc]-  | TransparentValue Uniqueness ValueDesc+    OpaqueValue String [ValueDesc]+  | TransparentValue ValueDesc   deriving (Show) +-- | Information about how this function can be called from the outside world.+data EntryPoint = EntryPoint+  { entryPointName :: Name,+    entryPointResults :: [(Uniqueness, ExternalValue)],+    entryPointArgs :: [((Name, Uniqueness), ExternalValue)]+  }+  deriving (Show)+ -- | A imperative function, containing the body as well as its -- low-level inputs and outputs, as well as its high-level arguments--- and results.  The latter are only used if the function is an entry+-- and results.  The latter are only present if the function is an entry -- point. data FunctionT a = Function-  { functionEntry :: Maybe Name,+  { functionEntry :: Maybe EntryPoint,     functionOutput :: [Param],     functionInput :: [Param],-    functionBody :: Code a,-    functionResult :: [ExternalValue],-    functionArgs :: [(Name, ExternalValue)]+    functionBody :: Code a   }   deriving (Show) @@ -347,8 +347,9 @@ -- to 'SetMem' a memory block declared outside it. lexicalMemoryUsage :: Function a -> M.Map VName Space lexicalMemoryUsage func =-  M.filterWithKey (const . not . (`nameIn` nonlexical)) $-    declared $ functionBody func+  M.filterWithKey (const . (`notNameIn` nonlexical)) $+    declared $+      functionBody func   where     nonlexical =       set (functionBody func)@@ -424,119 +425,139 @@ -- Prettyprinting definitions.  instance Pretty op => Pretty (Definitions op) where-  ppr (Definitions consts funs) =-    ppr consts </> ppr funs+  ppr (Definitions types consts funs) =+    ppr types </> ppr consts </> ppr funs  instance Pretty op => Pretty (Functions op) where   ppr (Functions funs) = stack $ intersperse mempty $ map ppFun funs     where       ppFun (name, fun) =-        text "Function " <> ppr name <> colon </> indent 2 (ppr fun)+        "Function " <> ppr name <> colon </> indent 2 (ppr fun)  instance Pretty op => Pretty (Constants op) where   ppr (Constants decls code) =-    text "Constants:" </> indent 2 (stack $ map ppr decls)+    "Constants:"+      </> indent 2 (stack $ map ppr decls)       </> mempty-      </> text "Initialisation:"+      </> "Initialisation:"       </> indent 2 (ppr code) +instance Pretty EntryPoint where+  ppr (EntryPoint name results args) =+    "Name:"+      </> indent 2 (pquote (ppr name))+      </> "Arguments:"+      </> indent 2 (stack $ map ppArg args)+      </> "Results:"+      </> indent 2 (stack $ map ppRes results)+    where+      ppArg ((p, u), t) = ppr p <+> ":" <+> ppRes (u, t)+      ppRes (u, t) = ppr u <> ppr t+ instance Pretty op => Pretty (FunctionT op) where-  ppr (Function _ outs ins body results args) =-    text "Inputs:" </> block ins-      </> text "Outputs:"-      </> block outs-      </> text "Arguments:"-      </> block args-      </> text "Result:"-      </> block results-      </> text "Body:"+  ppr (Function entry outs ins body) =+    "Inputs:"+      </> indent 2 (stack $ map ppr ins)+      </> "Outputs:"+      </> indent 2 (stack $ map ppr outs)+      </> "Entry:"+      </> indent 2 (ppr entry)+      </> "Body:"       </> indent 2 (ppr body)-    where-      block :: Pretty a => [a] -> Doc-      block = indent 2 . stack . map ppr  instance Pretty Param where   ppr (ScalarParam name ptype) = ppr ptype <+> ppr name-  ppr (MemParam name space) = text "mem" <> ppr space <> text " " <> ppr name+  ppr (MemParam name space) = "mem" <> ppr space <> " " <> ppr name  instance Pretty ValueDesc where   ppr (ScalarValue t ept name) =     ppr t <+> ppr name <> ept'     where       ept' = case ept of-        TypeUnsigned -> text " (unsigned)"-        TypeDirect -> mempty+        Unsigned -> " (unsigned)"+        Signed -> mempty   ppr (ArrayValue mem space et ept shape) =-    foldr f (ppr et) shape <+> text "at" <+> ppr mem <> ppr space <+> ept'+    foldr f (ppr et) shape <+> "at" <+> ppr mem <> ppr space <+> ept'     where       f e s = brackets $ s <> comma <> ppr e       ept' = case ept of-        TypeUnsigned -> text " (unsigned)"-        TypeDirect -> mempty+        Unsigned -> " (unsigned)"+        Signed -> mempty  instance Pretty ExternalValue where-  ppr (TransparentValue u v) = ppr u <> ppr v-  ppr (OpaqueValue u desc vs) =-    ppr u <> text "opaque" <+> text desc+  ppr (TransparentValue v) = ppr v+  ppr (OpaqueValue desc vs) =+    "opaque"+      <+> pquote (ppr desc)       <+> nestedBlock "{" "}" (stack $ map ppr vs)  instance Pretty ArrayContents where   ppr (ArrayValues vs) = braces (commasep $ map ppr vs)-  ppr (ArrayZeros n) = braces (text "0") <+> text "*" <+> ppr n+  ppr (ArrayZeros n) = braces "0" <+> "*" <+> ppr n  instance Pretty op => Pretty (Code op) where   ppr (Op op) = ppr op-  ppr Skip = text "skip"+  ppr Skip = "skip"   ppr (c1 :>>: c2) = ppr c1 </> ppr c2   ppr (For i limit body) =-    text "for" <+> ppr i <+> langle <+> ppr limit <+> text "{"+    "for"+      <+> ppr i+      <+> langle+      <+> ppr limit+      <+> "{"       </> indent 2 (ppr body)-      </> text "}"+      </> "}"   ppr (While cond body) =-    text "while" <+> ppr cond <+> text "{"+    "while"+      <+> ppr cond+      <+> "{"       </> indent 2 (ppr body)-      </> text "}"+      </> "}"   ppr (DeclareMem name space) =-    text "var" <+> ppr name <> text ": mem" <> ppr space+    "var" <+> ppr name <> ": mem" <> ppr space   ppr (DeclareScalar name vol t) =-    text "var" <+> ppr name <> text ":" <+> vol' <> ppr t+    "var" <+> ppr name <> ":" <+> vol' <> ppr t     where       vol' = case vol of-        Volatile -> text "volatile "+        Volatile -> "volatile "         Nonvolatile -> mempty   ppr (DeclareArray name space t vs) =-    text "array" <+> ppr name <> text "@" <> ppr space <+> text ":" <+> ppr t+    "array"+      <+> ppr name <> "@" <> ppr space+      <+> ":"+      <+> ppr t       <+> equals       <+> ppr vs   ppr (Allocate name e space) =-    ppr name <+> text "<-" <+> text "malloc" <> parens (ppr e) <> ppr space+    ppr name <+> "<-" <+> "malloc" <> parens (ppr e) <> ppr space   ppr (Free name space) =-    text "free" <> parens (ppr name) <> ppr space+    "free" <> parens (ppr name) <> ppr space   ppr (Write name i bt space vol val) =     ppr name <> langle <> vol' <> ppr bt <> ppr space <> rangle <> brackets (ppr i)-      <+> text "<-"+      <+> "<-"       <+> ppr val     where       vol' = case vol of-        Volatile -> text "volatile "+        Volatile -> "volatile "         Nonvolatile -> mempty   ppr (Read name v is bt space vol) =-    ppr name <+> text "<-"+    ppr name+      <+> "<-"       <+> ppr v <> langle <> vol' <> ppr bt <> ppr space <> rangle <> brackets (ppr is)     where       vol' = case vol of-        Volatile -> text "volatile "+        Volatile -> "volatile "         Nonvolatile -> mempty   ppr (SetScalar name val) =-    ppr name <+> text "<-" <+> ppr val+    ppr name <+> "<-" <+> ppr val   ppr (SetMem dest from DefaultSpace) =-    ppr dest <+> text "<-" <+> ppr from+    ppr dest <+> "<-" <+> ppr from   ppr (SetMem dest from space) =-    ppr dest <+> text "<-" <+> ppr from <+> text "@" <> ppr space+    ppr dest <+> "<-" <+> ppr from <+> "@" <> ppr space   ppr (Assert e msg _) =-    text "assert" <> parens (commasep [ppr msg, ppr e])+    "assert" <> parens (commasep [ppr msg, ppr e])   ppr (Copy t dest destoffset destspace src srcoffset srcspace size) =-    text "copy"+    "copy"       <> parens         ( ppr t <> comma             </> ppMemLoc dest destoffset <> ppr destspace <> comma@@ -545,24 +566,27 @@         )     where       ppMemLoc base offset =-        ppr base <+> text "+" <+> ppr offset+        ppr base <+> "+" <+> ppr offset   ppr (If cond tbranch fbranch) =-    text "if" <+> ppr cond <+> text "then {"+    "if"+      <+> ppr cond+      <+> "then {"       </> indent 2 (ppr tbranch)-      </> text "} else {"+      </> "} else {"       </> indent 2 (ppr fbranch)-      </> text "}"+      </> "}"   ppr (Call dests fname args) =-    commasep (map ppr dests) <+> text "<-"+    commasep (map ppr dests)+      <+> "<-"       <+> ppr fname <> parens (commasep $ map ppr args)   ppr (Comment s code) =-    text "--" <+> text s </> ppr code+    "--" <+> text s </> ppr code   ppr (DebugPrint desc (Just e)) =-    text "debug" <+> parens (commasep [text (show desc), ppr e])+    "debug" <+> parens (commasep [text (show desc), ppr e])   ppr (DebugPrint desc Nothing) =-    text "debug" <+> parens (text (show desc))+    "debug" <+> parens (text (show desc))   ppr (TracePrint msg) =-    text "trace" <+> parens (ppr msg)+    "trace" <+> parens (ppr msg)  instance Pretty Arg where   ppr (MemArg m) = ppr m@@ -587,8 +611,8 @@   foldMap = foldMapDefault  instance Traversable FunctionT where-  traverse f (Function entry outs ins body results args) =-    Function entry outs ins <$> traverse f body <*> pure results <*> pure args+  traverse f (Function entry outs ins body) =+    Function entry outs ins <$> traverse f body  instance Functor Code where   fmap = fmapDefault@@ -653,12 +677,15 @@ declaredIn (Comment _ body) = declaredIn body declaredIn _ = mempty +instance FreeIn EntryPoint where+  freeIn' (EntryPoint _ res args) =+    freeIn' (map snd res) <> freeIn' (map snd args)+ instance FreeIn a => FreeIn (Functions a) where   freeIn' (Functions fs) = foldMap (onFun . snd) fs     where       onFun f =-        fvBind pnames $-          freeIn' (functionBody f) <> freeIn' (functionResult f <> map snd (functionArgs f))+        fvBind pnames $ freeIn' (functionBody f) <> freeIn' (functionEntry f)         where           pnames =             namesFromList $ map paramName $ functionInput f <> functionOutput f@@ -668,8 +695,8 @@   freeIn' ScalarValue {} = mempty  instance FreeIn ExternalValue where-  freeIn' (TransparentValue _ vd) = freeIn' vd-  freeIn' (OpaqueValue _ _ vds) = foldMap freeIn' vds+  freeIn' (TransparentValue vd) = freeIn' vd+  freeIn' (OpaqueValue _ vds) = foldMap freeIn' vds  instance FreeIn a => FreeIn (Code a) where   freeIn' (x :>>: y) =
src/Futhark/CodeGen/ImpCode/GPU.hs view
@@ -95,12 +95,14 @@  instance Pretty HostOp where   ppr (GetSize dest key size_class) =-    ppr dest <+> text "<-"+    ppr dest+      <+> text "<-"       <+> text "get_size" <> parens (commasep [ppr key, ppr size_class])   ppr (GetSizeMax dest size_class) =     ppr dest <+> text "<-" <+> text "get_size_max" <> parens (ppr size_class)   ppr (CmpSizeLe dest name size_class x) =-    ppr dest <+> text "<-"+    ppr dest+      <+> text "<-"       <+> text "get_size" <> parens (commasep [ppr name, ppr size_class])       <+> text "<"       <+> ppr x@@ -126,12 +128,18 @@   ppr kernel =     text "kernel"       <+> brace-        ( text "groups" <+> brace (ppr $ kernelNumGroups kernel)-            </> text "group_size" <+> brace (ppr $ kernelGroupSize kernel)-            </> text "uses" <+> brace (commasep $ map ppr $ kernelUses kernel)-            </> text "failure_tolerant" <+> brace (ppr $ kernelFailureTolerant kernel)-            </> text "check_local_memory" <+> brace (ppr $ kernelCheckLocalMemory kernel)-            </> text "body" <+> brace (ppr $ kernelBody kernel)+        ( text "groups"+            <+> brace (ppr $ kernelNumGroups kernel)+            </> text "group_size"+            <+> brace (ppr $ kernelGroupSize kernel)+            </> text "uses"+            <+> brace (commasep $ map ppr $ kernelUses kernel)+            </> text "failure_tolerant"+            <+> brace (ppr $ kernelFailureTolerant kernel)+            </> text "check_local_memory"+            <+> brace (ppr $ kernelCheckLocalMemory kernel)+            </> text "body"+            <+> brace (ppr $ kernelBody kernel)         )  -- | When we do a barrier or fence, is it at the local or global@@ -190,16 +198,20 @@  instance Pretty KernelOp where   ppr (GetGroupId dest i) =-    ppr dest <+> "<-"+    ppr dest+      <+> "<-"       <+> "get_group_id" <> parens (ppr i)   ppr (GetLocalId dest i) =-    ppr dest <+> "<-"+    ppr dest+      <+> "<-"       <+> "get_local_id" <> parens (ppr i)   ppr (GetLocalSize dest i) =-    ppr dest <+> "<-"+    ppr dest+      <+> "<-"       <+> "get_local_size" <> parens (ppr i)   ppr (GetLockstepWidth dest) =-    ppr dest <+> "<-"+    ppr dest+      <+> "<-"       <+> "get_lockstep_width()"   ppr (Barrier FenceLocal) =     "local_barrier()"@@ -216,38 +228,71 @@   ppr (ErrorSync FenceGlobal) =     "error_sync_global()"   ppr (Atomic _ (AtomicAdd t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_add_" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_add_"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicFAdd t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_fadd_" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_fadd_"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicSMax t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_smax" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_smax"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicSMin t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_smin" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_smin"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicUMax t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_umax" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_umax"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicUMin t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_umin" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_umin"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicAnd t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_and" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_and"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicOr t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_or" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_or"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicXor t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_xor" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_xor"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])   ppr (Atomic _ (AtomicCmpXchg t old arr ind x y)) =-    ppr old <+> "<-" <+> "atomic_cmp_xchg" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x, ppr y])+    ppr old+      <+> "<-"+      <+> "atomic_cmp_xchg"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x, ppr y])   ppr (Atomic _ (AtomicXchg t old arr ind x)) =-    ppr old <+> "<-" <+> "atomic_xchg" <> ppr t-      <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])+    ppr old+      <+> "<-"+      <+> "atomic_xchg"+        <> ppr t+        <> parens (commasep [ppr arr <> brackets (ppr ind), ppr x])  instance FreeIn KernelOp where   freeIn' (Atomic _ op) = freeIn' op
src/Futhark/CodeGen/ImpCode/Multicore.hs view
@@ -26,6 +26,15 @@ data Multicore   = SegOp String [Param] ParallelTask (Maybe ParallelTask) [Param] SchedulerInfo   | ParLoop String MCCode [Param]+  | -- | A kernel of ISPC code, or a scoped block in regular C.+    ISPCKernel MCCode [Param]+  | -- | A foreach loop in ISPC, or a regular for loop in C.+    ForEach VName Exp Exp MCCode+  | -- | A foreach_active loop in ISPC, or a single execution in C.+    ForEachActive VName MCCode+  | -- | Extract a value from a given lane and assign it to a variable.+    -- This is just a regular assignment in C.+    ExtractLane VName Exp Exp   | -- | Retrieve inclusive start and exclusive end indexes of the     -- chunk we are supposed to be executing.  Only valid immediately     -- inside a 'ParLoop' construct!@@ -123,6 +132,22 @@           ]   ppr (Atomic _) =     "AtomicOp"+  ppr (ISPCKernel body _) =+    "ispc" <+> nestedBlock "{" "}" (ppr body)+  ppr (ForEach i from to body) =+    "foreach"+      <+> ppr i+      <+> "="+      <+> ppr from+      <+> "to"+      <+> ppr to+      <+> nestedBlock "{" "}" (ppr body)+  ppr (ForEachActive i body) =+    "foreach_active"+      <+> ppr i+      <+> nestedBlock "{" "}" (ppr body)+  ppr (ExtractLane dest tar lane) =+    ppr dest <+> "<-" <+> "extract" <+> parens (commasep $ map ppr [tar, lane])  instance FreeIn SchedulerInfo where   freeIn' (SchedulerInfo iter _) = freeIn' iter@@ -143,14 +168,25 @@     freeIn' body   freeIn' (Atomic aop) =     freeIn' aop+  freeIn' (ISPCKernel body _) =+    freeIn' body+  freeIn' (ForEach i from to body) =+    fvBind (oneName i) (freeIn' body <> freeIn' from <> freeIn' to)+  freeIn' (ForEachActive i body) =+    fvBind (oneName i) (freeIn' body)+  freeIn' (ExtractLane dest tar lane) =+    freeIn' dest <> freeIn' tar <> freeIn' lane +-- | Whether 'lexicalMemoryUsageMC' should look inside nested kernels+-- or not. data KernelHandling = TraverseKernels | OpaqueKernels  -- | Like @lexicalMemoryUsage@, but traverses some inner multicore ops. lexicalMemoryUsageMC :: KernelHandling -> Function Multicore -> M.Map VName Space lexicalMemoryUsageMC gokernel func =-  M.filterWithKey (const . not . (`nameIn` nonlexical)) $-    declared $ functionBody func+  M.filterWithKey (const . (`notNameIn` nonlexical)) $+    declared $+      functionBody func   where     nonlexical =       set (functionBody func)@@ -161,7 +197,20 @@     go f (For _ _ x) = f x     go f (While _ x) = f x     go f (Comment _ x) = f x+    go f (Op op) = goOp f op     go _ _ = mempty++    -- We want SetMems and declarations to be visible through custom control flow+    -- so we don't erroneously treat a memblock that could be lexical as needing+    -- refcounting. Importantly, for ISPC, we do not look into kernels, since they+    -- go into new functions. For the Multicore backend, we can do it, though.+    goOp f (ForEach _ _ _ body) = go f body+    goOp f (ForEachActive _ body) = go f body+    goOp f (ISPCKernel body _) =+      case gokernel of+        TraverseKernels -> go f body+        OpaqueKernels -> mempty+    goOp _ _ = mempty      declared (DeclareMem mem spc) =       M.singleton mem spc
src/Futhark/CodeGen/ImpGen.hs view
@@ -55,6 +55,7 @@     lookupArray,     lookupMemory,     lookupAcc,+    askAttrs,      -- * Building Blocks     TV,@@ -441,7 +442,7 @@   Imp.Space ->   Prog rep ->   m (Warnings, Imp.Definitions op)-compileProg r ops space (Prog consts funs) =+compileProg r ops space (Prog types consts funs) =   modifyNameSource $ \src ->     let (_, ss) =           unzip $ parMap rpar (compileFunDef' src) funs@@ -451,14 +452,14 @@           runImpM (compileConsts free_in_funs consts) r ops space $             combineStates ss      in ( ( stateWarnings s',-            Imp.Definitions consts' (stateFunctions s')+            Imp.Definitions types consts' (stateFunctions s')           ),           stateNameSource s'         )   where     compileFunDef' src fdef =       runImpM-        (compileFunDef fdef)+        (compileFunDef types fdef)         r         ops         space@@ -496,6 +497,33 @@     extract s =       (mempty, s) +lookupOpaqueType :: String -> OpaqueTypes -> OpaqueType+lookupOpaqueType v (OpaqueTypes types) =+  case lookup v types of+    Just t -> t+    Nothing -> error $ "Unknown opaque type: " ++ show v++valueTypeSign :: ValueType -> Signedness+valueTypeSign (ValueType sign _ _) = sign++entryPointSignedness :: OpaqueTypes -> EntryPointType -> [Signedness]+entryPointSignedness _ (TypeTransparent vt) = [valueTypeSign vt]+entryPointSignedness types (TypeOpaque desc) =+  case lookupOpaqueType desc types of+    OpaqueType vts -> map valueTypeSign vts+    OpaqueRecord fs -> foldMap (entryPointSignedness types . snd) fs++-- | How many value parameters are accepted by this entry point?  This+-- is used to determine which of the function parameters correspond to+-- the parameters of the original function (they must all come at the+-- end).+entryPointSize :: OpaqueTypes -> EntryPointType -> Int+entryPointSize _ (TypeTransparent _) = 1+entryPointSize types (TypeOpaque desc) =+  case lookupOpaqueType desc types of+    OpaqueType vts -> length vts+    OpaqueRecord fs -> sum $ map (entryPointSize types . snd) fs+ compileInParam ::   Mem rep inner =>   FParam rep ->@@ -516,13 +544,12 @@  compileInParams ::   Mem rep inner =>+  OpaqueTypes ->   [FParam rep] ->-  [EntryParam] ->-  ImpM rep r op ([Imp.Param], [ArrayDecl], [(Name, Imp.ExternalValue)])-compileInParams params eparams = do-  let (ctx_params, val_params) =-        splitAt (length params - sum (map (entryPointSize . entryParamType) eparams)) params-  (inparams, arrayds) <- partitionEithers <$> mapM compileInParam (ctx_params ++ val_params)+  Maybe [EntryParam] ->+  ImpM rep r op ([Imp.Param], [ArrayDecl], Maybe [((Name, Uniqueness), Imp.ExternalValue)])+compileInParams types params eparams = do+  (inparams, arrayds) <- partitionEithers <$> mapM compileInParam params   let findArray x = find (isArrayDecl x) arrayds        summaries = M.fromList $ mapMaybe memSummary params@@ -546,24 +573,31 @@           _ ->             Nothing -      mkExts (EntryParam v (TypeOpaque u desc n) : epts) fparams =-        let (fparams', rest) = splitAt n fparams-         in ( v,+      mkExts (EntryParam v u et@(TypeOpaque desc) : epts) fparams =+        let signs = entryPointSignedness types et+            n = entryPointSize types et+            (fparams', rest) = splitAt n fparams+         in ( (v, u),               Imp.OpaqueValue-                u                 desc-                (mapMaybe (`mkValueDesc` Imp.TypeDirect) fparams')-            ) :-            mkExts epts rest-      mkExts (EntryParam v (TypeUnsigned u) : epts) (fparam : fparams) =-        maybeToList ((v,) . Imp.TransparentValue u <$> mkValueDesc fparam Imp.TypeUnsigned)-          ++ mkExts epts fparams-      mkExts (EntryParam v (TypeDirect u) : epts) (fparam : fparams) =-        maybeToList ((v,) . Imp.TransparentValue u <$> mkValueDesc fparam Imp.TypeDirect)+                (catMaybes $ zipWith mkValueDesc fparams' signs)+            )+              : mkExts epts rest+      mkExts (EntryParam v u (TypeTransparent (ValueType s _ _)) : epts) (fparam : fparams) =+        maybeToList (((v, u),) . Imp.TransparentValue <$> mkValueDesc fparam s)           ++ mkExts epts fparams       mkExts _ _ = [] -  pure (inparams, arrayds, mkExts eparams val_params)+  pure+    ( inparams,+      arrayds,+      case eparams of+        Just eparams' ->+          let num_val_params = sum (map (entryPointSize types . entryParamType) eparams')+              (_ctx_params, val_params) = splitAt (length params - num_val_params) params+           in Just $ mkExts eparams' val_params+        Nothing -> Nothing+    )   where     isArrayDecl x (ArrayDecl y _ _) = x == y @@ -582,13 +616,16 @@  compileExternalValues ::   Mem rep inner =>+  OpaqueTypes ->   [RetType rep] ->-  [EntryPointType] ->+  [EntryResult] ->   [Maybe Imp.Param] ->-  ImpM rep r op [Imp.ExternalValue]-compileExternalValues orig_rts orig_epts maybe_params = do+  ImpM rep r op [(Uniqueness, Imp.ExternalValue)]+compileExternalValues types orig_rts orig_epts maybe_params = do   let (ctx_rts, val_rts) =-        splitAt (length orig_rts - sum (map entryPointSize orig_epts)) orig_rts+        splitAt+          (length orig_rts - sum (map (entryPointSize types . entryResultType) orig_epts))+          orig_rts    let nthOut i = case maybeNth i maybe_params of         Just (Just p) -> Imp.paramName p@@ -614,57 +651,61 @@       mkValueDesc _ _ MemMem {} =         error "mkValueDesc: unexpected MemMem output." -      mkExts i (TypeOpaque u desc n : epts) rets = do-        let (rets', rest) = splitAt n rets-        vds <- zipWithM (`mkValueDesc` Imp.TypeDirect) [i ..] rets'-        (Imp.OpaqueValue u desc vds :) <$> mkExts (i + n) epts rest-      mkExts i (TypeUnsigned u : epts) (ret : rets) = do-        vd <- mkValueDesc i Imp.TypeUnsigned ret-        (Imp.TransparentValue u vd :) <$> mkExts (i + 1) epts rets-      mkExts i (TypeDirect u : epts) (ret : rets) = do-        vd <- mkValueDesc i Imp.TypeDirect ret-        (Imp.TransparentValue u vd :) <$> mkExts (i + 1) epts rets+      mkExts i (EntryResult u et@(TypeOpaque desc) : epts) rets = do+        let signs = entryPointSignedness types et+            n = entryPointSize types et+            (rets', rest) = splitAt n rets+        vds <- forM (zip3 [i ..] signs rets') $ \(j, s, r) -> mkValueDesc j s r+        ((u, Imp.OpaqueValue desc vds) :) <$> mkExts (i + n) epts rest+      mkExts i (EntryResult u (TypeTransparent (ValueType s _ _)) : epts) (ret : rets) = do+        vd <- mkValueDesc i s ret+        ((u, Imp.TransparentValue vd) :) <$> mkExts (i + 1) epts rets       mkExts _ _ _ = pure []    mkExts (length ctx_rts) orig_epts val_rts  compileOutParams ::   Mem rep inner =>+  OpaqueTypes ->   [RetType rep] ->-  Maybe [EntryPointType] ->-  ImpM rep r op ([Imp.ExternalValue], [Imp.Param], [ValueDestination])-compileOutParams orig_rts maybe_orig_epts = do+  Maybe [EntryResult] ->+  ImpM rep r op (Maybe [(Uniqueness, Imp.ExternalValue)], [Imp.Param], [ValueDestination])+compileOutParams types orig_rts maybe_orig_epts = do   (maybe_params, dests) <- unzip <$> mapM compileOutParam orig_rts   evs <- case maybe_orig_epts of-    Just orig_epts -> compileExternalValues orig_rts orig_epts maybe_params-    Nothing -> pure []+    Just orig_epts ->+      Just <$> compileExternalValues types orig_rts orig_epts maybe_params+    Nothing -> pure Nothing   pure (evs, catMaybes maybe_params, dests)  compileFunDef ::   Mem rep inner =>+  OpaqueTypes ->   FunDef rep ->   ImpM rep r op ()-compileFunDef (FunDef entry _ fname rettype params body) =+compileFunDef types (FunDef entry _ fname rettype params body) =   local (\env -> env {envFunction = name_entry `mplus` Just fname}) $ do     ((outparams, inparams, results, args), body') <- collect' compile-    emitFunction fname $ Imp.Function name_entry outparams inparams body' results args+    let entry' = case (name_entry, results, args) of+          (Just name_entry', Just results', Just args') ->+            Just $ Imp.EntryPoint name_entry' results' args'+          _ ->+            Nothing+    emitFunction fname $ Imp.Function entry' outparams inparams body'   where     (name_entry, params_entry, ret_entry) = case entry of-      Nothing ->-        ( Nothing,-          replicate (length params) (EntryParam "" $ TypeDirect mempty),-          Nothing-        )-      Just (x, y, z) -> (Just x, y, Just z)+      Nothing -> (Nothing, Nothing, Nothing)+      Just (x, y, z) -> (Just x, Just y, Just z)     compile = do-      (inparams, arrayds, args) <- compileInParams params params_entry-      (results, outparams, dests) <- compileOutParams rettype ret_entry+      (inparams, arrayds, args) <- compileInParams types params params_entry+      (results, outparams, dests) <- compileOutParams types rettype ret_entry       addFParams params       addArrays arrayds        let Body _ stms ses = body       compileStms (freeIn ses) stms $-        forM_ (zip dests ses) $ \(d, SubExpRes _ se) -> copyDWIMDest d [] se []+        forM_ (zip dests ses) $+          \(d, SubExpRes _ se) -> copyDWIMDest d [] se []        pure (outparams, inparams, results, args) @@ -672,12 +713,14 @@ compileBody pat (Body _ stms ses) = do   dests <- destinationFromPat pat   compileStms (freeIn ses) stms $-    forM_ (zip dests ses) $ \(d, SubExpRes _ se) -> copyDWIMDest d [] se []+    forM_ (zip dests ses) $+      \(d, SubExpRes _ se) -> copyDWIMDest d [] se []  compileBody' :: [Param dec] -> Body rep -> ImpM rep r op () compileBody' params (Body _ stms ses) =   compileStms (freeIn ses) stms $-    forM_ (zip params ses) $ \(param, SubExpRes _ se) -> copyDWIM (paramName param) [] se []+    forM_ (zip params ses) $+      \(param, SubExpRes _ se) -> copyDWIM (paramName param) [] se []  compileLoopBody :: Typed dec => [Param dec] -> Body rep -> ImpM rep r op () compileLoopBody mergeparams (Body _ stms ses) = do@@ -725,11 +768,11 @@        e_code <-         localAttrs (stmAuxAttrs aux) $-          collect $ compileExp pat e+          collect $+            compileExp pat e       (live_after, bs_code) <- collect' $ compileStms' (patternAllocs pat <> allocs) bs       let dies_here v =-            not (v `nameIn` live_after)-              && v `nameIn` freeIn e_code+            (v `notNameIn` live_after) && (v `nameIn` freeIn e_code)           to_free = S.filter (dies_here . fst) allocs        emit e_code@@ -1018,7 +1061,9 @@   where     addFParam fparam =       addVar (paramName fparam) $-        memBoundToVarEntry Nothing $ noUniquenessReturns $ paramDec fparam+        memBoundToVarEntry Nothing $+          noUniquenessReturns $+            paramDec fparam  -- | Another hack. addLoopVar :: VName -> IntType -> ImpM rep r op ()@@ -1144,7 +1189,6 @@ everythingVolatile :: ImpM rep r op a -> ImpM rep r op a everythingVolatile = local $ \env -> env {envVolatility = Imp.Volatile} --- | Remove the array targets. funcallTargets :: [ValueDestination] -> ImpM rep r op [VName] funcallTargets dests =   concat <$> mapM funcallTarget dests@@ -1379,17 +1423,18 @@   src@(MemLoc src_name _ src_ixfn@(IxFun.IxFun src_lmads@(src_lmad :| _) _ _)) = do     -- If we can statically determine that the two index-functions     -- are equivalent, don't do anything-    unless (dst_name == src_name && dst_ixfn `IxFun.equivalent` src_ixfn) $+    unless (dst_name == src_name && dst_ixfn `IxFun.equivalent` src_ixfn)+      $       -- It's also possible that we can dynamically determine that the two       -- index-functions are equivalent.       sUnless         ( fromBool (dst_name == src_name && length dst_lmads == 1 && length src_lmads == 1)             .&&. IxFun.dynamicEqualsLMAD dst_lmad src_lmad         )-        $ do-          -- If none of the above is true, actually do the copy-          cc <- asks envCopyCompiler-          cc bt dst src+      $ do+        -- If none of the above is true, actually do the copy+        cc <- asks envCopyCompiler+        cc bt dst src  -- | Is this copy really a mapping with transpose? isMapTransposeCopy ::@@ -1453,19 +1498,19 @@   | Just (destoffset, srcoffset, num_arrays, size_x, size_y) <-       isMapTransposeCopy pt dest src = do       fname <- mapTransposeForType pt-      emit $-        Imp.Call+      emit+        $ Imp.Call           []           fname-          $ transposeArgs-            pt-            destmem-            (bytes destoffset)-            srcmem-            (bytes srcoffset)-            num_arrays-            size_x-            size_y+        $ transposeArgs+          pt+          destmem+          (bytes destoffset)+          srcmem+          (bytes srcoffset)+          num_arrays+          size_x+          size_y   | Just destoffset <-       IxFun.linearWithOffset dest_ixfun pt_size,     Just srcoffset <-@@ -1475,8 +1520,8 @@       if isScalarSpace srcspace || isScalarSpace destspace         then copyElementWise pt dest src         else-          emit $-            Imp.Copy+          emit+            $ Imp.Copy               pt               destmem               (bytes destoffset)@@ -1484,7 +1529,7 @@               srcmem               (bytes srcoffset)               srcspace-              $ num_elems `withElemType` pt+            $ num_elems `withElemType` pt   | otherwise =       copyElementWise pt dest src   where@@ -1566,8 +1611,8 @@               then pure mempty -- Copy would be no-op.               else collect $ copy bt destlocation' srclocation' --- | Like 'copyDWIM', but the target is a 'ValueDestination'--- instead of a variable name.+-- Like 'copyDWIM', but the target is a 'ValueDestination' instead of+-- a variable name. copyDWIMDest ::   ValueDestination ->   [DimIndex (Imp.TExp Int64)] ->@@ -1744,7 +1789,11 @@ sFor i bound body = do   i' <- newVName i   sFor' i' (untyped bound) $-    body $ TPrimExp $ Imp.var i' $ primExpType $ untyped bound+    body $+      TPrimExp $+        Imp.var i' $+          primExpType $+            untyped bound  sWhile :: Imp.TExp Bool -> ImpM rep r op () -> ImpM rep r op () sWhile cond body = do@@ -1808,7 +1857,9 @@ sArrayInMem :: String -> PrimType -> ShapeBase SubExp -> VName -> ImpM rep r op VName sArrayInMem name pt shape mem =   sArray name pt shape mem $-    IxFun.iota $ map (isInt64 . primExpFromSubExp int64) $ 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 rep r op VName@@ -1817,7 +1868,8 @@   mem <- sAlloc (name ++ "_mem") (typeSize (Array pt shape NoUniqueness)) space   let iota_ixfun = IxFun.iota $ map (isInt64 . primExpFromSubExp int64) permuted_dims   sArray name pt shape mem $-    IxFun.permute iota_ixfun $ rearrangeInverse perm+    IxFun.permute iota_ixfun $+      rearrangeInverse perm  -- | Uses linear/iota index function. sAllocArray :: String -> PrimType -> ShapeBase SubExp -> Space -> ImpM rep r op VName@@ -1887,7 +1939,7 @@   body <- collect $ do     mapM_ addParam $ outputs ++ inputs     m-  emitFunction fname $ Imp.Function Nothing outputs inputs body [] []+  emitFunction fname $ Imp.Function Nothing outputs inputs body   where     addParam (Imp.MemParam name space) =       addVar name $ MemVar Nothing $ MemEntry space
src/Futhark/CodeGen/ImpGen/GPU.hs view
@@ -83,12 +83,11 @@   Prog GPUMem ->   m (Warnings, Imp.Program) compileProg env prog =-  second (fmap setOpSpace . setDefsSpace)+  second (fmap setOpSpace . setDefaultSpace device_space)     <$> Futhark.CodeGen.ImpGen.compileProg env callKernelOperations device_space prog   where     device_space = Imp.Space "device"     global_space = Imp.Space "global"-    setDefsSpace = setDefaultSpace device_space     setOpSpace (Imp.CallKernel kernel) =       Imp.CallKernel         kernel@@ -145,7 +144,8 @@   segOpCompiler dest op opCompiler (Pat pes) (Inner (GPUBody _ (Body _ stms res))) = do   tid <- newVName "tid"-  sKernelThread "gpuseq" tid (defKernelAttrs 1 1) $+  let one = Count (intConst Int64 1)+  sKernelThread "gpuseq" tid (defKernelAttrs one one) $     compileStms (freeIn res) stms $       forM_ (zip pes res) $ \(pe, SubExpRes _ se) ->         copyDWIM (patElemName pe) [DimFix 0] se []@@ -296,8 +296,8 @@       let num_elems = Imp.elements $ product $ map toInt64Exp srcshape       srcspace <- entryMemSpace <$> lookupMemory srcmem       destspace <- entryMemSpace <$> lookupMemory destmem-      emit $-        Imp.Copy+      emit+        $ Imp.Copy           bt           destmem           (bytes $ sExt64 destoffset)@@ -305,7 +305,7 @@           srcmem           (bytes $ sExt64 srcoffset)           srcspace-          $ num_elems `Imp.withElemType` bt+        $ num_elems `Imp.withElemType` bt   | otherwise = sCopy bt destloc srcloc  mapTransposeForType :: PrimType -> CallKernelGen Name@@ -322,7 +322,7 @@  mapTransposeFunction :: PrimType -> Imp.Function Imp.HostOp mapTransposeFunction bt =-  Imp.Function Nothing [] params transpose_code [] []+  Imp.Function Nothing [] params transpose_code   where     params =       [ memparam destmem,@@ -421,7 +421,8 @@             (Imp.Count num_bytes)      callTransposeKernel =-      Imp.Op . Imp.CallKernel+      Imp.Op+        . Imp.CallKernel         . mapTransposeKernel           (mapTransposeName bt)           block_dim_int
src/Futhark/CodeGen/ImpGen/GPU/Base.hs view
@@ -91,6 +91,8 @@     kernelGlobalThreadIdVar :: VName,     kernelLocalThreadIdVar :: VName,     kernelGroupIdVar :: VName,+    kernelNumGroupsCount :: Count NumGroups SubExp,+    kernelGroupSizeCount :: Count GroupSize SubExp,     kernelNumGroups :: Imp.TExp Int64,     kernelGroupSize :: Imp.TExp Int64,     kernelNumThreads :: Imp.TExp Int32,@@ -444,7 +446,8 @@            locks_mem <- sAlloc "locks_mem" (typeSize locks_t) $ Space "local"           dArray locks int32 (arrayShape locks_t) locks_mem $-            IxFun.iota $ map pe64 $ arrayDims locks_t+            IxFun.iota . map pe64 . arrayDims $+              locks_t            sComment "All locks start out unlocked" $             groupCoverSpace [kernelGroupSize constants] $ \is ->@@ -462,7 +465,8 @@ fenceForArrays = fmap (foldl' max Imp.FenceLocal) . mapM need   where     need arr =-      fmap (fenceForSpace . entryMemSpace) . lookupMemory+      fmap (fenceForSpace . entryMemSpace)+        . lookupMemory         . memLocName         . entryArrayLoc         =<< lookupArray arr@@ -507,7 +511,9 @@   ArrayEntry arr_loc pt <- lookupArray arr   let flat_shape = Shape $ Var (tvVar flat) : drop k (memLocShape arr_loc)   sArray (baseString arr ++ "_flat") pt flat_shape (memLocName arr_loc) $-    IxFun.reshape (memLocIxFun arr_loc) $ map (DimNew . pe64) $ shapeDims flat_shape+    IxFun.reshape (memLocIxFun arr_loc) $+      map (DimNew . pe64) $+        shapeDims flat_shape  -- | @applyLambda lam dests args@ emits code that: --@@ -535,7 +541,7 @@     forM_ (zip dests res) $ \((dest, dest_slice), se) ->       copyDWIM dest dest_slice se [] --- | As 'applyLambda', but first rename the names in the lambda.  This+-- | As applyLambda, but first rename the names in the lambda.  This -- makes it safe to apply it in multiple places.  (It might be safe -- anyway, but you have to be more careful - use this if you are in -- doubt.)@@ -628,7 +634,8 @@       num_scan_results = length $ segBinOpNeutral scan   arrs_flat <-     mapM (flattenArray (length dims') dims_flat) $-      take num_scan_results $ patNames pat+      take num_scan_results $+        patNames pat    case segVirt lvl of     SegVirt ->@@ -893,7 +900,8 @@     primBitSize t `elem` [32, 64] = AtomicCAS $ \space [arr] bucket -> do       old <- dPrim "old" t       atomicUpdateCAS space t arr (tvVar old) bucket (paramName xp) $-        compileBody' [xp] $ lambdaBody op+        compileBody' [xp] $+          lambdaBody op atomicUpdateLocking _ op = AtomicLocking $ \locking space arrs bucket -> do   old <- dPrim "old" int32   continue <- dPrimVol "continue" Bool true@@ -947,12 +955,14 @@    let op_body =         sComment "execute operation" $-          compileBody' acc_params $ lambdaBody op+          compileBody' acc_params $+            lambdaBody op        do_hist =         everythingVolatile $           sComment "update global result" $-            zipWithM_ (writeArray bucket) arrs $ map (Var . paramName) acc_params+            zipWithM_ (writeArray bucket) arrs $+              map (Var . paramName) acc_params        fence = sOp $ Imp.MemFence $ fenceForSpace space @@ -1121,33 +1131,39 @@       num_elements - Imp.elements thread_index * elements_per_thread     is_last_thread =       Imp.unCount num_elements-        .<. (thread_index + 1) * Imp.unCount elements_per_thread+        .<. (thread_index + 1)+          * Imp.unCount elements_per_thread  kernelInitialisationSimple ::-  Count NumGroups (Imp.TExp Int64) ->-  Count GroupSize (Imp.TExp Int64) ->+  Count NumGroups SubExp ->+  Count GroupSize SubExp ->   CallKernelGen (KernelConstants, InKernelGen ())-kernelInitialisationSimple (Count num_groups) (Count group_size) = do+kernelInitialisationSimple num_groups group_size = do   global_tid <- newVName "global_tid"   local_tid <- newVName "local_tid"   group_id <- newVName "group_tid"   wave_size <- newVName "wave_size"   inner_group_size <- newVName "group_size"-  let constants =+  let num_groups' = Imp.pe64 (unCount num_groups)+      group_size' = Imp.pe64 (unCount group_size)+      constants =         KernelConstants-          (Imp.le32 global_tid)-          (Imp.le32 local_tid)-          (Imp.le32 group_id)-          global_tid-          local_tid-          group_id-          num_groups-          group_size-          (sExt32 (group_size * num_groups))-          (Imp.le32 wave_size)-          true-          mempty-          mempty+          { kernelGlobalThreadId = Imp.le32 global_tid,+            kernelLocalThreadId = Imp.le32 local_tid,+            kernelGroupId = Imp.le32 group_id,+            kernelGlobalThreadIdVar = global_tid,+            kernelLocalThreadIdVar = local_tid,+            kernelNumGroupsCount = num_groups,+            kernelGroupSizeCount = group_size,+            kernelGroupIdVar = group_id,+            kernelNumGroups = num_groups',+            kernelGroupSize = group_size',+            kernelNumThreads = sExt32 (group_size' * num_groups'),+            kernelWaveSize = Imp.le32 wave_size,+            kernelThreadActive = true,+            kernelLocalIdMap = mempty,+            kernelChunkItersMap = mempty+          }    let set_constants = do         dPrim_ local_tid int32@@ -1241,7 +1257,8 @@         comment "read array element" $           zipWithM_ readReduceArgument reduce_arr_params arrs         comment "apply reduction operation" $-          compileBody' reduce_acc_params $ lambdaBody lam+          compileBody' reduce_acc_params $+            lambdaBody lam         comment "write result of operation" $           zipWithM_ writeReduceOpResult reduce_acc_params arrs       in_wave_reduce = everythingVolatile do_reduce@@ -1470,7 +1487,8 @@   let op_to_x in_block_thread_active         | Nothing <- seg_flag =             sWhen in_block_thread_active $-              compileBody' x_params $ lambdaBody scan_lam+              compileBody' x_params $+                lambdaBody scan_lam         | Just flag_true <- seg_flag = do             inactive <-               dPrimVE "inactive" $ flag_true (ltid32 - tvExp skip_threads) ltid32@@ -1481,7 +1499,8 @@             -- hit this barrier (if applicable).             when array_scan barrier             sWhen in_block_thread_active . sUnless inactive $-              compileBody' x_params $ lambdaBody scan_lam+              compileBody' x_params $+                lambdaBody scan_lam        maybeBarrier =         sWhen@@ -1501,7 +1520,8 @@       maybeBarrier        sWhen thread_active . sComment "write result" $-        sequence_ $ zipWith3 writeResult x_params y_params arrs+        sequence_ $+          zipWith3 writeResult x_params y_params arrs        maybeBarrier @@ -1533,14 +1553,16 @@       | otherwise =           copyDWIM (paramName y) [] (Var $ paramName x) [] -computeMapKernelGroups :: Imp.TExp Int64 -> CallKernelGen (Imp.TExp Int64, Imp.TExp Int64)+computeMapKernelGroups ::+  Imp.TExp Int64 ->+  CallKernelGen (Count NumGroups SubExp, Count GroupSize SubExp) computeMapKernelGroups kernel_size = do   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` tvExp group_size-  pure (tvExp num_groups, tvExp group_size)+  pure (Count $ tvSize num_groups, Count $ tvSize group_size)  simpleKernelConstants ::   Imp.TExp Int64 ->@@ -1560,22 +1582,27 @@         sOp (Imp.GetLocalSize inner_group_size 0)         sOp (Imp.GetGroupId group_id 0)         dPrimV_ thread_gtid $ le32 group_id * le32 inner_group_size + le32 thread_ltid+      group_size' = Imp.pe64 $ unCount group_size+      num_groups' = Imp.pe64 $ unCount num_groups    pure     ( KernelConstants-        (Imp.le32 thread_gtid)-        (Imp.le32 thread_ltid)-        (Imp.le32 group_id)-        thread_gtid-        thread_ltid-        group_id-        num_groups-        group_size-        (sExt32 (group_size * num_groups))-        0-        (Imp.le64 thread_gtid .<. kernel_size)-        mempty-        mempty,+        { kernelGlobalThreadId = Imp.le32 thread_gtid,+          kernelLocalThreadId = Imp.le32 thread_ltid,+          kernelGroupId = Imp.le32 group_id,+          kernelGlobalThreadIdVar = thread_gtid,+          kernelLocalThreadIdVar = thread_ltid,+          kernelGroupIdVar = group_id,+          kernelNumGroupsCount = num_groups,+          kernelGroupSizeCount = group_size,+          kernelNumGroups = num_groups',+          kernelGroupSize = group_size',+          kernelNumThreads = sExt32 (group_size' * num_groups'),+          kernelWaveSize = 0,+          kernelThreadActive = Imp.le64 thread_gtid .<. kernel_size,+          kernelLocalIdMap = mempty,+          kernelChunkItersMap = mempty+        },       set_constants     ) @@ -1618,15 +1645,15 @@     -- | Does whatever launch this kernel check for local memory capacity itself?     kAttrCheckLocalMemory :: Bool,     -- | Number of groups.-    kAttrNumGroups :: Count NumGroups (Imp.TExp Int64),+    kAttrNumGroups :: Count NumGroups SubExp,     -- | Group size.-    kAttrGroupSize :: Count GroupSize (Imp.TExp Int64)+    kAttrGroupSize :: Count GroupSize SubExp   }  -- | The default kernel attributes. defKernelAttrs ::-  Count NumGroups (Imp.TExp Int64) ->-  Count GroupSize (Imp.TExp Int64) ->+  Count NumGroups SubExp ->+  Count GroupSize SubExp ->   KernelAttrs defKernelAttrs num_groups group_size =   KernelAttrs@@ -1703,8 +1730,8 @@   where     attrs =       ( defKernelAttrs-          (Count (kernelNumGroups constants))-          (Count (kernelGroupSize constants))+          (kernelNumGroupsCount constants)+          (kernelGroupSizeCount constants)       )         { kAttrFailureTolerant = tol         }@@ -1779,7 +1806,8 @@     set_constants     is' <- dIndexSpace' "rep_i" dims $ sExt64 $ kernelGlobalThreadId constants     sWhen (kernelThreadActive constants) $-      copyDWIMFix arr is' se $ drop (length ds) is'+      copyDWIMFix arr is' se $+        drop (length ds) is'  replicateName :: PrimType -> String replicateName bt = "replicate_" ++ pretty bt@@ -1803,7 +1831,9 @@     function fname [] params $ do       arr <-         sArray "arr" bt shape mem $-          IxFun.iota $ map pe64 $ shapeDims shape+          IxFun.iota $+            map pe64 $+              shapeDims shape       sReplicateKernel arr $ Var val    pure fname@@ -1854,7 +1884,9 @@   let name =         keyWithEntryPoint fname $           nameFromString $-            "iota_" ++ pretty et ++ "_"+            "iota_"+              ++ pretty et+              ++ "_"               ++ show (baseTag $ kernelGlobalThreadIdVar constants)    sKernelFailureTolerant True threadOperations constants name $ do@@ -1898,7 +1930,9 @@     function fname [] params $ do       arr <-         sArray "arr" (IntType bt) shape mem $-          IxFun.iota $ map pe64 $ shapeDims shape+          IxFun.iota $+            map pe64 $+              shapeDims shape       sIotaKernel arr (sExt64 n') x' s' bt    pure fname
src/Futhark/CodeGen/ImpGen/GPU/SegHist.hs view
@@ -72,7 +72,8 @@   Imp.Count Imp.Bytes (Imp.TExp Int64) histSpaceUsage op =   sum . map (typeSize . (`arrayOfShape` (histShape op <> histOpShape op))) $-    lambdaReturnType $ histOp op+    lambdaReturnType $+      histOp op  histSize :: HistOp GPUMem -> Imp.TExp Int64 histSize = product . map toInt64Exp . shapeDims . histShape@@ -114,7 +115,9 @@         (elemType dest_t)         subhistos_shape         subhistos_mem-        $ IxFun.iota $ map pe64 $ shapeDims subhistos_shape+        $ IxFun.iota+        $ map pe64+        $ shapeDims subhistos_shape      pure $       SubhistosInfo subhistos $ do@@ -149,7 +152,8 @@     ( h,       segmented_h,       SegHistSlug op num_subhistos subhisto_infos $-        atomicUpdateLocking atomics $ histOp op+        atomicUpdateLocking atomics $+          histOp op     )  prepareAtomicUpdateGlobal ::@@ -228,11 +232,15 @@    hist_C_max <-     dPrimVE "hist_C_max" $-      fMin64 (r64 hist_T) $ r64 hist_H / hist_k_ct_min+      fMin64 (r64 hist_T) $+        r64 hist_H / hist_k_ct_min    hist_M_min <-     dPrimVE "hist_M_min" $-      sMax32 1 $ sExt32 $ 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.@@ -240,11 +248,11 @@   hist_L2 <- dPrim "L2_size" int32   entry <- askFunction   -- Equivalent to F_L2*L2 in paper.-  sOp $-    Imp.GetSize+  sOp+    $ Imp.GetSize       (tvVar hist_L2)       (keyWithEntryPoint entry $ nameFromString (pretty (tvVar hist_L2)))-      $ Imp.SizeBespoke (nameFromString "L2_for_histogram") hist_L2_def+    $ Imp.SizeBespoke (nameFromString "L2_for_histogram") hist_L2_def    let hist_L2_ln_sz = 16 * 4 -- L2 cache line size approximation   hist_RACE_exp <-@@ -334,7 +342,8 @@        hist_C <-         dPrimVE "hist_C" $-          fMin64 (r64 hist_T) $ r64 (hist_u * hist_H_chk) / hist_k_max+          fMin64 (r64 hist_T) $+            r64 (hist_u * hist_H_chk) / hist_k_max        -- Number of subhistograms per result histogram.       hist_M <- dPrimVE "hist_M" $@@ -379,8 +388,8 @@  histKernelGlobalPass ::   [PatElem LetDecMem] ->-  Count NumGroups (Imp.TExp Int64) ->-  Count GroupSize (Imp.TExp Int64) ->+  Count NumGroups SubExp ->+  Count GroupSize SubExp ->   SegSpace ->   [SegHistSlug] ->   KernelBody GPUMem ->@@ -493,8 +502,8 @@   sFor "chk_i" hist_S $ \chk_i ->     histKernelGlobalPass       map_pes-      num_groups'-      group_size'+      num_groups+      group_size       space       slugs       kbody@@ -525,7 +534,9 @@        emit $         Imp.DebugPrint "Number of subhistograms in global memory per segment" $-          Just $ untyped $ tvExp num_subhistos+          Just $+            untyped $+              tvExp num_subhistos        mk_op <-         case do_op of@@ -534,8 +545,8 @@           AtomicLocking f -> pure $ \hist_H_chk -> do             let lock_shape =                   Shape $-                    tvSize num_subhistos_per_group :-                    shapeDims (histOpShape op)+                    tvSize num_subhistos_per_group+                      : shapeDims (histOpShape op)                       ++ [hist_H_chk]              let dims = map toInt64Exp $ shapeDims lock_shape@@ -577,8 +588,8 @@   TV Int32 ->   Count NumGroups (Imp.TExp Int64) ->   [PatElem LetDecMem] ->-  Count NumGroups (Imp.TExp Int64) ->-  Count GroupSize (Imp.TExp Int64) ->+  Count NumGroups SubExp ->+  Count GroupSize SubExp ->   SegSpace ->   [SegHistSlug] ->   KernelBody GPUMem ->@@ -607,21 +618,22 @@      num_segments <-       dPrimVE "num_segments" $-        product $ map toInt64Exp segment_dims+        product $+          map toInt64Exp segment_dims      hist_H_chks <- forM (map slugOp slugs) $ \op ->       dPrimV "hist_H_chk" $ histSize op `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 (histOpShape (slugOp slug)))+            tvExp hist_H_chk+              : map toInt64Exp (shapeDims (histOpShape (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+        dPrimVE "init_per_thread" $ sExt32 $ group_hists_size `divUp` pe64 (unCount group_size)       pure (histo_dims, histo_size, init_per_thread)      let attrs = (defKernelAttrs num_groups group_size) {kAttrCheckLocalMemory = False}@@ -639,11 +651,13 @@               + kernelLocalThreadId constants         threads_per_segment <-           dPrimVE "threads_per_segment" $-            sExt32 $ unCount groups_per_segment * kernelGroupSize constants+            sExt32 $+              unCount groups_per_segment * kernelGroupSize constants          -- Set segment indices.         zipWithM_ dPrimV_ segment_is $-          unflattenIndex (map toInt64Exp segment_dims) $ sExt64 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@@ -724,7 +738,8 @@           compileStms mempty (kernelBodyStms kbody) $ do             let (red_res, map_res) =                   splitFromEnd (length map_pes) $-                    map kernelResultSubExp $ kernelBodyResult kbody+                    map kernelResultSubExp $+                      kernelBodyResult kbody              sWhen (chk_i .==. 0) $               sComment "save map-out results" $@@ -769,8 +784,8 @@               dPrimV "trunc_H" . sMin64 hist_H_chk $                 histSize (slugOp slug) - sExt64 chk_i * head histo_dims             let trunc_histo_dims =-                  tvExp trunc_H :-                  map toInt64Exp (shapeDims (histOpShape (slugOp slug)))+                  tvExp trunc_H+                    : map toInt64Exp (shapeDims (histOpShape (slugOp slug)))             trunc_histo_size <- dPrimVE "histo_size" $ sExt32 $ product trunc_histo_dims              sFor "local_i" bins_per_thread $ \i -> do@@ -793,7 +808,9 @@                 let (global_dests, local_dests) = unzip dests                     (xparams, yparams) =                       splitAt (length local_dests) $-                        lambdaParams $ histOp $ slugOp slug+                        lambdaParams $+                          histOp $+                            slugOp slug                  sComment "Read values from subhistogram 0." $                   forM_ (zip xparams local_dests) $ \(xp, subhisto) ->@@ -833,13 +850,12 @@   KernelBody GPUMem ->   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 toInt64Exp num_groups-      group_size' = fmap toInt64Exp group_size-      num_subhistos_per_group = tvExp num_subhistos_per_group_var+  let num_subhistos_per_group = tvExp num_subhistos_per_group_var    emit $     Imp.DebugPrint "Number of local subhistograms per group" $-      Just $ untyped num_subhistos_per_group+      Just $+        untyped num_subhistos_per_group    init_histograms <-     prepareIntermediateArraysLocal num_subhistos_per_group_var groups_per_segment slugs@@ -849,8 +865,8 @@       num_subhistos_per_group_var       groups_per_segment       map_pes-      num_groups'-      group_size'+      num_groups+      group_size       space       slugs       kbody@@ -914,7 +930,8 @@   -- M in the paper, but not adjusted for asymptotic efficiency.   hist_M0 <-     dPrimVE "hist_M0" $-      sMax64 1 $ sMin64 (t64 hist_m') hist_B+      sMax64 1 $+        sMin64 (t64 hist_m') hist_B    -- Minimal sequential chunking factor.   let q_small = 2@@ -965,7 +982,9 @@   emit $ Imp.DebugPrint "local M" $ Just $ untyped $ tvExp hist_M   emit $     Imp.DebugPrint "local memory needed" $-      Just $ untyped $ hist_H * hist_el_size * sExt64 (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@@ -986,7 +1005,8 @@     if segmented       then         fmap Count $-          dPrimVE "groups_per_segment" $ unCount num_groups' `divUp` hist_Nout+          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@@ -1007,7 +1027,11 @@         emit $ Imp.DebugPrint "Cooperation level (C)" $ Just $ untyped hist_C         emit $ Imp.DebugPrint "Number of chunks (S)" $ Just $ untyped hist_S         when segmented $-          emit $ Imp.DebugPrint "Groups per segment" $ Just $ untyped $ unCount groups_per_segment+          emit $+            Imp.DebugPrint "Groups per segment" $+              Just $+                untyped $+                  unCount groups_per_segment         histKernelLocal           hist_M           groups_per_segment@@ -1084,7 +1108,10 @@     emit $ Imp.DebugPrint "Input elements per histogram (N)" $ Just $ untyped hist_N     emit $       Imp.DebugPrint "Number of segments" $-        Just $ untyped $ product $ map (toInt64Exp . 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
src/Futhark/CodeGen/ImpGen/GPU/SegMap.hs view
@@ -25,14 +25,14 @@ compileSegMap pat lvl space kbody = do   let (is, dims) = unzip $ unSegSpace space       dims' = map toInt64Exp dims-      num_groups' = toInt64Exp <$> segNumGroups lvl       group_size' = toInt64Exp <$> segGroupSize lvl+      attrs = defKernelAttrs (segNumGroups lvl) (segGroupSize lvl)    emit $ Imp.DebugPrint "\n# SegMap" Nothing   case lvl of     SegThread {} -> do       virt_num_groups <- dPrimVE "virt_num_groups" $ sExt32 $ product dims' `divUp` unCount group_size'-      sKernelThread "segmap" (segFlat space) (defKernelAttrs num_groups' group_size') $+      sKernelThread "segmap" (segFlat space) attrs $         virtualiseGroups (segVirt lvl) virt_num_groups $ \group_id -> do           local_tid <- kernelLocalThreadId . kernelConstants <$> askEnv @@ -50,7 +50,7 @@     SegGroup {} -> do       pc <- precomputeConstants group_size' $ kernelBodyStms kbody       virt_num_groups <- dPrimVE "virt_num_groups" $ sExt32 $ product dims'-      sKernelGroup "segmap_intragroup" (segFlat space) (defKernelAttrs num_groups' group_size') $ do+      sKernelGroup "segmap_intragroup" (segFlat space) attrs $ do         precomputedConstants pc $           virtualiseGroups (segVirt lvl) virt_num_groups $ \group_id -> do             dIndexSpace (zip is dims') $ sExt64 group_id
src/Futhark/CodeGen/ImpGen/GPU/SegRed.hs view
@@ -139,7 +139,9 @@       MemArray pt shape _ (ArrayIn mem _) -> do         let shape' = Shape [num_threads] <> shape         sArray "red_arr" pt shape' mem $-          IxFun.iota $ map pe64 $ shapeDims shape'+          IxFun.iota $+            map pe64 $+              shapeDims shape'       _ -> do         let pt = elemType $ paramType p             shape = Shape [group_size]@@ -188,7 +190,7 @@    counter <-     sStaticArray "counter" (Space "device") int32 $-      Imp.ArrayValues $ replicate (fromIntegral maxNumOps) $ IntValue $ Int32Value 0+      Imp.ArrayZeros (fromIntegral maxNumOps)    reds_group_res_arrs <- groupResultArrays num_groups group_size reds @@ -198,7 +200,7 @@    emit $ Imp.DebugPrint "\n# SegRed" Nothing -  sKernelThread "segred_nonseg" (segFlat space) (defKernelAttrs num_groups' group_size') $ do+  sKernelThread "segred_nonseg" (segFlat space) (defKernelAttrs num_groups group_size) $ do     constants <- kernelConstants <$> askEnv     sync_arr <- sAllocArray "sync_arr" Bool (Shape [intConst Int32 1]) $ Space "local"     reds_arrs <- mapM (intermediateArrays group_size (tvSize num_threads)) reds@@ -284,7 +286,7 @@   emit $ Imp.DebugPrint "segments_per_group" $ Just $ untyped segments_per_group   emit $ Imp.DebugPrint "required_groups" $ Just $ untyped required_groups -  sKernelThread "segred_small" (segFlat space) (defKernelAttrs num_groups' group_size') $ do+  sKernelThread "segred_small" (segFlat space) (defKernelAttrs num_groups group_size) $ do     constants <- kernelConstants <$> askEnv     reds_arrs <- mapM (intermediateArrays group_size (Var $ tvVar num_threads)) reds @@ -318,9 +320,12 @@        sComment "apply map function if in bounds" $         sIf-          ( segment_size .>. 0+          ( segment_size+              .>. 0               .&&. isActive (init $ zip gtids dims)-              .&&. ltid .<. segment_size * segments_per_group+              .&&. ltid+                .<. segment_size+                  * segments_per_group           )           in_bounds           out_of_bounds@@ -340,22 +345,27 @@        sOp $ Imp.Barrier Imp.FenceLocal -      sComment "save final values of segments" $-        sWhen-          ( sExt64 group_id' * segments_per_group + sExt64 ltid .<. num_segments-              .&&. ltid .<. segments_per_group+      sComment "save final values of segments"+        $ sWhen+          ( 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 =-                  sExt64 group_id' * segments_per_group + sExt64 ltid-                gtids' =-                  unflattenIndex (init dims') flat_segment_index-            copyDWIMFix-              (patElemName pe)-              gtids'-              (Var arr)-              [(ltid + 1) * segment_size_nonzero - 1]+        $ forM_ (zip segred_pes (concat reds_arrs))+        $ \(pe, arr) -> do+          -- Figure out which segment result this thread should write...+          let flat_segment_index =+                sExt64 group_id' * segments_per_group + sExt64 ltid+              gtids' =+                unflattenIndex (init dims') flat_segment_index+          copyDWIMFix+            (patElemName pe)+            gtids'+            (Var arr)+            [(ltid + 1) * segment_size_nonzero - 1]        -- Finally another barrier, because we will be writing to the       -- local memory array first thing in the next iteration.@@ -423,7 +433,7 @@     sStaticArray "counter" (Space "device") int32 $       Imp.ArrayZeros num_counters -  sKernelThread "segred_large" (segFlat space) (defKernelAttrs num_groups' group_size') $ do+  sKernelThread "segred_large" (segFlat space) (defKernelAttrs num_groups group_size) $ do     constants <- kernelConstants <$> askEnv     reds_arrs <- mapM (intermediateArrays group_size (tvSize num_threads)) reds     sync_arr <- sAllocArray "sync_arr" Bool (Shape [intConst Int32 1]) $ Space "local"@@ -640,7 +650,7 @@           let index_in_segment = global_tid `quot` kernelGroupSize constants            in sExt64 local_tid                 + (index_in_segment * Imp.unCount elems_per_thread + i)-                * kernelGroupSize constants+                  * kernelGroupSize constants      check_bounds $       sComment "apply map function" $@@ -655,16 +665,16 @@               sComment "load new values" $                 forM_ (zip (nextParams slug) red_res) $ \(p, (res, res_is)) ->                   copyDWIMFix (paramName p) [] res (res_is ++ vec_is)-              sComment "apply reduction operator" $-                compileStms mempty (bodyStms $ slugBody slug) $-                  sComment "store in accumulator" $-                    forM_-                      ( zip-                          (slugAccs slug)-                          (map resSubExp $ bodyResult $ slugBody slug)-                      )-                      $ \((acc, acc_is), se) ->-                        copyDWIMFix acc (acc_is ++ vec_is) se []+              sComment "apply reduction operator"+                $ compileStms mempty (bodyStms $ slugBody slug)+                $ sComment "store in accumulator"+                $ forM_+                  ( zip+                      (slugAccs slug)+                      (map resSubExp $ bodyResult $ slugBody slug)+                  )+                $ \((acc, acc_is), se) ->+                  copyDWIMFix acc (acc_is ++ vec_is) se []      case comm of       Noncommutative -> do@@ -756,14 +766,14 @@         sOp $ Imp.MemFence Imp.FenceGlobal         -- Increment the counter, thus stating that our result is         -- available.-        sOp $-          Imp.Atomic DefaultSpace $-            Imp.AtomicAdd-              Int32-              (tvVar old_counter)-              counter_mem-              counter_offset-              $ untyped (1 :: Imp.TExp Int32)+        sOp+          $ Imp.Atomic DefaultSpace+          $ Imp.AtomicAdd+            Int32+            (tvVar old_counter)+            counter_mem+            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.         sWrite sync_arr [0] $ untyped $ tvExp old_counter .==. groups_per_segment - 1@@ -783,7 +793,8 @@         sOp $           Imp.Atomic DefaultSpace $             Imp.AtomicAdd Int32 (tvVar old_counter) counter_mem counter_offset $-              untyped $ negate groups_per_segment+              untyped $+                negate groups_per_segment        sLoopNest (slugShape slug) $ \vec_is -> do         -- There is no guarantee that the number of workgroups for the
src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs view
@@ -217,52 +217,57 @@   CallKernelGen () compileSegScan pat lvl space scanOp kbody = do   let Pat all_pes = pat-      group_size = toInt64Exp <$> segGroupSize lvl-      n = product $ map toInt64Exp $ segSpaceDims space-      num_groups = Count (n `divUp` (unCount group_size * m))-      num_threads = unCount num_groups * unCount group_size-      (gtids, dims) = unzip $ unSegSpace space-      dims' = map toInt64Exp dims-      segmented = length dims' > 1-      not_segmented_e = if segmented then false else true-      segment_size = last dims'       scanOpNe = segBinOpNeutral scanOp       tys = map (\(Prim pt) -> pt) $ lambdaReturnType $ segBinOpLambda scanOp--      statusX, statusA, statusP :: Num a => a-      statusX = 0-      statusA = 1-      statusP = 2+      n = product $ map pe64 $ segSpaceDims space       sumT :: Integer       maxT :: Integer       sumT = foldl (\bytes typ -> bytes + primByteSize typ) 0 tys       primByteSize' = max 4 . primByteSize       sumT' = foldl (\bytes typ -> bytes + primByteSize' typ) 0 tys `div` 4       maxT = maximum (map primByteSize tys)+      m :: Num a => a+      m = fromIntegral $ max 1 $ min mem_constraint reg_constraint       -- TODO: Make these constants dynamic by querying device       k_reg = 64       k_mem = 95       mem_constraint = max k_mem sumT `div` maxT       reg_constraint = (k_reg - 1 - sumT') `div` (2 * sumT')-      m :: Num a => a-      m = fromIntegral $ max 1 $ min mem_constraint reg_constraint -  emit $ Imp.DebugPrint "SegScan: number of elements processed sequentially per thread is m:" $ Just $ untyped (m :: Imp.TExp Int32)-  emit $ Imp.DebugPrint "SegScan: memory constraints is: " $ Just $ untyped (fromIntegral mem_constraint :: Imp.TExp Int32)-  emit $ Imp.DebugPrint "SegScan: register constraints is: " $ Just $ untyped (fromIntegral reg_constraint :: Imp.TExp Int32)-  emit $ Imp.DebugPrint "SegScan: sumT' is: " $ Just $ untyped (fromIntegral sumT' :: Imp.TExp Int32)+      group_size = segGroupSize lvl+      group_size' = pe64 $ unCount group_size -  -- Allocate the shared memory for output component-  numThreads <- dPrimV "numThreads" num_threads-  numGroups <- dPrimV "numGroups" $ unCount num_groups+  num_groups <-+    Count . tvSize <$> dPrimV "num_groups" (n `divUp` (group_size' * m))+  let num_groups' = pe64 (unCount num_groups) +  num_threads <-+    dPrimVE "num_threads" $ num_groups' * group_size'++  let (gtids, dims) = unzip $ unSegSpace space+      dims' = map toInt64Exp dims+      segmented = length dims' > 1+      not_segmented_e = if segmented then false else true+      segment_size = last dims'++      statusX, statusA, statusP :: Num a => a+      statusX = 0+      statusA = 1+      statusP = 2++  emit $ Imp.DebugPrint "Sequential elements per thread (m):" $ Just $ untyped (m :: Imp.TExp Int32)+  emit $ Imp.DebugPrint "Memory constraint " $ Just $ untyped (fromIntegral mem_constraint :: Imp.TExp Int32)+  emit $ Imp.DebugPrint "Register constraint" $ Just $ untyped (fromIntegral reg_constraint :: Imp.TExp Int32)+  emit $ Imp.DebugPrint "sumT'" $ Just $ untyped (fromIntegral sumT' :: Imp.TExp Int32)+   globalId <- sStaticArray "id_counter" (Space "device") int32 $ Imp.ArrayZeros 1-  statusFlags <- sAllocArray "status_flags" int8 (Shape [tvSize numGroups]) (Space "device")+  statusFlags <- sAllocArray "status_flags" int8 (Shape [unCount num_groups]) (Space "device")   (aggregateArrays, incprefixArrays) <-     fmap unzip $       forM tys $ \ty ->-        (,) <$> sAllocArray "aggregates" ty (Shape [tvSize numGroups]) (Space "device")-          <*> sAllocArray "incprefixes" ty (Shape [tvSize numGroups]) (Space "device")+        (,)+          <$> sAllocArray "aggregates" ty (Shape [unCount num_groups]) (Space "device")+          <*> sAllocArray "incprefixes" ty (Shape [unCount num_groups]) (Space "device")    sReplicate statusFlags $ intConst Int8 statusX @@ -299,10 +304,12 @@     sgmIdx <- dPrimVE "sgm_idx" $ tvExp blockOff `mod` segment_size     boundary <-       dPrimVE "boundary" $-        sExt32 $ sMin64 (m * unCount group_size) (segment_size - sgmIdx)+        sExt32 $+          sMin64 (m * group_size') (segment_size - sgmIdx)     segsize_compact <-       dPrimVE "segsize_compact" $-        sExt32 $ sMin64 (m * unCount group_size) segment_size+        sExt32 $+          sMin64 (m * group_size') segment_size     privateArrays <-       forM tys $ \ty ->         sAllocArray@@ -316,7 +323,8 @@         -- The map's input index         phys_tid <-           dPrimVE "phys_tid" $-            tvExp blockOff + sExt64 (kernelLocalThreadId constants)+            tvExp blockOff+              + sExt64 (kernelLocalThreadId constants)               + i * kernelGroupSize constants         dIndexSpace (zip gtids dims') phys_tid         -- Perform the map@@ -397,7 +405,7 @@     sComment "Scan results (with warp scan)" $ do       groupScan         crossesSegment-        (tvExp numThreads)+        num_threads         (kernelGroupSize constants)         scanOp'         prefixArrays@@ -434,7 +442,7 @@       sWhen (bNot blockNewSgm .&&. kernelLocalThreadId constants .<. warpSize) $ do         sWhen (kernelLocalThreadId constants .==. 0) $ do           sIf-            (not_segmented_e .||. boundary .==. sExt32 (unCount group_size * m))+            (not_segmented_e .||. boundary .==. sExt32 (group_size' * m))             ( do                 everythingVolatile $                   forM_ (zip aggregateArrays accs) $ \(aggregateArray, acc) ->@@ -469,7 +477,8 @@           ( do               readOffset <-                 dPrimV "readOffset" $-                  sExt32 $ tvExp dynamicId - sExt64 (kernelWaveSize constants)+                  sExt32 $+                    tvExp dynamicId - sExt64 (kernelWaveSize constants)               let loopStop = warpSize * (-1)                   sameSegment readIdx                     | segmented =@@ -510,7 +519,7 @@                   lam' <- renameLambda scanOp'                   inBlockScanLookback                     constants-                    (tvExp numThreads)+                    num_threads                     warpscan                     exchanges                     lam'@@ -544,7 +553,7 @@           scanOp'''' <- renameLambda scanOp'           let xs = map paramName $ take (length tys) $ lambdaParams scanOp''''               ys = map paramName $ drop (length tys) $ lambdaParams scanOp''''-          sWhen (boundary .==. sExt32 (unCount group_size * m)) $ do+          sWhen (boundary .==. sExt32 (group_size' * m)) $ do             forM_ (zip xs prefixes) $ \(x, prefix) -> dPrimV_ x $ tvExp prefix             forM_ (zip ys accs) $ \(y, acc) -> dPrimV_ y $ tvExp acc             compileStms mempty (bodyStms $ lambdaBody scanOp'''') $@@ -616,7 +625,8 @@         sFor "i" m $ \i -> do           flat_idx <-             dPrimVE "flat_idx" $-              tvExp blockOff + kernelGroupSize constants * i+              tvExp blockOff+                + kernelGroupSize constants * i                 + sExt64 (kernelLocalThreadId constants)           dIndexSpace (zip gtids dims') flat_idx           sWhen (flat_idx .<. n) $ do@@ -628,5 +638,5 @@         sOp localBarrier      sComment "If this is the last block, reset the dynamicId" $-      sWhen (tvExp dynamicId .==. unCount num_groups - 1) $+      sWhen (tvExp dynamicId .==. num_groups' - 1) $         copyDWIMFix globalId [0] (constant (0 :: Int32)) []
src/Futhark/CodeGen/ImpGen/GPU/SegScan/TwoPass.hs view
@@ -43,7 +43,9 @@               let shape' = Shape [num_threads] <> shape               arr <-                 lift . sArray "scan_arr" pt shape' mem $-                  IxFun.iota $ map pe64 $ shapeDims shape'+                  IxFun.iota $+                    map pe64 $+                      shapeDims shape'               pure (arr, [])             _ -> do               let pt = elemType $ paramType p@@ -170,7 +172,7 @@             (to - from) .>. (to `rem` segment_size)           _ -> Nothing -  sKernelThread "scan_stage1" (segFlat space) (defKernelAttrs num_groups' group_size') $ do+  sKernelThread "scan_stage1" (segFlat space) (defKernelAttrs num_groups group_size) $ do     constants <- kernelConstants <$> askEnv     all_local_arrs <- makeLocalArrays group_size (tvSize num_threads) scans @@ -219,7 +221,8 @@         sWhen in_bounds when_in_bounds        unless (all (null . segBinOpShape) scans) $-        sOp $ Imp.Barrier Imp.FenceGlobal+        sOp $+          Imp.Barrier Imp.FenceGlobal        forM_ (zip3 per_scan_pes scans all_local_arrs) $         \(pes, scan@(SegBinOp _ scan_op nes vec_shape), local_arrs) ->@@ -287,7 +290,8 @@                             then sExt64 (kernelGroupSize constants) - 1                             else                               (sExt64 (kernelGroupId constants) + 1)-                                * sExt64 (kernelGroupSize constants) - 1+                                * sExt64 (kernelGroupSize constants)+                                - 1                         ]                   load_neutral =                     forM_ (zip nes scan_x_params) $ \(ne, p) ->@@ -300,7 +304,8 @@                     Just f ->                       f                         ( tvExp chunk_offset-                            + sExt64 (kernelGroupSize constants) - 1+                            + sExt64 (kernelGroupSize constants)+                            - 1                         )                         ( tvExp chunk_offset                             + sExt64 (kernelGroupSize constants)@@ -331,7 +336,6 @@    -- Our group size is the number of groups for the stage 1 kernel.   let group_size = Count $ unCount num_groups-      group_size' = fmap toInt64Exp group_size    let crossesSegment' = do         f <- crossesSegment@@ -340,7 +344,7 @@             ((sExt64 from + 1) * elems_per_group - 1)             ((sExt64 to + 1) * elems_per_group - 1) -  sKernelThread "scan_stage2" (segFlat space) (defKernelAttrs 1 group_size') $ do+  sKernelThread "scan_stage2" (segFlat space) (defKernelAttrs (Count (intConst Int64 1)) group_size) $ do     constants <- kernelConstants <$> askEnv     per_scan_local_arrs <- makeLocalArrays group_size (tvSize stage1_num_threads) scans     let per_scan_rets = map (lambdaReturnType . segBinOpLambda) scans@@ -403,15 +407,15 @@   [SegBinOp GPUMem] ->   CallKernelGen () scanStage3 (Pat all_pes) num_groups group_size elems_per_group crossesSegment space scans = do-  let num_groups' = fmap toInt64Exp num_groups-      group_size' = fmap toInt64Exp group_size+  let group_size' = fmap toInt64Exp group_size       (gtids, dims) = unzip $ unSegSpace space       dims' = map toInt64Exp dims   required_groups <-     dPrimVE "required_groups" $-      sExt32 $ product dims' `divUp` sExt64 (unCount group_size')+      sExt32 $+        product dims' `divUp` sExt64 (unCount group_size') -  sKernelThread "scan_stage3" (segFlat space) (defKernelAttrs num_groups' group_size') $+  sKernelThread "scan_stage3" (segFlat space) (defKernelAttrs num_groups group_size) $     virtualiseGroups SegVirt required_groups $ \virt_group_id -> do       constants <- kernelConstants <$> askEnv @@ -498,7 +502,9 @@     fmap (Imp.Count . tvSize) $       dPrimV "stage1_num_groups" $         sMin64 (tvExp stage1_max_num_groups) $-          toInt64Exp $ Imp.unCount $ segNumGroups lvl+          toInt64Exp $+            Imp.unCount $+              segNumGroups lvl    (stage1_num_threads, elems_per_group, crossesSegment) <-     scanStage1 pat stage1_num_groups (segGroupSize lvl) space scans kbody
src/Futhark/CodeGen/ImpGen/GPU/ToOpenCL.hs view
@@ -51,6 +51,7 @@         ) =           (`runState` initialOpenCL) . (`runReaderT` defFuns prog) $ do             let ImpGPU.Definitions+                  types                   (ImpGPU.Constants ps consts)                   (ImpGPU.Functions funs) = prog             consts' <- traverse (onHostOp target) consts@@ -59,6 +60,7 @@              pure $               ImpOpenCL.Definitions+                types                 (ImpOpenCL.Constants ps consts')                 (ImpOpenCL.Functions funs') @@ -248,7 +250,8 @@        (local_memory_args, local_memory_params, local_memory_init) =         unzip3 . flip evalState (blankNameSource :: VNameSource) $-          mapM (prepareLocalMemory target) $ kernelLocalMemory kstate+          mapM (prepareLocalMemory target) $+            kernelLocalMemory kstate        -- CUDA has very strict restrictions on the number of blocks       -- permitted along the 'y' and 'z' dimensions of the grid@@ -756,7 +759,7 @@       error "Cannot deallocate memory in kernel"      copyInKernel :: GC.Copy KernelOp KernelState-    copyInKernel _ _ _ _ _ _ _ =+    copyInKernel _ _ _ _ _ _ _ _ =       error "Cannot bulk copy in kernel."      noStaticArrays :: GC.StaticArray KernelOp KernelState@@ -790,9 +793,10 @@       | otherwise = do           let out_args = [[C.cexp|&$id:d|] | d <- dests]               args' =-                [C.cexp|global_failure|] :-                [C.cexp|global_failure_args|] :-                out_args ++ args+                [C.cexp|global_failure|]+                  : [C.cexp|global_failure_args|]+                  : out_args+                  ++ args            what_next <- whatNext 
src/Futhark/CodeGen/ImpGen/GPU/Transpose.hs view
@@ -67,22 +67,26 @@       mkTranspose $         lowDimBody           (le32 get_group_id_0 * block_dim + (le32 get_local_id_0 `quot` muly))-          ( le32 get_group_id_1 * block_dim * muly + le32 get_local_id_1+          ( le32 get_group_id_1 * block_dim * muly+              + le32 get_local_id_1               + (le32 get_local_id_0 `rem` muly) * block_dim           )-          ( le32 get_group_id_1 * block_dim * muly + le32 get_local_id_0+          ( le32 get_group_id_1 * block_dim * muly+              + le32 get_local_id_0               + (le32 get_local_id_1 `rem` muly) * block_dim           )           (le32 get_group_id_0 * block_dim + (le32 get_local_id_1 `quot` muly))     TransposeLowHeight ->       mkTranspose $         lowDimBody-          ( le32 get_group_id_0 * block_dim * mulx + le32 get_local_id_0+          ( le32 get_group_id_0 * block_dim * mulx+              + le32 get_local_id_0               + (le32 get_local_id_1 `rem` mulx) * block_dim           )           (le32 get_group_id_1 * block_dim + (le32 get_local_id_1 `quot` mulx))           (le32 get_group_id_1 * block_dim + (le32 get_local_id_0 `quot` mulx))-          ( le32 get_group_id_0 * block_dim * mulx + le32 get_local_id_1+          ( le32 get_group_id_0 * block_dim * mulx+              + le32 get_local_id_1               + (le32 get_local_id_0 `rem` mulx) * block_dim           )     TransposeNormal ->
src/Futhark/CodeGen/ImpGen/Multicore.hs view
@@ -5,7 +5,6 @@ module Futhark.CodeGen.ImpGen.Multicore   ( Futhark.CodeGen.ImpGen.Multicore.compileProg,     Warnings,-    SchedulingMode (..),   ) where @@ -41,22 +40,19 @@         (Or Int64, Imp.AtomicOr Int64)       ] -data SchedulingMode = AllowDynamicScheduling | NoDynamicScheduling- -- | Compile the program. compileProg ::   MonadFreshNames m =>-  SchedulingMode ->   Prog MCMem ->   m (Warnings, Imp.Definitions Imp.Multicore)-compileProg sched = Futhark.CodeGen.ImpGen.compileProg (HostEnv gccAtomics mempty) ops Imp.DefaultSpace+compileProg = Futhark.CodeGen.ImpGen.compileProg (HostEnv gccAtomics mempty) ops Imp.DefaultSpace   where     ops =       (defaultOperations opCompiler)         { opsExpCompiler = compileMCExp         }     opCompiler dest (Alloc e space) = compileAlloc dest e space-    opCompiler dest (Inner op) = compileMCOp sched dest op+    opCompiler dest (Inner op) = compileMCOp dest op  updateAcc :: VName -> [SubExp] -> [SubExp] -> MulticoreGen () updateAcc acc is vs = sComment "UpdateAcc" $ do@@ -121,12 +117,11 @@   defCompileExp dest e  compileMCOp ::-  SchedulingMode ->   Pat LetDecMem ->   MCOp MCMem () ->   ImpM MCMem HostEnv Imp.Multicore ()-compileMCOp _ _ (OtherOp ()) = pure ()-compileMCOp sched pat (ParOp par_op op) = do+compileMCOp _ (OtherOp ()) = pure ()+compileMCOp pat (ParOp par_op op) = do   let space = getSpace op   dPrimV_ (segFlat space) (0 :: Imp.TExp Int64)   iterations <- getIterationDomain op space@@ -154,9 +149,7 @@   free_params <- filter (`notElem` retvals) <$> freeParams (par_task, seq_task)   emit . Imp.Op $     Imp.SegOp s free_params seq_task par_task retvals $-      case sched of-        AllowDynamicScheduling -> scheduling_info (decideScheduling' op seq_code)-        NoDynamicScheduling -> scheduling_info Imp.Static+      scheduling_info (decideScheduling' op seq_code)  compileSegOp ::   Pat LetDecMem ->
src/Futhark/CodeGen/ImpGen/Multicore/Base.hs view
@@ -20,7 +20,13 @@     getIterationDomain,     getReturnParams,     segOpString,+    ChunkLoopVectorization (..),     generateChunkLoop,+    generateUniformizeLoop,+    extractVectorLane,+    inISPC,+    toParam,+    sLoopNestVectorized,   ) where @@ -164,6 +170,9 @@ isLoadBalanced (Imp.Comment _ a) = isLoadBalanced a isLoadBalanced Imp.While {} = False isLoadBalanced (Imp.Op (Imp.ParLoop _ code _)) = isLoadBalanced code+isLoadBalanced (Imp.Op (Imp.ForEachActive _ a)) = isLoadBalanced a+isLoadBalanced (Imp.Op (Imp.ForEach _ _ _ a)) = isLoadBalanced a+isLoadBalanced (Imp.Op (Imp.ISPCKernel a _)) = isLoadBalanced a isLoadBalanced _ = True  segBinOpComm' :: [SegBinOp rep] -> Commutativity@@ -215,9 +224,7 @@           (free_allocs, here_allocs) = f body_allocs           free' =             filter-              ( not-                  . (`nameIn` Imp.declaredIn body_allocs)-                  . Imp.paramName+              ( (`notNameIn` Imp.declaredIn body_allocs) . Imp.paramName               )               free        in ( free_allocs,@@ -226,6 +233,11 @@     f code =       (mempty, code) +-- | Indicates whether to vectorize a chunk loop or keep it sequential.+-- We use this to allow falling back to sequential chunk loops in cases+-- we don't care about trying to vectorize.+data ChunkLoopVectorization = Vectorized | Scalar+ -- | Emit code for the chunk loop, given an action that generates code -- for a single iteration. --@@ -233,10 +245,10 @@ -- iteration. generateChunkLoop ::   String ->+  ChunkLoopVectorization ->   (Imp.TExp Int64 -> MulticoreGen ()) ->   MulticoreGen ()-generateChunkLoop desc m = do-  emit $ Imp.DebugPrint (desc <> " " <> "fbody") Nothing+generateChunkLoop desc Scalar m = do   (start, end) <- getLoopBounds   n <- dPrimVE "n" $ end - start   i <- newVName (desc <> "_i")@@ -245,9 +257,100 @@       addLoopVar i Int64       m $ start + Imp.le64 i   emit body_allocs-  emit $ Imp.For i (untyped n) body+  -- Emit either foreach or normal for loop+  let bound = untyped n+  emit $ Imp.For i bound body+generateChunkLoop desc Vectorized m = do+  (start, end) <- getLoopBounds+  n <- dPrimVE "n" $ end - start+  i <- newVName (desc <> "_i")+  (body_allocs, body) <- fmap extractAllocations $+    collect $ do+      addLoopVar i Int64+      m $ Imp.le64 i+  emit body_allocs+  -- Emit either foreach or normal for loop+  let from = untyped start+  let bound = untyped (start + n)+  emit $ Imp.Op $ Imp.ForEach i from bound body +-- | Emit code for a sequential loop over each vector lane, given+-- and action that generates code for a single iteration. The action+-- is called with the symbolic index of the current iteration.+generateUniformizeLoop :: (Imp.TExp Int64 -> MulticoreGen ()) -> MulticoreGen ()+generateUniformizeLoop m = do+  i <- newVName "uni_i"+  body <- collect $ do+    addLoopVar i Int64+    m $ Imp.le64 i+  emit $ Imp.Op $ Imp.ForEachActive i body++-- | Given a piece of code, if that code performs an assignment, turn+-- that assignment into an extraction of element from a vector on the+-- right hand side, using a passed index for the extraction. Other code+-- is left as is.+extractVectorLane :: Imp.TExp Int64 -> MulticoreGen Imp.MCCode -> MulticoreGen ()+extractVectorLane j code = do+  let ut_exp = untyped j+  code' <- code+  case code' of+    Imp.SetScalar vname e -> do+      typ <- lookupType vname+      case typ of+        -- ISPC v1.17 does not support extract on f16 yet..+        -- Thus we do this stupid conversion to f32+        Prim (FloatType Float16) -> do+          tv <- dPrim "hack_extract_f16" (FloatType Float32)+          emit $ Imp.SetScalar (tvVar tv) e+          emit $ Imp.Op $ Imp.ExtractLane vname (untyped $ tvExp tv) ut_exp+        _ -> emit $ Imp.Op $ Imp.ExtractLane vname e ut_exp+    _ ->+      emit code'++-- | Given an action that may generate some code, put that code+-- into an ISPC kernel.+inISPC :: MulticoreGen () -> MulticoreGen ()+inISPC code = do+  code' <- collect code+  free <- freeParams code'+  emit $ Imp.Op $ Imp.ISPCKernel code' free+ -------------------------------+------- SegRed helpers  -------+-------------------------------+sForVectorized' :: VName -> Imp.Exp -> MulticoreGen () -> MulticoreGen ()+sForVectorized' i bound body = do+  let it = case primExpType bound of+        IntType bound_t -> bound_t+        t -> error $ "sFor': bound " ++ pretty bound ++ " is of type " ++ pretty t+  addLoopVar i it+  body' <- collect body+  emit $ Imp.Op $ Imp.ForEach i (Imp.ValueExp $ blankPrimValue $ Imp.IntType Imp.Int64) bound body'++sForVectorized :: String -> Imp.TExp t -> (Imp.TExp t -> MulticoreGen ()) -> MulticoreGen ()+sForVectorized i bound body = do+  i' <- newVName i+  sForVectorized' i' (untyped bound) $+    body $+      TPrimExp $+        Imp.var i' $+          primExpType $+            untyped bound++-- | Like sLoopNest, but puts a vectorized loop at the innermost layer.+sLoopNestVectorized ::+  Shape ->+  ([Imp.TExp Int64] -> MulticoreGen ()) ->+  MulticoreGen ()+sLoopNestVectorized = sLoopNest' [] . shapeDims+  where+    sLoopNest' is [] f = f $ reverse is+    sLoopNest' is [d] f =+      sForVectorized "nest_i" (toInt64Exp d) $ \i -> sLoopNest' (i : is) [] f+    sLoopNest' is (d : ds) f =+      sFor "nest_i" (toInt64Exp d) $ \i -> sLoopNest' (i : is) ds f++------------------------------- ------- SegHist helpers ------- ------------------------------- renameHistOpLambda :: [HistOp MCMem] -> MulticoreGen [HistOp MCMem]@@ -327,7 +430,8 @@     supportedPrims (primBitSize t) = AtomicCAS $ \[arr] bucket -> do       old <- dPrim "old" t       atomicUpdateCAS t arr (tvVar old) bucket (paramName xp) $-        compileBody' [xp] $ lambdaBody op+        compileBody' [xp] $+          lambdaBody op atomicUpdateLocking _ op = AtomicLocking $ \locking arrs bucket -> do   old <- dPrim "old" int32   continue <- dPrimVol "continue" int32 (0 :: Imp.TExp Int32)@@ -373,12 +477,14 @@    let op_body =         sComment "execute operation" $-          compileBody' acc_params $ lambdaBody op+          compileBody' acc_params $+            lambdaBody op        do_hist =         everythingVolatile $           sComment "update global result" $-            zipWithM_ (writeArray bucket) arrs $ map (Var . paramName) acc_params+            zipWithM_ (writeArray bucket) arrs $+              map (Var . paramName) acc_params    -- While-loop: Try to insert your value   sWhile (tvExp continue .==. 0) $ do
src/Futhark/CodeGen/ImpGen/Multicore/SegHist.hs view
@@ -11,6 +11,7 @@ import Futhark.CodeGen.ImpGen.Multicore.SegRed (compileSegRed') import Futhark.IR.MCMem import Futhark.MonadFreshNames+import Futhark.Transform.Rename (renameLambda) import Futhark.Util (chunks, splitFromEnd, takeLast) import Futhark.Util.IntegralExp (rem) import Prelude hiding (quot, rem)@@ -36,6 +37,16 @@ histSize :: HistOp MCMem -> Imp.TExp Int64 histSize = product . map toInt64Exp . shapeDims . histShape +genHistOpParams :: HistOp MCMem -> MulticoreGen ()+genHistOpParams histops =+  dScope Nothing $ scopeOfLParams $ lambdaParams $ histOp histops++renameHistop :: HistOp MCMem -> MulticoreGen (HistOp MCMem)+renameHistop histop = do+  let op = histOp histop+  lambda' <- renameLambda op+  pure histop {histOp = lambda'}+ nonsegmentedHist ::   Pat LetDecMem ->   SegSpace ->@@ -107,7 +118,7 @@   body <- collect $ do     dPrim_ (segFlat space) int64     sOp $ Imp.GetTaskId (segFlat space)-    generateChunkLoop "SegHist" $ \flat_idx -> do+    generateChunkLoop "SegHist" Scalar $ \flat_idx -> do       zipWithM_ dPrimV_ is $ unflattenIndex ns_64 flat_idx       compileStms mempty (kernelBodyStms kbody) $ do         let (red_res, map_res) =@@ -138,18 +149,23 @@   free_params <- freeParams body   emit $ Imp.Op $ Imp.ParLoop "atomic_seg_hist" body free_params -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+updateHisto ::+  HistOp MCMem ->+  [VName] ->+  [Imp.TExp Int64] ->+  Imp.TExp Int64 ->+  [Param LParamMem] ->+  MulticoreGen ()+updateHisto op arrs bucket j uni_acc = do+  let bind_acc_params =+        forM_ (zip uni_acc arrs) $ \(acc_u, arr) -> do+          copyDWIMFix (paramName acc_u) [] (Var arr) bucket+       op_body = compileBody' [] $ lambdaBody $ histOp op-      writeArray arr val = copyDWIMFix arr bucket val []+      writeArray arr val = extractVectorLane j $ collect $ copyDWIMFix arr bucket val []       do_hist = zipWithM_ writeArray arrs $ map resSubExp $ bodyResult $ lambdaBody $ histOp op    sComment "Start of body" $ do-    dLParams acc_params     bind_acc_params     op_body     do_hist@@ -211,36 +227,55 @@        pure op_local_subhistograms -    generateChunkLoop "SegRed" $ \i -> do-      zipWithM_ dPrimV_ is $ unflattenIndex ns_64 i-      compileStms mempty (kernelBodyStms kbody) $ do-        let (red_res, map_res) =-              splitFromEnd (length map_pes) $-                map kernelResultSubExp $ kernelBodyResult kbody+    inISPC $+      generateChunkLoop "SegRed" Vectorized $ \i -> do+        zipWithM_ dPrimV_ is $ unflattenIndex ns_64 i+        compileStms mempty (kernelBodyStms kbody) $ do+          let (red_res, map_res) =+                splitFromEnd (length map_pes) $+                  map kernelResultSubExp $+                    kernelBodyResult kbody -        sComment "save map-out results" $-          forM_ (zip map_pes map_res) $ \(pe, res) ->-            copyDWIMFix (patElemName pe) (map Imp.le64 is) res []+          sComment "save map-out results" $+            forM_ (zip map_pes map_res) $ \(pe, res) ->+              copyDWIMFix (patElemName pe) (map Imp.le64 is) res [] -        forM_ (zip3 histops local_subhistograms (splitHistResults histops red_res)) $-          \( histop@(HistOp dest_shape _ _ _ shape lam),-             histop_subhistograms,-             (bucket, vs')-             ) -> do-              let bucket' = map toInt64Exp bucket-                  dest_shape' = map toInt64Exp $ shapeDims dest_shape-                  bucket_in_bounds =-                    inBounds (Slice (map DimFix bucket')) dest_shape'-                  vs_params = takeLast (length vs') $ lambdaParams lam+          forM_ (zip3 histops local_subhistograms (splitHistResults histops red_res)) $+            \( histop@(HistOp dest_shape _ _ _ shape _),+               histop_subhistograms,+               (bucket, vs')+               ) -> do+                histop' <- renameHistop histop -              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) [] res is'-                    updateHisto histop histop_subhistograms (bucket' ++ is')+                let bucket' = map toInt64Exp bucket+                    dest_shape' = map toInt64Exp $ shapeDims dest_shape+                    acc_params' = (lambdaParams . histOp) histop'+                    vs_params' = takeLast (length vs') $ lambdaParams $ histOp histop' +                generateUniformizeLoop $ \j ->+                  sComment "perform updates" $ do+                    -- Create new set of uniform buckets+                    -- That is extract each bucket from a SIMD vector lane+                    extract_buckets <- mapM (dPrim "extract_bucket" . (primExpType . untyped)) bucket'+                    forM_ (zip extract_buckets bucket') $ \(x, y) ->+                      emit $ Imp.Op $ Imp.ExtractLane (tvVar x) (untyped y) (untyped j)+                    let bucket'' = map tvExp extract_buckets+                        bucket_in_bounds =+                          inBounds (Slice (map DimFix bucket'')) dest_shape'+                    sWhen bucket_in_bounds $ do+                      genHistOpParams histop'+                      sLoopNest shape $ \is' -> do+                        -- read values vs and perform lambda writing result back to is+                        forM_ (zip vs_params' vs') $ \(p, res) ->+                          ifPrimType (paramType p) $ \pt -> do+                            -- Hack to copy varying load into uniform result variable+                            tmp <- dPrim "tmp" pt+                            copyDWIMFix (tvVar tmp) [] res is'+                            extractVectorLane j $+                              pure $+                                Imp.SetScalar (paramName p) (Imp.LeafExp (tvVar tmp) pt)+                        updateHisto histop' histop_subhistograms (bucket'' ++ is') j acc_params'+     -- Copy the task-local subhistograms to the global subhistograms,     -- where they will be combined.     forM_ (zip (concat global_subhistograms) (concat local_subhistograms)) $@@ -268,11 +303,12 @@       sOp $ Imp.GetNumTasks $ tvVar nsubtasks       emit <=< compileSegRed' (Pat red_pes) segred_space [segred_op] nsubtasks $ \red_cont ->         red_cont $-          flip map hists $ \subhisto ->-            ( Var subhisto,-              map Imp.le64 $-                map fst segment_dims ++ [subhistogram_id] ++ bucket_ids-            )+          segBinOpChunks [segred_op] $+            flip map hists $ \subhisto ->+              ( Var subhisto,+                map Imp.le64 $+                  map fst segment_dims ++ [subhistogram_id] ++ bucket_ids+              )      let ns_red = map (toInt64Exp . snd) $ unSegSpace segred_space         iterations = product $ init ns_red -- The segmented reduction is sequential over the inner most dimension@@ -282,7 +318,10 @@     emit $ Imp.Op $ Imp.SegOp "seghist_red" free_params_red red_task Nothing mempty scheduler_info   where     segment_dims = init $ unSegSpace space+    ifPrimType (Prim pt) f = f pt+    ifPrimType _ _ = pure () +-- Note: This isn't currently used anywhere. -- This implementation for a Segmented Hist only -- parallelize over the segments, -- where each segment is updated sequentially.@@ -316,7 +355,7 @@   dPrim_ (segFlat space) int64   sOp $ Imp.GetTaskId (segFlat space) -  generateChunkLoop "SegHist" $ \idx -> do+  generateChunkLoop "SegHist" Scalar $ \idx -> do     let inner_bound = last ns_64     sFor "i" inner_bound $ \i -> do       zipWithM_ dPrimV_ (init is) $ unflattenIndex (init ns_64) idx@@ -325,7 +364,8 @@       compileStms mempty (kernelBodyStms kbody) $ do         let (red_res, map_res) =               splitFromEnd (length map_pes) $-                map kernelResultSubExp $ kernelBodyResult kbody+                map kernelResultSubExp $+                  kernelBodyResult kbody         forM_ (zip3 per_red_pes histops (splitHistResults histops red_res)) $           \(red_pes, HistOp dest_shape _ _ _ shape lam, (bucket, vs')) -> do             let (is_params, vs_params) = splitAt (length vs') $ lambdaParams lam
src/Futhark/CodeGen/ImpGen/Multicore/SegMap.hs view
@@ -39,10 +39,11 @@   dPrim_ (segFlat space) int64   sOp $ Imp.GetTaskId (segFlat space)   kstms' <- mapM renameStm kstms-  generateChunkLoop "SegMap" $ \i -> do-    dIndexSpace (zip is ns') i-    compileStms (freeIn kres) kstms' $-      zipWithM_ (writeResult is) (patElems pat) kres+  inISPC $+    generateChunkLoop "SegMap" Vectorized $ \i -> do+      dIndexSpace (zip is ns') i+      compileStms (freeIn kres) kstms' $+        zipWithM_ (writeResult is) (patElems pat) kres  compileSegMap ::   Pat LetDecMem ->
src/Futhark/CodeGen/ImpGen/Multicore/SegRed.hs view
@@ -10,10 +10,10 @@ import Futhark.CodeGen.ImpGen import Futhark.CodeGen.ImpGen.Multicore.Base import Futhark.IR.MCMem-import Futhark.Util (chunks)+import Futhark.Transform.Rename (renameLambda) import Prelude hiding (quot, rem) -type DoSegBody = (([(SubExp, [Imp.TExp Int64])] -> MulticoreGen ()) -> MulticoreGen ())+type DoSegBody = (([[(SubExp, [Imp.TExp Int64])]] -> MulticoreGen ()) -> MulticoreGen ())  -- | Generate code for a SegRed construct compileSegRed ::@@ -32,7 +32,7 @@         let map_arrs = drop (segBinOpResults reds) $ patElems pat         zipWithM_ (compileThreadResult space) map_arrs map_res -      red_cont $ zip (map kernelResultSubExp red_res) $ repeat []+      red_cont $ segBinOpChunks reds $ zip (map kernelResultSubExp red_res) $ repeat []  -- | Like 'compileSegRed', but where the body is a monadic action. compileSegRed' ::@@ -72,6 +72,14 @@ accParams slug = take (length (slugNeutral slug)) $ slugParams slug nextParams slug = drop (length (slugNeutral slug)) $ slugParams slug +renameSlug :: SegBinOpSlug -> MulticoreGen SegBinOpSlug+renameSlug slug = do+  let op = slugOp slug+  let lambda = segBinOpLambda op+  lambda' <- renameLambda lambda+  let op' = op {segBinOpLambda = lambda'}+  pure slug {slugOp = op'}+ nonsegmentedReduction ::   Pat LetDecMem ->   SegSpace ->@@ -84,82 +92,242 @@   let slugs1 = zipWith SegBinOpSlug reds thread_res_arrs       nsubtasks' = tvExp nsubtasks -  reductionStage1 space slugs1 kbody+  -- Are all the operators commutative?+  let comm = all ((== Commutative) . segBinOpComm) reds+  let dims = map (shapeDims . slugShape) slugs1+  let isScalar x = case x of MemPrim _ -> True; _ -> False+  -- Are we only working on scalar arrays?+  let scalars = all (all (isScalar . paramDec) . slugParams) slugs1 && all (== []) dims+  -- Are we working with vectorized inner maps?+  let inner_map = [] `notElem` dims++  let path+        | comm && scalars = reductionStage1CommScalar+        | inner_map = reductionStage1Array+        | scalars = reductionStage1NonCommScalar+        | otherwise = reductionStage1Fallback+  path space slugs1 kbody+   reds2 <- renameSegBinOp reds   let slugs2 = zipWith SegBinOpSlug reds2 thread_res_arrs   reductionStage2 pat space nsubtasks' slugs2 -reductionStage1 ::-  SegSpace ->+-- Generate code that declares the params for the binop+genBinOpParams :: [SegBinOpSlug] -> MulticoreGen ()+genBinOpParams slugs =+  dScope Nothing $ scopeOfLParams $ concatMap slugParams slugs++-- Generate code that declares accumulators, return a list of these+genAccumulators :: [SegBinOpSlug] -> MulticoreGen [[VName]]+genAccumulators 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++-- Datatype to represent all the different ways we can generate+-- code for a reduction.+data RedLoopType+  = RedSeq -- Fully sequential+  | RedComm -- Commutative scalar+  | RedNonComm -- Noncommutative scalar+  | RedNested -- Nested vectorized operator+  | RedUniformize -- Uniformize over scalar acc++-- Given a type of reduction and the loop index, should we wrap+-- the loop body in some extra code?+getRedLoop ::+  RedLoopType ->+  Imp.TExp Int64 ->+  (Imp.TExp Int64 -> MulticoreGen ()) ->+  MulticoreGen ()+getRedLoop RedNonComm _ = generateUniformizeLoop+getRedLoop RedUniformize uni = \body -> body uni+getRedLoop _ _ = \body -> body 0++-- Given a type of reduction, should we perform extracts on+-- the accumulator?+getExtract ::+  RedLoopType ->+  Imp.TExp Int64 ->+  MulticoreGen Imp.MCCode ->+  MulticoreGen ()+getExtract RedNonComm = extractVectorLane+getExtract RedUniformize = extractVectorLane+getExtract _ = \_ body -> body >>= emit++-- Given a type of reduction, should we vectorize the inner+-- map, if it exists?+getNestLoop ::+  RedLoopType ->+  Shape ->+  ([Imp.TExp Int64] -> MulticoreGen ()) ->+  MulticoreGen ()+getNestLoop RedNested = sLoopNestVectorized+getNestLoop _ = sLoopNest++-- Given a list of accumulators, use them as the source+-- data for reduction.+redSourceAccs :: [[VName]] -> DoSegBody+redSourceAccs slug_local_accs m =+  m $ map (map (\x -> (Var x, []))) slug_local_accs++-- Generate a reduction loop for uniformizing vectors+genPostbodyReductionLoop ::+  [[VName]] ->   [SegBinOpSlug] ->+  [[VName]] ->+  SegSpace ->+  Imp.TExp Int64 ->+  MulticoreGen ()+genPostbodyReductionLoop accs =+  genReductionLoop RedUniformize (redSourceAccs accs)++-- Generate a potentially vectorized body of code that performs reduction+-- when put inside a chunked loop.+genReductionLoop ::+  RedLoopType ->   DoSegBody ->+  [SegBinOpSlug] ->+  [[VName]] ->+  SegSpace ->+  Imp.TExp Int64 ->   MulticoreGen ()-reductionStage1 space slugs kbody = do+genReductionLoop typ kbodymap slugs slug_local_accs space i = do   let (is, ns) = unzip $ unSegSpace space       ns' = map toInt64Exp ns-  -- 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.--  fbody <- collect $ do-    dPrim_ (segFlat space) int64-    sOp $ Imp.GetTaskId (segFlat space)--    slug_local_accs <- do-      dScope Nothing $ scopeOfLParams $ concatMap slugParams slugs--      forM slugs $ \slug -> do-        let shape = segBinOpShape $ slugOp slug+  zipWithM_ dPrimV_ is $ unflattenIndex ns' i+  kbodymap $ \all_red_res' -> do+    forM_ (zip3 all_red_res' slugs slug_local_accs) $ \(red_res, slug, local_accs) ->+      getNestLoop typ (slugShape slug) $ \vec_is -> do+        let lamtypes = lambdaReturnType $ segBinOpLambda $ slugOp slug+        -- Load accum params+        getRedLoop typ i $ \uni -> do+          sComment "Load accum params" $+            forM_ (zip3 (accParams slug) local_accs lamtypes) $+              \(p, local_acc, t) ->+                when (primType t) $ do+                  copyDWIMFix (paramName p) [] (Var local_acc) vec_is -        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+          sComment "Load next params" $+            forM_ (zip (nextParams slug) red_res) $ \(p, (res, res_is)) -> do+              getExtract typ uni $+                collect $+                  copyDWIMFix (paramName p) [] res (res_is ++ vec_is) -          -- Now neutral-initialise the accumulator.-          sLoopNest (slugShape slug) $ \vec_is ->-            copyDWIMFix acc vec_is ne []+          sComment "SegRed body" $+            compileStms mempty (bodyStms $ slugBody slug) $+              forM_ (zip local_accs $ map resSubExp $ bodyResult $ slugBody slug) $+                \(local_acc, se) ->+                  copyDWIMFix local_acc vec_is se [] -          pure acc+-- Generate code to write back results from the accumulators+genWriteBack :: [SegBinOpSlug] -> [[VName]] -> SegSpace -> MulticoreGen ()+genWriteBack slugs slug_local_accs space =+  forM_ (zip slugs slug_local_accs) $ \(slug, local_accs) ->+    forM (zip (slugResArrs slug) local_accs) $ \(acc, local_acc) ->+      copyDWIMFix acc [Imp.le64 $ segFlat space] (Var local_acc) [] -    generateChunkLoop "SegRed" $ \i -> do-      zipWithM_ dPrimV_ is $ unflattenIndex ns' i-      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+type ReductionStage1 = SegSpace -> [SegBinOpSlug] -> DoSegBody -> MulticoreGen () -            sComment "Load next params" $-              forM_ (zip (nextParams slug) red_res) $ \(p, (res, res_is)) ->-                copyDWIMFix (paramName p) [] res (res_is ++ vec_is)+-- Pure sequential codegen with no fancy vectorization+reductionStage1Fallback :: ReductionStage1+reductionStage1Fallback space slugs kbody = do+  fbody <- collect $ do+    dPrim_ (segFlat space) int64+    sOp $ Imp.GetTaskId (segFlat space)+    -- Declare params+    genBinOpParams slugs+    slug_local_accs <- genAccumulators slugs+    -- Generate main reduction loop+    generateChunkLoop "SegRed" Scalar $+      genReductionLoop RedSeq kbody slugs slug_local_accs space+    -- Write back results+    genWriteBack slugs slug_local_accs space+  free_params <- freeParams fbody+  emit $ Imp.Op $ Imp.ParLoop "segred_stage_1" fbody free_params -            sComment "SegRed body" $-              compileStms mempty (bodyStms $ slugBody slug) $-                forM_ (zip local_accs $ map resSubExp $ bodyResult $ slugBody slug) $-                  \(local_acc, se) ->-                    copyDWIMFix local_acc vec_is se []+-- Codegen for noncommutative scalar reduction. We vectorize the+-- kernel body, and do the reduction sequentially.+reductionStage1NonCommScalar :: ReductionStage1+reductionStage1NonCommScalar space slugs kbody = do+  fbody <- collect $ do+    dPrim_ (segFlat space) int64+    sOp $ Imp.GetTaskId (segFlat space)+    inISPC $ do+      -- Declare params+      genBinOpParams slugs+      slug_local_accs <- genAccumulators slugs+      -- Generate main reduction loop+      generateChunkLoop "SegRed" Vectorized $+        genReductionLoop RedNonComm kbody slugs slug_local_accs space+      -- Write back results+      genWriteBack slugs slug_local_accs space+  free_params <- freeParams fbody+  emit $ Imp.Op $ Imp.ParLoop "segred_stage_1" fbody free_params -    forM_ (zip slugs slug_local_accs) $ \(slug, local_accs) ->-      forM (zip (slugResArrs slug) local_accs) $ \(acc, local_acc) ->-        copyDWIMFix acc [Imp.le64 $ segFlat space] (Var local_acc) []+-- Codegen for a commutative reduction on scalar arrays+-- In this case, we can generate an efficient interleaved reduction+reductionStage1CommScalar :: ReductionStage1+reductionStage1CommScalar space slugs kbody = do+  fbody <- collect $ do+    dPrim_ (segFlat space) int64+    sOp $ Imp.GetTaskId (segFlat space)+    -- Rename lambda params in slugs to get a new set of them+    slugs' <- mapM renameSlug slugs+    inISPC $ do+      -- Declare one set of params uniform+      genBinOpParams slugs'+      slug_local_accs_uni <- genAccumulators slugs'+      -- Declare the other varying+      genBinOpParams slugs+      slug_local_accs <- genAccumulators slugs+      -- Generate the main reduction loop over vectors+      generateChunkLoop "SegRed" Vectorized $+        genReductionLoop RedComm kbody slugs slug_local_accs space+      -- Now reduce over those vector accumulators to get scalar results+      generateUniformizeLoop $+        genPostbodyReductionLoop slug_local_accs slugs' slug_local_accs_uni space+      -- And write back the results+      genWriteBack slugs slug_local_accs_uni space+  free_params <- freeParams fbody+  emit $ Imp.Op $ Imp.ParLoop "segred_stage_1" fbody free_params +-- Codegen for a reduction on arrays, where the body is a perfect nested map.+-- We vectorize just the inner map.+reductionStage1Array :: ReductionStage1+reductionStage1Array space slugs kbody = do+  fbody <- collect $ do+    dPrim_ (segFlat space) int64+    sOp $ Imp.GetTaskId (segFlat space)+    -- Declare params+    lparams <- collect $ genBinOpParams slugs+    (slug_local_accs, uniform_prebody) <- collect' $ genAccumulators slugs+    -- Put the accumulators outside of the kernel, so they are forced uniform+    emit uniform_prebody+    inISPC $ do+      -- Put the lambda params inside the kernel so they are varying+      emit lparams+      -- Generate the main reduction loop+      generateChunkLoop "SegRed" Scalar $+        genReductionLoop RedNested kbody slugs slug_local_accs space+      -- Write back results+      genWriteBack slugs slug_local_accs space   free_params <- freeParams fbody   emit $ Imp.Op $ Imp.ParLoop "segred_stage_1" fbody free_params @@ -212,6 +380,7 @@     free_params <- freeParams body     emit $ Imp.Op $ Imp.ParLoop "segmented_segred" body free_params +-- Currently, this is only used as part of SegHist calculations, never alone. compileSegRedBody ::   Pat LetDecMem ->   SegSpace ->@@ -227,40 +396,40 @@    let per_red_pes = segBinOpChunks reds $ patElems pat   -- Perform sequential reduce on inner most dimension-  collect . generateChunkLoop "SegRed" $ \n_segments -> 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.le64 (init is) ++ vec_is) ne []+  collect . inISPC $+    generateChunkLoop "SegRed" Vectorized $ \n_segments -> 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.le64 (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.le64 (init is) ++ vec_is)+      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 $ \red_res' -> do+            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.le64 (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 "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 $ map resSubExp $ bodyResult lbody) $-                      \(pe, se') -> copyDWIMFix (patElemName pe) (map Imp.le64 (init is) ++ vec_is) se' []+                sComment "apply reduction" $ do+                  let lbody = (lambdaBody . segBinOpLambda) red+                  compileStms mempty (bodyStms lbody) $+                    sComment "write back to res" $+                      forM_ (zip pes $ map resSubExp $ bodyResult lbody) $+                        \(pe, se') -> copyDWIMFix (patElemName pe) (map Imp.le64 (init is) ++ vec_is) se' []
src/Futhark/CodeGen/ImpGen/Multicore/SegScan.hs view
@@ -54,79 +54,183 @@ nonsegmentedScan pat space scan_ops kbody nsubtasks = do   emit $ Imp.DebugPrint "nonsegmented segScan" Nothing   collect $ do-    scanStage1 pat space scan_ops kbody+    -- Are we working with nested arrays+    let dims = map (shapeDims . segBinOpShape) scan_ops+    -- Are we only working on scalars+    let scalars = all (all (primType . typeOf . paramDec) . (lambdaParams . segBinOpLambda)) scan_ops && all null dims+    -- Do we have nested vector operations+    let vectorize = [] `notElem` dims +    let param_types = concatMap (map paramType . (lambdaParams . segBinOpLambda)) scan_ops+    let no_array_param = all primType param_types++    let (scanStage1, scanStage3)+          | scalars = (scanStage1Scalar, scanStage3Scalar)+          | vectorize && no_array_param = (scanStage1Nested, scanStage3Nested)+          | otherwise = (scanStage1Fallback, scanStage3Fallback)++    scanStage1 pat space kbody scan_ops+     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+      scanStage3 pat space kbody scan_ops3 -scanStage1 ::+-- Different ways to generate code for a scan loop+data ScanLoopType+  = ScanSeq -- Fully sequential+  | ScanNested -- Nested vectorized map+  | ScanScalar -- Vectorized scan over scalars++-- Given a scan type, return a function to inject into the loop body+getScanLoop ::+  ScanLoopType ->+  (Imp.TExp Int64 -> MulticoreGen ()) ->+  MulticoreGen ()+getScanLoop ScanScalar = generateUniformizeLoop+getScanLoop _ = \body -> body 0++-- Given a scan type, return a function to extract a scalar from a vector+getExtract :: ScanLoopType -> Imp.TExp Int64 -> MulticoreGen Imp.MCCode -> MulticoreGen ()+getExtract ScanSeq = \_ body -> body >>= emit+getExtract _ = extractVectorLane++genBinOpParams :: [SegBinOp MCMem] -> MulticoreGen ()+genBinOpParams scan_ops = dScope Nothing $ scopeOfLParams $ concatMap (lambdaParams . segBinOpLambda) scan_ops++genLocalAccsStage1 :: [SegBinOp MCMem] -> MulticoreGen [[VName]]+genLocalAccsStage1 scan_ops = do+  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 <- -- update accumulator to have type decoration+        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++getNestLoop ::+  ScanLoopType ->+  Shape ->+  ([Imp.TExp Int64] -> MulticoreGen ()) ->+  MulticoreGen ()+getNestLoop ScanNested = sLoopNestVectorized+getNestLoop _ = sLoopNest++-- Generate a loop which performs a potentially vectorized scan.+genScanLoop ::+  ScanLoopType ->   Pat LetDecMem ->   SegSpace ->-  [SegBinOp MCMem] ->   KernelBody MCMem ->-  MulticoreGen ()-scanStage1 pat space scan_ops kbody = do+  [SegBinOp MCMem] ->+  [[VName]] ->+  Imp.TExp Int64 ->+  ImpM MCMem HostEnv Imp.Multicore ()+genScanLoop typ pat space kbody scan_ops local_accs i = 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 $ patElems pat   let (is, ns) = unzip $ unSegSpace space       ns' = map toInt64Exp ns -  -- Stage 1 : each thread partially scans a chunk of the input-  -- Writes directly to the resulting array+  zipWithM_ dPrimV_ is $ unflattenIndex ns' i+  compileStms mempty (kernelBodyStms kbody) $ do+    -- Potential vector load and then do sequential scan+    getScanLoop typ $ \j -> do+      sComment "write mapped values results to memory" $ do+        let map_arrs = drop (segBinOpResults scan_ops) $ patElems 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) ->+        getNestLoop typ (segBinOpShape scan_op) $ \vec_is -> do+          -- Read accum value+          forM_ (zip (xParams scan_op) acc) $ \(p, acc') -> do+            copyDWIMFix (paramName p) [] (Var acc') vec_is+          -- Read next value+          sComment "Read next values" $+            forM_ (zip (yParams scan_op) scan_res) $ \(p, se) ->+              getExtract typ j $+                collect $+                  copyDWIMFix (paramName p) [] (kernelResultSubExp se) vec_is+          -- Scan body+          sComment "Scan body" $+            compileStms mempty (bodyStms $ lamBody scan_op) $+              forM_ (zip3 acc pes $ map resSubExp $ bodyResult $ lamBody scan_op) $+                \(acc', pe, se) -> do+                  copyDWIMFix (patElemName pe) (map Imp.le64 is ++ vec_is) se []+                  copyDWIMFix acc' vec_is se [] -  body <- collect $ do+scanStage1Scalar ::+  Pat LetDecMem ->+  SegSpace ->+  KernelBody MCMem ->+  [SegBinOp MCMem] ->+  MulticoreGen ()+scanStage1Scalar pat space kbody scan_ops = do+  fbody <- collect $ do     dPrim_ (segFlat space) int64     sOp $ Imp.GetTaskId (segFlat space) -    dScope Nothing $ scopeOfLParams $ concatMap (lambdaParams . segBinOpLambda) scan_ops-    local_accs <- 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+    genBinOpParams scan_ops+    local_accs <- genLocalAccsStage1 scan_ops+    inISPC $+      generateChunkLoop "SegScan" Vectorized $+        genScanLoop ScanScalar pat space kbody scan_ops local_accs+  free_params <- freeParams fbody+  emit $ Imp.Op $ Imp.ParLoop "scan_stage_1" fbody free_params -        -- Now neutral-initialise the accumulator.-        sLoopNest (segBinOpShape scan_op) $ \vec_is ->-          copyDWIMFix acc vec_is ne []+scanStage1Nested ::+  Pat LetDecMem ->+  SegSpace ->+  KernelBody MCMem ->+  [SegBinOp MCMem] ->+  MulticoreGen ()+scanStage1Nested pat space kbody scan_ops = do+  fbody <- collect $ do+    dPrim_ (segFlat space) int64+    sOp $ Imp.GetTaskId (segFlat space) -        pure acc+    lparams <- collect $ genBinOpParams scan_ops+    local_accs <- genLocalAccsStage1 scan_ops -    generateChunkLoop "SegScan" $ \i -> do-      zipWithM_ dPrimV_ is $ unflattenIndex ns' i-      compileStms mempty (kernelBodyStms kbody) $ do-        sComment "write mapped values results to memory" $ do-          let map_arrs = drop (segBinOpResults scan_ops) $ patElems pat-          zipWithM_ (compileThreadResult space) map_arrs map_res+    inISPC $ do+      emit lparams+      generateChunkLoop "SegScan" Scalar $ \i -> do+        genScanLoop ScanNested pat space kbody scan_ops local_accs i -        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+  free_params <- freeParams fbody+  emit $ Imp.Op $ Imp.ParLoop "scan_stage_1" fbody free_params -            -- Read next value-            sComment "Read next values" $-              forM_ (zip (yParams scan_op) scan_res) $ \(p, se) ->-                copyDWIMFix (paramName p) [] (kernelResultSubExp se) vec_is+scanStage1Fallback ::+  Pat LetDecMem ->+  SegSpace ->+  KernelBody MCMem ->+  [SegBinOp MCMem] ->+  MulticoreGen ()+scanStage1Fallback pat space kbody scan_ops = do+  -- Stage 1 : each thread partially scans a chunk of the input+  -- Writes directly to the resulting array+  fbody <- collect $ do+    dPrim_ (segFlat space) int64+    sOp $ Imp.GetTaskId (segFlat space) -            compileStms mempty (bodyStms $ lamBody scan_op) $-              forM_ (zip3 acc pes $ map resSubExp $ bodyResult $ lamBody scan_op) $-                \(acc', pe, se) -> do-                  copyDWIMFix (patElemName pe) (map Imp.le64 is ++ vec_is) se []-                  copyDWIMFix acc' vec_is se []+    genBinOpParams scan_ops+    local_accs <- genLocalAccsStage1 scan_ops -  free_params <- freeParams body-  emit $ Imp.Op $ Imp.ParLoop "scan_stage_1" body free_params+    generateChunkLoop "SegScan" Scalar $+      genScanLoop ScanSeq pat space kbody scan_ops local_accs+  free_params <- freeParams fbody+  emit $ Imp.Op $ Imp.ParLoop "scan_stage_1" fbody free_params  scanStage2 ::   Pat LetDecMem ->@@ -184,70 +288,95 @@                 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 ::+genLocalAccsStage3 :: [SegBinOp MCMem] -> [[PatElem LetDecMem]] -> MulticoreGen [[VName]]+genLocalAccsStage3 scan_ops per_scan_pes =+  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``+      (start, _end) <- getLoopBounds+      sLoopNest (segBinOpShape scan_op) $ \vec_is -> do+        let read_carry_in =+              copyDWIMFix acc vec_is (Var $ patElemName pe) (start - 1 : vec_is)+            read_neutral =+              copyDWIMFix acc vec_is ne []+        sIf (start .==. 0) read_neutral read_carry_in+      pure acc++scanStage3Scalar ::   Pat LetDecMem ->   SegSpace ->-  [SegBinOp MCMem] ->   KernelBody MCMem ->+  [SegBinOp 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 $ patElems pat-      ns' = map toInt64Exp ns+scanStage3Scalar pat space kbody scan_ops = do+  let per_scan_pes = segBinOpChunks scan_ops $ patElems pat+  body <- collect $ do+    dPrim_ (segFlat space) int64+    sOp $ Imp.GetTaskId (segFlat space) +    genBinOpParams scan_ops+    local_accs <- genLocalAccsStage3 scan_ops per_scan_pes++    inISPC $+      generateChunkLoop "SegScan" Vectorized $+        genScanLoop ScanScalar pat space kbody scan_ops local_accs+  free_params <- freeParams body+  emit $ Imp.Op $ Imp.ParLoop "scan_stage_3" body free_params++scanStage3Nested ::+  Pat LetDecMem ->+  SegSpace ->+  KernelBody MCMem ->+  [SegBinOp MCMem] ->+  MulticoreGen ()+scanStage3Nested pat space kbody scan_ops = do+  let per_scan_pes = segBinOpChunks scan_ops $ patElems pat   body <- collect $ do     dPrim_ (segFlat space) int64     sOp $ Imp.GetTaskId (segFlat space) -    dScope Nothing $ scopeOfLParams $ concatMap (lambdaParams . segBinOpLambda) scan_ops-    local_accs <- 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+    lparams <- collect $ genBinOpParams scan_ops+    local_accs <- genLocalAccsStage3 scan_ops per_scan_pes -        -- Initialise the accumulator with neutral from previous chunk.-        -- or read neutral if first ``iter``-        (start, _end) <- getLoopBounds-        sLoopNest (segBinOpShape scan_op) $ \vec_is -> do-          let read_carry_in =-                copyDWIMFix acc vec_is (Var $ patElemName pe) (start - 1 : vec_is)-              read_neutral =-                copyDWIMFix acc vec_is ne []-          sIf (start .==. 0) read_neutral read_carry_in-        pure acc+    inISPC $ do+      emit lparams+      generateChunkLoop "SegScan" Scalar $ \i -> do+        genScanLoop ScanNested pat space kbody scan_ops local_accs i -    generateChunkLoop "SegScan" $ \i -> do-      zipWithM_ dPrimV_ is $ unflattenIndex ns' i-      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+  free_params <- freeParams body+  emit $ Imp.Op $ Imp.ParLoop "scan_stage_3" body free_params -              -- Read next value-              forM_ (zip (yParams scan_op) scan_res) $ \(p, se) ->-                copyDWIMFix (paramName p) [] (kernelResultSubExp se) vec_is+scanStage3Fallback ::+  Pat LetDecMem ->+  SegSpace ->+  KernelBody MCMem ->+  [SegBinOp MCMem] ->+  MulticoreGen ()+scanStage3Fallback pat space kbody scan_ops = do+  let per_scan_pes = segBinOpChunks scan_ops $ patElems pat+  body <- collect $ do+    dPrim_ (segFlat space) int64+    sOp $ Imp.GetTaskId (segFlat space) -              compileStms mempty (bodyStms $ lamBody scan_op) $-                forM_ (zip3 pes (map resSubExp $ bodyResult $ lamBody scan_op) acc) $-                  \(pe, se, acc') -> do-                    copyDWIMFix (patElemName pe) (map Imp.le64 is ++ vec_is) se []-                    copyDWIMFix acc' vec_is se []+    genBinOpParams scan_ops+    local_accs <- genLocalAccsStage3 scan_ops per_scan_pes -  free_params' <- freeParams body-  emit $ Imp.Op $ Imp.ParLoop "scan_stage_3" body free_params'+    generateChunkLoop "SegScan" Scalar $+      genScanLoop ScanSeq pat space kbody scan_ops local_accs+  free_params <- freeParams body+  emit $ Imp.Op $ Imp.ParLoop "scan_stage_3" body free_params +-- Note: This isn't currently used anywhere. -- This implementation for a Segmented scan only -- parallelize over the segments and each segment is -- scanned sequentially.@@ -278,7 +407,7 @@   sOp $ Imp.GetTaskId (segFlat space)    let per_scan_pes = segBinOpChunks scan_ops $ patElems pat-  generateChunkLoop "SegScan" $ \segment_i -> do+  generateChunkLoop "SegScan" Scalar $ \segment_i -> do     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
src/Futhark/CodeGen/ImpGen/Transpose.hs view
@@ -51,8 +51,6 @@           If (le64 num_arrays .==. 1) doTranspose doMapTranspose         ]     )-    []-    []   where     params =       [ memparam destmem,
src/Futhark/CodeGen/RTS/C.hs view
@@ -18,6 +18,8 @@     valuesH,     errorsH,     cacheH,+    uniformH,+    ispcUtilH,   ) where @@ -32,6 +34,11 @@ atomicsH = $(embedStringFile "rts/c/atomics.h") {-# NOINLINE atomicsH #-} +-- | @rts/c/uniform.h@+uniformH :: T.Text+uniformH = $(embedStringFile "rts/c/uniform.h")+{-# NOINLINE uniformH #-}+ -- | @rts/c/cuda.h@ cudaH :: T.Text cudaH = $(embedStringFile "rts/c/cuda.h")@@ -101,6 +108,11 @@ errorsH :: T.Text errorsH = $(embedStringFile "rts/c/errors.h") {-# NOINLINE errorsH #-}++-- | @rts/c/ispc_util.h@+ispcUtilH :: T.Text+ispcUtilH = $(embedStringFile "rts/c/ispc_util.h")+{-# NOINLINE ispcUtilH #-}  -- | @rts/c/cache.h@ cacheH :: T.Text
src/Futhark/CodeGen/SetDefaultSpace.hs view
@@ -13,8 +13,9 @@ -- | Set all uses of 'DefaultSpace' in the given definitions to another -- memory space. setDefaultSpace :: Space -> Definitions op -> Definitions op-setDefaultSpace space (Definitions (Constants ps consts) (Functions fundecs)) =+setDefaultSpace space (Definitions types (Constants ps consts) (Functions fundecs)) =   Definitions+    types     (Constants (map (setParamSpace space) ps) (setCodeSpace space consts))     ( Functions         [ (fname, setFunctionSpace space func)@@ -27,13 +28,18 @@ setDefaultCodeSpace = setCodeSpace  setFunctionSpace :: Space -> Function op -> Function op-setFunctionSpace space (Function entry outputs inputs body results args) =+setFunctionSpace space (Function entry outputs inputs body) =   Function-    entry+    (setEntrySpace space <$> entry)     (map (setParamSpace space) outputs)     (map (setParamSpace space) inputs)     (setCodeSpace space body)-    (map (setExtValueSpace space) results)++setEntrySpace :: Space -> EntryPoint -> EntryPoint+setEntrySpace space (EntryPoint name results args) =+  EntryPoint+    name+    (map (fmap $ setExtValueSpace space) results)     (map (fmap $ setExtValueSpace space) args)  setParamSpace :: Space -> Param -> Param@@ -43,10 +49,10 @@   param  setExtValueSpace :: Space -> ExternalValue -> ExternalValue-setExtValueSpace space (OpaqueValue u desc vs) =-  OpaqueValue u desc $ map (setValueSpace space) vs-setExtValueSpace space (TransparentValue u v) =-  TransparentValue u $ setValueSpace space v+setExtValueSpace space (OpaqueValue desc vs) =+  OpaqueValue desc $ map (setValueSpace space) vs+setExtValueSpace space (TransparentValue v) =+  TransparentValue $ setValueSpace space v  setValueSpace :: Space -> ValueDesc -> ValueDesc setValueSpace space (ArrayValue mem _ bt ept shape) =
src/Futhark/Compiler.hs view
@@ -66,12 +66,12 @@   where     report s info = do       T.hPutStrLn stderr s-      when (fst (futharkVerbose config) > NotVerbose) $-        maybe+      when (fst (futharkVerbose config) > NotVerbose)+        $ maybe           (T.hPutStr stderr)           T.writeFile           (snd (futharkVerbose config))-          $ info <> "\n"+        $ info <> "\n"  -- | Read a program from the given 'FilePath', run the given -- 'Pipeline', and finish up with the given 'Action'.@@ -93,7 +93,8 @@     compile = do       prog <- runPipelineOnProgram config pipeline file       when ((> NotVerbose) . fst $ futharkVerbose config) $-        logMsg $ "Running action " ++ actionName action+        logMsg $+          "Running action " ++ actionName action       actionProcedure action prog       when ((> NotVerbose) . fst $ futharkVerbose config) $         logMsg ("Done." :: String)
src/Futhark/Compiler/Program.hs view
@@ -248,10 +248,14 @@                       }                 Just (Left e) ->                   pure . UncheckedImport . Left . singleError $-                    ProgError NoLoc $ text $ show e+                    ProgError NoLoc $+                      text $+                        show e                 Nothing ->                   pure . UncheckedImport . Left . singleError $-                    ProgError NoLoc $ text $ fp <> ": file not found."+                    ProgError NoLoc $+                      text $+                        fp <> ": file not found."             pure (M.insert include prog_mvar state, (include, prog_mvar))       where         include = mkInitialImport fp_name
src/Futhark/Construct.hs view
@@ -397,12 +397,15 @@   let checkDim w i = do         less_than_zero <-           letSubExp "less_than_zero" $-            BasicOp $ CmpOp (CmpSlt Int64) i (constant (0 :: Int64))+            BasicOp $+              CmpOp (CmpSlt Int64) i (constant (0 :: Int64))         greater_than_size <-           letSubExp "greater_than_size" $-            BasicOp $ CmpOp (CmpSle Int64) w i+            BasicOp $+              CmpOp (CmpSle Int64) w i         letSubExp "outside_bounds_dim" $-          BasicOp $ BinOp LogOr less_than_zero greater_than_size+          BasicOp $+            BinOp LogOr less_than_zero greater_than_size   foldBinOp LogOr (constant False) =<< zipWithM checkDim ws is'  -- | Construct an unspecified value of the given type.@@ -484,7 +487,9 @@   y <- newVName "y"   body <-     buildBody_ . fmap (pure . subExpRes) $-      letSubExp "binlam_res" $ BasicOp $ bop (Var x) (Var y)+      letSubExp "binlam_res" $+        BasicOp $+          bop (Var x) (Var y)   pure     Lambda       { lambdaParams =
src/Futhark/Doc/Generator.hs view
@@ -141,7 +141,7 @@     forM imports $ \(current, fm) ->       let ctx =             Context-              { ctxCurrent = current,+              { ctxCurrent = makeRelative "/" current,                 ctxFileMod = fm,                 ctxImports = imports,                 ctxNoLink = mempty,@@ -208,20 +208,23 @@   H.docTypeHtml $     addBoilerplate "index.html" "Futhark Library Documentation" $       H.main $-        H.h2 "Main libraries"-          <> fileList important_pages-          <> if null unimportant_pages+        ( if null important_pages             then mempty-            else-              H.h2 "Supporting libraries"-                <> fileList unimportant_pages+            else H.h2 "Main libraries" <> fileList important_pages+        )+          <> ( if null unimportant_pages+                 then mempty+                 else H.h2 "Supporting libraries" <> fileList unimportant_pages+             )   where     (important_pages, unimportant_pages) =       partition ((`elem` important_imports) . fst) pages      fileList pages' =       H.dl ! A.class_ "file_list" $-        mconcat $ map linkTo $ sortOn fst pages'+        mconcat $+          map linkTo $+            sortOn fst pages'      linkTo (name, maybe_abstract) =       H.div ! A.class_ "file_desc" $@@ -251,7 +254,8 @@     (letter_names, sym_names) =       partition (isLetterName . baseString . fst) $         sortOn (map toUpper . baseString . fst) $-          mapMaybe isDocumented $ M.toList fm+          mapMaybe isDocumented $+            M.toList fm      isDocumented (k, (file, _)) = do       what <- M.lookup k documented@@ -280,11 +284,12 @@       )       where         initial' =-          H.tr $-            H.td ! A.colspan "2" ! A.class_ "doc_index_initial" $-              H.a ! A.id (fromString initial)-                ! A.href (fromString $ '#' : initial)-                $ fromString initial+          H.tr+            $ H.td ! A.colspan "2" ! A.class_ "doc_index_initial"+            $ H.a+              ! A.id (fromString initial)+              ! A.href (fromString $ '#' : initial)+            $ fromString initial      initialListEntry initial =       H.li $ H.a ! A.href (fromString $ '#' : initial) $ fromString initial@@ -293,7 +298,8 @@       let file' = makeRelative "/" file           link =             (H.a ! A.href (fromString (makeRelative "/" $ "doc" </> vnameLink' name "" file'))) $-              fromString $ baseString name+              fromString $+                baseString name           what' = case what of             IndexValue -> "value"             IxFun -> "function"@@ -314,11 +320,11 @@         H.head $           H.meta             ! A.charset "utf-8"-              <> H.title (fromString titleText)-              <> H.link-            ! A.href (fromString $ relativise "style.css" current)-            ! A.rel "stylesheet"-            ! A.type_ "text/css"+            <> H.title (fromString titleText)+            <> H.link+              ! A.href (fromString $ relativise "style.css" current)+              ! A.rel "stylesheet"+              ! A.type_ "text/css"        navigation =         H.ul ! A.id "navigation" $@@ -326,7 +332,8 @@             <> H.li (H.a ! A.href (fromString $ relativise "doc-index.html" current) $ "Index")        madeByHtml =-        "Generated by " <> (H.a ! A.href futhark_doc_url) "futhark-doc"+        "Generated by "+          <> (H.a ! A.href futhark_doc_url) "futhark-doc"           <> " "           <> fromString (showVersion version)    in headHtml@@ -474,7 +481,8 @@   let tps' = map typeParamHtml tps   t' <- typeHtml t   pure $-    keyword "val " <> vnameHtml name+    keyword "val "+      <> vnameHtml name       <> mconcat (map (" " <>) tps')       <> ": "       <> t'@@ -482,7 +490,7 @@ typeHtml :: StructType -> DocM Html typeHtml t = case t of   Array _ u shape et -> do-    shape' <- prettyShapeDecl shape+    shape' <- prettyShape shape     et' <- typeHtml $ Scalar et     pure $ prettyU u <> shape' <> et'   Scalar (Prim et) -> pure $ primTypeHtml et@@ -497,7 +505,7 @@         pure $ toHtml (nameToString name) <> ": " <> tp'   Scalar (TypeVar _ u et targs) -> do     targs' <- mapM typeArgHtml targs-    et' <- typeNameHtml et+    et' <- qualNameHtml et     pure $ prettyU u <> et' <> mconcat (map (" " <>) targs')   Scalar (Arrow _ pname t1 t2) -> do     t1' <- typeHtml t1@@ -518,11 +526,11 @@   t' <- typeHtml t   pure $ "?" <> mconcat (map (brackets . vnameHtml) dims) <> "." <> t' -prettyShapeDecl :: ShapeDecl (DimDecl VName) -> DocM Html-prettyShapeDecl (ShapeDecl ds) =+prettyShape :: Shape Size -> DocM Html+prettyShape (Shape ds) =   mconcat <$> mapM dimDeclHtml ds -typeArgHtml :: TypeArg (DimDecl VName) -> DocM Html+typeArgHtml :: TypeArg Size -> DocM Html typeArgHtml (TypeArgDim d _) = dimDeclHtml d typeArgHtml (TypeArgType t _) = typeHtml t @@ -532,7 +540,8 @@   liftM2 f (synopsisSigExp psig) (modParamHtml mps)   where     f se params =-      "(" <> vnameHtml pname+      "("+        <> vnameHtml pname         <> ": "         <> se         <> ") -> "@@ -575,11 +584,13 @@ vnameSynopsisDef :: VName -> Html vnameSynopsisDef (VName name tag) =   H.span ! A.id (fromString (show tag ++ "s")) $-    H.a ! A.href (fromString ("#" ++ show tag)) $ renderName name+    H.a ! A.href (fromString ("#" ++ show tag)) $+      renderName name  vnameSynopsisRef :: VName -> Html vnameSynopsisRef v =-  H.a ! A.class_ "synopsis_link"+  H.a+    ! A.class_ "synopsis_link"     ! A.href (fromString ("#" ++ show (baseTag v) ++ "s"))     $ "↑" @@ -671,9 +682,6 @@     then "#" ++ show tag     else relativise file current ++ ".html#" ++ show tag -typeNameHtml :: TypeName -> DocM Html-typeNameHtml = qualNameHtml . qualNameFromTypeName- patternHtml :: Pat -> DocM Html patternHtml pat = do   let (pat_param, t) = patternParam pat@@ -686,15 +694,15 @@ relativise dest src =   concat (replicate (length (splitPath src) - 1) "../") ++ dest -dimDeclHtml :: DimDecl VName -> DocM Html-dimDeclHtml (NamedDim v) = brackets <$> qualNameHtml v-dimDeclHtml (ConstDim n) = pure $ brackets $ toHtml (show n)-dimDeclHtml AnyDim {} = pure $ brackets mempty+dimDeclHtml :: Size -> DocM Html+dimDeclHtml (NamedSize v) = brackets <$> qualNameHtml v+dimDeclHtml (ConstSize n) = pure $ brackets $ toHtml (show n)+dimDeclHtml AnySize {} = pure $ brackets mempty -dimExpHtml :: DimExp VName -> DocM Html-dimExpHtml DimExpAny = pure $ brackets mempty-dimExpHtml (DimExpNamed v _) = brackets <$> qualNameHtml v-dimExpHtml (DimExpConst n _) = pure $ brackets $ toHtml (show n)+dimExpHtml :: SizeExp VName -> DocM Html+dimExpHtml SizeExpAny = pure $ brackets mempty+dimExpHtml (SizeExpNamed v _) = brackets <$> qualNameHtml v+dimExpHtml (SizeExpConst n _) = pure $ brackets $ toHtml (show n)  typeArgExpHtml :: TypeArgExp VName -> DocM Html typeArgExpHtml (TypeArgExpDim d _) = dimExpHtml d@@ -732,7 +740,9 @@           case maybe_v of             Nothing -> do               warn loc $-                "Identifier '" <> fromString name <> "' not found in namespace '"+                "Identifier '"+                  <> fromString name+                  <> "' not found in namespace '"                   <> fromString namespace                   <> "'"                   <> fromString (maybe "" (" in file " <>) file)
src/Futhark/IR/Aliases.hs view
@@ -175,7 +175,9 @@     als' ->       Just $         PP.oneLine $-          PP.text "-- Result for " <> PP.ppr name <> PP.text " aliases "+          PP.text "-- Result for "+            <> PP.ppr name+            <> PP.text " aliases "             <> PP.commasep (map PP.ppr als')  removeAliases :: CanBeAliased (Op rep) => Rephraser Identity (Aliases rep) rep
src/Futhark/IR/GPU/Op.hs view
@@ -81,11 +81,13 @@  instance Engine.Simplifiable SegLevel where   simplify (SegThread num_groups group_size virt) =-    SegThread <$> traverse Engine.simplify num_groups+    SegThread+      <$> traverse Engine.simplify num_groups       <*> traverse Engine.simplify group_size       <*> pure virt   simplify (SegGroup num_groups group_size virt) =-    SegGroup <$> traverse Engine.simplify num_groups+    SegGroup+      <$> traverse Engine.simplify num_groups       <*> traverse Engine.simplify group_size       <*> pure virt 
src/Futhark/IR/GPU/Simplify.hs view
@@ -15,6 +15,7 @@   ) where +import qualified Futhark.Analysis.SymbolTable as ST import qualified Futhark.Analysis.UsageTable as UT import Futhark.IR.GPU import qualified Futhark.IR.SOACS.Simplify as SOAC@@ -26,6 +27,7 @@ import Futhark.Optimise.Simplify.Rules import Futhark.Pass import Futhark.Tools+import Futhark.Util (focusNth)  simpleGPU :: Simplify.SimpleOps GPU simpleGPU = Simplify.bindableSimpleOps $ simplifyKernelOp SOAC.simplifySOAC@@ -57,7 +59,9 @@ simplifyKernelOp _ (SizeOp (SplitSpace o w i elems_per_thread)) =   (,)     <$> ( SizeOp-            <$> ( SplitSpace <$> Engine.simplify o <*> Engine.simplify w+            <$> ( SplitSpace+                    <$> Engine.simplify o+                    <*> Engine.simplify w                     <*> Engine.simplify i                     <*> Engine.simplify elems_per_thread                 )@@ -103,13 +107,15 @@  kernelRules :: RuleBook (Wise GPU) kernelRules =-  standardRules <> segOpRules+  standardRules+    <> segOpRules     <> ruleBook       [ RuleOp SOAC.simplifyKnownIterationSOAC,         RuleOp SOAC.removeReplicateMapping,         RuleOp SOAC.liftIdentityMapping,         RuleOp SOAC.simplifyMapIota,-        RuleOp SOAC.removeUnusedSOACInput+        RuleOp SOAC.removeUnusedSOACInput,+        RuleBasicOp removeScalarCopy       ]       [ RuleBasicOp removeUnnecessaryCopy,         RuleOp removeDeadGPUBodyResult@@ -133,3 +139,27 @@        in Simplify $ auxing aux $ letBind (Pat pat') $ Op $ GPUBody types' body'   | otherwise = Skip removeDeadGPUBodyResult _ _ _ _ = Skip++-- 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+-- Update with a slice of that array.  This matters when the arrays+-- are far away (on the GPU, say), because it avoids a copy of the+-- scalar to and from the host.+removeScalarCopy :: BuilderOps rep => TopDownRuleBasicOp rep+removeScalarCopy vtable pat aux (Update safety arr_x (Slice slice_x) (Var v))+  | Just _ <- sliceIndices (Slice slice_x),+    Just (Index arr_y (Slice slice_y), cs_y) <- ST.lookupBasicOp v vtable,+    ST.available arr_y vtable,+    not $ ST.aliases arr_x arr_y vtable,+    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 $ slice_x_bef ++ [DimSlice i (intConst Int64 1) (intConst Int64 1)]+          slice_y' = Slice $ 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 $+        letBind pat $+          BasicOp $+            Update safety arr_x slice_x' $+              Var v'+removeScalarCopy _ _ _ _ =+  Skip
src/Futhark/IR/MC/Op.hs view
@@ -131,8 +131,10 @@ instance (PrettyRep rep, Pretty op) => Pretty (MCOp rep op) where   ppr (ParOp Nothing op) = ppr op   ppr (ParOp (Just par_op) op) =-    "par" <+> nestedBlock "{" "}" (ppr par_op)-      </> "seq" <+> nestedBlock "{" "}" (ppr op)+    "par"+      <+> nestedBlock "{" "}" (ppr par_op)+      </> "seq"+      <+> nestedBlock "{" "}" (ppr op)   ppr (OtherOp op) = ppr op  instance (OpMetrics (Op rep), OpMetrics op) => OpMetrics (MCOp rep op) where
src/Futhark/IR/Mem.hs view
@@ -548,7 +548,9 @@ varInfoToExpReturns :: MemInfo SubExp NoUniqueness MemBind -> ExpReturns varInfoToExpReturns (MemArray et shape u (ArrayIn mem ixfun)) =   MemArray et (fmap Free shape) u $-    Just $ ReturnsInBlock mem $ existentialiseIxFun [] ixfun+    Just $+      ReturnsInBlock mem $+        existentialiseIxFun [] ixfun varInfoToExpReturns (MemPrim pt) = MemPrim pt varInfoToExpReturns (MemAcc acc ispace ts u) = MemAcc acc ispace ts u varInfoToExpReturns (MemMem space) = MemMem space@@ -586,7 +588,8 @@           | otherwise ->               TC.bad $                 TC.TypeError $-                  "Array " ++ pretty v+                  "Array "+                    ++ pretty v                     ++ " returned by function, but has nontrivial index function "                     ++ pretty ixfun @@ -775,11 +778,12 @@     ( length val_ts == length rt         && and (zipWith (matches ctx_map_ids ctx_map_exts) val_ts rt)     )-    $ TC.bad $-      TC.TypeError $-        "Expression type:\n  " ++ prettyTuple rt-          ++ "\ncannot match pattern type:\n  "-          ++ prettyTuple val_ts+    $ TC.bad+    $ TC.TypeError+    $ "Expression type:\n  "+      ++ prettyTuple rt+      ++ "\ncannot match pattern type:\n  "+      ++ prettyTuple val_ts   where     matches _ _ (MemPrim x) (MemPrim y) = x == y     matches _ _ (MemMem x_space) (MemMem y_space) =@@ -787,7 +791,8 @@     matches _ _ (MemAcc x_accs x_ispace x_ts _) (MemAcc y_accs y_ispace y_ts _) =       (x_accs, x_ispace, x_ts) == (y_accs, y_ispace, y_ts)     matches ctxids ctxexts (MemArray x_pt x_shape _ x_ret) (MemArray y_pt y_shape _ y_ret) =-      x_pt == y_pt && x_shape == y_shape+      x_pt == y_pt+        && x_shape == y_shape         && case (x_ret, y_ret) of           (ReturnsInBlock _ x_ixfun, Just (ReturnsInBlock _ y_ixfun)) ->             let x_ixfun' = IxFun.substituteInIxFun ctxids x_ixfun@@ -854,7 +859,9 @@       pure (mem, ixfun)     _ ->       error $-        "Expected " ++ pretty name ++ " to be array but bound to:\n"+        "Expected "+          ++ pretty name+          ++ " to be array but bound to:\n"           ++ pretty summary  checkMemInfo ::@@ -875,7 +882,8 @@     _ ->       TC.bad $         TC.TypeError $-          "Variable " ++ pretty v+          "Variable "+            ++ pretty v             ++ " used as memory block, but is of type "             ++ pretty t             ++ "."@@ -887,7 +895,8 @@     unless (ixfun_rank == ident_rank) $       TC.bad $         TC.TypeError $-          "Arity of index function (" ++ pretty ixfun_rank+          "Arity of index function ("+            ++ pretty ixfun_rank             ++ ") does not match rank of array "             ++ pretty name             ++ " ("@@ -936,7 +945,9 @@             MemArray bt shape u $               Just $                 ReturnsNewBlock DefaultSpace i $-                  IxFun.iota $ map convert $ shapeDims shape+                  IxFun.iota $+                    map convert $+                      shapeDims shape       | otherwise =           pure $ MemArray bt shape u Nothing     addDec (Acc acc ispace ts u) =@@ -968,7 +979,9 @@     MemArray et shape _ (ArrayIn mem ixfun) ->       pure $         MemArray et (fmap Free shape) NoUniqueness $-          Just $ ReturnsInBlock mem $ existentialiseIxFun [] ixfun+          Just $+            ReturnsInBlock mem $+              existentialiseIxFun [] ixfun     MemMem space ->       pure $ MemMem space     MemAcc acc ispace ts u ->@@ -1000,7 +1013,8 @@         Just $           ReturnsInBlock mem $             existentialiseIxFun [] $-              IxFun.reshape ixfun $ map (fmap pe64) newshape+              IxFun.reshape ixfun $+                map (fmap pe64) newshape     ] expReturns (BasicOp (Rearrange perm v)) = do   (et, Shape dims, mem, ixfun) <- arrayVarReturns v@@ -1008,7 +1022,9 @@       dims' = rearrangeShape perm dims   pure     [ MemArray et (Shape $ map Free dims') NoUniqueness $-        Just $ ReturnsInBlock mem $ existentialiseIxFun [] ixfun'+        Just $+          ReturnsInBlock mem $+            existentialiseIxFun [] ixfun'     ] expReturns (BasicOp (Rotate offsets v)) = do   (et, Shape dims, mem, ixfun) <- arrayVarReturns v@@ -1016,7 +1032,9 @@       ixfun' = IxFun.rotate ixfun offsets'   pure     [ MemArray et (Shape $ map Free dims) NoUniqueness $-        Just $ ReturnsInBlock mem $ existentialiseIxFun [] ixfun'+        Just $+          ReturnsInBlock mem $+            existentialiseIxFun [] ixfun'     ] expReturns (BasicOp (Index v slice)) = do   pure . varInfoToExpReturns <$> sliceInfo v slice
src/Futhark/IR/Mem/IxFun.hs view
@@ -469,7 +469,8 @@       let (dims', slc') =             unzip $               filter ((/= 0) . ldStride . fst) $-                zip dims $ map normIndex slc+                zip dims $+                  map normIndex slc           -- Check that:           -- 1. a clean split point exists between Fixed and Sliced dims           -- 2. the outermost sliced dim has +/- 1 stride AND is unrotated or full.@@ -658,7 +659,8 @@                 _ -> error "reshape: reached impossible case"           )           ([], [])-          $ reverse $ zip3 iota_shape newshape perm'+          $ reverse+          $ zip3 iota_shape newshape perm'        (sup_inds, support) = unzip $ sortBy (compare `on` fst) support_inds       (rpt_inds, repeats) = unzip repeat_inds@@ -1051,7 +1053,7 @@     closeEnoughLMADs (lmad1, lmad2) =       length (lmadDims lmad1) == length (lmadDims lmad2)         && map ldPerm (lmadDims lmad1)-        == map ldPerm (lmadDims lmad2)+          == map ldPerm (lmadDims lmad2)  -- | Returns true if two 'IxFun's are equivalent. --@@ -1065,13 +1067,13 @@     equivalentLMADs (lmad1, lmad2) =       length (lmadDims lmad1) == length (lmadDims lmad2)         && map ldPerm (lmadDims lmad1)-        == map ldPerm (lmadDims lmad2)+          == map ldPerm (lmadDims lmad2)         && lmadOffset lmad1-        == lmadOffset lmad2+          == lmadOffset lmad2         && map ldStride (lmadDims lmad1)-        == map ldStride (lmadDims lmad2)+          == map ldStride (lmadDims lmad2)         && map ldRotate (lmadDims lmad1)-        == map ldRotate (lmadDims lmad2)+          == map ldRotate (lmadDims lmad2)  -- | Dynamically determine if two 'LMADDim' are equal. --
src/Futhark/IR/Mem/Simplify.hs view
@@ -203,7 +203,9 @@     Just (BasicOp (Copy v2), v1_cs) <- ST.lookupExp v1 vtable = Simplify $ do       v0' <-         certifying (v0_cs <> v1_cs) $-          letExp "rearrange_v0" $ BasicOp $ Rearrange perm v2+          letExp "rearrange_v0" $+            BasicOp $+              Rearrange perm v2       letBind pat $ BasicOp $ Copy v0' copyCopyToCopy _ _ _ _ = Skip 
src/Futhark/IR/Parse.hs view
@@ -32,13 +32,13 @@ import Futhark.IR.MCMem (MCMem) import Futhark.IR.Mem import qualified Futhark.IR.Mem.IxFun as IxFun-import Futhark.IR.Primitive.Parse import Futhark.IR.SOACS (SOACS) import qualified Futhark.IR.SOACS.SOAC as SOAC import qualified Futhark.IR.SegOp as SegOp import Futhark.IR.Seq (Seq) import Futhark.IR.SeqMem (SeqMem) import Futhark.Util.Pretty (prettyText)+import Language.Futhark.Primitive.Parse import Text.Megaparsec import Text.Megaparsec.Char hiding (space) import qualified Text.Megaparsec.Char.Lexer as L@@ -46,7 +46,7 @@ type Parser = Parsec Void T.Text  pStringLiteral :: Parser String-pStringLiteral = char '"' >> manyTill L.charLiteral (char '"')+pStringLiteral = lexeme $ char '"' >> manyTill L.charLiteral (char '"')  pName :: Parser Name pName =@@ -58,7 +58,8 @@ pVName :: Parser VName pVName = lexeme $ do   (s, tag) <--    satisfy constituent `manyTill_` try pTag+    satisfy constituent+      `manyTill_` try pTag       <?> "variable name"   pure $ VName (nameFromString s) tag   where@@ -95,8 +96,10 @@       "acc"         *> parens           ( Acc-              <$> pVName <* pComma-              <*> pShape <* pComma+              <$> pVName+              <* pComma+              <*> pShape+              <* pComma               <*> pTypes               <*> pure NoUniqueness           )@@ -137,6 +140,9 @@ pExtType :: Parser ExtType pExtType = pTypeBase pExtShape (pure NoUniqueness) +pRank :: Parser Rank+pRank = Rank . length <$> many "[]"+ pUniqueness :: Parser Uniqueness pUniqueness = choice [pAsterisk $> Unique, pure Nonunique] @@ -190,8 +196,11 @@ pDimIndex =   choice     [ try $-        DimSlice <$> pSubExp <* lexeme ":+"-          <*> pSubExp <* lexeme "*"+        DimSlice+          <$> pSubExp+          <* lexeme ":+"+          <*> pSubExp+          <* lexeme "*"           <*> pSubExp,       DimFix <$> pSubExp     ]@@ -246,9 +255,11 @@       keyword ("iota" <> prettyText (primBitSize (IntType t)))         *> parens           ( Iota-              <$> pSubExp <* pComma-              <*> pSubExp <* pComma+              <$> pSubExp+              <* pComma               <*> pSubExp+              <* pComma+              <*> pSubExp               <*> pure t           ) @@ -256,13 +267,17 @@ pBasicOp =   choice     [ keyword "opaque" $> Opaque OpaqueNil <*> parens pSubExp,-      keyword "trace" $> uncurry (Opaque . OpaqueTrace)-        <*> parens ((,) <$> lexeme pStringLiteral <* pComma <*> pSubExp),+      keyword "trace"+        $> uncurry (Opaque . OpaqueTrace)+        <*> parens ((,) <$> pStringLiteral <* pComma <*> pSubExp),       keyword "copy" $> Copy <*> parens pVName,       keyword "assert"         *> parens-          ( Assert <$> pSubExp <* pComma-              <*> pErrorMsg <* pComma+          ( Assert+              <$> pSubExp+              <* pComma+              <*> pErrorMsg+              <* pComma               <*> pErrorLoc           ),       keyword "rotate"@@ -290,14 +305,18 @@       pIota,       try $         flip Update-          <$> pVName <* keyword "with"+          <$> pVName+          <* keyword "with"           <*> choice [lexeme "?" $> Safe, pure Unsafe]-          <*> pSlice <* lexeme "="+          <*> pSlice+          <* lexeme "="           <*> pSubExp,       try $         FlatUpdate-          <$> pVName <* keyword "with"-          <*> pFlatSlice <* lexeme "="+          <$> pVName+          <* keyword "with"+          <*> pFlatSlice+          <* lexeme "="           <*> pVName,       ArrayLit         <$> brackets (pSubExp `sepBy` pComma)@@ -398,7 +417,10 @@  pIf :: PR rep -> Parser (Exp rep) pIf pr =-  keyword "if" $> f <*> pSort <*> pSubExp+  keyword "if"+    $> f+    <*> pSort+    <*> pSubExp     <*> (keyword "then" *> pBranchBody)     <*> (keyword "else" *> pBranchBody)     <*> (lexeme ":" *> pBranchTypes pr)@@ -424,7 +446,8 @@     p safety =       Apply         <$> pName-        <*> parens (pArg `sepBy` pComma) <* pColon+        <*> parens (pArg `sepBy` pComma)+        <* pColon         <*> pRetTypes pr         <*> pure (safety, mempty, mempty) @@ -436,9 +459,11 @@  pLoop :: PR rep -> Parser (Exp rep) pLoop pr =-  keyword "loop" $> DoLoop+  keyword "loop"+    $> DoLoop     <*> pLoopParams-    <*> pLoopForm <* keyword "do"+    <*> pLoopForm+    <* keyword "do"     <*> braces (pBody pr)   where     pLoopParams = do@@ -449,9 +474,12 @@      pLoopForm =       choice-        [ keyword "for" $> ForLoop-            <*> pVName <* lexeme ":"-            <*> pIntType <* lexeme "<"+        [ keyword "for"+            $> ForLoop+            <*> pVName+            <* lexeme ":"+            <*> pIntType+            <* lexeme "<"             <*> pSubExp             <*> many ((,) <$> pLParam pr <* keyword "in" <*> pVName),           keyword "while" $> WhileLoop <*> pVName@@ -462,8 +490,10 @@   choice     [ lexeme "\\"         $> lam-        <*> pLParams pr <* pColon-        <*> pTypes <* pArrow+        <*> pLParams pr+        <* pColon+        <*> pTypes+        <* pArrow         <*> pBody pr,       keyword "nilFn" $> Lambda mempty (Body (pBodyDec pr) mempty []) []     ]@@ -474,13 +504,15 @@ pReduce pr =   SOAC.Reduce     <$> pComm-    <*> pLambda pr <* pComma+    <*> pLambda pr+    <* pComma     <*> braces (pSubExp `sepBy` pComma)  pScan :: PR rep -> Parser (SOAC.Scan rep) pScan pr =   SOAC.Scan-    <$> pLambda pr <* pComma+    <$> pLambda pr+    <* pComma     <*> braces (pSubExp `sepBy` pComma)  pWithAcc :: PR rep -> Parser (Exp rep)@@ -491,7 +523,8 @@     pInput =       parens         ( (,,)-            <$> pShape <* pComma+            <$> pShape+            <* pComma             <*> pVNames             <*> optional (pComma *> pCombFun)         )@@ -511,7 +544,8 @@ pCerts :: Parser Certs pCerts =   choice-    [ lexeme "#" *> braces (Certs <$> pVName `sepBy` pComma)+    [ lexeme "#"+        *> braces (Certs <$> pVName `sepBy` pComma)         <?> "certificates",       pure mempty     ]@@ -535,24 +569,42 @@       Body (pBodyDec pr) mempty <$> pResult     ] +pValueType :: Parser ValueType+pValueType = comb <$> pRank <*> pSignedType+  where+    comb r (s, t) = ValueType s r t+    pSignedType =+      choice+        [ keyword "u8" $> (Unsigned, IntType Int8),+          keyword "u16" $> (Unsigned, IntType Int16),+          keyword "u32" $> (Unsigned, IntType Int32),+          keyword "u64" $> (Unsigned, IntType Int64),+          (Signed,) <$> pPrimType+        ]++pEntryPointType :: Parser EntryPointType+pEntryPointType =+  choice+    [ keyword "opaque" $> TypeOpaque <*> pStringLiteral,+      TypeTransparent <$> pValueType+    ]+ pEntry :: Parser EntryPoint pEntry =   parens $-    (,,) <$> (nameFromString <$> pStringLiteral)-      <* pComma <*> pEntryPointInputs-      <* pComma <*> pEntryPointTypes+    (,,)+      <$> (nameFromString <$> pStringLiteral)+      <* pComma+      <*> pEntryPointInputs+      <* pComma+      <*> pEntryPointResults   where-    pEntryPointTypes = braces (pEntryPointType `sepBy` pComma)     pEntryPointInputs = braces (pEntryPointInput `sepBy` pComma)-    pEntryPointType = do-      u <- pUniqueness-      choice-        [ "direct" $> TypeDirect u,-          "unsigned" $> TypeUnsigned u,-          "opaque" *> parens (TypeOpaque u <$> pStringLiteral <* pComma <*> pInt)-        ]+    pEntryPointResults = braces (pEntryPointResult `sepBy` pComma)     pEntryPointInput =-      EntryParam <$> pName <* pColon <*> pEntryPointType+      EntryParam <$> pName <* pColon <*> pUniqueness <*> pEntryPointType+    pEntryPointResult =+      EntryResult <$> pUniqueness <*> pEntryPointType  pFunDef :: PR rep -> Parser (FunDef rep) pFunDef pr = do@@ -568,8 +620,22 @@   FunDef entry attrs fname ret fparams     <$> (pEqual *> braces (pBody pr)) +pOpaqueType :: Parser (String, OpaqueType)+pOpaqueType =+  (,)+    <$> (keyword "type" *> pStringLiteral <* pEqual)+    <*> choice [pRecord, pOpaque]+  where+    pFieldName = choice [pName, nameFromString . show <$> pInt]+    pField = (,) <$> pFieldName <* pColon <*> pEntryPointType+    pRecord = keyword "record" $> OpaqueRecord <*> braces (many pField)+    pOpaque = keyword "opaque" $> OpaqueType <*> braces (many pValueType)++pOpaqueTypes :: Parser OpaqueTypes+pOpaqueTypes = keyword "types" $> OpaqueTypes <*> braces (many pOpaqueType)+ pProg :: PR rep -> Parser (Prog rep)-pProg pr = Prog <$> pStms pr <*> many (pFunDef pr)+pProg pr = Prog <$> pOpaqueTypes <*> pStms pr <*> many (pFunDef pr)  pSOAC :: PR rep -> Parser (SOAC.SOAC rep) pSOAC pr =@@ -588,21 +654,27 @@     pScrema p =       parens $         SOAC.Screma-          <$> pSubExp <* pComma-          <*> braces (pVName `sepBy` pComma) <* pComma+          <$> pSubExp+          <* pComma+          <*> braces (pVName `sepBy` pComma)+          <* pComma           <*> p     pScremaForm =       SOAC.ScremaForm-        <$> braces (pScan pr `sepBy` pComma) <* pComma-        <*> braces (pReduce pr `sepBy` pComma) <* pComma+        <$> braces (pScan pr `sepBy` pComma)+        <* pComma+        <*> braces (pReduce pr `sepBy` pComma)+        <* pComma         <*> pLambda pr     pRedomapForm =       SOAC.ScremaForm mempty-        <$> braces (pReduce pr `sepBy` pComma) <* pComma+        <$> braces (pReduce pr `sepBy` pComma)+        <* pComma         <*> pLambda pr     pScanomapForm =       SOAC.ScremaForm-        <$> braces (pScan pr `sepBy` pComma) <* pComma+        <$> braces (pScan pr `sepBy` pComma)+        <* pComma         <*> pure mempty         <*> pLambda pr     pMapForm =@@ -610,8 +682,11 @@     pScatter =       keyword "scatter"         *> parens-          ( SOAC.Scatter <$> pSubExp <* pComma-              <*> braces (pVName `sepBy` pComma) <* pComma+          ( SOAC.Scatter+              <$> pSubExp+              <* pComma+              <*> braces (pVName `sepBy` pComma)+              <* pComma               <*> pLambda pr               <*> many (pComma *> pDest)           )@@ -622,18 +697,25 @@       keyword "hist"         *> parens           ( SOAC.Hist-              <$> pSubExp <* pComma-              <*> braces (pVName `sepBy` pComma) <* pComma-              <*> braces (pHistOp `sepBy` pComma) <* pComma+              <$> pSubExp+              <* pComma+              <*> braces (pVName `sepBy` pComma)+              <* pComma+              <*> braces (pHistOp `sepBy` pComma)+              <* pComma               <*> pLambda pr           )       where         pHistOp =           SOAC.HistOp-            <$> pShape <* pComma-            <*> pSubExp <* pComma-            <*> braces (pVName `sepBy` pComma) <* pComma-            <*> braces (pSubExp `sepBy` pComma) <* pComma+            <$> pShape+            <* pComma+            <*> pSubExp+            <* pComma+            <*> braces (pVName `sepBy` pComma)+            <* pComma+            <*> braces (pSubExp `sepBy` pComma)+            <* pComma             <*> pLambda pr     pStream =       choice@@ -646,33 +728,44 @@     pStreamPar order comm =       parens $         SOAC.Stream-          <$> pSubExp <* pComma-          <*> braces (pVName `sepBy` pComma) <* pComma-          <*> pParForm order comm <* pComma-          <*> braces (pSubExp `sepBy` pComma) <* pComma+          <$> pSubExp+          <* pComma+          <*> braces (pVName `sepBy` pComma)+          <* pComma+          <*> pParForm order comm+          <* pComma+          <*> braces (pSubExp `sepBy` pComma)+          <* pComma           <*> pLambda pr     pParForm order comm =       SOAC.Parallel order comm <$> pLambda pr     pStreamSeq =       parens $         SOAC.Stream-          <$> pSubExp <* pComma-          <*> braces (pVName `sepBy` pComma) <* pComma+          <$> pSubExp+          <* pComma+          <*> braces (pVName `sepBy` pComma)+          <* pComma           <*> pure SOAC.Sequential-          <*> braces (pSubExp `sepBy` pComma) <* pComma+          <*> braces (pSubExp `sepBy` pComma)+          <* pComma           <*> pLambda pr     pVJP =       parens $         SOAC.VJP-          <$> pLambda pr <* pComma-          <*> braces (pSubExp `sepBy` pComma) <* pComma+          <$> pLambda pr+          <* pComma           <*> braces (pSubExp `sepBy` pComma)+          <* pComma+          <*> braces (pSubExp `sepBy` pComma)     pJVP =       parens $         SOAC.JVP-          <$> pLambda pr <* pComma-          <*> braces (pSubExp `sepBy` pComma) <* pComma+          <$> pLambda pr+          <* pComma           <*> braces (pSubExp `sepBy` pComma)+          <* pComma+          <*> braces (pSubExp `sepBy` pComma)  pSizeClass :: Parser GPU.SizeClass pSizeClass =@@ -686,7 +779,8 @@       keyword "threshold"         *> parens           ( flip GPU.SizeThreshold-              <$> choice [Just <$> pInt64, "def" $> Nothing] <* pComma+              <$> choice [Just <$> pInt64, "def" $> Nothing]+              <* pComma               <*> pKernelPath           ),       keyword "bespoke"@@ -714,22 +808,31 @@       keyword "calc_num_groups"         *> parens           ( GPU.CalcNumGroups-              <$> pSubExp <* pComma <*> pName <* pComma <*> pSubExp+              <$> pSubExp+              <* pComma+              <*> pName+              <* pComma+              <*> pSubExp           ),       keyword "split_space"         *> parens           ( GPU.SplitSpace GPU.SplitContiguous-              <$> pSubExp <* pComma-              <*> pSubExp <* pComma+              <$> pSubExp+              <* pComma               <*> pSubExp+              <* pComma+              <*> pSubExp           ),       keyword "split_space_strided"         *> parens           ( GPU.SplitSpace-              <$> (GPU.SplitStrided <$> pSubExp) <* pComma-              <*> pSubExp <* pComma-              <*> pSubExp <* pComma+              <$> (GPU.SplitStrided <$> pSubExp)+              <* pComma               <*> pSubExp+              <* pComma+              <*> pSubExp+              <* pComma+              <*> pSubExp           )     ] @@ -745,7 +848,8 @@ pKernelResult = do   cs <- pCerts   choice-    [ keyword "returns" $> SegOp.Returns+    [ keyword "returns"+        $> SegOp.Returns         <*> choice           [ keyword "(manifest)" $> SegOp.ResultNoSimplify,             keyword "(private)" $> SegOp.ResultPrivate,@@ -755,26 +859,33 @@         <*> pSubExp,       try $         flip (SegOp.WriteReturns cs)-          <$> pVName <* pColon-          <*> pShape <* keyword "with"+          <$> pVName+          <* pColon+          <*> pShape+          <* keyword "with"           <*> parens (pWrite `sepBy` pComma),       try "tile"-        *> parens (SegOp.TileReturns cs <$> (pTile `sepBy` pComma)) <*> pVName,+        *> parens (SegOp.TileReturns cs <$> (pTile `sepBy` pComma))+        <*> pVName,       try "blkreg_tile"-        *> parens (SegOp.RegTileReturns cs <$> (pRegTile `sepBy` pComma)) <*> pVName,+        *> parens (SegOp.RegTileReturns cs <$> (pRegTile `sepBy` pComma))+        <*> pVName,       keyword "concat"         *> parens           ( SegOp.ConcatReturns cs SegOp.SplitContiguous-              <$> pSubExp <* pComma+              <$> pSubExp+              <* pComma               <*> pSubExp           )         <*> pVName,       keyword "concat_strided"         *> parens           ( SegOp.ConcatReturns cs-              <$> (SegOp.SplitStrided <$> pSubExp) <* pComma-              <*> pSubExp <* pComma+              <$> (SegOp.SplitStrided <$> pSubExp)+              <* pComma               <*> pSubExp+              <* pComma+              <*> pSubExp           )         <*> pVName     ]@@ -791,7 +902,8 @@ pKernelBody :: PR rep -> Parser (SegOp.KernelBody rep) pKernelBody pr =   SegOp.KernelBody (pBodyDec pr)-    <$> pStms pr <* keyword "return"+    <$> pStms pr+    <* keyword "return"     <*> braces (pKernelResult `sepBy` pComma)  pSegOp :: PR rep -> Parser lvl -> Parser (SegOp.SegOp lvl rep)@@ -806,13 +918,16 @@     pSegMap =       SegOp.SegMap         <$> pLvl-        <*> pSegSpace <* pColon+        <*> pSegSpace+        <* pColon         <*> pTypes         <*> braces (pKernelBody pr)     pSegOp' f p =-      f <$> pLvl+      f+        <$> pLvl         <*> pSegSpace-        <*> parens (p `sepBy` pComma) <* pColon+        <*> parens (p `sepBy` pComma)+        <* pColon         <*> pTypes         <*> braces (pKernelBody pr)     pSegBinOp = do@@ -823,11 +938,16 @@       pure $ SegOp.SegBinOp comm lam nes shape     pHistOp =       SegOp.HistOp-        <$> pShape <* pComma-        <*> pSubExp <* pComma-        <*> braces (pVName `sepBy` pComma) <* pComma-        <*> braces (pSubExp `sepBy` pComma) <* pComma-        <*> pShape <* pComma+        <$> pShape+        <* pComma+        <*> pSubExp+        <* pComma+        <*> braces (pVName `sepBy` pComma)+        <* pComma+        <*> braces (pSubExp `sepBy` pComma)+        <* pComma+        <*> pShape+        <* pComma         <*> pLambda pr     pSegRed = pSegOp' SegOp.SegRed pSegBinOp     pSegScan = pSegOp' SegOp.SegScan pSegBinOp@@ -845,7 +965,8 @@       <*> choice         [ pSemi             *> choice-              [ keyword "full" $> SegOp.SegNoVirtFull+              [ keyword "full"+                  $> SegOp.SegNoVirtFull                   <*> (SegOp.SegSeqDims <$> brackets (pInt `sepBy` pComma)),                 keyword "virtualise" $> SegOp.SegVirt               ],@@ -927,8 +1048,11 @@     pAcc u =       keyword "acc"         *> parens-          ( MemAcc <$> pVName <* pComma-              <*> pShape <* pComma+          ( MemAcc+              <$> pVName+              <* pComma+              <*> pShape+              <* pComma               <*> pTypes               <*> pure u           )
src/Futhark/IR/Pretty.hs view
@@ -51,6 +51,9 @@ instance Pretty Shape where   ppr = mconcat . map (brackets . ppr) . shapeDims +instance Pretty Rank where+  ppr (Rank r) = mconcat $ replicate r "[]"+ instance Pretty a => Pretty (Ext a) where   ppr (Free e) = ppr e   ppr (Ext x) = text "?" <> text (show x)@@ -109,7 +112,8 @@     | null stms = braces (commasep $ map ppr res)     | otherwise =         stack (map ppr $ stmsToList stms)-          </> text "in" <+> braces (commasep $ map ppr res)+          </> text "in"+          <+> braces (commasep $ map ppr res)  instance Pretty Attr where   ppr (AttrName v) = ppr v@@ -148,7 +152,8 @@ instance PrettyRep rep => Pretty (Stm rep) where   ppr stm@(Let pat aux e) =     align . hang 2 $-      text "let" <+> align (ppr pat)+      text "let"+        <+> align (ppr pat)         <+> case (linebreak, stmannot) of           (True, []) -> equals </> ppr e           (False, []) -> equals <+/> ppr e@@ -235,7 +240,9 @@  instance PrettyRep rep => Pretty (Exp rep) where   ppr (If c t f (IfDec ret ifsort)) =-    text "if" <+> info' <+> ppr c+    text "if"+      <+> info'+      <+> ppr c       </> text "then"       <+> maybeNest t       <+> text "else"@@ -254,7 +261,7 @@   ppr (Apply fname args ret (safety, _, _)) =     applykw       <+> text (nameToString fname)-      <> apply (map (align . pprArg) args)+        <> apply (map (align . pprArg) args)       </> colon       <+> braces (commasep $ map ppr ret)     where@@ -265,7 +272,8 @@         Safe -> text "apply"   ppr (Op op) = ppr op   ppr (DoLoop merge form loopbody) =-    text "loop" <+> braces (commastack $ map ppr params)+    text "loop"+      <+> braces (commastack $ map ppr params)       <+> equals       <+> ppTuple' args       </> ( case form of@@ -298,28 +306,40 @@     where       ppInput (shape, arrs, op) =         parens-          ( ppr shape <> comma <+> ppTuple' arrs-              <> case op of-                Nothing -> mempty-                Just (op', nes) ->-                  comma </> parens (ppr op' <> comma </> ppTuple' (map ppr nes))+          ( ppr shape <> comma+              <+> ppTuple' arrs+                <> case op of+                  Nothing -> mempty+                  Just (op', nes) ->+                    comma </> parens (ppr op' <> comma </> ppTuple' (map ppr nes))           )  instance PrettyRep rep => Pretty (Lambda rep) where   ppr (Lambda [] (Body _ stms []) []) | stms == mempty = text "nilFn"   ppr (Lambda params body rettype) =-    text "\\" <+> ppTuple' params+    text "\\"+      <+> ppTuple' params       </> indent 2 (colon <+> ppTupleLines' rettype <+> text "->")       </> indent 2 (ppr body) +instance Pretty Signedness where+  ppr Signed = "signed"+  ppr Unsigned = "unsigned"++instance Pretty ValueType where+  ppr (ValueType s (Rank r) t) =+    mconcat (replicate r "[]") <> text (prettySigned (s == Unsigned) t)+ instance Pretty EntryPointType where-  ppr (TypeDirect u) = ppr u <> "direct"-  ppr (TypeUnsigned u) = ppr u <> "unsigned"-  ppr (TypeOpaque u desc n) = ppr u <> "opaque" <> apply [ppr (show desc), ppr n]+  ppr (TypeTransparent t) = ppr t+  ppr (TypeOpaque desc) = "opaque" <+> pquote (text desc)  instance Pretty EntryParam where-  ppr (EntryParam name t) = ppr name <> colon <+> ppr t+  ppr (EntryParam name u t) = ppr name <> colon <+> ppr u <> ppr t +instance Pretty EntryResult where+  ppr (EntryResult u t) = ppr u <> ppr t+ instance PrettyRep rep => Pretty (FunDef rep) where   ppr (FunDef entry attrs name rettype fparams body) =     annot (attrAnnots attrs) $@@ -336,13 +356,26 @@           "entry"             <> parens               ( "\"" <> ppr p_name <> "\"" <> comma-                  </> ppTuple' p_entry <> comma-                  </> ppTuple' ret_entry+                  </> ppTupleLines' p_entry <> comma+                  </> ppTupleLines' ret_entry               ) +instance Pretty OpaqueType where+  ppr (OpaqueType ts) =+    "opaque" <+> nestedBlock "{" "}" (stack $ map ppr ts)+  ppr (OpaqueRecord fs) =+    "record" <+> nestedBlock "{" "}" (stack $ map p fs)+    where+      p (f, et) = ppr f <> ":" <+> ppr et++instance Pretty OpaqueTypes where+  ppr (OpaqueTypes ts) = "types" <+> nestedBlock "{" "}" (stack $ map p ts)+    where+      p (name, t) = "type" <+> pquote (ppr name) <+> equals <+> ppr t+ instance PrettyRep rep => Pretty (Prog rep) where-  ppr (Prog consts funs) =-    stack $ punctuate line $ ppr consts : map ppr funs+  ppr (Prog types consts funs) =+    stack $ punctuate line $ ppr types : ppr consts : map ppr funs  instance Pretty d => Pretty (DimChange d) where   ppr (DimCoercion se) = text "~" <> ppr se
− src/Futhark/IR/Primitive.hs
@@ -1,1873 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}---- | Definitions of primitive types, the values that inhabit these--- types, and operations on these values.  A primitive value can also--- be called a scalar.------ Essentially, this module describes the subset of the (internal)--- Futhark language that operates on primitive types.-module Futhark.IR.Primitive-  ( -- * Types-    IntType (..),-    allIntTypes,-    FloatType (..),-    allFloatTypes,-    PrimType (..),-    allPrimTypes,-    module Data.Int,-    Half,--    -- * Values-    IntValue (..),-    intValue,-    intValueType,-    valueIntegral,-    FloatValue (..),-    floatValue,-    floatValueType,-    PrimValue (..),-    primValueType,-    blankPrimValue,--    -- * Operations-    Overflow (..),-    Safety (..),-    UnOp (..),-    allUnOps,-    BinOp (..),-    allBinOps,-    ConvOp (..),-    allConvOps,-    CmpOp (..),-    allCmpOps,--    -- ** Unary Operations-    doUnOp,-    doComplement,-    doAbs,-    doFAbs,-    doSSignum,-    doUSignum,--    -- ** Binary Operations-    doBinOp,-    doAdd,-    doMul,-    doSDiv,-    doSMod,-    doPow,--    -- ** Conversion Operations-    doConvOp,-    doZExt,-    doSExt,-    doFPConv,-    doFPToUI,-    doFPToSI,-    doUIToFP,-    doSIToFP,-    intToInt64,-    intToWord64,-    flipConvOp,--    -- * Comparison Operations-    doCmpOp,-    doCmpEq,-    doCmpUlt,-    doCmpUle,-    doCmpSlt,-    doCmpSle,-    doFCmpLt,-    doFCmpLe,--    -- * Type Of-    binOpType,-    unOpType,-    cmpOpType,-    convOpType,--    -- * Primitive functions-    primFuns,--    -- * Utility-    zeroIsh,-    zeroIshInt,-    oneIsh,-    oneIshInt,-    negativeIsh,-    primBitSize,-    primByteSize,-    intByteSize,-    floatByteSize,-    commutativeBinOp,-    associativeBinOp,--    -- * Prettyprinting-    convOpFun,-    prettySigned,-  )-where--import Control.Category-import qualified Data.Binary.Get as G-import qualified Data.Binary.Put as P-import Data.Bits-  ( complement,-    countLeadingZeros,-    countTrailingZeros,-    popCount,-    shift,-    shiftR,-    xor,-    (.&.),-    (.|.),-  )-import Data.Fixed (mod') -- Weird location.-import Data.Int (Int16, Int32, Int64, Int8)-import qualified Data.Map as M-import Data.Word-import Foreign.C.Types (CUShort (..))-import Futhark.Util-  ( cbrt,-    cbrtf,-    ceilDouble,-    ceilFloat,-    convFloat,-    erf,-    erfc,-    erfcf,-    erff,-    floorDouble,-    floorFloat,-    hypot,-    hypotf,-    lgamma,-    lgammaf,-    roundDouble,-    roundFloat,-    tgamma,-    tgammaf,-  )-import Futhark.Util.Pretty-import Numeric.Half-import Prelude hiding (id, (.))---- | An integer type, ordered by size.  Note that signedness is not a--- property of the type, but a property of the operations performed on--- values of these types.-data IntType-  = Int8-  | Int16-  | Int32-  | Int64-  deriving (Eq, Ord, Show, Enum, Bounded)--instance Pretty IntType where-  ppr Int8 = text "i8"-  ppr Int16 = text "i16"-  ppr Int32 = text "i32"-  ppr Int64 = text "i64"---- | A list of all integer types.-allIntTypes :: [IntType]-allIntTypes = [minBound .. maxBound]---- | A floating point type.-data FloatType-  = Float16-  | Float32-  | Float64-  deriving (Eq, Ord, Show, Enum, Bounded)--instance Pretty FloatType where-  ppr Float16 = text "f16"-  ppr Float32 = text "f32"-  ppr Float64 = text "f64"---- | A list of all floating-point types.-allFloatTypes :: [FloatType]-allFloatTypes = [minBound .. maxBound]---- | Low-level primitive types.-data PrimType-  = IntType IntType-  | FloatType FloatType-  | Bool-  | -- | An informationless type - An array of this type takes up no space.-    Unit-  deriving (Eq, Ord, Show)--instance Enum PrimType where-  toEnum 0 = IntType Int8-  toEnum 1 = IntType Int16-  toEnum 2 = IntType Int32-  toEnum 3 = IntType Int64-  toEnum 4 = FloatType Float16-  toEnum 5 = FloatType Float32-  toEnum 6 = FloatType Float64-  toEnum 7 = Bool-  toEnum _ = Unit--  fromEnum (IntType Int8) = 0-  fromEnum (IntType Int16) = 1-  fromEnum (IntType Int32) = 2-  fromEnum (IntType Int64) = 3-  fromEnum (FloatType Float16) = 4-  fromEnum (FloatType Float32) = 5-  fromEnum (FloatType Float64) = 6-  fromEnum Bool = 7-  fromEnum Unit = 8--instance Bounded PrimType where-  minBound = IntType Int8-  maxBound = Unit--instance Pretty PrimType where-  ppr (IntType t) = ppr t-  ppr (FloatType t) = ppr t-  ppr Bool = text "bool"-  ppr Unit = text "unit"---- | A list of all primitive types.-allPrimTypes :: [PrimType]-allPrimTypes =-  map IntType allIntTypes-    ++ map FloatType allFloatTypes-    ++ [Bool, Unit]---- | An integer value.-data IntValue-  = Int8Value !Int8-  | Int16Value !Int16-  | Int32Value !Int32-  | Int64Value !Int64-  deriving (Eq, Ord, Show)--instance Pretty IntValue where-  ppr (Int8Value v) = text $ show v ++ "i8"-  ppr (Int16Value v) = text $ show v ++ "i16"-  ppr (Int32Value v) = text $ show v ++ "i32"-  ppr (Int64Value v) = text $ show v ++ "i64"---- | Create an t'IntValue' from a type and an 'Integer'.-intValue :: Integral int => IntType -> int -> IntValue-intValue Int8 = Int8Value . fromIntegral-intValue Int16 = Int16Value . fromIntegral-intValue Int32 = Int32Value . fromIntegral-intValue Int64 = Int64Value . fromIntegral---- | The type of an integer value.-intValueType :: IntValue -> IntType-intValueType Int8Value {} = Int8-intValueType Int16Value {} = Int16-intValueType Int32Value {} = Int32-intValueType Int64Value {} = Int64---- | Convert an t'IntValue' to any 'Integral' type.-valueIntegral :: Integral int => IntValue -> int-valueIntegral (Int8Value v) = fromIntegral v-valueIntegral (Int16Value v) = fromIntegral v-valueIntegral (Int32Value v) = fromIntegral v-valueIntegral (Int64Value v) = fromIntegral v---- | A floating-point value.-data FloatValue-  = Float16Value !Half-  | Float32Value !Float-  | Float64Value !Double-  deriving (Show)--instance Eq FloatValue where-  Float16Value x == Float16Value y = isNaN x && isNaN y || x == y-  Float32Value x == Float32Value y = isNaN x && isNaN y || x == y-  Float64Value x == Float64Value y = isNaN x && isNaN y || x == y-  _ == _ = False---- The derived Ord instance does not handle NaNs correctly.-instance Ord FloatValue where-  Float16Value x <= Float16Value y = x <= y-  Float32Value x <= Float32Value y = x <= y-  Float64Value x <= Float64Value y = x <= y-  Float16Value _ <= Float32Value _ = True-  Float16Value _ <= Float64Value _ = True-  Float32Value _ <= Float16Value _ = False-  Float32Value _ <= Float64Value _ = True-  Float64Value _ <= Float16Value _ = False-  Float64Value _ <= Float32Value _ = False--  Float16Value x < Float16Value y = x < y-  Float32Value x < Float32Value y = x < y-  Float64Value x < Float64Value y = x < y-  Float16Value _ < Float32Value _ = True-  Float16Value _ < Float64Value _ = True-  Float32Value _ < Float16Value _ = False-  Float32Value _ < Float64Value _ = True-  Float64Value _ < Float16Value _ = False-  Float64Value _ < Float32Value _ = False--  (>) = flip (<)-  (>=) = flip (<=)--instance Pretty FloatValue where-  ppr (Float16Value v)-    | isInfinite v, v >= 0 = text "f16.inf"-    | isInfinite v, v < 0 = text "-f16.inf"-    | isNaN v = text "f16.nan"-    | otherwise = text $ show v ++ "f16"-  ppr (Float32Value v)-    | isInfinite v, v >= 0 = text "f32.inf"-    | isInfinite v, v < 0 = text "-f32.inf"-    | isNaN v = text "f32.nan"-    | otherwise = text $ show v ++ "f32"-  ppr (Float64Value v)-    | isInfinite v, v >= 0 = text "f64.inf"-    | isInfinite v, v < 0 = text "-f64.inf"-    | isNaN v = text "f64.nan"-    | otherwise = text $ show v ++ "f64"---- | Create a t'FloatValue' from a type and a 'Rational'.-floatValue :: Real num => FloatType -> num -> FloatValue-floatValue Float16 = Float16Value . fromRational . toRational-floatValue Float32 = Float32Value . fromRational . toRational-floatValue Float64 = Float64Value . fromRational . toRational---- | The type of a floating-point value.-floatValueType :: FloatValue -> FloatType-floatValueType Float16Value {} = Float16-floatValueType Float32Value {} = Float32-floatValueType Float64Value {} = Float64---- | Non-array values.-data PrimValue-  = IntValue !IntValue-  | FloatValue !FloatValue-  | BoolValue !Bool-  | -- | The only value of type 'Unit'.-    UnitValue-  deriving (Eq, Ord, Show)--instance Pretty PrimValue where-  ppr (IntValue v) = ppr v-  ppr (BoolValue True) = text "true"-  ppr (BoolValue False) = text "false"-  ppr (FloatValue v) = ppr v-  ppr UnitValue = text "()"---- | The type of a basic value.-primValueType :: PrimValue -> PrimType-primValueType (IntValue v) = IntType $ intValueType v-primValueType (FloatValue v) = FloatType $ floatValueType v-primValueType BoolValue {} = Bool-primValueType UnitValue = Unit---- | A "blank" value of the given primitive type - this is zero, or--- whatever is close to it.  Don't depend on this value, but use it--- for e.g. creating arrays to be populated by do-loops.-blankPrimValue :: PrimType -> PrimValue-blankPrimValue (IntType Int8) = IntValue $ Int8Value 0-blankPrimValue (IntType Int16) = IntValue $ Int16Value 0-blankPrimValue (IntType Int32) = IntValue $ Int32Value 0-blankPrimValue (IntType Int64) = IntValue $ Int64Value 0-blankPrimValue (FloatType Float16) = FloatValue $ Float16Value 0.0-blankPrimValue (FloatType Float32) = FloatValue $ Float32Value 0.0-blankPrimValue (FloatType Float64) = FloatValue $ Float64Value 0.0-blankPrimValue Bool = BoolValue False-blankPrimValue Unit = UnitValue---- | Various unary operators.  It is a bit ad-hoc what is a unary--- operator and what is a built-in function.  Perhaps these should all--- go away eventually.-data UnOp-  = -- | E.g., @! True == False@.-    Not-  | -- | E.g., @~(~1) = 1@.-    Complement IntType-  | -- | @abs(-2) = 2@.-    Abs IntType-  | -- | @fabs(-2.0) = 2.0@.-    FAbs FloatType-  | -- | Signed sign function: @ssignum(-2)@ = -1.-    SSignum IntType-  | -- | Unsigned sign function: @usignum(2)@ = 1.-    USignum IntType-  | -- | Floating-point sign function.-    FSignum FloatType-  deriving (Eq, Ord, Show)---- | What to do in case of arithmetic overflow.  Futhark's semantics--- are that overflow does wraparound, but for generated code (like--- address arithmetic), it can be beneficial for overflow to be--- undefined behaviour, as it allows better optimisation of things--- such as GPU kernels.------ Note that all values of this type are considered equal for 'Eq' and--- 'Ord'.-data Overflow = OverflowWrap | OverflowUndef-  deriving (Show)--instance Eq Overflow where-  _ == _ = True--instance Ord Overflow where-  _ `compare` _ = EQ---- | Whether something is safe or unsafe (mostly function calls, and--- in the context of whether operations are dynamically checked).--- When we inline an 'Unsafe' function, we remove all safety checks in--- its body.  The 'Ord' instance picks 'Unsafe' as being less than--- 'Safe'.------ For operations like integer division, a safe division will not--- explode the computer in case of division by zero, but instead--- return some unspecified value.  This always involves a run-time--- check, so generally the unsafe variant is what the compiler will--- insert, but guarded by an explicit assertion elsewhere.  Safe--- operations are useful when the optimiser wants to move e.g. a--- division to a location where the divisor may be zero, but where the--- result will only be used when it is non-zero (so it doesn't matter--- what result is provided with a zero divisor, as long as the program--- keeps running).-data Safety = Unsafe | Safe deriving (Eq, Ord, Show)---- | Binary operators.  These correspond closely to the binary operators in--- LLVM.  Most are parametrised by their expected input and output--- types.-data BinOp-  = -- | Integer addition.-    Add IntType Overflow-  | -- | Floating-point addition.-    FAdd FloatType-  | -- | Integer subtraction.-    Sub IntType Overflow-  | -- | Floating-point subtraction.-    FSub FloatType-  | -- | Integer multiplication.-    Mul IntType Overflow-  | -- | Floating-point multiplication.-    FMul FloatType-  | -- | Unsigned integer division.  Rounds towards-    -- negativity infinity.  Note: this is different-    -- from LLVM.-    UDiv IntType Safety-  | -- | Unsigned integer division.  Rounds towards positive-    -- infinity.-    UDivUp IntType Safety-  | -- | Signed integer division.  Rounds towards-    -- negativity infinity.  Note: this is different-    -- from LLVM.-    SDiv IntType Safety-  | -- | Signed integer division.  Rounds towards positive-    -- infinity.-    SDivUp IntType Safety-  | -- | Floating-point division.-    FDiv FloatType-  | -- | Floating-point modulus.-    FMod FloatType-  | -- | Unsigned integer modulus; the countepart to 'UDiv'.-    UMod IntType Safety-  | -- | Signed integer modulus; the countepart to 'SDiv'.-    SMod IntType Safety-  | -- | Signed integer division.  Rounds towards zero.  This-    -- corresponds to the @sdiv@ instruction in LLVM and-    -- integer division in C.-    SQuot IntType Safety-  | -- | Signed integer division.  Rounds towards zero.  This-    -- corresponds to the @srem@ instruction in LLVM and-    -- integer modulo in C.-    SRem IntType Safety-  | -- | Returns the smallest of two signed integers.-    SMin IntType-  | -- | Returns the smallest of two unsigned integers.-    UMin IntType-  | -- | Returns the smallest of two floating-point numbers.-    FMin FloatType-  | -- | Returns the greatest of two signed integers.-    SMax IntType-  | -- | Returns the greatest of two unsigned integers.-    UMax IntType-  | -- | Returns the greatest of two floating-point numbers.-    FMax FloatType-  | -- | Left-shift.-    Shl IntType-  | -- | Logical right-shift, zero-extended.-    LShr IntType-  | -- | Arithmetic right-shift, sign-extended.-    AShr IntType-  | -- | Bitwise and.-    And IntType-  | -- | Bitwise or.-    Or IntType-  | -- | Bitwise exclusive-or.-    Xor IntType-  | -- | Integer exponentiation.-    Pow IntType-  | -- | Floating-point exponentiation.-    FPow FloatType-  | -- | Boolean and - not short-circuiting.-    LogAnd-  | -- | Boolean or - not short-circuiting.-    LogOr-  deriving (Eq, Ord, Show)---- | Comparison operators are like 'BinOp's, but they always return a--- boolean value.  The somewhat ugly constructor names are straight--- out of LLVM.-data CmpOp-  = -- | All types equality.-    CmpEq PrimType-  | -- | Unsigned less than.-    CmpUlt IntType-  | -- | Unsigned less than or equal.-    CmpUle IntType-  | -- | Signed less than.-    CmpSlt IntType-  | -- | Signed less than or equal.-    CmpSle IntType-  | -- Comparison operators for floating-point values.  TODO: extend-    -- this to handle NaNs and such, like the LLVM fcmp instruction.--    -- | Floating-point less than.-    FCmpLt FloatType-  | -- | Floating-point less than or equal.-    FCmpLe FloatType-  | -- Boolean comparison.--    -- | Boolean less than.-    CmpLlt-  | -- | Boolean less than or equal.-    CmpLle-  deriving (Eq, Ord, Show)---- | Conversion operators try to generalise the @from t0 x to t1@--- instructions from LLVM.-data ConvOp-  = -- | Zero-extend the former integer type to the latter.-    -- If the new type is smaller, the result is a-    -- truncation.-    ZExt IntType IntType-  | -- | Sign-extend the former integer type to the latter.-    -- If the new type is smaller, the result is a-    -- truncation.-    SExt IntType IntType-  | -- | Convert value of the former floating-point type to-    -- the latter.  If the new type is smaller, the result-    -- is a truncation.-    FPConv FloatType FloatType-  | -- | Convert a floating-point value to the nearest-    -- unsigned integer (rounding towards zero).-    FPToUI FloatType IntType-  | -- | Convert a floating-point value to the nearest-    -- signed integer (rounding towards zero).-    FPToSI FloatType IntType-  | -- | Convert an unsigned integer to a floating-point value.-    UIToFP IntType FloatType-  | -- | Convert a signed integer to a floating-point value.-    SIToFP IntType FloatType-  | -- | Convert an integer to a boolean value.  Zero-    -- becomes false; anything else is true.-    IToB IntType-  | -- | Convert a boolean to an integer.  True is converted-    -- to 1 and False to 0.-    BToI IntType-  | -- | Convert a float to a boolean value.  Zero becomes false;-    -- | anything else is true.-    FToB FloatType-  | -- | Convert a boolean to a float.  True is converted-    -- to 1 and False to 0.-    BToF FloatType-  deriving (Eq, Ord, Show)---- | A list of all unary operators for all types.-allUnOps :: [UnOp]-allUnOps =-  Not :-  map Complement [minBound .. maxBound]-    ++ map Abs [minBound .. maxBound]-    ++ map FAbs [minBound .. maxBound]-    ++ map SSignum [minBound .. maxBound]-    ++ map USignum [minBound .. maxBound]-    ++ map FSignum [minBound .. maxBound]---- | A list of all binary operators for all types.-allBinOps :: [BinOp]-allBinOps =-  concat-    [ Add <$> allIntTypes <*> [OverflowWrap, OverflowUndef],-      map FAdd allFloatTypes,-      Sub <$> allIntTypes <*> [OverflowWrap, OverflowUndef],-      map FSub allFloatTypes,-      Mul <$> allIntTypes <*> [OverflowWrap, OverflowUndef],-      map FMul allFloatTypes,-      UDiv <$> allIntTypes <*> [Unsafe, Safe],-      UDivUp <$> allIntTypes <*> [Unsafe, Safe],-      SDiv <$> allIntTypes <*> [Unsafe, Safe],-      SDivUp <$> allIntTypes <*> [Unsafe, Safe],-      map FDiv allFloatTypes,-      map FMod allFloatTypes,-      UMod <$> allIntTypes <*> [Unsafe, Safe],-      SMod <$> allIntTypes <*> [Unsafe, Safe],-      SQuot <$> allIntTypes <*> [Unsafe, Safe],-      SRem <$> allIntTypes <*> [Unsafe, Safe],-      map SMin allIntTypes,-      map UMin allIntTypes,-      map FMin allFloatTypes,-      map SMax allIntTypes,-      map UMax allIntTypes,-      map FMax allFloatTypes,-      map Shl allIntTypes,-      map LShr allIntTypes,-      map AShr allIntTypes,-      map And allIntTypes,-      map Or allIntTypes,-      map Xor allIntTypes,-      map Pow allIntTypes,-      map FPow allFloatTypes,-      [LogAnd, LogOr]-    ]---- | A list of all comparison operators for all types.-allCmpOps :: [CmpOp]-allCmpOps =-  concat-    [ map CmpEq allPrimTypes,-      map CmpUlt allIntTypes,-      map CmpUle allIntTypes,-      map CmpSlt allIntTypes,-      map CmpSle allIntTypes,-      map FCmpLt allFloatTypes,-      map FCmpLe allFloatTypes,-      [CmpLlt, CmpLle]-    ]---- | A list of all conversion operators for all types.-allConvOps :: [ConvOp]-allConvOps =-  concat-    [ ZExt <$> allIntTypes <*> allIntTypes,-      SExt <$> allIntTypes <*> allIntTypes,-      FPConv <$> allFloatTypes <*> allFloatTypes,-      FPToUI <$> allFloatTypes <*> allIntTypes,-      FPToSI <$> allFloatTypes <*> allIntTypes,-      UIToFP <$> allIntTypes <*> allFloatTypes,-      SIToFP <$> allIntTypes <*> allFloatTypes,-      IToB <$> allIntTypes,-      BToI <$> allIntTypes,-      FToB <$> allFloatTypes,-      BToF <$> allFloatTypes-    ]---- | Apply an 'UnOp' to an operand.  Returns 'Nothing' if the--- application is mistyped.-doUnOp :: UnOp -> PrimValue -> Maybe PrimValue-doUnOp Not (BoolValue b) = Just $ BoolValue $ not b-doUnOp Complement {} (IntValue v) = Just $ IntValue $ doComplement v-doUnOp Abs {} (IntValue v) = Just $ IntValue $ doAbs v-doUnOp FAbs {} (FloatValue v) = Just $ FloatValue $ doFAbs v-doUnOp SSignum {} (IntValue v) = Just $ IntValue $ doSSignum v-doUnOp USignum {} (IntValue v) = Just $ IntValue $ doUSignum v-doUnOp FSignum {} (FloatValue v) = Just $ FloatValue $ doFSignum v-doUnOp _ _ = Nothing---- | E.g., @~(~1) = 1@.-doComplement :: IntValue -> IntValue-doComplement v = intValue (intValueType v) $ complement $ intToInt64 v---- | @abs(-2) = 2@.-doAbs :: IntValue -> IntValue-doAbs v = intValue (intValueType v) $ abs $ intToInt64 v---- | @abs(-2.0) = 2.0@.-doFAbs :: FloatValue -> FloatValue-doFAbs (Float16Value x) = Float16Value $ abs x-doFAbs (Float32Value x) = Float32Value $ abs x-doFAbs (Float64Value x) = Float64Value $ abs x---- | @ssignum(-2)@ = -1.-doSSignum :: IntValue -> IntValue-doSSignum v = intValue (intValueType v) $ signum $ intToInt64 v---- | @usignum(-2)@ = -1.-doUSignum :: IntValue -> IntValue-doUSignum v = intValue (intValueType v) $ signum $ intToWord64 v---- | @fsignum(-2.0)@ = -1.0.-doFSignum :: FloatValue -> FloatValue-doFSignum (Float16Value v) = Float16Value $ signum v-doFSignum (Float32Value v) = Float32Value $ signum v-doFSignum (Float64Value v) = Float64Value $ signum v---- | Apply a 'BinOp' to an operand.  Returns 'Nothing' if the--- application is mistyped, or outside the domain (e.g. division by--- zero).-doBinOp :: BinOp -> PrimValue -> PrimValue -> Maybe PrimValue-doBinOp Add {} = doIntBinOp doAdd-doBinOp FAdd {} = doFloatBinOp (+) (+) (+)-doBinOp Sub {} = doIntBinOp doSub-doBinOp FSub {} = doFloatBinOp (-) (-) (-)-doBinOp Mul {} = doIntBinOp doMul-doBinOp FMul {} = doFloatBinOp (*) (*) (*)-doBinOp UDiv {} = doRiskyIntBinOp doUDiv-doBinOp UDivUp {} = doRiskyIntBinOp doUDivUp-doBinOp SDiv {} = doRiskyIntBinOp doSDiv-doBinOp SDivUp {} = doRiskyIntBinOp doSDivUp-doBinOp FDiv {} = doFloatBinOp (/) (/) (/)-doBinOp FMod {} = doFloatBinOp mod' mod' mod'-doBinOp UMod {} = doRiskyIntBinOp doUMod-doBinOp SMod {} = doRiskyIntBinOp doSMod-doBinOp SQuot {} = doRiskyIntBinOp doSQuot-doBinOp SRem {} = doRiskyIntBinOp doSRem-doBinOp SMin {} = doIntBinOp doSMin-doBinOp UMin {} = doIntBinOp doUMin-doBinOp FMin {} = doFloatBinOp fmin fmin fmin-  where-    fmin x y-      | isNaN x = y-      | isNaN y = x-      | otherwise = min x y-doBinOp SMax {} = doIntBinOp doSMax-doBinOp UMax {} = doIntBinOp doUMax-doBinOp FMax {} = doFloatBinOp fmax fmax fmax-  where-    fmax x y-      | isNaN x = y-      | isNaN y = x-      | otherwise = max x y-doBinOp Shl {} = doIntBinOp doShl-doBinOp LShr {} = doIntBinOp doLShr-doBinOp AShr {} = doIntBinOp doAShr-doBinOp And {} = doIntBinOp doAnd-doBinOp Or {} = doIntBinOp doOr-doBinOp Xor {} = doIntBinOp doXor-doBinOp Pow {} = doRiskyIntBinOp doPow-doBinOp FPow {} = doFloatBinOp (**) (**) (**)-doBinOp LogAnd {} = doBoolBinOp (&&)-doBinOp LogOr {} = doBoolBinOp (||)--doIntBinOp ::-  (IntValue -> IntValue -> IntValue) ->-  PrimValue ->-  PrimValue ->-  Maybe PrimValue-doIntBinOp f (IntValue v1) (IntValue v2) =-  Just $ IntValue $ f v1 v2-doIntBinOp _ _ _ = Nothing--doRiskyIntBinOp ::-  (IntValue -> IntValue -> Maybe IntValue) ->-  PrimValue ->-  PrimValue ->-  Maybe PrimValue-doRiskyIntBinOp f (IntValue v1) (IntValue v2) =-  IntValue <$> f v1 v2-doRiskyIntBinOp _ _ _ = Nothing--doFloatBinOp ::-  (Half -> Half -> Half) ->-  (Float -> Float -> Float) ->-  (Double -> Double -> Double) ->-  PrimValue ->-  PrimValue ->-  Maybe PrimValue-doFloatBinOp f16 _ _ (FloatValue (Float16Value v1)) (FloatValue (Float16Value v2)) =-  Just $ FloatValue $ Float16Value $ f16 v1 v2-doFloatBinOp _ f32 _ (FloatValue (Float32Value v1)) (FloatValue (Float32Value v2)) =-  Just $ FloatValue $ Float32Value $ f32 v1 v2-doFloatBinOp _ _ f64 (FloatValue (Float64Value v1)) (FloatValue (Float64Value v2)) =-  Just $ FloatValue $ Float64Value $ f64 v1 v2-doFloatBinOp _ _ _ _ _ = Nothing--doBoolBinOp ::-  (Bool -> Bool -> Bool) ->-  PrimValue ->-  PrimValue ->-  Maybe PrimValue-doBoolBinOp f (BoolValue v1) (BoolValue v2) =-  Just $ BoolValue $ f v1 v2-doBoolBinOp _ _ _ = Nothing---- | Integer addition.-doAdd :: IntValue -> IntValue -> IntValue-doAdd v1 v2 = intValue (intValueType v1) $ intToInt64 v1 + intToInt64 v2---- | Integer subtraction.-doSub :: IntValue -> IntValue -> IntValue-doSub v1 v2 = intValue (intValueType v1) $ intToInt64 v1 - intToInt64 v2---- | Integer multiplication.-doMul :: IntValue -> IntValue -> IntValue-doMul v1 v2 = intValue (intValueType v1) $ intToInt64 v1 * intToInt64 v2---- | Unsigned integer division.  Rounds towards negativity infinity.--- Note: this is different from LLVM.-doUDiv :: IntValue -> IntValue -> Maybe IntValue-doUDiv v1 v2-  | zeroIshInt v2 = Nothing-  | otherwise =-      Just $-        intValue (intValueType v1) $-          intToWord64 v1 `div` intToWord64 v2---- | Unsigned integer division.  Rounds towards positive infinity.-doUDivUp :: IntValue -> IntValue -> Maybe IntValue-doUDivUp v1 v2-  | zeroIshInt v2 = Nothing-  | otherwise =-      Just $-        intValue (intValueType v1) $-          (intToWord64 v1 + intToWord64 v2 - 1) `div` intToWord64 v2---- | Signed integer division.  Rounds towards negativity infinity.--- Note: this is different from LLVM.-doSDiv :: IntValue -> IntValue -> Maybe IntValue-doSDiv v1 v2-  | zeroIshInt v2 = Nothing-  | otherwise =-      Just $-        intValue (intValueType v1) $-          intToInt64 v1 `div` intToInt64 v2---- | Signed integer division.  Rounds towards positive infinity.-doSDivUp :: IntValue -> IntValue -> Maybe IntValue-doSDivUp v1 v2-  | zeroIshInt v2 = Nothing-  | otherwise =-      Just $-        intValue (intValueType v1) $-          (intToInt64 v1 + intToInt64 v2 - 1) `div` intToInt64 v2---- | Unsigned integer modulus; the countepart to 'UDiv'.-doUMod :: IntValue -> IntValue -> Maybe IntValue-doUMod v1 v2-  | zeroIshInt v2 = Nothing-  | otherwise = Just $ intValue (intValueType v1) $ intToWord64 v1 `mod` intToWord64 v2---- | Signed integer modulus; the countepart to 'SDiv'.-doSMod :: IntValue -> IntValue -> Maybe IntValue-doSMod v1 v2-  | zeroIshInt v2 = Nothing-  | otherwise = Just $ intValue (intValueType v1) $ intToInt64 v1 `mod` intToInt64 v2---- | Signed integer division.  Rounds towards zero.--- This corresponds to the @sdiv@ instruction in LLVM.-doSQuot :: IntValue -> IntValue -> Maybe IntValue-doSQuot v1 v2-  | zeroIshInt v2 = Nothing-  | otherwise = Just $ intValue (intValueType v1) $ intToInt64 v1 `quot` intToInt64 v2---- | Signed integer division.  Rounds towards zero.--- This corresponds to the @srem@ instruction in LLVM.-doSRem :: IntValue -> IntValue -> Maybe IntValue-doSRem v1 v2-  | zeroIshInt v2 = Nothing-  | otherwise = Just $ intValue (intValueType v1) $ intToInt64 v1 `rem` intToInt64 v2---- | Minimum of two signed integers.-doSMin :: IntValue -> IntValue -> IntValue-doSMin v1 v2 = intValue (intValueType v1) $ intToInt64 v1 `min` intToInt64 v2---- | Minimum of two unsigned integers.-doUMin :: IntValue -> IntValue -> IntValue-doUMin v1 v2 = intValue (intValueType v1) $ intToWord64 v1 `min` intToWord64 v2---- | Maximum of two signed integers.-doSMax :: IntValue -> IntValue -> IntValue-doSMax v1 v2 = intValue (intValueType v1) $ intToInt64 v1 `max` intToInt64 v2---- | Maximum of two unsigned integers.-doUMax :: IntValue -> IntValue -> IntValue-doUMax v1 v2 = intValue (intValueType v1) $ intToWord64 v1 `max` intToWord64 v2---- | Left-shift.-doShl :: IntValue -> IntValue -> IntValue-doShl v1 v2 = intValue (intValueType v1) $ intToInt64 v1 `shift` intToInt v2---- | Logical right-shift, zero-extended.-doLShr :: IntValue -> IntValue -> IntValue-doLShr v1 v2 = intValue (intValueType v1) $ intToWord64 v1 `shift` negate (intToInt v2)---- | Arithmetic right-shift, sign-extended.-doAShr :: IntValue -> IntValue -> IntValue-doAShr v1 v2 = intValue (intValueType v1) $ intToInt64 v1 `shift` negate (intToInt v2)---- | Bitwise and.-doAnd :: IntValue -> IntValue -> IntValue-doAnd v1 v2 = intValue (intValueType v1) $ intToWord64 v1 .&. intToWord64 v2---- | Bitwise or.-doOr :: IntValue -> IntValue -> IntValue-doOr v1 v2 = intValue (intValueType v1) $ intToWord64 v1 .|. intToWord64 v2---- | Bitwise exclusive-or.-doXor :: IntValue -> IntValue -> IntValue-doXor v1 v2 = intValue (intValueType v1) $ intToWord64 v1 `xor` intToWord64 v2---- | Signed integer exponentatation.-doPow :: IntValue -> IntValue -> Maybe IntValue-doPow v1 v2-  | negativeIshInt v2 = Nothing-  | otherwise = Just $ intValue (intValueType v1) $ intToInt64 v1 ^ intToInt64 v2---- | Apply a 'ConvOp' to an operand.  Returns 'Nothing' if the--- application is mistyped.-doConvOp :: ConvOp -> PrimValue -> Maybe PrimValue-doConvOp (ZExt _ to) (IntValue v) = Just $ IntValue $ doZExt v to-doConvOp (SExt _ to) (IntValue v) = Just $ IntValue $ doSExt v to-doConvOp (FPConv _ to) (FloatValue v) = Just $ FloatValue $ doFPConv v to-doConvOp (FPToUI _ to) (FloatValue v) = Just $ IntValue $ doFPToUI v to-doConvOp (FPToSI _ to) (FloatValue v) = Just $ IntValue $ doFPToSI v to-doConvOp (UIToFP _ to) (IntValue v) = Just $ FloatValue $ doUIToFP v to-doConvOp (SIToFP _ to) (IntValue v) = Just $ FloatValue $ doSIToFP v to-doConvOp (IToB _) (IntValue v) = Just $ BoolValue $ intToInt64 v /= 0-doConvOp (BToI to) (BoolValue v) = Just $ IntValue $ intValue to $ if v then 1 else 0 :: Int-doConvOp (FToB _) (FloatValue v) = Just $ BoolValue $ floatToDouble v /= 0-doConvOp (BToF to) (BoolValue v) = Just $ FloatValue $ floatValue to $ if v then 1 else 0 :: Double-doConvOp _ _ = Nothing---- | Turn the conversion the other way around.  Note that most--- conversions are lossy, so there is no guarantee the value will--- round-trip.-flipConvOp :: ConvOp -> ConvOp-flipConvOp (ZExt from to) = ZExt to from-flipConvOp (SExt from to) = SExt to from-flipConvOp (FPConv from to) = FPConv to from-flipConvOp (FPToUI from to) = UIToFP to from-flipConvOp (FPToSI from to) = SIToFP to from-flipConvOp (UIToFP from to) = FPToSI to from-flipConvOp (SIToFP from to) = FPToSI to from-flipConvOp (IToB from) = BToI from-flipConvOp (BToI to) = IToB to-flipConvOp (FToB from) = BToF from-flipConvOp (BToF to) = FToB to---- | Zero-extend the given integer value to the size of the given--- type.  If the type is smaller than the given value, the result is a--- truncation.-doZExt :: IntValue -> IntType -> IntValue-doZExt (Int8Value x) t = intValue t $ toInteger (fromIntegral x :: Word8)-doZExt (Int16Value x) t = intValue t $ toInteger (fromIntegral x :: Word16)-doZExt (Int32Value x) t = intValue t $ toInteger (fromIntegral x :: Word32)-doZExt (Int64Value x) t = intValue t $ toInteger (fromIntegral x :: Word64)---- | Sign-extend the given integer value to the size of the given--- type.  If the type is smaller than the given value, the result is a--- truncation.-doSExt :: IntValue -> IntType -> IntValue-doSExt (Int8Value x) t = intValue t $ toInteger x-doSExt (Int16Value x) t = intValue t $ toInteger x-doSExt (Int32Value x) t = intValue t $ toInteger x-doSExt (Int64Value x) t = intValue t $ toInteger x---- | Convert the former floating-point type to the latter.-doFPConv :: FloatValue -> FloatType -> FloatValue-doFPConv v Float16 = Float16Value $ floatToHalf v-doFPConv v Float32 = Float32Value $ floatToFloat v-doFPConv v Float64 = Float64Value $ floatToDouble v---- | Convert a floating-point value to the nearest--- unsigned integer (rounding towards zero).-doFPToUI :: FloatValue -> IntType -> IntValue-doFPToUI v t = intValue t (truncate $ floatToDouble v :: Word64)---- | Convert a floating-point value to the nearest--- signed integer (rounding towards zero).-doFPToSI :: FloatValue -> IntType -> IntValue-doFPToSI v t = intValue t (truncate $ floatToDouble v :: Word64)---- | Convert an unsigned integer to a floating-point value.-doUIToFP :: IntValue -> FloatType -> FloatValue-doUIToFP v t = floatValue t $ intToWord64 v---- | Convert a signed integer to a floating-point value.-doSIToFP :: IntValue -> FloatType -> FloatValue-doSIToFP v t = floatValue t $ intToInt64 v---- | Apply a 'CmpOp' to an operand.  Returns 'Nothing' if the--- application is mistyped.-doCmpOp :: CmpOp -> PrimValue -> PrimValue -> Maybe Bool-doCmpOp CmpEq {} v1 v2 = Just $ doCmpEq v1 v2-doCmpOp CmpUlt {} (IntValue v1) (IntValue v2) = Just $ doCmpUlt v1 v2-doCmpOp CmpUle {} (IntValue v1) (IntValue v2) = Just $ doCmpUle v1 v2-doCmpOp CmpSlt {} (IntValue v1) (IntValue v2) = Just $ doCmpSlt v1 v2-doCmpOp CmpSle {} (IntValue v1) (IntValue v2) = Just $ doCmpSle v1 v2-doCmpOp FCmpLt {} (FloatValue v1) (FloatValue v2) = Just $ doFCmpLt v1 v2-doCmpOp FCmpLe {} (FloatValue v1) (FloatValue v2) = Just $ doFCmpLe v1 v2-doCmpOp CmpLlt {} (BoolValue v1) (BoolValue v2) = Just $ not v1 && v2-doCmpOp CmpLle {} (BoolValue v1) (BoolValue v2) = Just $ not (v1 && not v2)-doCmpOp _ _ _ = Nothing---- | Compare any two primtive values for exact equality.-doCmpEq :: PrimValue -> PrimValue -> Bool-doCmpEq (FloatValue (Float32Value v1)) (FloatValue (Float32Value v2)) = v1 == v2-doCmpEq (FloatValue (Float64Value v1)) (FloatValue (Float64Value v2)) = v1 == v2-doCmpEq v1 v2 = v1 == v2---- | Unsigned less than.-doCmpUlt :: IntValue -> IntValue -> Bool-doCmpUlt v1 v2 = intToWord64 v1 < intToWord64 v2---- | Unsigned less than or equal.-doCmpUle :: IntValue -> IntValue -> Bool-doCmpUle v1 v2 = intToWord64 v1 <= intToWord64 v2---- | Signed less than.-doCmpSlt :: IntValue -> IntValue -> Bool-doCmpSlt = (<)---- | Signed less than or equal.-doCmpSle :: IntValue -> IntValue -> Bool-doCmpSle = (<=)---- | Floating-point less than.-doFCmpLt :: FloatValue -> FloatValue -> Bool-doFCmpLt = (<)---- | Floating-point less than or equal.-doFCmpLe :: FloatValue -> FloatValue -> Bool-doFCmpLe = (<=)---- | Translate an t'IntValue' to 'Word64'.  This is guaranteed to fit.-intToWord64 :: IntValue -> Word64-intToWord64 (Int8Value v) = fromIntegral (fromIntegral v :: Word8)-intToWord64 (Int16Value v) = fromIntegral (fromIntegral v :: Word16)-intToWord64 (Int32Value v) = fromIntegral (fromIntegral v :: Word32)-intToWord64 (Int64Value v) = fromIntegral (fromIntegral v :: Word64)---- | Translate an t'IntValue' to t'Int64'.  This is guaranteed to fit.-intToInt64 :: IntValue -> Int64-intToInt64 (Int8Value v) = fromIntegral v-intToInt64 (Int16Value v) = fromIntegral v-intToInt64 (Int32Value v) = fromIntegral v-intToInt64 (Int64Value v) = fromIntegral v---- | Careful - there is no guarantee this will fit.-intToInt :: IntValue -> Int-intToInt = fromIntegral . intToInt64--floatToDouble :: FloatValue -> Double-floatToDouble (Float16Value v)-  | isInfinite v, v > 0 = 1 / 0-  | isInfinite v, v < 0 = -1 / 0-  | isNaN v = 0 / 0-  | otherwise = fromRational $ toRational v-floatToDouble (Float32Value v)-  | isInfinite v, v > 0 = 1 / 0-  | isInfinite v, v < 0 = -1 / 0-  | isNaN v = 0 / 0-  | otherwise = fromRational $ toRational v-floatToDouble (Float64Value v) = v--floatToFloat :: FloatValue -> Float-floatToFloat (Float16Value v)-  | isInfinite v, v > 0 = 1 / 0-  | isInfinite v, v < 0 = -1 / 0-  | isNaN v = 0 / 0-  | otherwise = fromRational $ toRational v-floatToFloat (Float32Value v) = v-floatToFloat (Float64Value v)-  | isInfinite v, v > 0 = 1 / 0-  | isInfinite v, v < 0 = -1 / 0-  | isNaN v = 0 / 0-  | otherwise = fromRational $ toRational v--floatToHalf :: FloatValue -> Half-floatToHalf (Float16Value v) = v-floatToHalf (Float32Value v)-  | isInfinite v, v > 0 = 1 / 0-  | isInfinite v, v < 0 = -1 / 0-  | isNaN v = 0 / 0-  | otherwise = fromRational $ toRational v-floatToHalf (Float64Value v)-  | isInfinite v, v > 0 = 1 / 0-  | isInfinite v, v < 0 = -1 / 0-  | isNaN v = 0 / 0-  | otherwise = fromRational $ toRational v---- | The result type of a binary operator.-binOpType :: BinOp -> PrimType-binOpType (Add t _) = IntType t-binOpType (Sub t _) = IntType t-binOpType (Mul t _) = IntType t-binOpType (SDiv t _) = IntType t-binOpType (SDivUp t _) = IntType t-binOpType (SMod t _) = IntType t-binOpType (SQuot t _) = IntType t-binOpType (SRem t _) = IntType t-binOpType (UDiv t _) = IntType t-binOpType (UDivUp t _) = IntType t-binOpType (UMod t _) = IntType t-binOpType (SMin t) = IntType t-binOpType (UMin t) = IntType t-binOpType (FMin t) = FloatType t-binOpType (SMax t) = IntType t-binOpType (UMax t) = IntType t-binOpType (FMax t) = FloatType t-binOpType (Shl t) = IntType t-binOpType (LShr t) = IntType t-binOpType (AShr t) = IntType t-binOpType (And t) = IntType t-binOpType (Or t) = IntType t-binOpType (Xor t) = IntType t-binOpType (Pow t) = IntType t-binOpType (FPow t) = FloatType t-binOpType LogAnd = Bool-binOpType LogOr = Bool-binOpType (FAdd t) = FloatType t-binOpType (FSub t) = FloatType t-binOpType (FMul t) = FloatType t-binOpType (FDiv t) = FloatType t-binOpType (FMod t) = FloatType t---- | The operand types of a comparison operator.-cmpOpType :: CmpOp -> PrimType-cmpOpType (CmpEq t) = t-cmpOpType (CmpSlt t) = IntType t-cmpOpType (CmpSle t) = IntType t-cmpOpType (CmpUlt t) = IntType t-cmpOpType (CmpUle t) = IntType t-cmpOpType (FCmpLt t) = FloatType t-cmpOpType (FCmpLe t) = FloatType t-cmpOpType CmpLlt = Bool-cmpOpType CmpLle = Bool---- | The operand and result type of a unary operator.-unOpType :: UnOp -> PrimType-unOpType (SSignum t) = IntType t-unOpType (USignum t) = IntType t-unOpType Not = Bool-unOpType (Complement t) = IntType t-unOpType (Abs t) = IntType t-unOpType (FAbs t) = FloatType t-unOpType (FSignum t) = FloatType t---- | The input and output types of a conversion operator.-convOpType :: ConvOp -> (PrimType, PrimType)-convOpType (ZExt from to) = (IntType from, IntType to)-convOpType (SExt from to) = (IntType from, IntType to)-convOpType (FPConv from to) = (FloatType from, FloatType to)-convOpType (FPToUI from to) = (FloatType from, IntType to)-convOpType (FPToSI from to) = (FloatType from, IntType to)-convOpType (UIToFP from to) = (IntType from, FloatType to)-convOpType (SIToFP from to) = (IntType from, FloatType to)-convOpType (IToB from) = (IntType from, Bool)-convOpType (BToI to) = (Bool, IntType to)-convOpType (FToB from) = (FloatType from, Bool)-convOpType (BToF to) = (Bool, FloatType to)--halfToWord :: Half -> Word16-halfToWord (Half (CUShort x)) = x--wordToHalf :: Word16 -> Half-wordToHalf = Half . CUShort--floatToWord :: Float -> Word32-floatToWord = G.runGet G.getWord32le . P.runPut . P.putFloatle--wordToFloat :: Word32 -> Float-wordToFloat = G.runGet G.getFloatle . P.runPut . P.putWord32le--doubleToWord :: Double -> Word64-doubleToWord = G.runGet G.getWord64le . P.runPut . P.putDoublele--wordToDouble :: Word64 -> Double-wordToDouble = G.runGet G.getDoublele . P.runPut . P.putWord64le---- | A mapping from names of primitive functions to their parameter--- types, their result type, and a function for evaluating them.-primFuns ::-  M.Map-    String-    ( [PrimType],-      PrimType,-      [PrimValue] -> Maybe PrimValue-    )-primFuns =-  M.fromList-    [ f16 "sqrt16" sqrt,-      f32 "sqrt32" sqrt,-      f64 "sqrt64" sqrt,-      ---      f16 "cbrt16" $ convFloat . cbrtf . convFloat,-      f32 "cbrt32" cbrtf,-      f64 "cbrt64" cbrt,-      ---      f16 "log16" log,-      f32 "log32" log,-      f64 "log64" log,-      ---      f16 "log10_16" (logBase 10),-      f32 "log10_32" (logBase 10),-      f64 "log10_64" (logBase 10),-      ---      f16 "log2_16" (logBase 2),-      f32 "log2_32" (logBase 2),-      f64 "log2_64" (logBase 2),-      ---      f16 "exp16" exp,-      f32 "exp32" exp,-      f64 "exp64" exp,-      ---      f16 "sin16" sin,-      f32 "sin32" sin,-      f64 "sin64" sin,-      ---      f16 "sinh16" sinh,-      f32 "sinh32" sinh,-      f64 "sinh64" sinh,-      ---      f16 "cos16" cos,-      f32 "cos32" cos,-      f64 "cos64" cos,-      ---      f16 "cosh16" cosh,-      f32 "cosh32" cosh,-      f64 "cosh64" cosh,-      ---      f16 "tan16" tan,-      f32 "tan32" tan,-      f64 "tan64" tan,-      ---      f16 "tanh16" tanh,-      f32 "tanh32" tanh,-      f64 "tanh64" tanh,-      ---      f16 "asin16" asin,-      f32 "asin32" asin,-      f64 "asin64" asin,-      ---      f16 "asinh16" asinh,-      f32 "asinh32" asinh,-      f64 "asinh64" asinh,-      ---      f16 "acos16" acos,-      f32 "acos32" acos,-      f64 "acos64" acos,-      ---      f16 "acosh16" acosh,-      f32 "acosh32" acosh,-      f64 "acosh64" acosh,-      ---      f16 "atan16" atan,-      f32 "atan32" atan,-      f64 "atan64" atan,-      ---      f16 "atanh16" atanh,-      f32 "atanh32" atanh,-      f64 "atanh64" atanh,-      ---      f16 "round16" $ convFloat . roundFloat . convFloat,-      f32 "round32" roundFloat,-      f64 "round64" roundDouble,-      ---      f16 "ceil16" $ convFloat . ceilFloat . convFloat,-      f32 "ceil32" ceilFloat,-      f64 "ceil64" ceilDouble,-      ---      f16 "floor16" $ convFloat . floorFloat . convFloat,-      f32 "floor32" floorFloat,-      f64 "floor64" floorDouble,-      ---      f16 "gamma16" $ convFloat . tgammaf . convFloat,-      f32 "gamma32" tgammaf,-      f64 "gamma64" tgamma,-      ---      f16 "lgamma16" $ convFloat . lgammaf . convFloat,-      f32 "lgamma32" lgammaf,-      f64 "lgamma64" lgamma,-      ---      ---      f16 "erf16" $ convFloat . erff . convFloat,-      f32 "erf32" erff,-      f64 "erf64" erf,-      ---      f16 "erfc16" $ convFloat . erfcf . convFloat,-      f32 "erfc32" erfcf,-      f64 "erfc64" erfc,-      ---      i8 "clz8" $ IntValue . Int32Value . fromIntegral . countLeadingZeros,-      i16 "clz16" $ IntValue . Int32Value . fromIntegral . countLeadingZeros,-      i32 "clz32" $ IntValue . Int32Value . fromIntegral . countLeadingZeros,-      i64 "clz64" $ IntValue . Int32Value . fromIntegral . countLeadingZeros,-      i8 "ctz8" $ IntValue . Int32Value . fromIntegral . countTrailingZeros,-      i16 "ctz16" $ IntValue . Int32Value . fromIntegral . countTrailingZeros,-      i32 "ctz32" $ IntValue . Int32Value . fromIntegral . countTrailingZeros,-      i64 "ctz64" $ IntValue . Int32Value . fromIntegral . countTrailingZeros,-      i8 "popc8" $ IntValue . Int32Value . fromIntegral . popCount,-      i16 "popc16" $ IntValue . Int32Value . fromIntegral . popCount,-      i32 "popc32" $ IntValue . Int32Value . fromIntegral . popCount,-      i64 "popc64" $ IntValue . Int32Value . fromIntegral . popCount,-      ( "mad_hi8",-        ( [IntType Int8, IntType Int8, IntType Int8],-          IntType Int8,-          \case-            [IntValue (Int8Value a), IntValue (Int8Value b), IntValue (Int8Value c)] ->-              Just $ IntValue . Int8Value $ mad_hi8 (Int8Value a) (Int8Value b) c-            _ -> Nothing-        )-      ),-      ( "mad_hi16",-        ( [IntType Int16, IntType Int16, IntType Int16],-          IntType Int16,-          \case-            [IntValue (Int16Value a), IntValue (Int16Value b), IntValue (Int16Value c)] ->-              Just $ IntValue . Int16Value $ mad_hi16 (Int16Value a) (Int16Value b) c-            _ -> Nothing-        )-      ),-      ( "mad_hi32",-        ( [IntType Int32, IntType Int32, IntType Int32],-          IntType Int32,-          \case-            [IntValue (Int32Value a), IntValue (Int32Value b), IntValue (Int32Value c)] ->-              Just $ IntValue . Int32Value $ mad_hi32 (Int32Value a) (Int32Value b) c-            _ -> Nothing-        )-      ),-      ( "mad_hi64",-        ( [IntType Int64, IntType Int64, IntType Int64],-          IntType Int64,-          \case-            [IntValue (Int64Value a), IntValue (Int64Value b), IntValue (Int64Value c)] ->-              Just $ IntValue . Int64Value $ mad_hi64 (Int64Value a) (Int64Value b) c-            _ -> Nothing-        )-      ),-      ( "mul_hi8",-        ( [IntType Int8, IntType Int8],-          IntType Int8,-          \case-            [IntValue (Int8Value a), IntValue (Int8Value b)] ->-              Just $ IntValue . Int8Value $ mul_hi8 (Int8Value a) (Int8Value b)-            _ -> Nothing-        )-      ),-      ( "mul_hi16",-        ( [IntType Int16, IntType Int16],-          IntType Int16,-          \case-            [IntValue (Int16Value a), IntValue (Int16Value b)] ->-              Just $ IntValue . Int16Value $ mul_hi16 (Int16Value a) (Int16Value b)-            _ -> Nothing-        )-      ),-      ( "mul_hi32",-        ( [IntType Int32, IntType Int32],-          IntType Int32,-          \case-            [IntValue (Int32Value a), IntValue (Int32Value b)] ->-              Just $ IntValue . Int32Value $ mul_hi32 (Int32Value a) (Int32Value b)-            _ -> Nothing-        )-      ),-      ( "mul_hi64",-        ( [IntType Int64, IntType Int64],-          IntType Int64,-          \case-            [IntValue (Int64Value a), IntValue (Int64Value b)] ->-              Just $ IntValue . Int64Value $ mul_hi64 (Int64Value a) (Int64Value b)-            _ -> Nothing-        )-      ),-      ---      ( "atan2_16",-        ( [FloatType Float16, FloatType Float16],-          FloatType Float16,-          \case-            [FloatValue (Float16Value x), FloatValue (Float16Value y)] ->-              Just $ FloatValue $ Float16Value $ atan2 x y-            _ -> Nothing-        )-      ),-      ( "atan2_32",-        ( [FloatType Float32, FloatType Float32],-          FloatType Float32,-          \case-            [FloatValue (Float32Value x), FloatValue (Float32Value y)] ->-              Just $ FloatValue $ Float32Value $ atan2 x y-            _ -> Nothing-        )-      ),-      ( "atan2_64",-        ( [FloatType Float64, FloatType Float64],-          FloatType Float64,-          \case-            [FloatValue (Float64Value x), FloatValue (Float64Value y)] ->-              Just $ FloatValue $ Float64Value $ atan2 x y-            _ -> Nothing-        )-      ),-      ---      ( "hypot16",-        ( [FloatType Float16, FloatType Float16],-          FloatType Float16,-          \case-            [FloatValue (Float16Value x), FloatValue (Float16Value y)] ->-              Just $ FloatValue $ Float16Value $ convFloat $ hypotf (convFloat x) (convFloat y)-            _ -> Nothing-        )-      ),-      ( "hypot32",-        ( [FloatType Float32, FloatType Float32],-          FloatType Float32,-          \case-            [FloatValue (Float32Value x), FloatValue (Float32Value y)] ->-              Just $ FloatValue $ Float32Value $ hypotf x y-            _ -> Nothing-        )-      ),-      ( "hypot64",-        ( [FloatType Float64, FloatType Float64],-          FloatType Float64,-          \case-            [FloatValue (Float64Value x), FloatValue (Float64Value y)] ->-              Just $ FloatValue $ Float64Value $ hypot x y-            _ -> Nothing-        )-      ),-      ( "isinf16",-        ( [FloatType Float16],-          Bool,-          \case-            [FloatValue (Float16Value x)] -> Just $ BoolValue $ isInfinite x-            _ -> Nothing-        )-      ),-      ( "isinf32",-        ( [FloatType Float32],-          Bool,-          \case-            [FloatValue (Float32Value x)] -> Just $ BoolValue $ isInfinite x-            _ -> Nothing-        )-      ),-      ( "isinf64",-        ( [FloatType Float64],-          Bool,-          \case-            [FloatValue (Float64Value x)] -> Just $ BoolValue $ isInfinite x-            _ -> Nothing-        )-      ),-      ( "isnan16",-        ( [FloatType Float16],-          Bool,-          \case-            [FloatValue (Float16Value x)] -> Just $ BoolValue $ isNaN x-            _ -> Nothing-        )-      ),-      ( "isnan32",-        ( [FloatType Float32],-          Bool,-          \case-            [FloatValue (Float32Value x)] -> Just $ BoolValue $ isNaN x-            _ -> Nothing-        )-      ),-      ( "isnan64",-        ( [FloatType Float64],-          Bool,-          \case-            [FloatValue (Float64Value x)] -> Just $ BoolValue $ isNaN x-            _ -> Nothing-        )-      ),-      ( "to_bits16",-        ( [FloatType Float16],-          IntType Int16,-          \case-            [FloatValue (Float16Value x)] ->-              Just $ IntValue $ Int16Value $ fromIntegral $ halfToWord x-            _ -> Nothing-        )-      ),-      ( "to_bits32",-        ( [FloatType Float32],-          IntType Int32,-          \case-            [FloatValue (Float32Value x)] ->-              Just $ IntValue $ Int32Value $ fromIntegral $ floatToWord x-            _ -> Nothing-        )-      ),-      ( "to_bits64",-        ( [FloatType Float64],-          IntType Int64,-          \case-            [FloatValue (Float64Value x)] ->-              Just $ IntValue $ Int64Value $ fromIntegral $ doubleToWord x-            _ -> Nothing-        )-      ),-      ( "from_bits16",-        ( [IntType Int16],-          FloatType Float16,-          \case-            [IntValue (Int16Value x)] ->-              Just $ FloatValue $ Float16Value $ wordToHalf $ fromIntegral x-            _ -> Nothing-        )-      ),-      ( "from_bits32",-        ( [IntType Int32],-          FloatType Float32,-          \case-            [IntValue (Int32Value x)] ->-              Just $ FloatValue $ Float32Value $ wordToFloat $ fromIntegral x-            _ -> Nothing-        )-      ),-      ( "from_bits64",-        ( [IntType Int64],-          FloatType Float64,-          \case-            [IntValue (Int64Value x)] ->-              Just $ FloatValue $ Float64Value $ wordToDouble $ fromIntegral x-            _ -> Nothing-        )-      ),-      f16_3 "lerp16" (\v0 v1 t -> v0 + (v1 - v0) * max 0 (min 1 t)),-      f32_3 "lerp32" (\v0 v1 t -> v0 + (v1 - v0) * max 0 (min 1 t)),-      f64_3 "lerp64" (\v0 v1 t -> v0 + (v1 - v0) * max 0 (min 1 t)),-      f16_3 "mad16" (\a b c -> a * b + c),-      f32_3 "mad32" (\a b c -> a * b + c),-      f64_3 "mad64" (\a b c -> a * b + c),-      f16_3 "fma16" (\a b c -> a * b + c),-      f32_3 "fma32" (\a b c -> a * b + c),-      f64_3 "fma64" (\a b c -> a * b + c)-    ]-  where-    i8 s f = (s, ([IntType Int8], IntType Int32, i8PrimFun f))-    i16 s f = (s, ([IntType Int16], IntType Int32, i16PrimFun f))-    i32 s f = (s, ([IntType Int32], IntType Int32, i32PrimFun f))-    i64 s f = (s, ([IntType Int64], IntType Int32, i64PrimFun f))-    f16 s f = (s, ([FloatType Float16], FloatType Float16, f16PrimFun f))-    f32 s f = (s, ([FloatType Float32], FloatType Float32, f32PrimFun f))-    f64 s f = (s, ([FloatType Float64], FloatType Float64, f64PrimFun f))-    f16_3 s f =-      ( s,-        ( [FloatType Float16, FloatType Float16, FloatType Float16],-          FloatType Float16,-          f16PrimFun3 f-        )-      )-    f32_3 s f =-      ( s,-        ( [FloatType Float32, FloatType Float32, FloatType Float32],-          FloatType Float32,-          f32PrimFun3 f-        )-      )-    f64_3 s f =-      ( s,-        ( [FloatType Float64, FloatType Float64, FloatType Float64],-          FloatType Float64,-          f64PrimFun3 f-        )-      )--    i8PrimFun f [IntValue (Int8Value x)] =-      Just $ f x-    i8PrimFun _ _ = Nothing--    i16PrimFun f [IntValue (Int16Value x)] =-      Just $ f x-    i16PrimFun _ _ = Nothing--    i32PrimFun f [IntValue (Int32Value x)] =-      Just $ f x-    i32PrimFun _ _ = Nothing--    i64PrimFun f [IntValue (Int64Value x)] =-      Just $ f x-    i64PrimFun _ _ = Nothing--    f16PrimFun f [FloatValue (Float16Value x)] =-      Just $ FloatValue $ Float16Value $ f x-    f16PrimFun _ _ = Nothing--    f32PrimFun f [FloatValue (Float32Value x)] =-      Just $ FloatValue $ Float32Value $ f x-    f32PrimFun _ _ = Nothing--    f64PrimFun f [FloatValue (Float64Value x)] =-      Just $ FloatValue $ Float64Value $ f x-    f64PrimFun _ _ = Nothing--    f16PrimFun3-      f-      [ FloatValue (Float16Value a),-        FloatValue (Float16Value b),-        FloatValue (Float16Value c)-        ] =-        Just $ FloatValue $ Float16Value $ f a b c-    f16PrimFun3 _ _ = Nothing--    f32PrimFun3-      f-      [ FloatValue (Float32Value a),-        FloatValue (Float32Value b),-        FloatValue (Float32Value c)-        ] =-        Just $ FloatValue $ Float32Value $ f a b c-    f32PrimFun3 _ _ = Nothing--    f64PrimFun3-      f-      [ FloatValue (Float64Value a),-        FloatValue (Float64Value b),-        FloatValue (Float64Value c)-        ] =-        Just $ FloatValue $ Float64Value $ f a b c-    f64PrimFun3 _ _ = Nothing---- | Is the given value kind of zero?-zeroIsh :: PrimValue -> Bool-zeroIsh (IntValue k) = zeroIshInt k-zeroIsh (FloatValue (Float16Value k)) = k == 0-zeroIsh (FloatValue (Float32Value k)) = k == 0-zeroIsh (FloatValue (Float64Value k)) = k == 0-zeroIsh (BoolValue False) = True-zeroIsh _ = False---- | Is the given value kind of one?-oneIsh :: PrimValue -> Bool-oneIsh (IntValue k) = oneIshInt k-oneIsh (FloatValue (Float16Value k)) = k == 1-oneIsh (FloatValue (Float32Value k)) = k == 1-oneIsh (FloatValue (Float64Value k)) = k == 1-oneIsh (BoolValue True) = True-oneIsh _ = False---- | Is the given value kind of negative?-negativeIsh :: PrimValue -> Bool-negativeIsh (IntValue k) = negativeIshInt k-negativeIsh (FloatValue (Float16Value k)) = k < 0-negativeIsh (FloatValue (Float32Value k)) = k < 0-negativeIsh (FloatValue (Float64Value k)) = k < 0-negativeIsh (BoolValue _) = False-negativeIsh UnitValue = False---- | Is the given integer value kind of zero?-zeroIshInt :: IntValue -> Bool-zeroIshInt (Int8Value k) = k == 0-zeroIshInt (Int16Value k) = k == 0-zeroIshInt (Int32Value k) = k == 0-zeroIshInt (Int64Value k) = k == 0---- | Is the given integer value kind of one?-oneIshInt :: IntValue -> Bool-oneIshInt (Int8Value k) = k == 1-oneIshInt (Int16Value k) = k == 1-oneIshInt (Int32Value k) = k == 1-oneIshInt (Int64Value k) = k == 1---- | Is the given integer value kind of negative?-negativeIshInt :: IntValue -> Bool-negativeIshInt (Int8Value k) = k < 0-negativeIshInt (Int16Value k) = k < 0-negativeIshInt (Int32Value k) = k < 0-negativeIshInt (Int64Value k) = k < 0---- | The size of a value of a given primitive type in bits.-primBitSize :: PrimType -> Int-primBitSize = (* 8) . primByteSize---- | The size of a value of a given primitive type in eight-bit bytes.-primByteSize :: Num a => PrimType -> a-primByteSize (IntType t) = intByteSize t-primByteSize (FloatType t) = floatByteSize t-primByteSize Bool = 1-primByteSize Unit = 0---- | The size of a value of a given integer type in eight-bit bytes.-intByteSize :: Num a => IntType -> a-intByteSize Int8 = 1-intByteSize Int16 = 2-intByteSize Int32 = 4-intByteSize Int64 = 8---- | The size of a value of a given floating-point type in eight-bit bytes.-floatByteSize :: Num a => FloatType -> a-floatByteSize Float16 = 2-floatByteSize Float32 = 4-floatByteSize Float64 = 8---- | True if the given binary operator is commutative.-commutativeBinOp :: BinOp -> Bool-commutativeBinOp Add {} = True-commutativeBinOp FAdd {} = True-commutativeBinOp Mul {} = True-commutativeBinOp FMul {} = True-commutativeBinOp And {} = True-commutativeBinOp Or {} = True-commutativeBinOp Xor {} = True-commutativeBinOp LogOr {} = True-commutativeBinOp LogAnd {} = True-commutativeBinOp SMax {} = True-commutativeBinOp SMin {} = True-commutativeBinOp UMax {} = True-commutativeBinOp UMin {} = True-commutativeBinOp FMax {} = True-commutativeBinOp FMin {} = True-commutativeBinOp _ = False---- | True if the given binary operator is associative.-associativeBinOp :: BinOp -> Bool-associativeBinOp Add {} = True-associativeBinOp Mul {} = True-associativeBinOp And {} = True-associativeBinOp Or {} = True-associativeBinOp Xor {} = True-associativeBinOp LogOr {} = True-associativeBinOp LogAnd {} = True-associativeBinOp SMax {} = True-associativeBinOp SMin {} = True-associativeBinOp UMax {} = True-associativeBinOp UMin {} = True-associativeBinOp FMax {} = True-associativeBinOp FMin {} = True-associativeBinOp _ = False---- Prettyprinting instances--instance Pretty BinOp where-  ppr (Add t OverflowWrap) = taggedI "add" t-  ppr (Add t OverflowUndef) = taggedI "add_nw" t-  ppr (Sub t OverflowWrap) = taggedI "sub" t-  ppr (Sub t OverflowUndef) = taggedI "sub_nw" t-  ppr (Mul t OverflowWrap) = taggedI "mul" t-  ppr (Mul t OverflowUndef) = taggedI "mul_nw" t-  ppr (FAdd t) = taggedF "fadd" t-  ppr (FSub t) = taggedF "fsub" t-  ppr (FMul t) = taggedF "fmul" t-  ppr (UDiv t Safe) = taggedI "udiv_safe" t-  ppr (UDiv t Unsafe) = taggedI "udiv" t-  ppr (UDivUp t Safe) = taggedI "udiv_up_safe" t-  ppr (UDivUp t Unsafe) = taggedI "udiv_up" t-  ppr (UMod t Safe) = taggedI "umod_safe" t-  ppr (UMod t Unsafe) = taggedI "umod" t-  ppr (SDiv t Safe) = taggedI "sdiv_safe" t-  ppr (SDiv t Unsafe) = taggedI "sdiv" t-  ppr (SDivUp t Safe) = taggedI "sdiv_up_safe" t-  ppr (SDivUp t Unsafe) = taggedI "sdiv_up" t-  ppr (SMod t Safe) = taggedI "smod_safe" t-  ppr (SMod t Unsafe) = taggedI "smod" t-  ppr (SQuot t Safe) = taggedI "squot_safe" t-  ppr (SQuot t Unsafe) = taggedI "squot" t-  ppr (SRem t Safe) = taggedI "srem_safe" t-  ppr (SRem t Unsafe) = taggedI "srem" t-  ppr (FDiv t) = taggedF "fdiv" t-  ppr (FMod t) = taggedF "fmod" t-  ppr (SMin t) = taggedI "smin" t-  ppr (UMin t) = taggedI "umin" t-  ppr (FMin t) = taggedF "fmin" t-  ppr (SMax t) = taggedI "smax" t-  ppr (UMax t) = taggedI "umax" t-  ppr (FMax t) = taggedF "fmax" t-  ppr (Shl t) = taggedI "shl" t-  ppr (LShr t) = taggedI "lshr" t-  ppr (AShr t) = taggedI "ashr" t-  ppr (And t) = taggedI "and" t-  ppr (Or t) = taggedI "or" t-  ppr (Xor t) = taggedI "xor" t-  ppr (Pow t) = taggedI "pow" t-  ppr (FPow t) = taggedF "fpow" t-  ppr LogAnd = text "logand"-  ppr LogOr = text "logor"--instance Pretty CmpOp where-  ppr (CmpEq t) = text "eq_" <> ppr t-  ppr (CmpUlt t) = taggedI "ult" t-  ppr (CmpUle t) = taggedI "ule" t-  ppr (CmpSlt t) = taggedI "slt" t-  ppr (CmpSle t) = taggedI "sle" t-  ppr (FCmpLt t) = taggedF "lt" t-  ppr (FCmpLe t) = taggedF "le" t-  ppr CmpLlt = text "llt"-  ppr CmpLle = text "lle"--instance Pretty ConvOp where-  ppr op = convOp (convOpFun op) from to-    where-      (from, to) = convOpType op--instance Pretty UnOp where-  ppr Not = text "not"-  ppr (Abs t) = taggedI "abs" t-  ppr (FAbs t) = taggedF "fabs" t-  ppr (SSignum t) = taggedI "ssignum" t-  ppr (USignum t) = taggedI "usignum" t-  ppr (FSignum t) = taggedF "fsignum" t-  ppr (Complement t) = taggedI "complement" t---- | The human-readable name for a 'ConvOp'.  This is used to expose--- the 'ConvOp' in the @intrinsics@ module of a Futhark program.-convOpFun :: ConvOp -> String-convOpFun ZExt {} = "zext"-convOpFun SExt {} = "sext"-convOpFun FPConv {} = "fpconv"-convOpFun FPToUI {} = "fptoui"-convOpFun FPToSI {} = "fptosi"-convOpFun UIToFP {} = "uitofp"-convOpFun SIToFP {} = "sitofp"-convOpFun IToB {} = "itob"-convOpFun BToI {} = "btoi"-convOpFun FToB {} = "ftob"-convOpFun BToF {} = "btof"--taggedI :: String -> IntType -> Doc-taggedI s Int8 = text $ s ++ "8"-taggedI s Int16 = text $ s ++ "16"-taggedI s Int32 = text $ s ++ "32"-taggedI s Int64 = text $ s ++ "64"--taggedF :: String -> FloatType -> Doc-taggedF s Float16 = text $ s ++ "16"-taggedF s Float32 = text $ s ++ "32"-taggedF s Float64 = text $ s ++ "64"--convOp :: (Pretty from, Pretty to) => String -> from -> to -> Doc-convOp s from to = text s <> text "_" <> ppr from <> text "_" <> ppr to---- | True if signed.  Only makes a difference for integer types.-prettySigned :: Bool -> PrimType -> String-prettySigned True (IntType it) = 'u' : drop 1 (pretty it)-prettySigned _ t = pretty t--mul_hi8 :: IntValue -> IntValue -> Int8-mul_hi8 a b =-  let a' = intToWord64 a-      b' = intToWord64 b-   in fromIntegral (shiftR (a' * b') 8)--mul_hi16 :: IntValue -> IntValue -> Int16-mul_hi16 a b =-  let a' = intToWord64 a-      b' = intToWord64 b-   in fromIntegral (shiftR (a' * b') 16)--mul_hi32 :: IntValue -> IntValue -> Int32-mul_hi32 a b =-  let a' = intToWord64 a-      b' = intToWord64 b-   in fromIntegral (shiftR (a' * b') 32)--mul_hi64 :: IntValue -> IntValue -> Int64-mul_hi64 a b =-  let a' = (toInteger . intToWord64) a-      b' = (toInteger . intToWord64) b-   in fromIntegral (shiftR (a' * b') 64)--mad_hi8 :: IntValue -> IntValue -> Int8 -> Int8-mad_hi8 a b c = mul_hi8 a b + c--mad_hi16 :: IntValue -> IntValue -> Int16 -> Int16-mad_hi16 a b c = mul_hi16 a b + c--mad_hi32 :: IntValue -> IntValue -> Int32 -> Int32-mad_hi32 a b c = mul_hi32 a b + c--mad_hi64 :: IntValue -> IntValue -> Int64 -> Int64-mad_hi64 a b c = mul_hi64 a b + c
− src/Futhark/IR/Primitive/Parse.hs
@@ -1,112 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}---- | Parsers for primitive values and types.  Mostly useful for--- "Futhark.IR.Parse", but can perhaps come in handy elsewhere too.-module Futhark.IR.Primitive.Parse-  ( pPrimValue,-    pPrimType,-    pFloatType,-    pIntType,--    -- * Building blocks-    constituent,-    lexeme,-    keyword,-    whitespace,-  )-where--import Data.Char (isAlphaNum)-import Data.Functor-import qualified Data.Text as T-import Data.Void-import Futhark.IR.Primitive-import Futhark.Util.Pretty hiding (empty)-import Text.Megaparsec-import Text.Megaparsec.Char-import qualified Text.Megaparsec.Char.Lexer as L---- | Is this character a valid member of an identifier?-constituent :: Char -> Bool-constituent c = isAlphaNum c || (c `elem` ("_/'+-=!&^.<>*|" :: String))---- | Consume whitespace (including skipping line comments).-whitespace :: Parsec Void T.Text ()-whitespace = L.space space1 (L.skipLineComment "--") empty---- | Consume whitespace after the provided parser, if it succeeds.-lexeme :: Parsec Void T.Text a -> Parsec Void T.Text a-lexeme = try . L.lexeme whitespace---- | @keyword k@ parses @k@, which must not be immediately followed by--- a 'constituent' character.  This ensures that @iff@ is not seen as--- the @if@ keyword followed by @f@.  Sometimes called the "maximum--- munch" rule.-keyword :: T.Text -> Parsec Void T.Text ()-keyword s = lexeme $ chunk s *> notFollowedBy (satisfy constituent)---- | Parse an integer value.-pIntValue :: Parsec Void T.Text IntValue-pIntValue = try $ do-  x <- L.signed (pure ()) L.decimal-  t <- pIntType-  pure $ intValue t (x :: Integer)---- | Parse a floating-point value.-pFloatValue :: Parsec Void T.Text FloatValue-pFloatValue =-  choice-    [ pNum,-      keyword "f16.nan" $> Float16Value (0 / 0),-      keyword "f16.inf" $> Float16Value (1 / 0),-      keyword "-f16.inf" $> Float16Value (-1 / 0),-      keyword "f32.nan" $> Float32Value (0 / 0),-      keyword "f32.inf" $> Float32Value (1 / 0),-      keyword "-f32.inf" $> Float32Value (-1 / 0),-      keyword "f64.nan" $> Float64Value (0 / 0),-      keyword "f64.inf" $> Float64Value (1 / 0),-      keyword "-f64.inf" $> Float64Value (-1 / 0)-    ]-  where-    pNum = try $ do-      x <- L.signed (pure ()) L.float-      t <- pFloatType-      pure $ floatValue t (x :: Double)---- | Parse a boolean value.-pBoolValue :: Parsec Void T.Text Bool-pBoolValue =-  choice-    [ keyword "true" $> True,-      keyword "false" $> False-    ]---- | Defined in this module for convenience.-pPrimValue :: Parsec Void T.Text PrimValue-pPrimValue =-  choice-    [ FloatValue <$> pFloatValue,-      IntValue <$> pIntValue,-      BoolValue <$> pBoolValue,-      UnitValue <$ "()"-    ]-    <?> "primitive value"---- | Parse a floating-point type.-pFloatType :: Parsec Void T.Text FloatType-pFloatType = choice $ map p allFloatTypes-  where-    p t = keyword (prettyText t) $> t---- | Parse an integer type.-pIntType :: Parsec Void T.Text IntType-pIntType = choice $ map p allIntTypes-  where-    p t = keyword (prettyText t) $> t---- | Parse a primitive type.-pPrimType :: Parsec Void T.Text PrimType-pPrimType =-  choice [p Bool, p Unit, FloatType <$> pFloatType, IntType <$> pIntType]-  where-    p t = keyword (prettyText t) $> t
src/Futhark/IR/Prop.hs view
@@ -5,10 +5,9 @@ {-# LANGUAGE TypeFamilies #-}  -- | This module provides various simple ways to query and manipulate--- fundamental Futhark terms, such as types and values.  The intent is to--- keep "Futhark.IRrsentation.AST.Syntax" simple, and put whatever--- embellishments we need here.  This is an internal, desugared--- representation.+-- fundamental Futhark terms, such as types and values.  The intent is+-- to keep "Futhark.IR.Syntax" simple, and put whatever embellishments+-- we need here.  This is an internal, desugared representation. module Futhark.IR.Prop   ( module Futhark.IR.Prop.Reshape,     module Futhark.IR.Prop.Rearrange,@@ -29,7 +28,6 @@     subExpVars,     subExpVar,     commutativeLambda,-    entryPointSize,     defAux,     stmCerts,     certify,@@ -171,15 +169,6 @@         && n2 == length (bodyResult body)         && all okComponent (zip3 xps yps $ bodyResult body) --- | How many value parameters are accepted by this entry point?  This--- is used to determine which of the function parameters correspond to--- the parameters of the original function (they must all come at the--- end).-entryPointSize :: EntryPointType -> Int-entryPointSize (TypeOpaque _ _ x) = x-entryPointSize (TypeUnsigned _) = 1-entryPointSize (TypeDirect _) = 1- -- | A 'StmAux' with empty 'Certs'. defAux :: dec -> StmAux dec defAux = StmAux mempty mempty@@ -240,7 +229,9 @@ expExtTypesFromPat :: Typed dec => Pat dec -> [ExtType] expExtTypesFromPat pat =   existentialiseExtTypes (patNames pat) $-    staticShapes $ map patElemType $ patElems pat+    staticShapes $+      map patElemType $+        patElems pat  -- | Keep only those attributes that are relevant for 'Assert' -- expressions.@@ -259,7 +250,9 @@       guard $ cs == mempty       Let (Pat [pe]) _ (BasicOp (BinOp op (Var x) (Var y))) <-         find (([res] ==) . patNames . stmPat) $-          stmsToList $ bodyStms $ lambdaBody lam+          stmsToList $+            bodyStms $+              lambdaBody lam       i <- Var res `elemIndex` map resSubExp (bodyResult (lambdaBody lam))       xp <- maybeNth i $ lambdaParams lam       yp <- maybeNth (n + i) $ lambdaParams lam
src/Futhark/IR/Prop/Constants.hs view
@@ -7,7 +7,8 @@   ) where -import Futhark.IR.Syntax.Core+import Futhark.IR.Syntax.Core (SubExp (..))+import Language.Futhark.Primitive  -- | If a Haskell type is an instance of 'IsValue', it means that a -- value of that type can be converted to a Futhark 'PrimValue'.
src/Futhark/IR/Prop/Names.hs view
@@ -299,7 +299,8 @@   FreeIn (Stm rep)   where   freeIn' (Let pat (StmAux cs attrs dec) e) =-    freeIn' cs <> freeIn' attrs+    freeIn' cs+      <> freeIn' attrs       <> precomputed dec (freeIn' dec <> freeIn' e <> freeIn' pat)  instance FreeIn (Stm rep) => FreeIn (Stms rep) where
src/Futhark/IR/Prop/Scope.hs view
@@ -88,7 +88,8 @@     where       notFound =         error $-          "Scope.lookupInfo: Name " ++ pretty name+          "Scope.lookupInfo: Name "+            ++ pretty name             ++ " not found in type environment."    -- | Return the type environment contained in the applicative
src/Futhark/IR/Prop/Types.hs view
@@ -376,9 +376,12 @@   TypeBase shape u ->   Bool subtypeOf (Array t1 shape1 u1) (Array t2 shape2 u2) =-  u2 <= u1-    && t1 == t2-    && shape1 `subShapeOf` shape2+  u2+    <= u1+    && t1+    == t2+    && shape1+    `subShapeOf` shape2 subtypeOf t1 t2 = t1 == t2  -- | @xs \`subtypesOf\` ys@ is true if @xs@ is the same size as @ys@,@@ -443,10 +446,7 @@  -- | The 'Ext' integers used for existential sizes in the given types. shapeContext :: [TypeBase ExtShape u] -> S.Set Int-shapeContext = S.fromList . concatMap (mapMaybe ext . shapeDims . arrayShape)-  where-    ext (Ext x) = Just x-    ext (Free _) = Nothing+shapeContext = S.fromList . concatMap (mapMaybe isExt . shapeDims . arrayShape)  -- | If all dimensions of the given 'ExtShape' are statically known, -- change to the corresponding t'Shape'.
src/Futhark/IR/Rep.hs view
@@ -12,7 +12,7 @@ import qualified Data.Kind import Futhark.IR.Prop.Types import Futhark.IR.RetType-import Futhark.IR.Syntax.Core+import Futhark.IR.Syntax.Core (DeclExtType, DeclType, ExtType, Type)  -- | A collection of type families giving various common types for a -- representation, along with constraints specifying that the types
src/Futhark/IR/RetType.hs view
@@ -64,7 +64,8 @@     if length args == length params       && and         ( zipWith subtypeOf argtypes $-            expectedTypes (map paramName params) params $ map fst args+            expectedTypes (map paramName params) params $+              map fst args         )       then Just $ map correctExtDims extret       else Nothing
src/Futhark/IR/SOACS/SOAC.hs view
@@ -40,6 +40,8 @@     scremaLambda,     ppScrema,     ppHist,+    ppStream,+    ppScatter,     groupScatterResults,     groupScatterResults',     splitScatterResults,@@ -405,15 +407,18 @@   SOAC frep ->   m (SOAC trep) mapSOACM tv (JVP lam args vec) =-  JVP <$> mapOnSOACLambda tv lam+  JVP+    <$> mapOnSOACLambda tv lam     <*> mapM (mapOnSOACSubExp tv) args     <*> mapM (mapOnSOACSubExp tv) vec mapSOACM tv (VJP lam args vec) =-  VJP <$> mapOnSOACLambda tv lam+  VJP+    <$> mapOnSOACLambda tv lam     <*> mapM (mapOnSOACSubExp tv) args     <*> mapM (mapOnSOACSubExp tv) vec mapSOACM tv (Stream size arrs form accs lam) =-  Stream <$> mapOnSOACSubExp tv size+  Stream+    <$> mapOnSOACSubExp tv size     <*> mapM (mapOnSOACVName tv) arrs     <*> mapOnStreamForm form     <*> mapM (mapOnSOACSubExp tv) accs@@ -430,7 +435,8 @@     <*> mapOnSOACLambda tv lam     <*> mapM       ( \(aw, an, a) ->-          (,,) <$> mapM (mapOnSOACSubExp tv) aw+          (,,)+            <$> mapM (mapOnSOACSubExp tv) aw             <*> pure an             <*> mapOnSOACVName tv a       )@@ -441,7 +447,8 @@     <*> mapM (mapOnSOACVName tv) arrs     <*> mapM       ( \(HistOp shape rf op_arrs nes op) ->-          HistOp <$> mapM (mapOnSOACSubExp tv) shape+          HistOp+            <$> mapM (mapOnSOACSubExp tv) shape             <*> mapOnSOACSubExp tv rf             <*> mapM (mapOnSOACVName tv) op_arrs             <*> mapM (mapOnSOACSubExp tv) nes@@ -450,19 +457,22 @@       ops     <*> mapOnSOACLambda tv bucket_fun mapSOACM tv (Screma w arrs (ScremaForm scans reds map_lam)) =-  Screma <$> mapOnSOACSubExp tv w+  Screma+    <$> mapOnSOACSubExp tv w     <*> mapM (mapOnSOACVName tv) arrs     <*> ( ScremaForm             <$> forM               scans               ( \(Scan red_lam red_nes) ->-                  Scan <$> mapOnSOACLambda tv red_lam+                  Scan+                    <$> mapOnSOACLambda tv red_lam                     <*> mapM (mapOnSOACSubExp tv) red_nes               )             <*> forM               reds               ( \(Reduce comm red_lam red_nes) ->-                  Reduce comm <$> mapOnSOACLambda tv red_lam+                  Reduce comm+                    <$> mapOnSOACLambda tv red_lam                     <*> mapM (mapOnSOACSubExp tv) red_nes               )             <*> mapOnSOACLambda tv map_lam@@ -474,6 +484,24 @@   where     mapper = identitySOACMapper {mapOnSOACLambda = traverseLambdaStms f} +instance ASTRep rep => FreeIn (Scan rep) where+  freeIn' (Scan lam ne) = freeIn' lam <> freeIn' ne++instance ASTRep rep => FreeIn (Reduce rep) where+  freeIn' (Reduce _ lam ne) = freeIn' lam <> freeIn' ne++instance ASTRep rep => FreeIn (ScremaForm rep) where+  freeIn' (ScremaForm scans reds lam) =+    freeIn' scans <> freeIn' reds <> freeIn' lam++instance ASTRep rep => FreeIn (StreamForm rep) where+  freeIn' Sequential = mempty+  freeIn' (Parallel _ _ lam) = freeIn' lam++instance ASTRep rep => FreeIn (HistOp rep) where+  freeIn' (HistOp w rf dests nes lam) =+    freeIn' w <> freeIn' rf <> freeIn' dests <> freeIn' nes <> freeIn' lam+ instance ASTRep rep => FreeIn (SOAC rep) where   freeIn' = flip execState mempty . mapSOACM free     where@@ -611,7 +639,7 @@  instance ASTRep rep => IsOp (SOAC rep) where   safeOp _ = False-  cheapOp _ = True+  cheapOp _ = False  substNamesInType :: M.Map VName SubExp -> Type -> Type substNamesInType _ t@Prim {} = t@@ -672,8 +700,26 @@  -- | Type-check a SOAC. typeCheckSOAC :: TC.Checkable rep => SOAC (Aliases rep) -> TC.TypeM rep ()-typeCheckSOAC JVP {} = pure ()-typeCheckSOAC VJP {} = pure ()+typeCheckSOAC (VJP lam args vec) = do+  args' <- mapM TC.checkArg args+  TC.checkLambda lam $ map TC.noArgAliases args'+  vec_ts <- mapM TC.checkSubExp vec+  unless (vec_ts == lambdaReturnType lam) $+    TC.bad . TC.TypeError . pretty $+      "Return type"+        </> PP.indent 2 (ppr (lambdaReturnType lam))+        </> "does not match type of seed vector"+        </> PP.indent 2 (ppr vec_ts)+typeCheckSOAC (JVP lam args vec) = do+  args' <- mapM TC.checkArg args+  TC.checkLambda lam $ map TC.noArgAliases args'+  vec_ts <- mapM TC.checkSubExp vec+  unless (vec_ts == map TC.argType args') $+    TC.bad . TC.TypeError . pretty $+      "Parameter type"+        </> PP.indent 2 (ppr $ map TC.argType args')+        </> "does not match type of seed vector"+        </> PP.indent 2 (ppr vec_ts) typeCheckSOAC (Stream size arrexps form accexps lam) = do   TC.require [Prim int64] size   accargs <- mapM TC.checkArg accexps@@ -686,7 +732,8 @@   let acc_len = length accexps   let lamrtp = take acc_len $ lambdaReturnType lam   unless (map TC.argType accargs == lamrtp) $-    TC.bad $ TC.TypeError "Stream with inconsistent accumulator type in lambda."+    TC.bad $+      TC.TypeError "Stream with inconsistent accumulator type in lambda."   -- check reduce's lambda, if any   _ <- case form of     Parallel _ _ lam0 -> do@@ -696,7 +743,8 @@       unless (acct == outerRetType) $         TC.bad $           TC.TypeError $-            "Initial value is of type " ++ prettyTuple acct+            "Initial value is of type "+              ++ prettyTuple acct               ++ ", but stream's reduce lambda returns type "               ++ prettyTuple outerRetType               ++ "."@@ -739,12 +787,14 @@    -- 1.   unless (length rts == sum as_ns + sum (zipWith (*) as_ns $ map length as_ws)) $-    TC.bad $ TC.TypeError "Scatter: number of index types, value types and array outputs do not match."+    TC.bad $+      TC.TypeError "Scatter: number of index types, value types and array outputs do not match."    -- 2.   forM_ rtsI $ \rtI ->     unless (Prim int64 == rtI) $-      TC.bad $ TC.TypeError "Scatter: Index return type must be i64."+      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 i64.@@ -840,10 +890,11 @@     ( take (length scan_nes' + length red_nes') map_lam_ts         == map TC.argType (scan_nes' ++ red_nes')     )-    $ TC.bad $-      TC.TypeError $-        "Map function return type " ++ prettyTuple map_lam_ts-          ++ " wrong for given scan and reduction functions."+    $ TC.bad+    $ TC.TypeError+    $ "Map function return type "+      ++ prettyTuple map_lam_ts+      ++ " wrong for given scan and reduction functions."  instance OpMetrics (Op rep) => OpMetrics (SOAC rep) where   opMetrics (VJP lam _ _) =@@ -880,36 +931,9 @@               </> PP.braces (commasep $ map ppr vec)         )   ppr (Stream size arrs form acc lam) =-    case form of-      Parallel o comm lam0 ->-        let ord_str = if o == Disorder then "Per" else ""-            comm_str = case comm of-              Commutative -> "Comm"-              Noncommutative -> ""-         in text ("streamPar" ++ ord_str ++ comm_str)-              <> parens-                ( ppr size <> comma-                    </> ppTuple' arrs <> comma-                    </> ppr lam0 <> comma-                    </> ppTuple' acc <> comma-                    </> ppr lam-                )-      Sequential ->-        text "streamSeq"-          <> parens-            ( ppr size <> comma-                </> ppTuple' arrs <> comma-                </> ppTuple' acc <> comma-                </> ppr lam-            )+    ppStream size arrs form acc lam   ppr (Scatter w arrs lam dests) =-    "scatter"-      <> parens-        ( ppr w <> comma-            </> ppTuple' arrs <> comma-            </> ppr lam <> comma-            </> commasep (map ppr dests)-        )+    ppScatter w arrs lam dests   ppr (Hist w arrs ops bucket_fun) =     ppHist w arrs ops bucket_fun   ppr (Screma w arrs (ScremaForm scans reds map_lam))@@ -952,6 +976,45 @@           </> ppr map_lam       ) +-- | Prettyprint the given Stream.+ppStream ::+  (PrettyRep rep, Pretty inp) => SubExp -> [inp] -> StreamForm rep -> [SubExp] -> Lambda rep -> Doc+ppStream size arrs form acc lam =+  case form of+    Parallel o comm lam0 ->+      let ord_str = if o == Disorder then "Per" else ""+          comm_str = case comm of+            Commutative -> "Comm"+            Noncommutative -> ""+       in text ("streamPar" ++ ord_str ++ comm_str)+            <> parens+              ( ppr size <> comma+                  </> ppTuple' arrs <> comma+                  </> ppr lam0 <> comma+                  </> ppTuple' acc <> comma+                  </> ppr lam+              )+    Sequential ->+      text "streamSeq"+        <> parens+          ( ppr size <> comma+              </> ppTuple' arrs <> comma+              </> ppTuple' acc <> comma+              </> ppr lam+          )++-- | Prettyprint the given Scatter.+ppScatter ::+  (PrettyRep rep, Pretty inp) => SubExp -> [inp] -> Lambda rep -> [(Shape, Int, VName)] -> Doc+ppScatter w arrs lam dests =+  "scatter"+    <> parens+      ( ppr w <> comma+          </> ppTuple' arrs <> comma+          </> ppr lam <> comma+          </> commasep (map ppr dests)+      )+ instance PrettyRep rep => Pretty (Scan rep) where   ppr (Scan scan_lam scan_nes) =     ppr scan_lam <> comma </> PP.braces (commasep $ map ppr scan_nes)@@ -983,6 +1046,8 @@       )   where     ppOp (HistOp dest_w rf dests nes op) =-      ppr dest_w <> comma <+> ppr rf <> comma <+> PP.braces (commasep $ map ppr dests) <> comma+      ppr dest_w <> comma+        <+> ppr rf <> comma+        <+> PP.braces (commasep $ map ppr dests) <> comma         </> ppTuple' nes <> comma         </> ppr op
src/Futhark/IR/SOACS/Simplify.hs view
@@ -147,7 +147,8 @@   (map_lam', map_lam_hoisted) <- Engine.enterLoop $ Engine.simplifyLambda map_lam    (,)-    <$> ( Screma <$> Engine.simplify w+    <$> ( Screma+            <$> Engine.simplify w             <*> Engine.simplify arrs             <*> pure (ScremaForm scans' reds' map_lam')         )@@ -251,7 +252,8 @@     onStm (Let se_pat se_aux (BasicOp (SubExp se))) = do       let (invariant, variant) =             partition (`ST.elem` vtable) $-              unCerts $ stmAuxCerts se_aux+              unCerts $+                stmAuxCerts se_aux           se_aux' = se_aux {stmAuxCerts = Certs variant}       modify (Certs invariant <>)       pure $ Let se_pat se_aux' $ BasicOp $ SubExp se@@ -308,7 +310,10 @@                   }           mapM_ (uncurry letBind) invariant           auxing aux $-            letBindNames (map patElemName pat') $ Op $ soacOp $ Screma w arrs (mapSOAC fun')+            letBindNames (map patElemName pat') $+              Op $+                soacOp $+                  Screma w arrs (mapSOAC fun') liftIdentityMapping _ _ _ _ = Skip  liftIdentityStreaming :: BottomUpRuleOp (Wise SOACS)@@ -328,7 +333,8 @@        auxing aux $         letBind (Pat $ fold_pes ++ variant_map_pes) $-          Op $ Stream w arrs form nes lam'+          Op $+            Stream w arrs form nes lam'   where     num_folds = length nes     (fold_pes, map_pes) = splitAt num_folds pes@@ -391,7 +397,7 @@     isReplicateAndNotConsumed p v       | Just (BasicOp (Replicate (Shape (_ : ds)) e), v_cs) <-           ST.lookupExp v vtable,-        not $ paramName p `nameIn` consumedByLambda fun =+        paramName p `notNameIn` consumedByLambda fun =           Right             ( [paramName p],               v_cs,@@ -437,7 +443,10 @@        in if map_pes /= map_pes'             then               Simplify . auxing aux $-                letBind (Pat $ nonmap_pes <> map_pes') $ Op $ Screma w arrs $ ScremaForm scans reds lam'+                letBind (Pat $ nonmap_pes <> map_pes') $+                  Op $+                    Screma w arrs $+                      ScremaForm scans reds lam'             else Skip   where     num_nonmap_res = scanResults scans + redResults reds@@ -546,7 +555,7 @@             (zip redlam_params $ map resSubExp $ redlam_res <> redlam_res)             redlam_deps,     let alive_mask = map ((`nameIn` necessary) . paramName) redlam_params,-    not $ all (== True) alive_mask = Simplify $ do+    not $ all (== True) (take (length nes) alive_mask) = Simplify $ do       let fixDeadToNeutral lives ne = if lives then Nothing else Just ne           dead_fix = zipWith fixDeadToNeutral alive_mask nes           (used_red_pes, _, used_nes) =@@ -558,7 +567,9 @@        auxing aux $         letBind (Pat $ used_red_pes ++ map_pes) $-          Op $ Screma w arrs $ redomapSOAC [Reduce comm redlam' used_nes] maplam'+          Op $+            Screma w arrs $+              redomapSOAC [Reduce comm redlam' used_nes] maplam' removeDeadReduction _ _ _ _ = Skip  -- | If we are writing to an array that is never used, get rid of it.@@ -577,7 +588,9 @@    in if pat /= Pat pat'         then           Simplify . auxing aux $-            letBind (Pat pat') $ Op $ Scatter w arrs fun' dests'+            letBind (Pat pat') $+              Op $+                Scatter w arrs fun' dests'         else Skip removeDeadWrite _ _ _ _ = Skip @@ -602,7 +615,8 @@                 lambdaReturnType = mix its <> mix vts               }       certifying (mconcat css) . letBind pat . Op $-        Scatter w' (concat xivs) fun' $ map (incWrites r) dests+        Scatter w' (concat xivs) fun' $+          map (incWrites r) dests   where     sizeOf :: VName -> Maybe SubExp     sizeOf x = arraySize 0 . typeOf <$> ST.lookup x vtable@@ -647,10 +661,15 @@           bindMapParam p a = do             a_t <- lookupType a             letBindNames [paramName p] $-              BasicOp $ Index a $ fullSlice a_t [DimFix $ constant (0 :: Int64)]+              BasicOp $+                Index a $+                  fullSlice a_t [DimFix $ constant (0 :: Int64)]           bindArrayResult pe (SubExpRes cs se) =             certifying cs . letBindNames [patElemName pe] $-              BasicOp $ ArrayLit [se] $ rowType $ patElemType pe+              BasicOp $+                ArrayLit [se] $+                  rowType $+                    patElemType pe           bindResult pe (SubExpRes cs se) =             certifying cs $ letBindNames [patElemName pe] $ BasicOp $ SubExp se @@ -671,7 +690,9 @@             partitionChunkedFoldParameters (length nes) (lambdaParams fold_lam)        letBindNames [paramName chunk_param] $-        BasicOp $ SubExp $ intConst Int64 1+        BasicOp $+          SubExp $+            intConst Int64 1        forM_ (zip acc_params nes) $ \(p, ne) ->         letBindNames [paramName p] $ BasicOp $ SubExp ne@@ -815,7 +836,8 @@     Just (p, _) <- find isIota (zip (lambdaParams map_lam) arrs),     indexings <-       mapMaybe (indexesWith (paramName p)) . S.toList $-        arrayOps $ lambdaBody map_lam,+        arrayOps $+          lambdaBody map_lam,     not $ null indexings = Simplify $ do       -- For each indexing with iota, add the corresponding array to       -- the Screma, and construct a new lambda parameter.@@ -897,7 +919,9 @@               }        auxing aux $-        letBind screma_pat $ Op $ Screma w (arrs <> more_arrs) (ScremaForm scan reduce map_lam')+        letBind screma_pat $+          Op $+            Screma w (arrs <> more_arrs) (ScremaForm scan reduce map_lam')   where     -- It is not safe to move the transform if the root array is being     -- consumed by the Screma.  This is a bit too conservative - it's@@ -936,7 +960,7 @@      mapOverArr (pat, op)       | Just (_, arr) <- find ((== arrayOpArr op) . fst) (zip map_param_names arrs),-        not $ arr `nameIn` consumed = do+        arr `notNameIn` consumed = do           arr_t <- lookupType arr           let whole_dim = DimSlice (intConst Int64 0) (arraySize 0 arr_t) (intConst Int64 1)           arr_transformed <- certifying (arrayOpCerts op) $
src/Futhark/IR/SegOp.hs view
@@ -149,7 +149,8 @@ histType :: HistOp rep -> [Type] histType op =   map (`arrayOfShape` (histShape op <> histOpShape op)) $-    lambdaReturnType $ histOp op+    lambdaReturnType $+      histOp op  -- | Split reduction results returned by a 'KernelBody' into those -- that correspond to indexes for the 'HistOp's, and those that@@ -378,7 +379,8 @@     unless (length ts == length kres) $       TC.bad $         TC.TypeError $-          "Kernel return type is " ++ prettyTuple ts+          "Kernel return type is "+            ++ prettyTuple ts             ++ ", but body returns "             ++ show (length kres)             ++ " values."@@ -419,7 +421,9 @@       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+        TC.bad $+          TC.TypeError $+            "Invalid type for ConcatReturns " ++ pretty v     checkKernelResult (TileReturns cs dims v) t = do       TC.checkCerts cs       forM_ dims $ \(dim, tile) -> do@@ -427,7 +431,9 @@         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+        TC.bad $+          TC.TypeError $+            "Invalid type for TileReturns " ++ pretty v     checkKernelResult (RegTileReturns cs dims_n_tiles arr) t = do       TC.checkCerts cs       mapM_ (TC.require [Prim int64]) dims@@ -452,7 +458,8 @@ instance PrettyRep rep => Pretty (KernelBody rep) where   ppr (KernelBody _ stms res) =     PP.stack (map ppr (stmsToList stms))-      </> text "return" <+> PP.braces (PP.commasep $ map ppr res)+      </> text "return"+      <+> PP.braces (PP.commasep $ map ppr res)  certAnnots :: Certs -> [PP.Doc] certAnnots cs@@ -469,8 +476,11 @@   ppr (WriteReturns cs shape arr res) =     PP.spread $       certAnnots cs-        ++ [ ppr arr <+> PP.colon <+> ppr shape-               </> "with" <+> PP.apply (map ppRes res)+        ++ [ ppr arr+               <+> PP.colon+               <+> ppr shape+               </> "with"+               <+> PP.apply (map ppRes res)            ]     where       ppRes (slice, e) = ppr slice <+> text "=" <+> ppr e@@ -478,13 +488,15 @@     PP.spread $       certAnnots cs         ++ [ "concat"-               <> parens (commasep [ppr w, ppr per_thread_elems]) <+> ppr v+               <> parens (commasep [ppr w, ppr per_thread_elems])+               <+> ppr v            ]   ppr (ConcatReturns cs (SplitStrided stride) w per_thread_elems v) =     PP.spread $       certAnnots cs         ++ [ "concat_strided"-               <> parens (commasep [ppr stride, ppr w, ppr per_thread_elems]) <+> ppr v+               <> parens (commasep [ppr stride, ppr w, ppr per_thread_elems])+               <+> ppr v            ]   ppr (TileReturns cs dims v) =     PP.spread $ certAnnots cs ++ ["tile" <> parens (commasep $ map onDim dims) <+> ppr v]@@ -760,7 +772,8 @@       let nes_t = map TC.argType nes'        unless (lambdaReturnType lam == nes_t) $-        TC.bad $ TC.TypeError "wrong type for operator or neutral elements."+        TC.bad $+          TC.TypeError "wrong type for operator or neutral elements."        pure $ map (`arrayOfShape` shape) nes_t @@ -850,7 +863,8 @@     <*> mapOnSegOpBody tv body   where     onHistOp (HistOp w rf arrs nes shape op) =-      HistOp <$> mapM (mapOnSegOpSubExp tv) w+      HistOp+        <$> mapM (mapOnSegOpSubExp tv) w         <*> mapOnSegOpSubExp tv rf         <*> mapM (mapOnSegOpVName tv) arrs         <*> mapM (mapOnSegOpSubExp tv) nes@@ -914,7 +928,8 @@   where   freeIn' e =     fvBind (namesFromList $ M.keys $ scopeOfSegSpace (segSpace e)) $-      flip execState mempty $ mapSegOpM free e+      flip execState mempty $+        mapSegOpM free e     where       walk f x = modify (<> f x) >> pure x       free =@@ -991,7 +1006,8 @@       <+> PP.nestedBlock "{" "}" (ppr body)     where       ppOp (HistOp w rf dests nes shape op) =-        ppr w <> PP.comma <+> ppr rf <> PP.comma+        ppr w <> PP.comma+          <+> ppr rf <> PP.comma           </> PP.braces (PP.commasep $ map ppr dests) <> PP.comma           </> PP.braces (PP.commasep $ map ppr nes) <> PP.comma           </> ppr shape <> PP.comma@@ -1124,7 +1140,8 @@   simplify (Returns manifest cs what) =     Returns manifest <$> Engine.simplify cs <*> Engine.simplify what   simplify (WriteReturns cs ws a res) =-    WriteReturns <$> Engine.simplify cs+    WriteReturns+      <$> Engine.simplify cs       <*> Engine.simplify ws       <*> Engine.simplify a       <*> Engine.simplify res@@ -1188,7 +1205,8 @@       . Engine.localVtable (<> scope_vtable)       . Engine.localVtable (\vtable -> vtable {ST.simplifyMemory = True})       . Engine.enterLoop-      $ Engine.blockIf blocker stms $ do+      $ Engine.blockIf blocker stms+      $ do         res' <-           Engine.localVtable (ST.hideCertified $ namesFromList $ M.keys $ scopeOf stms) $             mapM Engine.simplify res@@ -1351,7 +1369,10 @@    kbody <- mkKernelBodyM kstms kres'   addStm $-    Let (Pat kpes') dec $ Op $ segOp $ SegMap lvl space ts' kbody+    Let (Pat kpes') dec $+      Op $+        segOp $+          SegMap lvl space ts' kbody   where     isInvariant Constant {} = True     isInvariant (Var v) = isJust $ ST.lookup v vtable@@ -1361,7 +1382,8 @@         rm == ResultMaySimplify,         isInvariant se = do           letBindNames [patElemName pe] $-            BasicOp $ Replicate (Shape $ segSpaceDims space) se+            BasicOp $+              Replicate (Shape $ segSpaceDims space) se           pure False     checkForInvarianceResult _ =       pure True@@ -1403,7 +1425,8 @@           lam =             Lambda               { lambdaParams =-                  op1_xparams ++ op2_xparams+                  op1_xparams+                    ++ op2_xparams                     ++ op1_yparams                     ++ op2_yparams,                 lambdaReturnType = lambdaReturnType lam1 ++ lambdaReturnType lam2,@@ -1502,9 +1525,12 @@                   $ segSpaceDims space               index kpe' =                 letBindNames [patElemName kpe'] . BasicOp . Index arr $-                  Slice $ outer_slice <> remaining_slice-          if patElemName kpe `UT.isConsumed` used-            || arr `nameIn` consumed_in_segop+                  Slice $+                    outer_slice <> remaining_slice+          if patElemName kpe+            `UT.isConsumed` used+            || arr+            `nameIn` consumed_in_segop             then do               precopy <- newVName $ baseString (patElemName kpe) <> "_precopy"               index kpe {patElemName = precopy}
src/Futhark/IR/Syntax.hs view
@@ -32,7 +32,7 @@ -- curly braces. -- -- The system of primitive types is interesting in itself.  See--- "Futhark.IR.Primitive".+-- "Language.Futhark.Primitive". -- -- == Overall AST design --@@ -147,9 +147,9 @@     FParam,     LParam,     FunDef (..),-    EntryPoint,     EntryParam (..),-    EntryPointType (..),+    EntryResult (..),+    EntryPoint,     Prog (..),      -- * Utils@@ -525,37 +525,35 @@  deriving instance RepTypes rep => Ord (FunDef rep) --- | Every entry point argument and return value has an annotation--- indicating how it maps to the original source program type.-data EntryPointType-  = -- | Is an unsigned integer or array of unsigned-    -- integers.-    TypeUnsigned Uniqueness-  | -- | A black box type comprising this many core-    -- values.  The string is a human-readable-    -- description with no other semantics.-    TypeOpaque Uniqueness String Int-  | -- | Maps directly.-    TypeDirect Uniqueness-  deriving (Eq, Show, Ord)- -- | An entry point parameter, comprising its name and original type. data EntryParam = EntryParam   { entryParamName :: Name,+    entryParamUniqueness :: Uniqueness,     entryParamType :: EntryPointType   }   deriving (Eq, Show, Ord) +-- | An entry point result type.+data EntryResult = EntryResult+  { entryResultUniqueness :: Uniqueness,+    entryResultType :: EntryPointType+  }+  deriving (Eq, Show, Ord)+ -- | Information about the inputs and outputs (return value) of an entry -- point.-type EntryPoint = (Name, [EntryParam], [EntryPointType])+type EntryPoint = (Name, [EntryParam], [EntryResult])  -- | An entire Futhark program. data Prog rep = Prog-  { -- | Top-level constants that are computed at program startup, and+  { -- | The opaque types used in entry points.  This information is+    -- used to generate extra API functions for+    -- construction and deconstruction of values of these types.+    progTypes :: OpaqueTypes,+    -- | Top-level constants that are computed at program startup, and     -- which are in scope inside all functions.     progConsts :: Stms rep,-    -- | The functions comprising the program.  All funtions are also+    -- | The functions comprising the program.  All functions are also     -- available in scope in the definitions of the constants, so be     -- careful not to introduce circular dependencies (not currently     -- checked).
src/Futhark/IR/Syntax/Core.hs view
@@ -11,7 +11,7 @@ -- there should be no reason to include it explicitly. module Futhark.IR.Syntax.Core   ( module Language.Futhark.Core,-    module Futhark.IR.Primitive,+    module Language.Futhark.Primitive,      -- * Types     Commutativity (..),@@ -37,6 +37,13 @@     ErrorMsgPart (..),     errorMsgArgTypes, +    -- * Entry point information+    ValueType (..),+    OpaqueType (..),+    OpaqueTypes (..),+    Signedness (..),+    EntryPointType (..),+     -- * Attributes     Attr (..),     Attrs (..),@@ -81,8 +88,8 @@ import qualified Data.Set as S import Data.String import Data.Traversable (fmapDefault, foldMapDefault)-import Futhark.IR.Primitive import Language.Futhark.Core+import Language.Futhark.Primitive import Prelude hiding (id, (.))  -- | Whether some operator is commutative or not.  The 'Monoid'@@ -558,3 +565,48 @@ -- | Map a function over an attribute set. mapAttrs :: (Attr -> a) -> Attrs -> [a] mapAttrs f (Attrs attrs) = map f $ S.toList attrs++-- | Since the core language does not care for signedness, but the+-- source language does, entry point input/output information has+-- metadata for integer types (and arrays containing these) that+-- indicate whether they are really unsigned integers.  This doesn't+-- matter for non-integer types.+data Signedness+  = Unsigned+  | Signed+  deriving (Eq, Ord, Show)++-- | An actual non-opaque type that can be passed to and from Futhark+-- programs, or serve as the contents of opaque types.  Scalars are+-- represented with zero rank.+data ValueType+  = ValueType Signedness Rank PrimType+  deriving (Eq, Ord, Show)++-- | Every entry point argument and return value has an annotation+-- indicating how it maps to the original source program type.+data EntryPointType+  = -- | An opaque type of this name.+    TypeOpaque String+  | -- | A transparent type, which is scalar if the rank is zero.+    TypeTransparent ValueType+  deriving (Eq, Show, Ord)++-- | The representation of an opaque type.+data OpaqueType+  = OpaqueType [ValueType]+  | -- | Note that the field ordering here denote the actual+    -- representation - make sure it is preserved.+    OpaqueRecord [(Name, EntryPointType)]+  deriving (Eq, Ord, Show)++-- | Names of opaque types and their representation.+newtype OpaqueTypes = OpaqueTypes [(String, OpaqueType)]+  deriving (Eq, Ord, Show)++instance Monoid OpaqueTypes where+  mempty = OpaqueTypes mempty++instance Semigroup OpaqueTypes where+  OpaqueTypes x <> OpaqueTypes y =+    OpaqueTypes $ x <> filter ((`notElem` map fst x) . fst) y
src/Futhark/IR/Traversals.hs view
@@ -91,7 +91,8 @@   BasicOp <$> (SubExp <$> mapOnSubExp tv se) mapExpM tv (BasicOp (ArrayLit els rowt)) =   BasicOp-    <$> ( ArrayLit <$> mapM (mapOnSubExp tv) els+    <$> ( ArrayLit+            <$> mapM (mapOnSubExp tv) els             <*> mapOnType (mapOnSubExp tv) rowt         ) mapExpM tv (BasicOp (BinOp bop x y)) =@@ -103,7 +104,10 @@ mapExpM tv (BasicOp (UnOp op x)) =   BasicOp <$> (UnOp op <$> mapOnSubExp tv x) mapExpM tv (If c texp fexp (IfDec ts s)) =-  If <$> mapOnSubExp tv c <*> mapOnBody tv mempty texp <*> mapOnBody tv mempty fexp+  If+    <$> mapOnSubExp tv c+    <*> mapOnBody tv mempty texp+    <*> mapOnBody tv mempty fexp     <*> (IfDec <$> mapM (mapOnBranchType tv) ts <*> pure s) mapExpM tv (Apply fname args ret loc) = do   args' <- forM args $ \(arg, d) ->@@ -111,23 +115,27 @@   Apply fname args' <$> mapM (mapOnRetType tv) ret <*> pure loc mapExpM tv (BasicOp (Index arr slice)) =   BasicOp-    <$> ( Index <$> mapOnVName tv arr+    <$> ( Index+            <$> mapOnVName tv arr             <*> traverse (mapOnSubExp tv) slice         ) mapExpM tv (BasicOp (Update safety arr slice se)) =   BasicOp-    <$> ( Update safety <$> mapOnVName tv arr+    <$> ( Update safety+            <$> mapOnVName tv arr             <*> traverse (mapOnSubExp tv) slice             <*> mapOnSubExp tv se         ) mapExpM tv (BasicOp (FlatIndex arr slice)) =   BasicOp-    <$> ( FlatIndex <$> mapOnVName tv arr+    <$> ( FlatIndex+            <$> mapOnVName tv arr             <*> traverse (mapOnSubExp tv) slice         ) mapExpM tv (BasicOp (FlatUpdate arr slice se)) =   BasicOp-    <$> ( FlatUpdate <$> mapOnVName tv arr+    <$> ( FlatUpdate+            <$> mapOnVName tv arr             <*> traverse (mapOnSubExp tv) slice             <*> mapOnVName tv se         )@@ -171,7 +179,9 @@   WithAcc <$> mapM onInput inputs <*> mapOnLambda tv lam   where     onInput (shape, vs, op) =-      (,,) <$> mapOnShape tv shape <*> mapM (mapOnVName tv) vs+      (,,)+        <$> mapOnShape tv shape+        <*> mapM (mapOnVName tv) vs         <*> traverse (bitraverse (mapOnLambda tv) (mapM (mapOnSubExp tv))) op mapExpM tv (DoLoop merge form loopbody) = do   params' <- mapM (mapOnFParam tv) params@@ -195,7 +205,10 @@   LoopForm frep ->   m (LoopForm trep) mapOnLoopForm tv (ForLoop i it bound loop_vars) =-  ForLoop <$> mapOnVName tv i <*> pure it <*> mapOnSubExp tv bound+  ForLoop+    <$> mapOnVName tv i+    <*> pure it+    <*> mapOnSubExp tv bound     <*> (zip <$> mapM (mapOnLParam tv) loop_lparams <*> mapM (mapOnVName tv) loop_arrs)   where     (loop_lparams, loop_arrs) = unzip loop_vars@@ -259,7 +272,8 @@  walkOnLoopForm :: Monad m => Walker rep m -> LoopForm rep -> m () walkOnLoopForm tv (ForLoop i _ bound loop_vars) =-  walkOnVName tv i >> walkOnSubExp tv bound+  walkOnVName tv i+    >> walkOnSubExp tv bound     >> mapM_ (walkOnLParam tv) loop_lparams     >> mapM_ (walkOnVName tv) loop_arrs   where
src/Futhark/IR/TypeCheck.hs view
@@ -55,7 +55,6 @@ import Control.Monad.Reader import Control.Monad.State.Strict import Control.Parallel.Strategies-import Data.Bifunctor (second) import Data.List (find, intercalate, isPrefixOf, sort) import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.Map.Strict as M@@ -103,7 +102,8 @@       ++ pretty t       ++ "."   show (ReturnTypeError fname rettype bodytype) =-    "Declaration of function " ++ nameToString fname+    "Declaration of function "+      ++ nameToString fname       ++ " declares return type\n  "       ++ prettyTuple rettype       ++ "\nBut body has type\n  "@@ -111,14 +111,16 @@   show (DupDefinitionError name) =     "Duplicate definition of function " ++ nameToString name ++ ""   show (DupParamError funname paramname) =-    "Parameter " ++ pretty paramname+    "Parameter "+      ++ pretty paramname       ++ " mentioned multiple times in argument list of function "       ++ nameToString funname       ++ "."   show (DupPatError name) =     "Variable " ++ pretty name ++ " bound twice in pattern."   show (InvalidPatError pat t desc) =-    "Pat\n" ++ pretty pat+    "Pat\n"+      ++ pretty pat       ++ "\ncannot match value of type\n"       ++ prettyTupleLines t       ++ end@@ -131,7 +133,9 @@   show (UnknownFunctionError fname) =     "Call of unknown function " ++ nameToString fname ++ "."   show (ParameterMismatch fname expected got) =-    "In call of " ++ fname' ++ ":\n"+    "In call of "+      ++ fname'+      ++ ":\n"       ++ "expecting "       ++ show nexpected       ++ " arguments of type(s)\n"@@ -147,12 +151,16 @@   show (SlicingError dims got) =     show got ++ " indices given, but type of indexee has " ++ show dims ++ " dimension(s)."   show (BadAnnotation desc expected got) =-    "Annotation of \"" ++ desc ++ "\" type of expression is " ++ pretty expected+    "Annotation of \""+      ++ desc+      ++ "\" type of expression is "+      ++ pretty expected       ++ ", but derived to be "       ++ pretty got       ++ "."   show (ReturnAliased fname name) =-    "Unique return value of function " ++ nameToString fname+    "Unique return value of function "+      ++ nameToString fname       ++ " is aliased to "       ++ pretty name       ++ ", which is not consumed."@@ -161,12 +169,14 @@       ++ nameToString fname       ++ " is aliased to some other tuple component."   show (NotAnArray e t) =-    "The expression " ++ pretty e+    "The expression "+      ++ pretty e       ++ " is expected to be an array, but is "       ++ pretty t       ++ "."   show (PermutationError perm rank name) =-    "The permutation (" ++ intercalate ", " (map show perm)+    "The permutation ("+      ++ intercalate ", " (map show perm)       ++ ") is not valid for array "       ++ name'       ++ "of rank "@@ -284,12 +294,7 @@  -- | The type checker runs in this monad. newtype TypeM rep a-  = TypeM-      ( ReaderT-          (Env rep)-          (StateT TState (Either (TypeError rep)))-          a-      )+  = TypeM (ReaderT (Env rep) (StateT TState (Either (TypeError rep))) a)   deriving     ( Monad,       Functor,@@ -310,9 +315,9 @@ runTypeM ::   Env rep ->   TypeM rep a ->-  Either (TypeError rep) (a, Consumption)+  Either (TypeError rep) a runTypeM env (TypeM m) =-  second stateCons <$> runStateT (runReaderT m env) (TState mempty mempty)+  evalStateT (runReaderT m env) (TState mempty mempty)  -- | Signal a type error. bad :: ErrorCase rep -> TypeM rep a@@ -348,7 +353,9 @@ bound name = do   already_seen <- gets $ nameIn name . stateNames   when already_seen $-    bad $ TypeError $ "Name " ++ pretty name ++ " bound twice"+    bad $+      TypeError $+        "Name " ++ pretty name ++ " bound twice"   modify $ \s -> s {stateNames = oneName name <> stateNames s}  occur :: Occurences -> TypeM rep ()@@ -418,12 +425,10 @@     wasConsumed v       | Just als <- lookup v consumable = pure als       | otherwise =-          bad $-            TypeError $-              unlines-                [ pretty v ++ " was invalidly consumed.",-                  what ++ " can be consumed here."-                ]+          bad . TypeError . unlines $+            [ pretty v ++ " was invalidly consumed.",+              what ++ " can be consumed here."+            ]     what       | null consumable = "Nothing"       | otherwise = "Only " ++ intercalate ", " (map (pretty . fst) consumable)@@ -524,7 +529,8 @@ require ts se = do   t <- checkSubExp se   unless (t `elem` ts) $-    bad $ UnexpectedType (BasicOp $ SubExp se) t ts+    bad $+      UnexpectedType (BasicOp $ SubExp se) t ts  -- | Variant of 'require' working on variable names. requireI :: Checkable rep => [Type] -> VName -> TypeM rep ()@@ -555,6 +561,23 @@           ++ " should be an accumulator but is of type "           ++ pretty t +checkOpaques :: OpaqueTypes -> Either (TypeError rep) ()+checkOpaques (OpaqueTypes types) = descend [] types+  where+    descend _ [] = pure ()+    descend known ((name, t) : ts) = do+      check known t+      descend (name : known) ts+    check known (OpaqueRecord fs) =+      mapM_ (checkEntryPointType known . snd) fs+    check _ (OpaqueType _) =+      pure ()+    checkEntryPointType known (TypeOpaque s) =+      when (s `notElem` known) $+        Left . Error [] . TypeError $+          "Opaque not defined before first use: " <> s+    checkEntryPointType _ (TypeTransparent _) = pure ()+ -- | Type check a program containing arbitrary type information, -- yielding either a type error or a program with complete type -- information.@@ -562,7 +585,8 @@   Checkable rep =>   Prog (Aliases rep) ->   Either (TypeError rep) ()-checkProg (Prog consts funs) = do+checkProg (Prog opaques consts funs) = do+  checkOpaques opaques   let typeenv =         Env           { envVtable = M.empty,@@ -570,15 +594,15 @@             envContext = [],             envCheckOp = checkOp           }-  let onFunction ftable vtable fun =-        fmap fst $-          runTypeM typeenv $-            local (\env -> env {envFtable = ftable, envVtable = vtable}) $-              checkFun fun-  (ftable, _) <- runTypeM typeenv buildFtable-  (vtable, _) <--    runTypeM typeenv {envFtable = ftable} $-      checkStms consts $ asks envVtable+  let const_names = foldMap (patNames . stmPat) consts+      onFunction ftable vtable fun = runTypeM typeenv $ do+        modify $ \s -> s {stateNames = namesFromList const_names}+        local (\env -> env {envFtable = ftable, envVtable = vtable}) $+          checkFun fun+  ftable <-+    runTypeM typeenv buildFtable+  vtable <-+    runTypeM typeenv {envFtable = ftable} $ checkStms consts $ asks envVtable   sequence_ $ parMap rpar (onFunction ftable vtable) funs   where     buildFtable = do@@ -605,17 +629,17 @@   FunDef (Aliases rep) ->   TypeM rep () checkFun (FunDef _ _ fname rettype params body) =-  context ("In function " ++ nameToString fname) $-    checkFun'+  context ("In function " ++ nameToString fname)+    $ checkFun'       ( fname,         map declExtTypeOf rettype,         funParamsToNameInfos params       )       (Just consumable)-      $ do-        checkFunParams params-        checkRetType rettype-        context "When checking function body" $ checkFunBody rettype body+    $ do+      checkFunParams params+      checkRetType rettype+      context "When checking function body" $ checkFunBody rettype body   where     consumable =       [ (paramName param, mempty)@@ -669,7 +693,8 @@         ( "When checking the body aliases: "             ++ pretty (map namesToList body_aliases)         )-        $ checkReturnAlias $ map (namesFromList . filter isArray . namesToList) body_aliases+        $ checkReturnAlias+        $ map (namesFromList . filter isArray . namesToList) body_aliases   where     param_names = map fst params @@ -772,23 +797,24 @@   TypeM rep () checkLambdaResult ts es   | length ts /= length es =-      bad $-        TypeError $-          "Lambda has return type " ++ prettyTuple ts-            ++ " describing "-            ++ show (length ts)-            ++ " values, but body returns "-            ++ show (length es)-            ++ " values: "-            ++ prettyTuple es+      bad . TypeError $+        "Lambda has return type "+          ++ prettyTuple ts+          ++ " describing "+          ++ show (length ts)+          ++ " values, but body returns "+          ++ show (length es)+          ++ " values: "+          ++ prettyTuple es   | otherwise = forM_ (zip ts es) $ \(t, e) -> do       et <- checkSubExpRes e-      unless (et == t) $-        bad $-          TypeError $-            "Subexpression " ++ pretty e ++ " has type " ++ pretty et-              ++ " but expected "-              ++ pretty t+      unless (et == t) . bad . TypeError $+        "Subexpression "+          ++ pretty e+          ++ " has type "+          ++ pretty et+          ++ " but expected "+          ++ pretty t  checkBody ::   Checkable rep =>@@ -812,13 +838,11 @@ checkBasicOp (ArrayLit (e : es') t) = do   let check elemt eleme = do         elemet <- checkSubExp eleme-        unless (elemet == elemt) $-          bad $-            TypeError $-              pretty elemet-                ++ " is not of expected type "-                ++ pretty elemt-                ++ "."+        unless (elemet == elemt) . bad . TypeError $+          pretty elemet+            ++ " is not of expected type "+            ++ pretty elemt+            ++ "."   et <- checkSubExp e    -- Compare that type with the one given for the array literal.@@ -833,16 +857,19 @@   vt <- lookupType ident   observe ident   when (arrayRank vt /= length idxes) $-    bad $ SlicingError (arrayRank vt) (length idxes)+    bad $+      SlicingError (arrayRank vt) (length idxes)   mapM_ checkDimIndex idxes checkBasicOp (Update _ src (Slice idxes) se) = do   (src_shape, src_pt) <- checkArrIdent src   when (shapeRank src_shape /= length idxes) $-    bad $ SlicingError (shapeRank src_shape) (length idxes)+    bad $+      SlicingError (shapeRank src_shape) (length idxes)    se_aliases <- subExpAliasesM se   when (src `nameIn` se_aliases) $-    bad $ TypeError "The target of an Update must not alias the value to be written."+    bad $+      TypeError "The target of an Update must not alias the value to be written."    mapM_ checkDimIndex idxes   require [arrayOf (Prim src_pt) (Shape (sliceDims (Slice idxes))) NoUniqueness] se@@ -851,16 +878,19 @@   vt <- lookupType ident   observe ident   when (arrayRank vt /= 1) $-    bad $ SlicingError (arrayRank vt) 1+    bad $+      SlicingError (arrayRank vt) 1   checkFlatSlice slice checkBasicOp (FlatUpdate src slice v) = do   (src_shape, src_pt) <- checkArrIdent src   when (shapeRank src_shape /= 1) $-    bad $ SlicingError (shapeRank src_shape) 1+    bad $+      SlicingError (shapeRank src_shape) 1    v_aliases <- lookupAliases v   when (src `nameIn` v_aliases) $-    bad $ TypeError "The target of an Update must not alias the value to be written."+    bad $+      TypeError "The target of an Update must not alias the value to be written."    checkFlatSlice slice   requireI [arrayOf (Prim src_pt) (Shape (flatSliceDims slice)) NoUniqueness] v@@ -883,21 +913,25 @@       pure ()     checkDimChange rank (DimCoercion se) i       | i >= rank =-          bad $-            TypeError $-              "Asked to coerce dimension " ++ show i ++ " to " ++ pretty se-                ++ ", but array "-                ++ pretty arrexp-                ++ " has only "-                ++ pretty rank-                ++ " dimensions"+          bad . TypeError $+            "Asked to coerce dimension "+              ++ show i+              ++ " to "+              ++ pretty se+              ++ ", but array "+              ++ pretty arrexp+              ++ " has only "+              ++ pretty rank+              ++ " dimensions"       | otherwise =           pure () checkBasicOp (Rearrange perm arr) = do   arrt <- lookupType arr   let rank = arrayRank arrt   when (length perm /= rank || sort perm /= [0 .. rank - 1]) $-    bad $ PermutationError perm rank $ Just arr+    bad $+      PermutationError perm rank $+        Just arr checkBasicOp (Rotate rots arr) = do   arrt <- lookupType arr   let rank = arrayRank arrt@@ -905,7 +939,8 @@   when (length rots /= rank) $     bad $       TypeError $-        "Cannot rotate " ++ show (length rots)+        "Cannot rotate "+          ++ show (length rots)           ++ " dimensions of "           ++ show rank           ++ "-dimensional array."@@ -913,7 +948,8 @@   arr1_dims <- shapeDims . fst <$> checkArrIdent arr1exp   arr2s_dims <- map (shapeDims . fst) <$> mapM checkArrIdent arr2exps   unless (all ((== dropAt i 1 arr1_dims) . dropAt i 1) arr2s_dims) $-    bad $ TypeError "Types of arguments to concat do not match."+    bad $+      TypeError "Types of arguments to concat do not match."   require [Prim int64] ressize checkBasicOp (Copy e) =   void $ checkArrIdent e@@ -928,23 +964,20 @@ checkBasicOp (UpdateAcc acc is ses) = do   (shape, ts) <- checkAccIdent acc -  unless (length ses == length ts) $-    bad $-      TypeError $-        "Accumulator requires "-          ++ show (length ts)-          ++ " values, but "-          ++ show (length ses)-          ++ " provided."+  unless (length ses == length ts) . bad . TypeError $+    "Accumulator requires "+      ++ show (length ts)+      ++ " values, but "+      ++ show (length ses)+      ++ " provided."    unless (length is == shapeRank shape) $-    bad $-      TypeError $-        "Accumulator requires "-          ++ show (shapeRank shape)-          ++ " indices, but "-          ++ show (length is)-          ++ " provided."+    bad . TypeError $+      "Accumulator requires "+        ++ show (shapeRank shape)+        ++ " indices, but "+        ++ show (length is)+        ++ " provided."    zipWithM_ require (map pure ts) ses   consume =<< lookupAliases acc@@ -957,7 +990,8 @@ matchLoopResultExt merge loopres = do   let rettype_ext =         existentialiseExtTypes (map paramName merge) $-          staticShapes $ map typeOf merge+          staticShapes $+            map typeOf merge    bodyt <- mapM subExpResType loopres @@ -969,12 +1003,11 @@           rettype_ext           (staticShapes bodyt)     Just rettype' ->-      unless (bodyt `subtypesOf` rettype') $-        bad $-          ReturnTypeError-            (nameFromString "<loop body>")-            (staticShapes rettype')-            (staticShapes bodyt)+      unless (bodyt `subtypesOf` rettype') . bad $+        ReturnTypeError+          (nameFromString "<loop body>")+          (staticShapes rettype')+          (staticShapes bodyt)  checkExp ::   Checkable rep =>@@ -1015,28 +1048,30 @@           ]             ++ form_consumable -    context "Inside the loop body" $-      checkFun'+    context "Inside the loop body"+      $ checkFun'         ( nameFromString "<loop body>",           staticShapes rettype,           funParamsToNameInfos mergepat         )         (Just consumable)-        $ do-          checkFunParams mergepat-          checkBodyDec $ snd $ bodyDec loopbody+      $ do+        checkFunParams mergepat+        checkBodyDec $ snd $ bodyDec loopbody -          checkStms (bodyStms loopbody) $ do-            context "In loop body result" $-              checkResult $ bodyResult loopbody+        checkStms (bodyStms loopbody) $ do+          context "In loop body result" $+            checkResult $+              bodyResult loopbody -            context "When matching result of body with loop parameters" $-              matchLoopResult (map fst merge) $ bodyResult loopbody+          context "When matching result of body with loop parameters" $+            matchLoopResult (map fst merge) $+              bodyResult loopbody -            let bound_here =-                  namesFromList $ M.keys $ scopeOf $ bodyStms loopbody-            map (`namesSubtract` bound_here)-              <$> mapM (subExpAliasesM . resSubExp) (bodyResult loopbody)+          let bound_here =+                namesFromList $ M.keys $ scopeOf $ bodyStms loopbody+          map (`namesSubtract` bound_here)+            <$> mapM (subExpAliasesM . resSubExp) (bodyResult loopbody)   where     checkLoopVar (p, a) = do       a_t <- lookupType a@@ -1045,21 +1080,21 @@         Just a_t_r -> do           checkLParamDec (paramName p) $ paramDec p           unless (a_t_r `subtypeOf` typeOf (paramDec p)) $-            bad $-              TypeError $-                "Loop parameter " ++ pretty p-                  ++ " not valid for element of "-                  ++ pretty a-                  ++ ", which has row type "-                  ++ pretty a_t_r+            bad . TypeError $+              "Loop parameter "+                ++ pretty p+                ++ " not valid for element of "+                ++ pretty a+                ++ ", which has row type "+                ++ pretty a_t_r           als <- lookupAliases a           pure (paramName p, als)         _ ->-          bad $-            TypeError $-              "Cannot loop over " ++ pretty a-                ++ " of type "-                ++ pretty a_t+          bad . TypeError $+            "Cannot loop over "+              ++ pretty a+              ++ " of type "+              ++ pretty a_t     checkForm mergeargs (ForLoop loopvar it boundexp loopvars) = do       iparam <- primFParam loopvar $ IntType it       let mergepat = map fst merge@@ -1074,11 +1109,12 @@       case find ((== cond) . paramName . fst) merge of         Just (condparam, _) ->           unless (paramType condparam == Prim Bool) $-            bad $-              TypeError $-                "Conditional '" ++ pretty cond ++ "' of while-loop is not boolean, but "-                  ++ pretty (paramType condparam)-                  ++ "."+            bad . TypeError $+              "Conditional '"+                ++ pretty cond+                ++ "' of while-loop is not boolean, but "+                ++ pretty (paramType condparam)+                ++ "."         Nothing ->           bad $             TypeError $@@ -1116,7 +1152,8 @@     elem_ts <- forM arrs $ \arr -> do       arr_t <- lookupType arr       unless (shapeDims shape `isPrefixOf` arrayDims arr_t) $-        bad . TypeError $ pretty arr <> " is not an array of outer shape " <> pretty shape+        bad . TypeError $+          pretty arr <> " is not an array of outer shape " <> pretty shape       consume =<< lookupAliases arr       pure $ stripArray (shapeRank shape) arr_t @@ -1159,12 +1196,13 @@         Acc {} -> pure (t, als)         Array {} -> do           let argSize = arraySize 0 t-          unless (argSize == width) $-            bad . TypeError $-              "SOAC argument " ++ pretty v ++ " has outer size "-                ++ pretty argSize-                ++ ", but width of SOAC is "-                ++ pretty width+          unless (argSize == width) . bad . TypeError $+            "SOAC argument "+              ++ pretty v+              ++ " has outer size "+              ++ pretty argSize+              ++ ", but width of SOAC is "+              ++ pretty width           pure (rowType t, als)         _ ->           bad . TypeError $@@ -1282,7 +1320,8 @@   TypeM rep () matchExtPat pat ts =   unless (expExtTypesFromPat pat == ts) $-    bad $ InvalidPatError pat ts Nothing+    bad $+      InvalidPatError pat ts Nothing  matchExtReturnType ::   Checkable rep =>@@ -1308,14 +1347,12 @@ matchExtReturns rettype res ts = do   let problem :: TypeM rep a       problem =-        bad $-          TypeError $-            unlines-              [ "Type annotation is",-                "  " ++ prettyTuple rettype,-                "But result returns type",-                "  " ++ prettyTuple ts-              ]+        bad . TypeError . unlines $+          [ "Type annotation is",+            "  " ++ prettyTuple rettype,+            "But result returns type",+            "  " ++ prettyTuple ts+          ]    unless (length res == length rettype) problem @@ -1371,7 +1408,9 @@ checkFuncall fname paramts args = do   let argts = map argType args   unless (validApply paramts argts) $-    bad $ ParameterMismatch fname (map fromDecl paramts) $ map argType args+    bad $+      ParameterMismatch fname (map fromDecl paramts) $+        map argType args   consumeArgs paramts args  consumeArgs ::@@ -1402,28 +1441,24 @@             if soac               then Just $ zip (map paramName params) (map argAliases args)               else Nothing+          params' =+            [(paramName param, LParamName $ paramDec param) | param <- params]       checkFun'-        ( fname,-          staticShapes $ map (`toDecl` Nonunique) rettype,-          [ ( paramName param,-              LParamName $ paramDec param-            )-            | param <- params-          ]-        )+        (fname, staticShapes $ map (`toDecl` Nonunique) rettype, params')         consumable         $ do           checkLambdaParams params           mapM_ checkType rettype           checkLambdaBody rettype body     else-      bad $-        TypeError $-          "Anonymous function defined with " ++ show (length params) ++ " parameters:\n"-            ++ pretty params-            ++ "\nbut expected to take "-            ++ show (length args)-            ++ " arguments."+      bad . TypeError $+        "Anonymous function defined with "+          ++ show (length params)+          ++ " parameters:\n"+          ++ pretty params+          ++ "\nbut expected to take "+          ++ show (length args)+          ++ " arguments."  checkLambda :: Checkable rep => Lambda (Aliases rep) -> [Arg] -> TypeM rep () checkLambda = checkAnyLambda True@@ -1445,28 +1480,24 @@       (bad $ TypeError $ "Unknown function: " ++ h)       pure       $ M.lookup h primFuns-  when (length h_ts /= length args) $-    bad $-      TypeError $-        "Function expects " ++ show (length h_ts)-          ++ " parameters, but given "-          ++ show (length args)-          ++ " arguments."-  when (h_ret /= t) $-    bad $-      TypeError $-        "Function return annotation is " ++ pretty t-          ++ ", but expected "-          ++ pretty h_ret+  when (length h_ts /= length args) . bad . TypeError $+    "Function expects "+      ++ show (length h_ts)+      ++ " parameters, but given "+      ++ show (length args)+      ++ " arguments."+  when (h_ret /= t) . bad . TypeError $+    "Function return annotation is "+      ++ pretty t+      ++ ", but expected "+      ++ pretty h_ret   zipWithM_ requirePrimExp h_ts args  requirePrimExp :: Checkable rep => PrimType -> PrimExp VName -> TypeM rep () requirePrimExp t e = context ("in PrimExp " ++ pretty e) $ do   checkPrimExp e-  unless (primExpType e == t) $-    bad $-      TypeError $-        pretty e ++ " must have type " ++ pretty t+  unless (primExpType e == t) . bad . TypeError $+    pretty e ++ " must have type " ++ pretty t  class ASTRep rep => CheckableOp rep where   checkOp :: OpWithAliases (Op rep) -> TypeM rep ()
src/Futhark/Internalise.hs view
@@ -47,6 +47,7 @@ import Futhark.IR.SOACS as I hiding (stmPat) import Futhark.Internalise.Defunctionalise as Defunctionalise import Futhark.Internalise.Defunctorise as Defunctorise+import Futhark.Internalise.Entry (visibleTypes) import qualified Futhark.Internalise.Exps as Exps import Futhark.Internalise.LiftLambdas as LiftLambdas import Futhark.Internalise.Monad as I@@ -71,7 +72,7 @@   maybeLog "Defunctionalising"   prog_decs''' <- Defunctionalise.transformProg prog_decs''   maybeLog "Converting to core IR"-  Exps.transformProg (futharkSafe config) prog_decs'''+  Exps.transformProg (futharkSafe config) (visibleTypes prog) prog_decs'''   where     verbose = fst (futharkVerbose config) > NotVerbose     maybeLog s
src/Futhark/Internalise/Bindings.hs view
@@ -53,7 +53,8 @@     let (certparams, valueparams') = unzip $ map fixAccParam (concat valueparams)     I.localScope (I.scopeOfFParams $ catMaybes certparams ++ shape_params ++ valueparams') $       substitutingVars shape_subst $-        m (catMaybes certparams ++ shape_params) $ chunks num_param_ts valueparams'+        m (catMaybes certparams ++ shape_params) $+          chunks num_param_ts valueparams'   where     fixAccParam (I.Param attrs pv (I.Acc acc ispace ts u)) =       ( Just (I.Param attrs acc $ I.Prim I.Unit),@@ -76,7 +77,9 @@    bindingFlatPat pat_idents pat_ts $ \valueparams ->     I.localScope (I.scopeOfFParams $ shape_params ++ concat valueparams) $-      substitutingVars shape_subst $ m shape_params $ concat valueparams+      substitutingVars shape_subst $+        m shape_params $+          concat valueparams  bindingLambdaParams ::   [E.Pat] ->@@ -115,10 +118,9 @@     internaliseBindee :: E.Ident -> InternaliseM [VName]     internaliseBindee bindee = do       let name = E.identName bindee-      n <- internalisedTypeSize $ E.unInfo $ E.identType bindee-      case n of+      case internalisedTypeSize $ E.unInfo $ E.identType bindee of         1 -> pure [name]-        _ -> replicateM n $ newVName $ baseString name+        n -> replicateM n $ newVName $ baseString name  bindingFlatPat ::   Show t =>
src/Futhark/Internalise/Defunctionalise.hs view
@@ -19,7 +19,6 @@ import Data.Maybe import qualified Data.Set as S import Futhark.IR.Pretty ()-import qualified Futhark.Internalise.FreeVars as FV import Futhark.MonadFreshNames import Language.Futhark import Language.Futhark.Traversals@@ -77,15 +76,15 @@  replaceTypeSizes ::   M.Map VName SizeSubst ->-  TypeBase (DimDecl VName) als ->-  TypeBase (DimDecl VName) als+  TypeBase Size als ->+  TypeBase Size als replaceTypeSizes substs = first onDim   where-    onDim (NamedDim v) =+    onDim (NamedSize v) =       case M.lookup (qualLeaf v) substs of-        Just (SubstNamed v') -> NamedDim v'-        Just (SubstConst d) -> ConstDim d-        Nothing -> NamedDim v+        Just (SubstNamed v') -> NamedSize v'+        Just (SubstConst d) -> ConstSize d+        Nothing -> NamedSize v     onDim d = d  replaceStaticValSizes ::@@ -145,12 +144,12 @@         te' = onTypeExp substs te     onExp substs e = onAST substs e -    onTypeExpDim substs d@(DimExpNamed v loc) =+    onTypeExpDim substs d@(SizeExpNamed v loc) =       case M.lookup (qualLeaf v) substs of         Just (SubstNamed v') ->-          DimExpNamed v' loc+          SizeExpNamed v' loc         Just (SubstConst x) ->-          DimExpConst x loc+          SizeExpConst x loc         Nothing ->           d     onTypeExpDim _ d = d@@ -203,8 +202,8 @@  -- | Returns the defunctionalization environment restricted -- to the given set of variable names and types.-restrictEnvTo :: FV.NameSet -> DefM Env-restrictEnvTo (FV.NameSet m) = asks restrict+restrictEnvTo :: FV -> DefM Env+restrictEnvTo (FV m) = asks restrict   where     restrict (globals, env) = M.mapMaybeWithKey keep env       where@@ -272,7 +271,7 @@           -- Anything not in scope is going to be an existential size.           pure $ Dynamic $ Scalar $ Prim $ Signed Int64 --- Like patternDimNames, but ignores sizes that are only found in+-- Like freeInPat, but ignores sizes that are only found in -- funtion types. arraySizes :: StructType -> S.Set VName arraySizes (Scalar Arrow {}) = mempty@@ -281,15 +280,15 @@ arraySizes (Scalar (TypeVar _ _ _ targs)) =   mconcat $ map f targs   where-    f (TypeArgDim (NamedDim d) _) = S.singleton $ qualLeaf d+    f (TypeArgDim (NamedSize d) _) = S.singleton $ qualLeaf d     f TypeArgDim {} = mempty     f (TypeArgType t _) = arraySizes t arraySizes (Scalar Prim {}) = mempty arraySizes (Array _ _ shape t) =   arraySizes (Scalar t) <> foldMap dimName (shapeDims shape)   where-    dimName :: DimDecl VName -> S.Set VName-    dimName (NamedDim qn) = S.singleton $ qualLeaf qn+    dimName :: Size -> S.Set VName+    dimName (NamedSize qn) = S.singleton $ qualLeaf qn     dimName _ = mempty  patternArraySizes :: Pat -> S.Set VName@@ -302,25 +301,25 @@  dimMapping ::   Monoid a =>-  TypeBase (DimDecl VName) a ->-  TypeBase (DimDecl VName) a ->+  TypeBase Size a ->+  TypeBase Size a ->   M.Map VName SizeSubst dimMapping t1 t2 = execState (matchDims f t1 t2) mempty   where-    f bound d1 (NamedDim d2)+    f bound d1 (NamedSize d2)       | qualLeaf d2 `elem` bound = pure d1-    f _ (NamedDim d1) (NamedDim d2) = do+    f _ (NamedSize d1) (NamedSize d2) = do       modify $ M.insert (qualLeaf d1) $ SubstNamed d2-      pure $ NamedDim d1-    f _ (NamedDim d1) (ConstDim d2) = do+      pure $ NamedSize d1+    f _ (NamedSize d1) (ConstSize d2) = do       modify $ M.insert (qualLeaf d1) $ SubstConst d2-      pure $ NamedDim d1+      pure $ NamedSize d1     f _ d _ = pure d  dimMapping' ::   Monoid a =>-  TypeBase (DimDecl VName) a ->-  TypeBase (DimDecl VName) a ->+  TypeBase Size a ->+  TypeBase Size a ->   M.Map VName VName dimMapping' t1 t2 = M.mapMaybe f $ dimMapping t1 t2   where@@ -339,7 +338,7 @@ sizesToRename (SumSV _ svs _) =   foldMap sizesToRename svs sizesToRename (LambdaSV param _ _ _) =-  patternDimNames param+  freeInPat param     <> S.map identName (S.filter couldBeSize $ patIdents param)   where     couldBeSize ident =@@ -400,8 +399,8 @@   -- the lambda.  Closed-over 'DynamicFun's are converted to their   -- closure representation.   let used =-        FV.freeVars (Lambda pats e0 Nothing (Info (mempty, ret)) loc)-          `FV.without` S.fromList tparams+        freeInExp (Lambda pats e0 Nothing (Info (mempty, ret)) loc)+          `freeWithout` S.fromList tparams   used_env <- restrictEnvTo used    -- The closure parts that are sizes are proactively turned into size@@ -411,7 +410,9 @@           <> patternArraySizes pat       notSize = not . (`S.member` sizes_of_arrays)       (fields, env) =-        second M.fromList . unzip . map closureFromDynamicFun+        second M.fromList+          . unzip+          . map closureFromDynamicFun           . filter (notSize . fst)           $ M.toList used_env @@ -527,7 +528,8 @@   -- newly computed body type.   let mapping = dimMapping' (typeOf e2) t       subst v = fromMaybe v $ M.lookup v mapping-      t' = first (fmap subst) $ typeOf e2'+      mapper = identityMapper {mapOnName = pure . subst}+      t' = first (runIdentity . astMap mapper) $ typeOf e2'   pure (AppExp (LetPat sizes pat' e1' e2' loc) (Info (AppRes t' retext)), sv2) defuncExp (AppExp (LetFun vn _ _ _) _) =   error $ "defuncExp: Unexpected LetFun: " ++ prettyName vn@@ -645,15 +647,15 @@   where     defuncType ::       Monoid als =>-      TypeBase (DimDecl VName) als ->-      TypeBase (DimDecl VName) als+      TypeBase Size als ->+      TypeBase Size als     defuncType (Array as u shape t) = Array as u shape (defuncScalar t)     defuncType (Scalar t) = Scalar $ defuncScalar t      defuncScalar ::       Monoid als =>-      ScalarTypeBase (DimDecl VName) als ->-      ScalarTypeBase (DimDecl VName) als+      ScalarTypeBase Size als ->+      ScalarTypeBase Size als     defuncScalar (Record fs) = Record $ M.map defuncType fs     defuncScalar Arrow {} = Record mempty     defuncScalar (Sum fs) = Sum $ M.map (map defuncType) fs@@ -661,7 +663,9 @@     defuncScalar (TypeVar as u tn targs) = TypeVar as u tn targs defuncExp (Constr name _ (Info t) loc) =   error $-    "Constructor " ++ pretty name ++ " given type "+    "Constructor "+      ++ pretty name+      ++ " given type "       ++ pretty t       ++ " at "       ++ locStr loc@@ -757,7 +761,7 @@   DefM ([VName], [Pat], Exp, StaticVal) defuncLet dims ps@(pat : pats) body (RetType ret_dims rettype)   | patternOrderZero pat = do-      let bound_by_pat = (`S.member` patternDimNames pat)+      let bound_by_pat = (`S.member` freeInPat pat)           -- Take care to not include more size parameters than necessary.           (pat_dims, rest_dims) = partition bound_by_pat dims           env = envFromPat pat <> envFromDimNames pat_dims@@ -790,24 +794,26 @@   where     bound = bound_sizes <> foldMap patNames params     tv = identityMapper {mapOnPatType = bitraverse onDim pure}-    onDim (AnyDim (Just v)) = do+    onDim (AnySize (Just v)) = do       modify $ S.insert v-      pure $ NamedDim $ qualName v-    onDim (AnyDim Nothing) = do+      pure $ NamedSize $ qualName v+    onDim (AnySize Nothing) = do       v <- lift $ newVName "size"       modify $ S.insert v-      pure $ NamedDim $ qualName v-    onDim (NamedDim d) = do+      pure $ NamedSize $ qualName v+    onDim (NamedSize d) = do       unless (qualLeaf d `S.member` bound) $-        modify $ S.insert $ qualLeaf d-      pure $ NamedDim d+        modify $+          S.insert $+            qualLeaf d+      pure $ NamedSize d     onDim d = pure d  unRetType :: StructRetType -> StructType unRetType (RetType [] t) = t unRetType (RetType ext t) = first onDim t   where-    onDim (NamedDim d) | qualLeaf d `elem` ext = AnyDim Nothing+    onDim (NamedSize d) | qualLeaf d `elem` ext = AnySize Nothing     onDim d = d  -- | Defunctionalize an application expression at a given depth of application.@@ -844,7 +850,8 @@           rettype = buildRetType closure_env params_for_rettype (unRetType e0_t) $ typeOf e0'            already_bound =-            globals <> S.fromList dims+            globals+              <> S.fromList dims               <> S.map identName (foldMap patIdents params)            more_dims =@@ -861,7 +868,7 @@             liftedName (i + 1) f           liftedName _ _ = "defunc" -      -- Ensure that no parameter sizes are AnyDim.  The internaliser+      -- Ensure that no parameter sizes are AnySize.  The internaliser       -- expects this.  This is easy, because they are all       -- first-order.       let bound_sizes = S.fromList (dims <> more_dims) <> globals@@ -883,7 +890,8 @@               fname'               ( Info                   ( Scalar . Arrow mempty Unnamed t1 . RetType [] $-                      Scalar . Arrow mempty Unnamed t2 $ RetType [] rettype+                      Scalar . Arrow mempty Unnamed t2 $+                        RetType [] rettype                   )               )               loc@@ -967,7 +975,7 @@               (argtypes', rettype) = dynamicFunType sv' argtypes               dims' = mempty -          -- Ensure that no parameter sizes are AnyDim.  The internaliser+          -- Ensure that no parameter sizes are AnySize.  The internaliser           -- expects this.  This is easy, because they are all           -- first-order.           globals <- asks fst@@ -1046,7 +1054,7 @@     mkExt v       | not $ v `S.member` bound_here = Just v     mkExt _ = Nothing-    rettype_st = RetType (mapMaybe mkExt (S.toList (typeDimNames ret)) ++ ret_dims) ret+    rettype_st = RetType (mapMaybe mkExt (S.toList (freeInType ret)) ++ ret_dims) ret      dec =       ValBind@@ -1089,7 +1097,9 @@       S.fromList (M.keys env) <> S.map identName (foldMap patIdents pats)     boundAsUnique v =       maybe False (unique . unInfo . identType) $-        find ((== v) . identName) $ S.toList $ foldMap patIdents pats+        find ((== v) . identName) $+          S.toList $+            foldMap patIdents pats     problematic v = (v `S.member` bound) && not (boundAsUnique v)     comb (Scalar (Record fs_annot)) (Scalar (Record fs_got)) =       Scalar $ Record $ M.intersectionWith comb fs_annot fs_got@@ -1154,7 +1164,7 @@     else dim_env <> M.singleton vn (Binding Nothing sv)   where     dim_env =-      M.fromList $ map (,i64) $ S.toList $ typeDimNames t+      M.fromList $ map (,i64) $ S.toList $ freeInType t     i64 = Binding Nothing $ Dynamic $ Scalar $ Prim $ Signed Int64 matchPatSV (Wildcard _ _) _ = mempty matchPatSV (PatAscription pat _ _) sv = matchPatSV pat sv@@ -1174,7 +1184,8 @@ matchPatSV pat (Dynamic t) = matchPatSV pat $ svFromType t matchPatSV pat sv =   error $-    "Tried to match pattern " ++ pretty pat+    "Tried to match pattern "+      ++ pretty pat       ++ " with static value "       ++ show sv       ++ "."@@ -1226,7 +1237,8 @@ updatePat pat (Dynamic t) = updatePat pat (svFromType t) updatePat pat sv =   error $-    "Tried to update pattern " ++ pretty pat+    "Tried to update pattern "+      ++ pretty pat       ++ "to reflect the static value "       ++ show sv @@ -1260,7 +1272,8 @@ defuncValBind valbind@(ValBind _ name retdecl (Info (RetType ret_dims rettype)) tparams params body _ _ _) = do   when (any isTypeParam tparams) $     error $-      prettyName name ++ " has type parameters, "+      prettyName name+        ++ " has type parameters, "         ++ "but the defunctionaliser expects a monomorphic input program."   (tparams', params', body', sv) <-     defuncLet (map typeParamName tparams) params body $ RetType ret_dims rettype@@ -1272,7 +1285,7 @@         -- applications of lifted functions, we don't properly update         -- the types in the return type annotation.         combineTypeShapes rettype $ first (anyDimIfNotBound bound_sizes) $ toStruct $ typeOf body'-      ret_dims' = filter (`S.member` typeDimNames rettype') ret_dims+      ret_dims' = filter (`S.member` freeInType rettype') ret_dims   (missing_dims, params'') <- sizesForAll bound_sizes params'    pure@@ -1294,8 +1307,8 @@           sv     )   where-    anyDimIfNotBound bound_sizes (NamedDim v)-      | qualLeaf v `S.notMember` bound_sizes = AnyDim $ Just $ qualLeaf v+    anyDimIfNotBound bound_sizes (NamedSize v)+      | qualLeaf v `S.notMember` bound_sizes = AnySize $ Just $ qualLeaf v     anyDimIfNotBound _ d = d  -- | Defunctionalize a list of top-level declarations.
src/Futhark/Internalise/Defunctorise.hs view
@@ -255,8 +255,6 @@         { mapOnExp = onExp scope,           mapOnName = \v ->             pure $ qualLeaf $ fst $ lookupSubstInScope (qualName v) scope,-          mapOnQualName = \v ->-            pure $ fst $ lookupSubstInScope v scope,           mapOnStructType = astMap (substituter scope),           mapOnPatType = astMap (substituter scope),           mapOnStructRetType = astMap (substituter scope),@@ -281,21 +279,32 @@ transformExp :: Exp -> TransformM Exp transformExp = transformNames +transformEntry :: EntryPoint -> TransformM EntryPoint+transformEntry (EntryPoint params ret) =+  EntryPoint <$> mapM onEntryParam params <*> onEntryType ret+  where+    onEntryParam (EntryParam v t) =+      EntryParam v <$> onEntryType t+    onEntryType (EntryType t te) =+      EntryType <$> transformStructType t <*> pure te+ transformValBind :: ValBind -> TransformM () transformValBind (ValBind entry name tdecl (Info (RetType dims t)) tparams params e doc attrs loc) = do+  entry' <- traverse (traverse transformEntry) entry   name' <- transformName name   tdecl' <- traverse transformTypeExp tdecl   t' <- transformStructType t   e' <- transformExp e   tparams' <- traverse transformNames tparams   params' <- traverse transformNames params-  emit $ ValDec $ ValBind entry name' tdecl' (Info (RetType dims t')) tparams' params' e' doc attrs loc+  emit $ ValDec $ ValBind entry' name' tdecl' (Info (RetType dims t')) tparams' params' e' doc attrs loc  transformTypeBind :: TypeBind -> TransformM () transformTypeBind (TypeBind name l tparams te (Info (RetType dims t)) doc loc) = do   name' <- transformName name   emit . TypeDec-    =<< ( TypeBind name' l <$> traverse transformNames tparams+    =<< ( TypeBind name' l+            <$> traverse transformNames tparams             <*> transformTypeExp te             <*> (Info . RetType dims <$> transformStructType t)             <*> pure doc@@ -306,11 +315,11 @@ transformModBind mb = do   let addParam p me = ModLambda p Nothing me $ srclocOf me   mod <--    evalModExp $-      foldr+    evalModExp+      $ foldr         addParam         (maybeAscript (srclocOf mb) (modSignature mb) $ modExp mb)-        $ modParams mb+      $ modParams mb   mname <- transformName $ modName mb   pure $ Scope (scopeSubsts $ modScope mod) $ M.singleton mname mod @@ -348,7 +357,10 @@   let abs = S.fromList $ map qualLeaf $ M.keys $ fileAbs imp   scope <-     censor (fmap maybeHideEntryPoint) $-      bindingAbs abs $ transformDecs $ progDecs $ fileProg imp+      bindingAbs abs $+        transformDecs $+          progDecs $+            fileProg imp   bindingAbs abs $ bindingImport name scope $ transformImports imps   where     -- Only the "main" file (last import) is allowed to have entry points.
+ src/Futhark/Internalise/Entry.hs view
@@ -0,0 +1,165 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}++-- | Generating metadata so that programs can run at all.+module Futhark.Internalise.Entry+  ( entryPoint,+    VisibleTypes,+    visibleTypes,+  )+where++import Control.Monad.State+import Data.List (find)+import qualified Data.Map as M+import Data.String (fromString)+import qualified Futhark.IR as I+import Futhark.Internalise.TypesValues (internalisedTypeSize)+import Futhark.Util.Pretty (prettyOneLine)+import qualified Language.Futhark as E hiding (TypeArg)+import Language.Futhark.Core (Name, Uniqueness (..), VName)+import qualified Language.Futhark.Semantic as E++-- | The types that are visible to the outside world.+newtype VisibleTypes = VisibleTypes [E.TypeBind]++-- | Retrieve those type bindings that should be visible to the+-- outside world.  Currently that is everything at top level that does+-- not have type parameters.+visibleTypes :: E.Imports -> VisibleTypes+visibleTypes = VisibleTypes . foldMap (modTypes . snd)+  where+    modTypes = progTypes . E.fileProg+    progTypes = foldMap decTypes . E.progDecs+    decTypes (E.TypeDec tb) = [tb]+    decTypes _ = []++findType :: VName -> VisibleTypes -> Maybe (E.TypeExp VName)+findType v (VisibleTypes ts) = E.typeExp <$> find ((== v) . E.typeAlias) ts++valueType :: I.TypeBase I.Rank Uniqueness -> I.ValueType+valueType (I.Prim pt) = I.ValueType I.Signed (I.Rank 0) pt+valueType (I.Array pt rank _) = I.ValueType I.Signed rank pt+valueType I.Acc {} = error "valueType Acc"+valueType I.Mem {} = error "valueType Mem"++withoutDims :: E.TypeExp VName -> (Int, E.TypeExp VName)+withoutDims (E.TEArray _ te _) =+  let (d, te') = withoutDims te+   in (d + 1, te')+withoutDims te = (0 :: Int, te)++rootType :: E.TypeExp VName -> E.TypeExp VName+rootType (E.TEApply te E.TypeArgExpDim {} _) = rootType te+rootType (E.TEUnique te _) = rootType te+rootType te = te++typeExpOpaqueName :: E.TypeExp VName -> String+typeExpOpaqueName = f . rootType+  where+    f (E.TEArray _ te _) =+      let (d, te') = withoutDims te+       in "arr_" <> typeExpOpaqueName te' <> "_" <> show (1 + d) <> "d"+    f te = fromString $ prettyOneLine te++type GenOpaque = State I.OpaqueTypes++runGenOpaque :: GenOpaque a -> (a, I.OpaqueTypes)+runGenOpaque = flip runState mempty++addType :: String -> I.OpaqueType -> GenOpaque ()+addType s t = modify (<> I.OpaqueTypes [(s, t)])++isRecord :: VisibleTypes -> E.TypeExp VName -> Maybe (M.Map Name (E.TypeExp VName))+isRecord _ (E.TERecord fs _) = Just $ M.fromList fs+isRecord _ (E.TETuple fs _) = Just $ E.tupleFields fs+isRecord types (E.TEVar v _) = isRecord types =<< findType (E.qualLeaf v) types+isRecord _ _ = Nothing++recordFields ::+  VisibleTypes ->+  M.Map Name E.StructType ->+  Maybe (E.TypeExp VName) ->+  [(Name, E.EntryType)]+recordFields types fs t =+  case isRecord types . rootType =<< t of+    Just e_fs ->+      zipWith f (E.sortFields fs) (E.sortFields e_fs)+      where+        f (k, f_t) (_, e_f_t) = (k, E.EntryType f_t $ Just e_f_t)+    Nothing ->+      map (fmap (`E.EntryType` Nothing)) $ E.sortFields fs++opaqueRecord ::+  VisibleTypes ->+  [(Name, E.EntryType)] ->+  [I.TypeBase I.Rank Uniqueness] ->+  GenOpaque [(Name, I.EntryPointType)]+opaqueRecord _ [] _ = pure []+opaqueRecord types ((f, t) : fs) ts = do+  let (f_ts, ts') = splitAt (internalisedTypeSize $ E.entryType t) ts+  f' <- opaqueField t f_ts+  ((f, f') :) <$> opaqueRecord types fs ts'+  where+    opaqueField e_t i_ts = snd <$> entryPointType types e_t i_ts++entryPointType ::+  VisibleTypes ->+  E.EntryType ->+  [I.TypeBase I.Rank Uniqueness] ->+  GenOpaque (Uniqueness, I.EntryPointType)+entryPointType types t ts+  | E.Scalar (E.Prim E.Unsigned {}) <- E.entryType t,+    [I.Prim ts0] <- ts =+      pure (u, I.TypeTransparent $ I.ValueType I.Unsigned (I.Rank 0) ts0)+  | E.Array _ _ _ (E.Prim E.Unsigned {}) <- E.entryType t,+    [I.Array ts0 r _] <- ts =+      pure (u, I.TypeTransparent $ I.ValueType I.Unsigned r ts0)+  | E.Scalar E.Prim {} <- E.entryType t,+    [I.Prim ts0] <- ts =+      pure (u, I.TypeTransparent $ I.ValueType I.Signed (I.Rank 0) ts0)+  | E.Array _ _ _ E.Prim {} <- E.entryType t,+    [I.Array ts0 r _] <- ts =+      pure (u, I.TypeTransparent $ I.ValueType I.Signed r ts0)+  | otherwise = do+      case E.entryType t of+        E.Scalar (E.Record fs)+          | not $ null fs ->+              let fs' = recordFields types fs $ E.entryAscribed t+               in addType desc . I.OpaqueRecord =<< opaqueRecord types fs' ts+        _ -> addType desc $ I.OpaqueType $ map valueType ts+      pure (u, I.TypeOpaque desc)+  where+    u = foldl max Nonunique $ map I.uniqueness ts+    desc =+      maybe (fromString $ prettyOneLine t') typeExpOpaqueName $+        E.entryAscribed t+    t' = E.noSizes (E.entryType t) `E.setUniqueness` Nonunique++entryPoint ::+  VisibleTypes ->+  Name ->+  [(E.EntryParam, [I.Param I.DeclType])] ->+  ( E.EntryType,+    [[I.TypeBase I.Rank I.Uniqueness]]+  ) ->+  (I.EntryPoint, I.OpaqueTypes)+entryPoint types name params (eret, crets) =+  runGenOpaque $+    (name,,)+      <$> mapM onParam params+      <*> ( map (uncurry I.EntryResult)+              <$> case ( E.isTupleRecord $ E.entryType eret,+                         E.entryAscribed eret+                       ) of+                (Just ts, Just (E.TETuple e_ts _)) ->+                  zipWithM (entryPointType types) (zipWith E.EntryType ts (map Just e_ts)) crets+                (Just ts, Nothing) ->+                  zipWithM (entryPointType types) (map (`E.EntryType` Nothing) ts) crets+                _ ->+                  pure <$> entryPointType types eret (concat crets)+          )+  where+    onParam (E.EntryParam e_p e_t, ps) =+      uncurry (I.EntryParam e_p)+        <$> entryPointType types e_t (map (I.rankShaped . I.paramDeclType) ps)
src/Futhark/Internalise/Exps.hs view
@@ -17,31 +17,32 @@ import Futhark.IR.SOACS as I hiding (stmPat) import Futhark.Internalise.AccurateSizes import Futhark.Internalise.Bindings+import Futhark.Internalise.Entry import Futhark.Internalise.Lambdas import Futhark.Internalise.Monad as I import Futhark.Internalise.TypesValues import Futhark.Transform.Rename as I import Futhark.Util (splitAt3)-import Futhark.Util.Pretty (align, ppr, prettyOneLine)+import Futhark.Util.Pretty (align, ppr) import Language.Futhark as E hiding (TypeArg)  -- | Convert a program in source Futhark to a program in the Futhark -- core language.-transformProg :: MonadFreshNames m => Bool -> [E.ValBind] -> m (I.Prog SOACS)-transformProg always_safe vbinds = do-  (consts, funs) <--    runInternaliseM always_safe (internaliseValBinds vbinds)-  I.renameProg $ I.Prog consts funs+transformProg :: MonadFreshNames m => Bool -> VisibleTypes -> [E.ValBind] -> m (I.Prog SOACS)+transformProg always_safe types vbinds = do+  (opaques, consts, funs) <-+    runInternaliseM always_safe (internaliseValBinds types vbinds)+  I.renameProg $ I.Prog opaques consts funs -internaliseValBinds :: [E.ValBind] -> InternaliseM ()-internaliseValBinds = mapM_ internaliseValBind+internaliseValBinds :: VisibleTypes -> [E.ValBind] -> InternaliseM ()+internaliseValBinds types = mapM_ $ internaliseValBind types  internaliseFunName :: VName -> Name internaliseFunName = nameFromString . pretty -internaliseValBind :: E.ValBind -> InternaliseM ()-internaliseValBind fb@(E.ValBind entry fname retdecl (Info rettype) tparams params body _ attrs loc) = do-  localConstsScope . bindingFParams tparams params $ \shapeparams params' -> do+internaliseValBind :: VisibleTypes -> E.ValBind -> InternaliseM ()+internaliseValBind types fb@(E.ValBind entry fname retdecl (Info rettype) tparams params body _ attrs loc) = do+  bindingFParams tparams params $ \shapeparams params' -> do     let shapenames = map I.paramName shapeparams      msg <- case retdecl of@@ -54,7 +55,7 @@     (body', rettype') <- buildBody $ do       body_res <- internaliseExp (baseString fname <> "_res") body       rettype' <--        fmap zeroExts . internaliseReturnType rettype =<< mapM subExpType body_res+        zeroExts . internaliseReturnType rettype <$> mapM subExpType body_res       body_res' <-         ensureResultExtShape msg loc (map I.fromDecl rettype') $ subExpsRes body_res       pure@@ -88,19 +89,26 @@           )    case entry of-    Just (Info entry') -> generateEntryPoint entry' fb+    Just (Info entry') -> generateEntryPoint types entry' fb     Nothing -> pure ()   where     zeroExts ts = generaliseExtTypes ts ts -generateEntryPoint :: E.EntryPoint -> E.ValBind -> InternaliseM ()-generateEntryPoint (E.EntryPoint e_params e_rettype) vb = localConstsScope $ do+generateEntryPoint :: VisibleTypes -> E.EntryPoint -> E.ValBind -> InternaliseM ()+generateEntryPoint types (E.EntryPoint e_params e_rettype) vb = do   let (E.ValBind _ ofname _ (Info rettype) tparams params _ _ attrs loc) = vb   bindingFParams tparams params $ \shapeparams params' -> do-    entry_rettype <- internaliseEntryReturnType rettype-    let entry' = entryPoint (baseName ofname) (zip e_params params') (e_rettype, entry_rettype)+    let entry_rettype = internaliseEntryReturnType rettype+        (entry', opaques) =+          entryPoint+            types+            (baseName ofname)+            (zip e_params params')+            (e_rettype, map (map I.rankShaped) entry_rettype)         args = map (I.Var . I.paramName) $ concat params' +    addOpaques opaques+     (entry_body, ctx_ts) <- buildBody $ do       -- Special case the (rare) situation where the entry point is       -- not a function.@@ -127,67 +135,6 @@   where     zeroExts ts = generaliseExtTypes ts ts -entryPoint ::-  Name ->-  [(E.EntryParam, [I.FParam SOACS])] ->-  ( E.EntryType,-    [[I.TypeBase ExtShape Uniqueness]]-  ) ->-  I.EntryPoint-entryPoint name params (eret, crets) =-  ( name,-    map onParam params,-    case ( isTupleRecord $ entryType eret,-           entryAscribed eret-         ) of-      (Just ts, Just (E.TETuple e_ts _)) ->-        zipWith-          entryPointType-          (zipWith E.EntryType ts (map Just e_ts))-          crets-      (Just ts, Nothing) ->-        zipWith-          entryPointType-          (map (`E.EntryType` Nothing) ts)-          crets-      _ ->-        [entryPointType eret $ concat crets]-  )-  where-    onParam (E.EntryParam e_p e_t, ps) =-      I.EntryParam e_p $ entryPointType e_t $ staticShapes $ map I.paramDeclType ps--    entryPointType t ts-      | E.Scalar (E.Prim E.Unsigned {}) <- E.entryType t =-          I.TypeUnsigned u-      | E.Array _ _ _ (E.Prim E.Unsigned {}) <- E.entryType t =-          I.TypeUnsigned u-      | E.Scalar E.Prim {} <- E.entryType t =-          I.TypeDirect u-      | E.Array _ _ _ E.Prim {} <- E.entryType t =-          I.TypeDirect u-      | otherwise =-          I.TypeOpaque u desc $ length ts-      where-        u = foldl max Nonunique $ map I.uniqueness ts-        desc = maybe (prettyOneLine t') typeExpOpaqueName $ E.entryAscribed t-        t' = noSizes (E.entryType t) `E.setUniqueness` Nonunique-    typeExpOpaqueName (TEApply te TypeArgExpDim {} _) =-      typeExpOpaqueName te-    typeExpOpaqueName (TEArray _ te _) =-      let (d, te') = withoutDims te-       in "arr_" ++ typeExpOpaqueName te'-            ++ "_"-            ++ show (1 + d)-            ++ "d"-    typeExpOpaqueName (TEUnique te _) = prettyOneLine te-    typeExpOpaqueName te = prettyOneLine te--    withoutDims (TEArray _ te _) =-      let (d, te') = withoutDims te-       in (d + 1, te')-    withoutDims te = (0 :: Int, te)- internaliseBody :: String -> E.Exp -> InternaliseM (Body SOACS) internaliseBody desc e =   buildBody_ $ subExpsRes <$> internaliseExp (desc <> "_res") e@@ -277,7 +224,8 @@     Just second' -> do       subtracted_step <-         letSubExp "subtracted_step" $-          I.BasicOp $ I.BinOp (I.Sub it I.OverflowWrap) second' start'+          I.BasicOp $+            I.BinOp (I.Sub it I.OverflowWrap) second' start'       step_zero <- letSubExp "step_zero" $ I.BasicOp $ I.CmpOp (I.CmpEq $ IntType it) start' second'       pure (subtracted_step, step_zero)     Nothing ->@@ -288,53 +236,61 @@    bounds_invalid_downwards <-     letSubExp "bounds_invalid_downwards" $-      I.BasicOp $ I.CmpOp le_op start' end'+      I.BasicOp $+        I.CmpOp le_op start' end'   bounds_invalid_upwards <-     letSubExp "bounds_invalid_upwards" $-      I.BasicOp $ I.CmpOp lt_op end' start'+      I.BasicOp $+        I.CmpOp lt_op end' start'    (distance, step_wrong_dir, bounds_invalid) <- case end of     DownToExclusive {} -> do       step_wrong_dir <-         letSubExp "step_wrong_dir" $-          I.BasicOp $ I.CmpOp (I.CmpEq $ IntType it) step_sign one+          I.BasicOp $+            I.CmpOp (I.CmpEq $ IntType it) step_sign one       distance <-         letSubExp "distance" $-          I.BasicOp $ I.BinOp (Sub it I.OverflowWrap) start' end'+          I.BasicOp $+            I.BinOp (Sub it I.OverflowWrap) start' end'       distance_i64 <- asIntS Int64 distance       pure (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+          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_i64 <- asIntS Int64 distance       pure (distance_i64, step_wrong_dir, bounds_invalid_upwards)     ToInclusive {} -> do       downwards <-         letSubExp "downwards" $-          I.BasicOp $ I.CmpOp (I.CmpEq $ IntType it) step_sign negone+          I.BasicOp $+            I.CmpOp (I.CmpEq $ IntType it) step_sign negone       distance_downwards_exclusive <-         letSubExp "distance_downwards_exclusive" $-          I.BasicOp $ I.BinOp (Sub it I.OverflowWrap) start' end'+          I.BasicOp $+            I.BinOp (Sub it I.OverflowWrap) start' end'       distance_upwards_exclusive <-         letSubExp "distance_upwards_exclusive" $-          I.BasicOp $ I.BinOp (Sub it I.OverflowWrap) end' start'+          I.BasicOp $+            I.BinOp (Sub it I.OverflowWrap) end' start'        bounds_invalid <--        letSubExp "bounds_invalid" $-          I.If+        letSubExp "bounds_invalid"+          $ I.If             downwards             (resultBody [bounds_invalid_downwards])             (resultBody [bounds_invalid_upwards])-            $ ifCommon [I.Prim I.Bool]+          $ ifCommon [I.Prim I.Bool]       distance_exclusive <--        letSubExp "distance_exclusive" $-          I.If+        letSubExp "distance_exclusive"+          $ I.If             downwards             (resultBody [distance_downwards_exclusive])             (resultBody [distance_upwards_exclusive])-            $ ifCommon [I.Prim $ IntType it]+          $ ifCommon [I.Prim $ IntType it]       distance_exclusive_i64 <- asIntS Int64 distance_exclusive       distance <-         letSubExp "distance" $@@ -347,29 +303,33 @@    step_invalid <-     letSubExp "step_invalid" $-      I.BasicOp $ I.BinOp I.LogOr step_wrong_dir step_zero+      I.BasicOp $+        I.BinOp I.LogOr step_wrong_dir step_zero    invalid <-     letSubExp "range_invalid" $-      I.BasicOp $ I.BinOp I.LogOr step_invalid bounds_invalid+      I.BasicOp $+        I.BinOp I.LogOr step_invalid bounds_invalid   valid <- letSubExp "valid" $ I.BasicOp $ I.UnOp I.Not invalid   cs <- assert "range_valid_c" valid errmsg loc    step_i64 <- asIntS Int64 step   pos_step <-     letSubExp "pos_step" $-      I.BasicOp $ I.BinOp (Mul Int64 I.OverflowWrap) step_i64 step_sign_i64+      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 Int64 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)   pure [se] internaliseAppExp desc (E.AppRes et ext) (E.Coerce e dt loc) = do   ses <- internaliseExp desc e-  ts <- internaliseReturnType (E.RetType ext (E.toStruct et)) =<< mapM subExpType ses+  ts <- internaliseReturnType (E.RetType ext (E.toStruct et)) <$> mapM subExpType ses   dt' <- typeExpForError dt   forM (zip ses ts) $ \(e', t') -> do     dims <- arrayDims <$> subExpType e'@@ -545,7 +505,9 @@           loop_end_cond_body <- renameBody <=< buildBody_ $ do             forM_ (zip shapepat shapeargs) $ \(p, se) ->               unless (se == I.Var (paramName p)) $-                letBindNames [paramName p] $ BasicOp $ SubExp se+                letBindNames [paramName p] $+                  BasicOp $+                    SubExp se             forM_ (zip mergepat' ses) $ \(p, se) ->               unless (se == I.Var (paramName p)) $                 letBindNames [paramName p] $@@ -586,7 +548,8 @@         (_, pertinent) <- generateCond pLast ses         eLast' <- internalisePat' [] pLast pertinent eLast (internaliseBody desc)         foldM (\bf c' -> eValBody $ pure $ generateCaseIf ses c' bf) eLast' $-          reverse $ NE.init cs'+          reverse $+            NE.init cs'       letValExp' desc =<< generateCaseIf ses c bFalse internaliseAppExp desc _ (E.If ce te fe _) =   letValExp' desc@@ -602,8 +565,8 @@   internaliseExp desc e internaliseExp desc (E.Hole (Info t) loc) = do   let msg = pretty $ "Reached hole of type: " <> align (ppr t)+      ts = internaliseType (E.toStruct t)   c <- assert "hole_c" (constant False) (errorMsg [ErrorString msg]) loc-  ts <- internaliseType (E.toStruct t)   case mapM hasStaticShape ts of     Nothing ->       error $ "Hole at " <> locStr loc <> " has existential type:\n" <> show ts@@ -614,7 +577,9 @@   internaliseExp desc e internaliseExp desc (E.StringLit vs _) =   fmap pure . letSubExp desc $-    I.BasicOp $ I.ArrayLit (map constant vs) $ I.Prim int8+    I.BasicOp $+      I.ArrayLit (map constant vs) $+        I.Prim int8 internaliseExp _ (E.Var (E.QualName _ name) _ _) = do   subst <- lookupSubst name   case subst of@@ -666,7 +631,7 @@         letSubExp desc $ I.BasicOp $ I.Reshape new_shape' flat_arr   | otherwise = do       es' <- mapM (internaliseExp "arr_elem") es-      arr_t_ext <- internaliseType $ E.toStruct arr_t+      let arr_t_ext = internaliseType $ E.toStruct arr_t        rowtypes <-         case mapM (fmap rowType . hasStaticShape . I.fromDecl) arr_t_ext of@@ -754,12 +719,12 @@   where     replace (E.Scalar (E.Record m)) (f : fs) ve' src'       | Just t <- M.lookup f m = do-          i <--            fmap sum $-              mapM (internalisedTypeSize . snd) $-                takeWhile ((/= f) . fst) $ sortFields m-          k <- internalisedTypeSize t-          let (bef, to_update, aft) = splitAt3 i k src'+          let i =+                sum . map (internalisedTypeSize . snd) $+                  takeWhile ((/= f) . fst) . sortFields $+                    m+              k = internalisedTypeSize t+              (bef, to_update, aft) = splitAt3 i k src'           src'' <- replace t fs ve' to_update           pure $ bef ++ src'' ++ aft     replace _ _ ve' _ = pure ve'@@ -838,14 +803,13 @@ -- Builtin operators are handled specially because they are -- overloaded. internaliseExp desc (E.Project k e (Info rt) _) = do-  n <- internalisedTypeSize $ rt `setAliases` ()-  i' <- fmap sum $-    mapM internalisedTypeSize $-      case E.typeOf e `setAliases` () of-        E.Scalar (Record fs) ->-          map snd $ takeWhile ((/= k) . fst) $ sortFields fs-        t -> [t]-  take n . drop i' <$> internaliseExp desc e+  let i' = sum . map internalisedTypeSize $+        case E.typeOf e `setAliases` () of+          E.Scalar (Record fs) ->+            map snd $ takeWhile ((/= k) . fst) $ sortFields fs+          t -> [t]+  take (internalisedTypeSize $ rt `setAliases` ()) . drop i'+    <$> internaliseExp desc e internaliseExp _ e@E.Lambda {} =   error $ "internaliseExp: Unexpected lambda at " ++ locStr (srclocOf e) internaliseExp _ e@E.OpSection {} =@@ -906,8 +870,7 @@     compares (E.Id _ t loc) ses =       compares (E.Wildcard t loc) ses     compares (E.Wildcard (Info t) _) ses = do-      n <- internalisedTypeSize $ E.toStruct t-      let (id_ses, rest_ses) = splitAt n ses+      let (id_ses, rest_ses) = splitAt (internalisedTypeSize $ E.toStruct t) ses       pure ([], id_ses, rest_ses)     compares (E.PatParens pat _) ses =       compares pat ses@@ -984,7 +947,8 @@   ok <- letSubExp "index_ok" =<< eAll oks   let msg =         errorMsg $-          ["Index ["] ++ intercalate [", "] parts+          ["Index ["]+            ++ intercalate [", "] parts             ++ ["] out of bounds for array of shape ["]             ++ intersperse "][" (map (ErrorVal int64) $ take (length idxs) dims)             ++ ["]."]@@ -996,7 +960,7 @@   E.DimIndex ->   InternaliseM (I.DimIndex SubExp, SubExp, [ErrorMsgPart SubExp]) internaliseDimIndex w (E.DimFix i) = do-  (i', _) <- internaliseDimExp "i" i+  (i', _) <- internaliseSizeExp "i" i   let lowerBound =         I.BasicOp $ I.CmpOp (I.CmpSle I.Int64) (I.constant (0 :: I.Int64)) i'       upperBound =@@ -1014,7 +978,8 @@     ) = do     w_minus_1 <-       letSubExp "w_minus_1" $-        BasicOp $ I.BinOp (Sub Int64 I.OverflowWrap) w one+        BasicOp $+          I.BinOp (Sub Int64 I.OverflowWrap) w one     pure       ( I.DimSlice w_minus_1 w $ intConst Int64 (-1),         constant True,@@ -1023,26 +988,26 @@     where       one = constant (1 :: Int64) internaliseDimIndex w (E.DimSlice i j s) = do-  s' <- maybe (pure one) (fmap fst . internaliseDimExp "s") s+  s' <- maybe (pure one) (fmap fst . internaliseSizeExp "s") s   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+        letSubExp "i_def"+          $ I.If             backwards             (resultBody [w_minus_1])             (resultBody [zero])-            $ ifCommon [I.Prim int64]+          $ ifCommon [I.Prim int64]       j_def =-        letSubExp "j_def" $-          I.If+        letSubExp "j_def"+          $ I.If             backwards             (resultBody [negone])             (resultBody [w])-            $ ifCommon [I.Prim int64]-  i' <- maybe i_def (fmap fst . internaliseDimExp "i") i-  j' <- maybe j_def (fmap fst . internaliseDimExp "j") j+          $ ifCommon [I.Prim int64]+  i' <- maybe i_def (fmap fst . internaliseSizeExp "i") i+  j' <- maybe j_def (fmap fst . internaliseSizeExp "j") j   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.@@ -1071,13 +1036,16 @@   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 Int64) 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 Int64) 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 Int64) 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 Int64) zero i'   i_lte_j <- letSubExp "i_lte_j" $ I.BasicOp $ I.CmpOp (I.CmpSle Int64) i' j'@@ -1093,20 +1061,22 @@         [negone_lte_j, negone_lte_j, j_lte_i, zero_leq_i_p_m_t_s, i_p_m_t_s_leq_w]    slice_ok <--    letSubExp "slice_ok" $-      I.If+    letSubExp "slice_ok"+      $ I.If         backwards         (resultBody [backwards_ok])         (resultBody [forwards_ok])-        $ ifCommon [I.Prim I.Bool]+      $ ifCommon [I.Prim I.Bool]    ok_or_empty <-     letSubExp "ok_or_empty" $-      I.BasicOp $ I.BinOp I.LogOr empty_slice slice_ok+      I.BasicOp $+        I.BinOp I.LogOr empty_slice slice_ok    acceptable <-     letSubExp "slice_acceptable" $-      I.BasicOp $ I.BinOp I.LogAnd nonzero_stride ok_or_empty+      I.BasicOp $+        I.BinOp I.LogAnd nonzero_stride ok_or_empty    let parts = case (i, j, s) of         (_, _, Just {}) ->@@ -1200,7 +1170,7 @@         =<< bodyBind body    -- get sizes of histogram and image arrays-  shape_hist <- Shape . take dim . I.arrayDims <$> lookupType (head hist')+  shape_hist <- I.Shape . take dim . I.arrayDims <$> lookupType (head hist')   w_img <- I.arraySize 0 <$> lookupType (head img')    letValExp' desc . I.Op $@@ -1238,11 +1208,14 @@   -- Synthesize neutral elements by applying the fold function   -- to an empty chunk.   letBindNames [I.paramName chunk_param] $-    I.BasicOp $ I.SubExp $ constant (0 :: Int64)+    I.BasicOp $+      I.SubExp $+        constant (0 :: Int64)   forM_ lam_val_params $ \p ->     letBindNames [I.paramName p] $       I.BasicOp . I.Scratch (I.elemType $ I.paramType p) $-        I.arrayDims $ I.paramType p+        I.arrayDims $+          I.paramType p   nes <- bodyBind =<< renameBody lam_body    nes_ts <- mapM I.subExpResType nes@@ -1293,15 +1266,15 @@   acc_cert_v <- newVName "acc_cert"   dest_ts <- mapM lookupType dest'   let dest_w = arraysSize 0 dest_ts-      acc_t = Acc acc_cert_v (Shape [dest_w]) (map rowType dest_ts) NoUniqueness+      acc_t = Acc acc_cert_v (I.Shape [dest_w]) (map rowType dest_ts) NoUniqueness   acc_p <- newParam "acc_p" acc_t   withacc_lam <- mkLambda [Param mempty acc_cert_v (I.Prim I.Unit), acc_p] $ do-    lam' <--      internaliseMapLambda internaliseLambda lam $-        map I.Var $ paramName acc_p : bs'-    w <- arraysSize 0 <$> mapM lookupType bs'+    bs_ts <- mapM lookupType bs'+    lam' <- internaliseLambdaCoerce lam $ map rowType $ paramType acc_p : bs_ts+    let w = arraysSize 0 bs_ts     fmap subExpsRes . letValExp' "acc_res" $-      I.Op $ I.Screma w (paramName acc_p : bs') (I.mapSOAC lam')+      I.Op $+        I.Screma w (paramName acc_p : bs') (I.mapSOAC lam')    op' <-     case op of@@ -1318,7 +1291,8 @@    destw <- arraysSize 0 <$> mapM lookupType dest'   fmap (map I.Var) $-    letTupExp desc $ WithAcc [(Shape [destw], dest', op')] withacc_lam+    letTupExp desc $+      WithAcc [(I.Shape [destw], dest', op')] withacc_lam  internaliseExp1 :: String -> E.Exp -> InternaliseM I.SubExp internaliseExp1 desc e = do@@ -1329,12 +1303,12 @@  -- | Promote to dimension type as appropriate for the original type. -- Also return original type.-internaliseDimExp :: String -> E.Exp -> InternaliseM (I.SubExp, IntType)-internaliseDimExp s e = do+internaliseSizeExp :: String -> E.Exp -> InternaliseM (I.SubExp, IntType)+internaliseSizeExp s e = do   e' <- internaliseExp1 s e   case E.typeOf e of-    E.Scalar (E.Prim (Signed it)) -> (,it) <$> asIntS Int64 e'-    _ -> error "internaliseDimExp: bad type"+    E.Scalar (E.Prim (E.Signed it)) -> (,it) <$> asIntS Int64 e'+    _ -> error "internaliseSizeExp: bad type"  internaliseExpToVars :: String -> E.Exp -> InternaliseM [I.VName] internaliseExpToVars desc e =@@ -1503,7 +1477,8 @@   simpleCmpOp desc I.CmpLle y x -- Note the swapped x and y internaliseBinOp _ _ op _ _ t1 t2 =   error $-    "Invalid binary operator " ++ pretty op+    "Invalid binary operator "+      ++ pretty op       ++ " with operand types "       ++ pretty t1       ++ ", "@@ -1563,6 +1538,16 @@     pure (params', body', rettype') internaliseLambda e _ = error $ "internaliseLambda: unexpected expression:\n" ++ pretty e +internaliseLambdaCoerce :: E.Exp -> [Type] -> InternaliseM (I.Lambda SOACS)+internaliseLambdaCoerce lam argtypes = do+  (params, body, rettype) <- internaliseLambda lam argtypes+  mkLambda params $+    ensureResultShape+      (ErrorMsg [ErrorString "unexpected lambda result size"])+      (srclocOf lam)+      rettype+      =<< bodyBind body+ -- | Some operators and functions are overloaded or otherwise special -- - we detect and treat them here. isOverloadedFunction ::@@ -1688,11 +1673,10 @@      handleSOACs [TupLit [lam, arr] _] "map" = Just $ \desc -> do       arr' <- internaliseExpToVars "map_arr" arr-      lam' <- internaliseMapLambda internaliseLambda lam $ map I.Var arr'-      w <- arraysSize 0 <$> mapM lookupType arr'-      letTupExp' desc $-        I.Op $-          I.Screma w arr' (I.mapSOAC lam')+      arr_ts <- mapM lookupType arr'+      lam' <- internaliseLambdaCoerce lam $ map rowType arr_ts+      let w = arraysSize 0 arr_ts+      letTupExp' desc $ I.Op $ I.Screma w arr' (I.mapSOAC lam')     handleSOACs [TupLit [k, lam, arr] _] "partition" = do       k' <- fromIntegral <$> fromInt32 k       Just $ \_desc -> do@@ -1701,7 +1685,7 @@         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'+        fromInt32 (IntLit k' (Info (E.Scalar (E.Prim (E.Signed Int32)))) _) = Just $ fromInteger k'         fromInt32 _ = Nothing     handleSOACs [TupLit [lam, ne, arr] _] "reduce" = Just $ \desc ->       internaliseScanOrReduce desc "reduce" reduce (lam, ne, arr, loc)@@ -1751,9 +1735,7 @@       | fname `elem` ["jvp2", "vjp2"] = Just $ \desc -> do           x' <- internaliseExp "ad_x" x           v' <- internaliseExp "ad_v" v-          xts <- mapM subExpType x'-          (ps, body, ret) <- internaliseLambda f xts-          let lam = I.Lambda ps body ret+          lam <- internaliseLambdaCoerce f =<< mapM subExpType x'           fmap (map I.Var) . letTupExp desc . Op $             case fname of               "jvp2" -> JVP lam x' v'@@ -1858,12 +1840,12 @@       e' <- internaliseExp1 "trunc_arg" e       case E.typeOf e of         E.Scalar (E.Prim E.Bool) ->-          letTupExp' desc $-            I.If+          letTupExp' desc+            $ I.If               e'               (resultBody [intConst int_to 1])               (resultBody [intConst int_to 0])-              $ ifCommon [I.Prim $ I.IntType int_to]+            $ ifCommon [I.Prim $ I.IntType int_to]         E.Scalar (E.Prim (E.Signed int_from)) ->           letTupExp' desc $ I.BasicOp $ I.ConvOp (I.SExt int_from int_to) e'         E.Scalar (E.Prim (E.Unsigned int_from)) ->@@ -1876,12 +1858,12 @@       e' <- internaliseExp1 "trunc_arg" e       case E.typeOf e of         E.Scalar (E.Prim E.Bool) ->-          letTupExp' desc $-            I.If+          letTupExp' desc+            $ I.If               e'               (resultBody [intConst int_to 1])               (resultBody [intConst int_to 0])-              $ ifCommon [I.Prim $ I.IntType int_to]+            $ ifCommon [I.Prim $ I.IntType int_to]         E.Scalar (E.Prim (E.Signed int_from)) ->           letTupExp' desc $ I.BasicOp $ I.ConvOp (I.ZExt int_from int_to) e'         E.Scalar (E.Prim (E.Unsigned int_from)) ->@@ -1916,7 +1898,8 @@             loc         certifying c $           letExp (baseString sv ++ "_write_sv") $-            I.BasicOp $ I.Reshape (reshapeOuter [DimCoercion si_w] 1 sv_shape) sv+            I.BasicOp $+              I.Reshape (reshapeOuter [DimCoercion si_w] 1 sv_shape) sv        indexType <- fmap rowType <$> mapM lookupType si'       indexName <- mapM (\_ -> newVName "write_index") indexType@@ -1948,7 +1931,7 @@               }           sivs = si' <> svs' -      let sa_ws = map (Shape . take dim . arrayDims) sa_ts+      let sa_ws = map (I.Shape . take dim . arrayDims) sa_ts       letTupExp' desc $ I.Op $ I.Scatter si_w sivs lam $ zip3 sa_ws (repeat 1) sas  flatIndexHelper :: String -> SrcLoc -> E.Exp -> E.Exp -> [(E.Exp, E.Exp)] -> InternaliseM [SubExp]@@ -2100,7 +2083,7 @@ -- language. bindExtSizes :: AppRes -> [SubExp] -> InternaliseM () bindExtSizes (AppRes ret retext) ses = do-  ts <- internaliseType $ E.toStruct ret+  let ts = internaliseType $ E.toStruct ret   ses_ts <- mapM subExpType ses    let combine t1 t2 =@@ -2165,7 +2148,9 @@   sizes <-     letTupExp "partition_size" $       I.If is_empty empty_body nonempty_body $-        ifCommon $ replicate k $ I.Prim int64+        ifCommon $+          replicate k $+            I.Prim int64    -- The total size of all partitions must necessarily be equal to the   -- size of the input array.@@ -2173,7 +2158,8 @@   -- Create scratch arrays for the result.   blanks <- forM arr_ts $ \arr_t ->     letExp "partition_dest" $-      I.BasicOp $ Scratch (I.elemType arr_t) (w : drop 1 (I.arrayDims arr_t))+      I.BasicOp $+        Scratch (I.elemType arr_t) (w : drop 1 (I.arrayDims arr_t))    -- Now write into the result.   write_lam <- do@@ -2201,11 +2187,12 @@   results <-     letTupExp "partition_res" . I.Op $       I.Scatter w (classes : all_offsets ++ arrs) write_lam $-        zip3 (repeat $ Shape [w]) (repeat 1) blanks+        zip3 (repeat $ I.Shape [w]) (repeat 1) blanks   sizes' <-     letSubExp "partition_sizes" $       I.BasicOp $-        I.ArrayLit (map I.Var sizes) $ I.Prim int64+        I.ArrayLit (map I.Var sizes) $+          I.Prim int64   pure (map I.Var results, [sizes'])   where     mkOffsetLambdaBody ::@@ -2221,7 +2208,8 @@         letSubExp "is_this_one" $           I.BasicOp $             I.CmpOp (CmpEq int64) c $-              intConst Int64 $ toInteger i+              intConst Int64 $+                toInteger i       next_one <- mkOffsetLambdaBody sizes c (i + 1) ps       this_one <-         letSubExp "this_offset"@@ -2229,12 +2217,12 @@             (Add Int64 OverflowUndef)             (constant (-1 :: Int64))             (I.Var (I.paramName p) : take i sizes)-      letSubExp "total_res" $-        I.If+      letSubExp "total_res"+        $ I.If           is_this_one           (resultBody [this_one])           (resultBody [next_one])-          $ ifCommon [I.Prim int64]+        $ ifCommon [I.Prim int64]  typeExpForError :: E.TypeExp VName -> InternaliseM [ErrorMsgPart SubExp] typeExpForError (E.TEVar qn _) =@@ -2277,16 +2265,16 @@       c' <- mapM typeExpForError c       pure $ intercalate [" "] c' -dimExpForError :: E.DimExp VName -> InternaliseM (ErrorMsgPart SubExp)-dimExpForError (DimExpNamed d _) = do+dimExpForError :: E.SizeExp VName -> InternaliseM (ErrorMsgPart SubExp)+dimExpForError (SizeExpNamed d _) = do   substs <- lookupSubst $ E.qualLeaf d   d' <- case substs of     Just [v] -> pure v     _ -> pure $ I.Var $ E.qualLeaf d   pure $ ErrorVal int64 d'-dimExpForError (DimExpConst d _) =+dimExpForError (SizeExpConst d _) =   pure $ ErrorString $ pretty d-dimExpForError DimExpAny = pure ""+dimExpForError SizeExpAny = pure ""  -- A smart constructor that compacts neighbouring literals for easier -- reading in the IR.
− src/Futhark/Internalise/FreeVars.hs
@@ -1,132 +0,0 @@--- | Facilities for computing free variables in an expression, which--- we need for both lambda-lifting and defunctionalisation.-module Futhark.Internalise.FreeVars-  ( freeVars,-    without,-    ident,-    sizes,-    NameSet (..),-    patVars,-  )-where--import qualified Data.Map.Strict as M-import qualified Data.Set as S-import Futhark.IR.Pretty ()-import Language.Futhark---- | A set of names where we also track uniqueness.-newtype NameSet = NameSet {unNameSet :: M.Map VName StructType}-  deriving (Show)--instance Semigroup NameSet where-  NameSet x <> NameSet y = NameSet $ M.unionWith max x y--instance Monoid NameSet where-  mempty = NameSet mempty---- | Set subtraction.-without :: NameSet -> S.Set VName -> NameSet-without (NameSet x) y = NameSet $ M.filterWithKey keep x-  where-    keep k _ = k `S.notMember` y--withoutM :: NameSet -> NameSet -> NameSet-withoutM (NameSet x) (NameSet y) = NameSet $ x `M.difference` y---- | A 'NameSet' with a single 'Nonunique' name.-ident :: Ident -> NameSet-ident v = NameSet $ M.singleton (identName v) (toStruct $ unInfo $ identType v)--size :: VName -> NameSet-size v = NameSet $ M.singleton v $ Scalar $ Prim $ Signed Int64---- | A 'NameSet' with these names, considered to be sizes.-sizes :: S.Set VName -> NameSet-sizes = foldMap size---- | Compute the set of free variables of an expression.-freeVars :: Exp -> NameSet-freeVars expr = case expr of-  Literal {} -> mempty-  IntLit {} -> mempty-  FloatLit {} -> mempty-  StringLit {} -> mempty-  Hole {} -> mempty-  Parens e _ -> freeVars e-  QualParens _ e _ -> freeVars e-  TupLit es _ -> foldMap freeVars es-  RecordLit fs _ -> foldMap freeVarsField fs-    where-      freeVarsField (RecordFieldExplicit _ e _) = freeVars e-      freeVarsField (RecordFieldImplicit vn t _) = ident $ Ident vn t mempty-  ArrayLit es t _ ->-    foldMap freeVars es <> sizes (typeDimNames $ unInfo t)-  AppExp (Range e me incl _) _ ->-    freeVars e <> foldMap freeVars me <> foldMap freeVars incl-  Var qn (Info t) _ -> NameSet $ M.singleton (qualLeaf qn) $ toStruct t-  Ascript e _ _ -> freeVars e-  AppExp (Coerce e _ _) (Info ar) ->-    freeVars e <> sizes (typeDimNames (appResType ar))-  AppExp (LetPat let_sizes pat e1 e2 _) _ ->-    freeVars e1-      <> ( (sizes (patternDimNames pat) <> freeVars e2)-             `withoutM` (patVars pat <> foldMap (size . sizeName) let_sizes)-         )-  AppExp (LetFun vn (tparams, pats, _, _, e1) e2 _) _ ->-    ( (freeVars e1 <> sizes (foldMap patternDimNames pats))-        `without` ( S.map identName (foldMap patIdents pats)-                      <> S.fromList (map typeParamName tparams)-                  )-    )-      <> (freeVars e2 `without` S.singleton vn)-  AppExp (If e1 e2 e3 _) _ -> freeVars e1 <> freeVars e2 <> freeVars e3-  AppExp (Apply e1 e2 _ _) _ -> freeVars e1 <> freeVars e2-  Negate e _ -> freeVars e-  Not e _ -> freeVars e-  Lambda pats e0 _ (Info (_, RetType dims t)) _ ->-    (sizes (foldMap patternDimNames pats) <> freeVars e0 <> sizes (typeDimNames t))-      `withoutM` (foldMap patVars pats <> foldMap size dims)-  OpSection {} -> mempty-  OpSectionLeft _ _ e _ _ _ -> freeVars e-  OpSectionRight _ _ e _ _ _ -> freeVars e-  ProjectSection {} -> mempty-  IndexSection idxs _ _ -> foldMap freeDimIndex idxs-  AppExp (DoLoop sparams pat e1 form e3 _) _ ->-    let (e2fv, e2ident) = formVars form-     in freeVars e1-          <> ( (e2fv <> freeVars e3)-                 `withoutM` (sizes (S.fromList sparams) <> patVars pat <> e2ident)-             )-    where-      formVars (For v e2) = (freeVars e2, ident v)-      formVars (ForIn p e2) = (freeVars e2, patVars p)-      formVars (While e2) = (freeVars e2, mempty)-  AppExp (BinOp (qn, _) (Info qn_t) (e1, _) (e2, _) _) _ ->-    NameSet (M.singleton (qualLeaf qn) $ toStruct qn_t)-      <> freeVars e1-      <> freeVars e2-  Project _ e _ _ -> freeVars e-  AppExp (LetWith id1 id2 idxs e1 e2 _) _ ->-    ident id2 <> foldMap freeDimIndex idxs <> freeVars e1-      <> (freeVars e2 `without` S.singleton (identName id1))-  AppExp (Index e idxs _) _ -> freeVars e <> foldMap freeDimIndex idxs-  Update e1 idxs e2 _ -> freeVars e1 <> foldMap freeDimIndex idxs <> freeVars e2-  RecordUpdate e1 _ e2 _ _ -> freeVars e1 <> freeVars e2-  Assert e1 e2 _ _ -> freeVars e1 <> freeVars e2-  Constr _ es _ _ -> foldMap freeVars es-  Attr _ e _ -> freeVars e-  AppExp (Match e cs _) _ -> freeVars e <> foldMap caseFV cs-    where-      caseFV (CasePat p eCase _) =-        (sizes (patternDimNames p) <> freeVars eCase)-          `withoutM` patVars p--freeDimIndex :: DimIndexBase Info VName -> NameSet-freeDimIndex (DimFix e) = freeVars e-freeDimIndex (DimSlice me1 me2 me3) =-  foldMap (foldMap freeVars) [me1, me2, me3]---- | Extract all the variable names bound in a pattern.-patVars :: Pat -> NameSet-patVars = mconcat . map ident . S.toList . patIdents
src/Futhark/Internalise/Lambdas.hs view
@@ -2,7 +2,6 @@  module Futhark.Internalise.Lambdas   ( InternaliseLambda,-    internaliseMapLambda,     internaliseStreamMapLambda,     internaliseFoldLambda,     internaliseStreamLambda,@@ -19,22 +18,6 @@ type InternaliseLambda =   E.Exp -> [I.Type] -> InternaliseM ([I.LParam SOACS], I.Body SOACS, [I.Type]) -internaliseMapLambda ::-  InternaliseLambda ->-  E.Exp ->-  [I.SubExp] ->-  InternaliseM (I.Lambda SOACS)-internaliseMapLambda internaliseLambda lam args = do-  argtypes <- mapM I.subExpType args-  let rowtypes = map I.rowType argtypes-  (params, body, rettype) <- internaliseLambda lam rowtypes-  mkLambda params $-    ensureResultShape-      (ErrorMsg [ErrorString "not all iterations produce same shape"])-      (srclocOf lam)-      rettype-      =<< bodyBind body- internaliseStreamMapLambda ::   InternaliseLambda ->   E.Exp ->@@ -122,8 +105,8 @@     rettype = replicate (k + 2) $ I.Prim int64     result i =       map constant $-        fromIntegral i :-        (replicate i 0 ++ [1 :: Int64] ++ replicate (k - i) 0)+        fromIntegral i+          : (replicate i 0 ++ [1 :: Int64] ++ replicate (k - i) 0)      mkResult _ i | i >= k = pure $ result i     mkResult eq_class i = do@@ -131,7 +114,8 @@         letSubExp "is_i" $           BasicOp $             CmpOp (CmpEq int64) eq_class $-              intConst Int64 $ toInteger i+              intConst Int64 $+                toInteger i       letTupExp' "part_res"         =<< eIf           (eSubExp is_i)
src/Futhark/Internalise/LiftLambdas.hs view
@@ -16,7 +16,6 @@ import Data.Maybe import qualified Data.Set as S import Futhark.IR.Pretty ()-import qualified Futhark.Internalise.FreeVars as FV import Futhark.MonadFreshNames import Language.Futhark import Language.Futhark.Traversals@@ -71,6 +70,10 @@       m = identityMapper {mapOnExp = \e' -> modify (<> existentials e') >> pure e'}    in execState (astMap m e) here +freeSizes :: S.Set VName -> FV+freeSizes vs =+  FV $ M.fromList $ zip (S.toList vs) $ repeat $ Scalar $ Prim $ Signed Int64+ liftFunction :: VName -> [TypeParam] -> [Pat] -> StructRetType -> Exp -> LiftM Exp liftFunction fname tparams params (RetType dims ret) funbody = do   -- Find free variables@@ -82,20 +85,19 @@           <> S.fromList dims        free =-        let immediate_free = FV.freeVars funbody `FV.without` (bound <> existentials funbody)+        let immediate_free = freeInExp funbody `freeWithout` (bound <> existentials funbody)             sizes_in_free =-              foldMap typeDimNames $-                M.elems $ FV.unNameSet immediate_free+              foldMap freeInType $ M.elems $ unFV immediate_free             sizes =-              FV.sizes $+              freeSizes $                 sizes_in_free-                  <> foldMap patternDimNames params-                  <> typeDimNames ret-         in M.toList $ FV.unNameSet $ immediate_free <> (sizes `FV.without` bound)+                  <> foldMap freeInPat params+                  <> freeInType ret+         in M.toList $ unFV $ immediate_free <> (sizes `freeWithout` bound)        -- Those parameters that correspond to sizes must come first.       sizes_in_types =-        foldMap typeDimNames (ret : map snd free ++ map patternStructType params)+        foldMap freeInType (ret : map snd free ++ map patternStructType params)       isSize (v, _) = v `S.member` sizes_in_types       (free_dims, free_nondims) = partition isSize free @@ -117,10 +119,10 @@         valBindEntryPoint = Nothing       } -  pure $-    apply+  pure+    $ apply       (Var (qualName fname) (Info (augType $ free_dims ++ free_nondims)) mempty)-      $ free_dims ++ free_nondims+    $ free_dims ++ free_nondims   where     orig_type = funType params $ RetType dims ret     mkParam (v, t) = Id v (Info (fromStruct t)) mempty
src/Futhark/Internalise/Monad.hs view
@@ -14,13 +14,13 @@     FunInfo,     substitutingVars,     lookupSubst,+    addOpaques,     addFunDef,     lookupFunction,     lookupFunction',     lookupConst,     bindFunction,     bindConstant,-    localConstsScope,     assert,      -- * Convenient reexports@@ -60,8 +60,8 @@   { stateNameSource :: VNameSource,     stateFunTable :: FunTable,     stateConstSubsts :: VarSubsts,-    stateConstScope :: Scope SOACS,-    stateFuns :: [FunDef SOACS]+    stateFuns :: [FunDef SOACS],+    stateTypes :: OpaqueTypes   }  newtype InternaliseM a@@ -74,10 +74,20 @@       MonadReader InternaliseEnv,       MonadState InternaliseState,       MonadFreshNames,-      HasScope SOACS,-      LocalScope SOACS+      HasScope SOACS     ) +-- Internalisation has to deal with the risk of multiple binding of+-- the same variable (although always of the same type) in the+-- program; in particular this might imply shadowing a constant.  The+-- LocalScope instance for BuilderT does not handle this properly (and+-- doing so would make it slower).  So we remove already-known+-- variables before passing the scope on.+instance LocalScope SOACS InternaliseM where+  localScope scope (InternaliseM m) = do+    old_scope <- askScope+    InternaliseM $ localScope (scope `M.difference` old_scope) m+ instance MonadFreshNames (State InternaliseState) where   getNameSource = gets stateNameSource   putNameSource src = modify $ \s -> s {stateNameSource = src}@@ -95,12 +105,14 @@   MonadFreshNames m =>   Bool ->   InternaliseM () ->-  m (Stms SOACS, [FunDef SOACS])+  m (OpaqueTypes, Stms SOACS, [FunDef SOACS]) runInternaliseM safe (InternaliseM m) =   modifyNameSource $ \src ->     let ((_, consts), s) =           runState (runReaderT (runBuilderT m mempty) newEnv) (newState src)-     in ((consts, reverse $ stateFuns s), stateNameSource s)+     in ( (stateTypes s, consts, reverse $ stateFuns s),+          stateNameSource s+        )   where     newEnv =       InternaliseEnv@@ -114,8 +126,8 @@         { stateNameSource = src,           stateFunTable = mempty,           stateConstSubsts = mempty,-          stateConstScope = mempty,-          stateFuns = mempty+          stateFuns = mempty,+          stateTypes = mempty         }  substitutingVars :: VarSubsts -> InternaliseM a -> InternaliseM a@@ -127,6 +139,12 @@   const_substs <- gets $ M.lookup v . stateConstSubsts   pure $ env_substs `mplus` const_substs +-- | Add opaque types.  If the types are already known, they will not+-- be added.+addOpaques :: OpaqueTypes -> InternaliseM ()+addOpaques ts = modify $ \s ->+  s {stateTypes = stateTypes s <> ts}+ -- | Add a function definition to the program being constructed. addFunDef :: FunDef SOACS -> InternaliseM () addFunDef fd = modify $ \s -> s {stateFuns = fd : stateFuns s}@@ -140,7 +158,13 @@     bad = error $ "Internalise.lookupFunction: Function '" ++ pretty fname ++ "' not found."  lookupConst :: VName -> InternaliseM (Maybe [SubExp])-lookupConst fname = gets $ M.lookup fname . stateConstSubsts+lookupConst fname = do+  is_var <- asksScope (fname `M.member`)+  fname_subst <- lookupSubst fname+  case (is_var, fname_subst) of+    (_, Just ses) -> pure $ Just ses+    (True, _) -> pure $ Just [Var fname]+    _ -> pure Nothing  bindFunction :: VName -> FunDef SOACS -> FunInfo -> InternaliseM () bindFunction fname fd info = do@@ -149,21 +173,18 @@  bindConstant :: VName -> FunDef SOACS -> InternaliseM () bindConstant cname fd = do-  let stms = bodyStms $ funDefBody fd-      substs =-        drop (length (shapeContext (funDefRetType fd))) $-          map resSubExp $ bodyResult $ funDefBody fd-  addStms stms-  modify $ \s ->-    s-      { stateConstSubsts = M.insert cname substs $ stateConstSubsts s,-        stateConstScope = scopeOf stms <> stateConstScope s-      }+  addStms $ bodyStms $ funDefBody fd -localConstsScope :: InternaliseM a -> InternaliseM a-localConstsScope m = do-  scope <- gets stateConstScope-  localScope scope m+  case map resSubExp . bodyResult . funDefBody $ fd of+    [se] -> do+      letBindNames [cname] $ BasicOp $ SubExp se+    ses -> do+      let substs =+            drop (length (shapeContext (funDefRetType fd))) ses+      modify $ \s ->+        s+          { stateConstSubsts = M.insert cname substs $ stateConstSubsts s+          }  -- | Construct an 'Assert' statement, but taking attributes into -- account.  Always use this function, and never construct 'Assert'@@ -178,7 +199,8 @@   attrs <- asks $ attrsForAssert . envAttrs   attributing attrs $     letExp desc $-      BasicOp $ Assert se msg (loc, mempty)+      BasicOp $+        Assert se msg (loc, mempty)  -- | Execute the given action if 'envDoBoundsChecks' is true, otherwise -- just return an empty list.
src/Futhark/Internalise/Monomorphise.hs view
@@ -159,18 +159,18 @@   ppr (MonoKnown i) = text "?" <> ppr i   ppr (MonoAnon v) = text "?" <> pprName v -instance Pretty (ShapeDecl MonoSize) where-  ppr (ShapeDecl ds) = mconcat (map (brackets . ppr) ds)+instance Pretty (Shape MonoSize) where+  ppr (Shape ds) = mconcat (map (brackets . ppr) ds)  -- The kind of type relative to which we monomorphise.  What is most -- important to us is not the specific dimensions, but merely whether -- they are known or anonymous/local. type MonoType = TypeBase MonoSize () -monoType :: TypeBase (DimDecl VName) als -> MonoType+monoType :: TypeBase Size als -> MonoType monoType = (`evalState` (0, mempty)) . traverseDims onDim . toStruct   where-    onDim bound _ (NamedDim d)+    onDim bound _ (NamedSize d)       -- A locally bound size.       | qualLeaf d `S.member` bound = pure $ MonoAnon $ qualLeaf d     onDim _ _ d = do@@ -267,10 +267,10 @@   pure (sizes, params')   where     tv = identityMapper {mapOnPatType = bitraverse onDim pure}-    onDim (AnyDim _) = do+    onDim (AnySize _) = do       v <- lift $ newVName "size"       modify (v :)-      pure $ NamedDim $ qualName v+      pure $ NamedSize $ qualName v     onDim d = pure d  transformAppRes :: AppRes -> MonoM AppRes@@ -288,7 +288,8 @@ transformAppExp (LetPat sizes pat e1 e2 loc) res = do   (pat', rr) <- transformPat pat   AppExp-    <$> ( LetPat sizes pat' <$> transformExp e1+    <$> ( LetPat sizes pat'+            <$> transformExp e1             <*> withRecordReplacements rr (transformExp e2)             <*> pure loc         )@@ -324,7 +325,7 @@     While e2 -> While <$> transformExp e2   e3' <- transformExp e3   -- Maybe monomorphisation introduced new arrays to the loop, and-  -- maybe they have AnyDim sizes.  This is not allowed.  Invent some+  -- maybe they have AnySize sizes.  This is not allowed.  Invent some   -- sizes for them.   (pat_sizes, pat') <- sizesForPat pat   pure $ AppExp (DoLoop (sparams ++ pat_sizes) pat' e1' form' e3' loc) (Info res)@@ -491,11 +492,15 @@       e' <- transformExp e       pure $ Project n e' tp loc transformExp (Update e1 idxs e2 loc) =-  Update <$> transformExp e1 <*> mapM transformDimIndex idxs+  Update+    <$> transformExp e1+    <*> mapM transformDimIndex idxs     <*> transformExp e2     <*> pure loc transformExp (RecordUpdate e1 fs e2 t loc) =-  RecordUpdate <$> transformExp e1 <*> pure fs+  RecordUpdate+    <$> transformExp e1+    <*> pure fs     <*> transformExp e2     <*> pure t     <*> pure loc@@ -542,9 +547,9 @@           )           (Info $ AppRes (Scalar $ Arrow mempty yp ytype (RetType [] t)) [])       rettype' =-        let onDim (NamedDim d)-              | Named p <- xp, qualLeaf d == p = NamedDim $ qualName v1-              | Named p <- yp, qualLeaf d == p = NamedDim $ qualName v2+        let onDim (NamedSize d)+              | Named p <- xp, qualLeaf d == p = NamedSize $ qualName v1+              | Named p <- yp, qualLeaf d == p = NamedSize $ qualName v2             onDim d = d          in first onDim rettype       body =@@ -599,7 +604,8 @@               Project field e (Info t) mempty         t ->           error $-            "desugarOpSection: type " ++ pretty t+            "desugarOpSection: type "+              ++ pretty t               ++ " does not have field "               ++ pretty field desugarProjectSection _ t _ = error $ "desugarOpSection: not a function type: " ++ pretty t@@ -619,11 +625,10 @@     t1' = fromStruct t1 desugarIndexSection _ t _ = error $ "desugarIndexSection: not a function type: " ++ pretty t -noticeDims :: TypeBase (DimDecl VName) as -> MonoM ()-noticeDims = mapM_ notice . nestedDims+noticeDims :: TypeBase Size as -> MonoM ()+noticeDims = mapM_ notice . freeInType   where-    notice (NamedDim v) = void $ transformFName mempty v i64-    notice _ = pure ()+    notice v = void $ transformFName mempty (qualName v) i64  -- Convert a collection of 'ValBind's to a nested sequence of let-bound, -- monomorphic functions with the given expression at the bottom.@@ -678,20 +683,20 @@ wildcard t loc =   Wildcard (Info t) loc -type DimInst = M.Map VName (DimDecl VName)+type DimInst = M.Map VName Size  dimMapping ::   Monoid a =>-  TypeBase (DimDecl VName) a ->-  TypeBase (DimDecl VName) a ->+  TypeBase Size a ->+  TypeBase Size a ->   DimInst dimMapping t1 t2 = execState (matchDims f t1 t2) mempty   where-    f bound d1 (NamedDim d2)+    f bound d1 (NamedSize d2)       | qualLeaf d2 `elem` bound = pure d1-    f _ (NamedDim d1) d2 = do+    f _ (NamedSize d1) d2 = do       modify $ M.insert (qualLeaf d1) d2-      pure $ NamedDim d1+      pure $ NamedSize d1     f _ d _ = pure d  inferSizeArgs :: [TypeParam] -> StructType -> StructType -> [Exp]@@ -700,9 +705,9 @@   where     tparamArg dinst tp =       case M.lookup (typeParamName tp) dinst of-        Just (NamedDim d) ->+        Just (NamedSize d) ->           Just $ Var d (Info i64) mempty-        Just (ConstDim x) ->+        Just (ConstSize x) ->           Just $ Literal (SignedValue $ Int64Value $ fromIntegral x) mempty         _ ->           Just $ Literal (SignedValue $ Int64Value 0) mempty@@ -746,7 +751,7 @@         params' = map (substPat entry substPatType) params         bind_t' = substTypesAny (`M.lookup` substs') bind_t         (shape_params_explicit, shape_params_implicit) =-          partition ((`S.member` mustBeExplicit bind_t') . typeParamName) $+          partition ((`S.member` mustBeExplicitInBinding bind_t') . typeParamName) $             shape_params ++ t_shape_params      (params'', rrs) <- unzip <$> mapM transformPat params'@@ -789,7 +794,6 @@       ASTMapper         { mapOnExp = updateExpTypes substs,           mapOnName = pure,-          mapOnQualName = pure,           mapOnStructType = pure . applySubst substs,           mapOnPatType = pure . applySubst substs,           mapOnStructRetType = pure . applySubst substs,@@ -822,7 +826,7 @@   runWriterT $ fst <$> execStateT (sub orig_t1 orig_t2) (mempty, mempty)   where     subRet (Scalar (TypeVar _ _ v _)) rt =-      unless (baseTag (typeLeaf v) <= maxIntrinsicTag) $+      unless (baseTag (qualLeaf v) <= maxIntrinsicTag) $         addSubst v rt     subRet t1 (RetType _ t2) =       sub t1 t2@@ -832,8 +836,9 @@         Just t2' <- peelArray (arrayRank t1) t2 =           sub t1' t2'     sub (Scalar (TypeVar _ _ v _)) t =-      unless (baseTag (typeLeaf v) <= maxIntrinsicTag) $-        addSubst v $ RetType [] t+      unless (baseTag (qualLeaf v) <= maxIntrinsicTag) $+        addSubst v $+          RetType [] t     sub (Scalar (Record fields1)) (Scalar (Record fields2)) =       zipWithM_         sub@@ -851,7 +856,7 @@     sub t1 t2@(Scalar Sum {}) = sub t1 t2     sub t1 t2 = error $ unlines ["typeSubstsM: mismatched types:", pretty t1, pretty t2] -    addSubst (TypeName _ v) (RetType ext t) = do+    addSubst (QualName _ v) (RetType ext t) = do       (ts, sizes) <- get       unless (v `M.member` ts) $ do         t' <- bitraverse onDim pure t@@ -864,10 +869,10 @@           d <- lift $ lift $ newVName "d"           tell [TypeParamDim d loc]           put (ts, M.insert i d sizes)-          pure $ NamedDim $ qualName d+          pure $ NamedSize $ qualName d         Just d ->-          pure $ NamedDim $ qualName d-    onDim (MonoAnon v) = pure $ AnyDim $ Just v+          pure $ NamedSize $ qualName d+    onDim (MonoAnon v) = pure $ AnySize $ Just v  -- Perform a given substitution on the types in a pattern. substPat :: Bool -> (PatType -> PatType) -> Pat -> Pat@@ -899,7 +904,6 @@         ASTMapper           { mapOnExp = onExp,             mapOnName = pure,-            mapOnQualName = pure,             mapOnStructType = pure . applySubst (`M.lookup` subs),             mapOnPatType = pure . applySubst (`M.lookup` subs),             mapOnStructRetType = pure . applySubst (`M.lookup` subs),@@ -922,21 +926,34 @@   subs <- asks $ M.map substFromAbbr . envTypeBindings   pure $ applySubst (`M.lookup` subs) t +transformEntryPoint :: EntryPoint -> MonoM EntryPoint+transformEntryPoint (EntryPoint params ret) =+  EntryPoint <$> mapM onEntryParam params <*> onEntryType ret+  where+    onEntryParam (EntryParam v t) =+      EntryParam v <$> onEntryType t+    onEntryType (EntryType t te) =+      EntryType <$> removeTypeVariablesInType t <*> pure te+ transformValBind :: ValBind -> MonoM Env transformValBind valbind = do   valbind' <-     toPolyBinding       <$> removeTypeVariables (isJust (valBindEntryPoint valbind)) valbind -  when (isJust $ valBindEntryPoint valbind) $ do-    t <--      removeTypeVariablesInType $-        foldFunType-          (map patternStructType (valBindParams valbind))-          $ unInfo $ valBindRetType valbind-    (name, infer, valbind'') <- monomorphiseBinding True valbind' $ monoType t-    tell $ Seq.singleton (name, valbind'' {valBindEntryPoint = valBindEntryPoint valbind})-    addLifted (valBindName valbind) (monoType t) (name, infer)+  case valBindEntryPoint valbind of+    Nothing -> pure ()+    Just (Info entry) -> do+      t <-+        removeTypeVariablesInType+          $ foldFunType+            (map patternStructType (valBindParams valbind))+          $ unInfo+          $ valBindRetType valbind+      (name, infer, valbind'') <- monomorphiseBinding True valbind' $ monoType t+      entry' <- transformEntryPoint entry+      tell $ Seq.singleton (name, valbind'' {valBindEntryPoint = Just $ Info entry'})+      addLifted (valBindName valbind) (monoType t) (name, infer)    pure mempty {envPolyBindings = M.singleton (valBindName valbind) valbind'} 
src/Futhark/Internalise/TypesValues.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE OverloadedStrings #-}  module Futhark.Internalise.TypesValues   ( -- * Internalising types@@ -19,8 +19,8 @@   ) where -import Control.Monad.Reader import Control.Monad.State+import Data.Bitraversable (bitraverse) import Data.List (delete, find, foldl') import qualified Data.Map.Strict as M import Data.Maybe@@ -35,23 +35,21 @@ newtype TypeState = TypeState {typeCounter :: Int}  newtype InternaliseTypeM a-  = InternaliseTypeM (StateT TypeState InternaliseM a)+  = InternaliseTypeM (State TypeState a)   deriving (Functor, Applicative, Monad, MonadState TypeState) -liftInternaliseM :: InternaliseM a -> InternaliseTypeM a-liftInternaliseM = InternaliseTypeM . lift--runInternaliseTypeM :: InternaliseTypeM a -> InternaliseM a+runInternaliseTypeM :: InternaliseTypeM a -> a runInternaliseTypeM = runInternaliseTypeM' mempty -runInternaliseTypeM' :: [VName] -> InternaliseTypeM a -> InternaliseM a-runInternaliseTypeM' exts (InternaliseTypeM m) = evalStateT m $ TypeState (length exts)+runInternaliseTypeM' :: [VName] -> InternaliseTypeM a -> a+runInternaliseTypeM' exts (InternaliseTypeM m) = evalState m $ TypeState (length exts)  internaliseParamTypes ::-  [E.TypeBase (E.DimDecl VName) ()] ->+  [E.TypeBase E.Size ()] ->   InternaliseM [[I.TypeBase Shape Uniqueness]] internaliseParamTypes ts =-  runInternaliseTypeM $ mapM (fmap (map onType) . internaliseTypeM mempty) ts+  mapM (mapM mkAccCerts) . runInternaliseTypeM $+    mapM (fmap (map onType) . internaliseTypeM mempty) ts   where     onType = fromMaybe bad . hasStaticShape     bad = error $ "internaliseParamTypes: " ++ pretty ts@@ -59,30 +57,44 @@ -- We need to fix up the arrays for any Acc return values or loop -- parameters.  We look at the concrete types for this, since the Acc -- parameter name in the second list will just be something we made up.-fixupTypes :: [TypeBase shape1 u1] -> [TypeBase shape2 u2] -> [TypeBase shape2 u2]-fixupTypes = zipWith fixup+fixupKnownTypes :: [TypeBase shape1 u1] -> [TypeBase shape2 u2] -> [TypeBase shape2 u2]+fixupKnownTypes = zipWith fixup   where     fixup (Acc acc ispace ts _) (Acc _ _ _ u2) = Acc acc ispace ts u2     fixup _ t = t +-- Generate proper certificates for the placeholder accumulator+-- certificates produced by internaliseType (identified with tag 0).+-- Only needed when we cannot use 'fixupKnownTypes'.+mkAccCerts :: TypeBase shape u -> InternaliseM (TypeBase shape u)+mkAccCerts (Array pt shape u) =+  pure $ Array pt shape u+mkAccCerts (Acc c shape ts u) =+  Acc <$> c' <*> pure shape <*> pure ts <*> pure u+  where+    c'+      | baseTag c == 0 = newVName "acc_cert"+      | otherwise = pure c+mkAccCerts t = pure t+ internaliseLoopParamType ::-  E.TypeBase (E.DimDecl VName) () ->+  E.TypeBase E.Size () ->   [TypeBase shape u] ->   InternaliseM [I.TypeBase Shape Uniqueness] internaliseLoopParamType et ts =-  fixupTypes ts . concat <$> internaliseParamTypes [et]+  fixupKnownTypes ts . concat <$> internaliseParamTypes [et]  internaliseReturnType ::   E.StructRetType ->   [TypeBase shape u] ->-  InternaliseM [I.TypeBase ExtShape Uniqueness]+  [I.TypeBase ExtShape Uniqueness] internaliseReturnType (E.RetType dims et) ts =-  fixupTypes ts <$> runInternaliseTypeM' dims (internaliseTypeM exts et)+  fixupKnownTypes ts $ runInternaliseTypeM' dims (internaliseTypeM exts et)   where     exts = M.fromList $ zip dims [0 ..]  internaliseLambdaReturnType ::-  E.TypeBase (E.DimDecl VName) () ->+  E.TypeBase E.Size () ->   [TypeBase shape u] ->   InternaliseM [I.TypeBase Shape NoUniqueness] internaliseLambdaReturnType et ts =@@ -92,7 +104,7 @@ -- tuple type piecemeal. internaliseEntryReturnType ::   E.StructRetType ->-  InternaliseM [[I.TypeBase ExtShape Uniqueness]]+  [[I.TypeBase ExtShape Uniqueness]] internaliseEntryReturnType (E.RetType dims et) =   runInternaliseTypeM' dims . mapM (internaliseTypeM exts) $     case E.isTupleRecord et of@@ -102,8 +114,8 @@     exts = M.fromList $ zip dims [0 ..]  internaliseType ::-  E.TypeBase (E.DimDecl VName) () ->-  InternaliseM [I.TypeBase I.ExtShape Uniqueness]+  E.TypeBase E.Size () ->+  [I.TypeBase I.ExtShape Uniqueness] internaliseType = runInternaliseTypeM . internaliseTypeM mempty  newId :: InternaliseTypeM Int@@ -114,21 +126,17 @@  internaliseDim ::   M.Map VName Int ->-  E.DimDecl VName ->+  E.Size ->   InternaliseTypeM ExtSize internaliseDim exts d =   case d of-    E.AnyDim _ -> Ext <$> newId-    E.ConstDim n -> pure $ Free $ intConst I.Int64 $ toInteger n-    E.NamedDim name -> namedDim name+    E.AnySize _ -> Ext <$> newId+    E.ConstSize n -> pure $ Free $ intConst I.Int64 $ toInteger n+    E.NamedSize name -> pure $ namedDim name   where     namedDim (E.QualName _ name)-      | Just x <- name `M.lookup` exts = pure $ I.Ext x-      | otherwise = do-          subst <- liftInternaliseM $ lookupSubst name-          case subst of-            Just [v] -> pure $ I.Free v-            _ -> pure $ I.Free $ I.Var name+      | Just x <- name `M.lookup` exts = I.Ext x+      | otherwise = I.Free $ I.Var name  internaliseTypeM ::   M.Map VName Int ->@@ -149,14 +157,14 @@       | otherwise ->           concat <$> mapM (internaliseTypeM exts . snd) (E.sortFields ets)     E.Scalar (E.TypeVar _ u tn [E.TypeArgType arr_t _])-      | baseTag (E.typeLeaf tn) <= E.maxIntrinsicTag,-        baseString (E.typeLeaf tn) == "acc" -> do+      | baseTag (E.qualLeaf tn) <= E.maxIntrinsicTag,+        baseString (E.qualLeaf tn) == "acc" -> do           ts <- map (fromDecl . onAccType) <$> internaliseTypeM exts arr_t-          acc_param <- liftInternaliseM $ newVName "acc_cert"-          let acc_t = Acc acc_param (Shape [arraysSize 0 ts]) (map rowType ts) $ internaliseUniqueness u+          let acc_param = VName "PLACEHOLDER" 0 -- See mkAccCerts.+              acc_t = Acc acc_param (Shape [arraysSize 0 ts]) (map rowType ts) $ internaliseUniqueness u           pure [acc_t]     E.Scalar E.TypeVar {} ->-      error "internaliseTypeM: cannot handle type variable."+      error $ "internaliseTypeM: cannot handle type variable: " ++ pretty orig_t     E.Scalar E.Arrow {} ->       error $ "internaliseTypeM: cannot handle function type: " ++ pretty orig_t     E.Scalar (E.Sum cs) -> do@@ -202,17 +210,17 @@       M.Map Name (Int, [Int])     ) internaliseSumType cs =-  runInternaliseTypeM $+  bitraverse (mapM mkAccCerts) pure . runInternaliseTypeM $     internaliseConstructors       <$> traverse (fmap concat . mapM (internaliseTypeM mempty)) cs  -- | How many core language values are needed to represent one source -- language value of the given type?-internalisedTypeSize :: E.TypeBase (E.DimDecl VName) als -> InternaliseM Int+internalisedTypeSize :: E.TypeBase E.Size als -> Int -- A few special cases for performance.-internalisedTypeSize (E.Scalar (E.Prim _)) = pure 1-internalisedTypeSize (E.Array _ _ _ (E.Prim _)) = pure 1-internalisedTypeSize t = length <$> internaliseType (t `E.setAliases` ())+internalisedTypeSize (E.Scalar (E.Prim _)) = 1+internalisedTypeSize (E.Array _ _ _ (E.Prim _)) = 1+internalisedTypeSize t = length $ internaliseType (t `E.setAliases` ())  -- | Convert an external primitive to an internal primitive. internalisePrimType :: E.PrimType -> I.PrimType
src/Futhark/LSP/Compile.hs view
@@ -4,6 +4,8 @@ -- the old state around. module Futhark.LSP.Compile (tryTakeStateFromIORef, tryReCompile) where +import Colog.Core (logStringStderr, (<&))+import Control.Lens.Getter (view) import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.IORef (IORef, readIORef, writeIORef) import qualified Data.Map as M@@ -13,7 +15,6 @@ import Futhark.LSP.Diagnostic (diagnosticSource, maxDiagnostic, publishErrorDiagnostics, publishWarningDiagnostics) import Futhark.LSP.State (State (..), emptyState, updateStaleContent, updateStaleMapping) import Futhark.LSP.Tool (computeMapping)-import Futhark.Util (debug) import Language.Futhark.Warnings (listWarnings) import Language.LSP.Server (LspT, flushDiagnosticsBySource, getVirtualFile, getVirtualFiles) import Language.LSP.Types@@ -22,7 +23,7 @@     toNormalizedUri,     uriToNormalizedFilePath,   )-import Language.LSP.VFS (VFS (vfsMap), virtualFileText)+import Language.LSP.VFS (VFS, vfsMap, virtualFileText)  -- | Try to take state from IORef, if it's empty, try to compile. tryTakeStateFromIORef :: IORef State -> Maybe FilePath -> LspT () IO State@@ -40,8 +41,8 @@       state <- case file_path of         Just file_path'           | file_path' `notElem` files -> do-              debug $ "File not part of program: " <> show file_path'-              debug $ "Program contains: " <> show files+              logStringStderr <& ("File not part of program: " <> show file_path')+              logStringStderr <& ("Program contains: " <> show files)               tryCompile old_state file_path noLoadedProg         _ -> pure old_state       liftIO $ writeIORef state_mvar state@@ -50,18 +51,18 @@ -- | Try to (re)-compile, replace old state if successful. tryReCompile :: IORef State -> Maybe FilePath -> LspT () IO () tryReCompile state_mvar file_path = do-  debug "(Re)-compiling ..."+  logStringStderr <& "(Re)-compiling ..."   old_state <- liftIO $ readIORef state_mvar   let loaded_prog = getLoadedProg old_state   new_state <- tryCompile old_state file_path loaded_prog   case stateProgram new_state of     Nothing -> do-      debug "Failed to (re)-compile, using old state or Nothing"-      debug $ "Computing PositionMapping for: " <> show file_path+      logStringStderr <& "Failed to (re)-compile, using old state or Nothing"+      logStringStderr <& "Computing PositionMapping for: " <> show file_path       mapping <- computeMapping old_state file_path       liftIO $ writeIORef state_mvar $ updateStaleMapping file_path mapping old_state     Just _ -> do-      debug "(Re)-compile successful"+      logStringStderr <& "(Re)-compile successful"       liftIO $ writeIORef state_mvar new_state  -- | Try to compile, publish diagnostics on warnings and errors, return newly compiled state.@@ -69,7 +70,7 @@ tryCompile :: State -> Maybe FilePath -> LoadedProg -> LspT () IO State tryCompile _ Nothing _ = pure emptyState tryCompile state (Just path) old_loaded_prog = do-  debug $ "Reloading program from " <> show path+  logStringStderr <& "Reloading program from " <> show path   vfs <- getVirtualFiles   res <- liftIO $ reloadProg old_loaded_prog [path] (transformVFS vfs) -- NOTE: vfs only keeps track of current opened files   flushDiagnosticsBySource maxDiagnostic diagnosticSource@@ -85,7 +86,7 @@     -- But still might need an update on re-compile logic, don't discard all state afterwards,     -- try to compile from root file, if there is a depencency relatetion, improve performance and provide more dignostic.     Left prog_error -> do-      debug "Compilation failed, publishing diagnostics"+      logStringStderr <& "Compilation failed, publishing diagnostics"       publishErrorDiagnostics prog_error       pure emptyState @@ -101,7 +102,7 @@             M.insert (fromNormalizedFilePath file_path) (virtualFileText virtual_file) acc     )     M.empty-    (vfsMap vfs)+    (view vfsMap vfs)  getLoadedProg :: State -> LoadedProg getLoadedProg state = fromMaybe noLoadedProg (stateProgram state)
src/Futhark/LSP/Diagnostic.hs view
@@ -10,6 +10,7 @@   ) where +import Colog.Core (logStringStderr, (<&)) import Control.Lens ((^.)) import Data.Foldable (for_) import qualified Data.List.NonEmpty as NE@@ -17,7 +18,6 @@ import qualified Data.Text as T import Futhark.Compiler.Program (ProgError (..)) import Futhark.LSP.Tool (posToUri, rangeFromLoc, rangeFromSrcLoc)-import Futhark.Util (debug) import Futhark.Util.Loc (Loc (..), SrcLoc, locOf) import Futhark.Util.Pretty (Doc, prettyText) import Language.LSP.Diagnostics (partitionBySource)@@ -39,7 +39,8 @@ publish :: [(Uri, [Diagnostic])] -> LspT () IO () publish uri_diags_map = for_ uri_diags_map $ \(uri, diags) -> do   doc <- getVersionedTextDoc $ TextDocumentIdentifier uri-  debug $ "Publishing diagnostics for " ++ show uri ++ " Verion: " ++ show (doc ^. version)+  logStringStderr+    <& ("Publishing diagnostics for " ++ show uri ++ " Version: " ++ show (doc ^. version))   publishDiagnostics maxDiagnostic (toNormalizedUri uri) (doc ^. version) (partitionBySource diags)  -- | Send warning diagnostics to the client.
src/Futhark/LSP/Handlers.hs view
@@ -3,6 +3,7 @@ -- | The handlers exposed by the language server. module Futhark.LSP.Handlers (handlers) where +import Colog.Core (logStringStderr, (<&)) import Control.Lens ((^.)) import Data.Aeson.Types (Value (Array, String)) import Data.IORef@@ -10,7 +11,6 @@ import Futhark.LSP.Compile (tryReCompile, tryTakeStateFromIORef) import Futhark.LSP.State (State (..)) import Futhark.LSP.Tool (findDefinitionRange, getHoverInfoFromState)-import Futhark.Util (debug) import Language.LSP.Server (Handlers, LspM, notificationHandler, requestHandler) import Language.LSP.Types import Language.LSP.Types.Lens (HasUri (uri))@@ -32,23 +32,24 @@     ]  onInitializeHandler :: Handlers (LspM ())-onInitializeHandler = notificationHandler SInitialized $ \_msg -> debug "Initialized"+onInitializeHandler = notificationHandler SInitialized $ \_msg ->+  logStringStderr <& "Initialized"  onHoverHandler :: IORef State -> Handlers (LspM ()) onHoverHandler state_mvar = requestHandler STextDocumentHover $ \req responder -> do   let RequestMessage _ _ _ (HoverParams doc pos _workDone) = req       Position l c = pos       file_path = uriToFilePath $ doc ^. uri-  debug $ "Got hover request: " <> show (file_path, pos)+  logStringStderr <& ("Got hover request: " <> show (file_path, pos))   state <- tryTakeStateFromIORef state_mvar file_path   responder $ Right $ getHoverInfoFromState state file_path (fromEnum l + 1) (fromEnum c + 1)  onDocumentFocusHandler :: IORef State -> Handlers (LspM ()) onDocumentFocusHandler state_mvar = notificationHandler (SCustomMethod "custom/onFocusTextDocument") $ \msg -> do-  debug "Got custom request: onFocusTextDocument"+  logStringStderr <& "Got custom request: onFocusTextDocument"   let NotificationMessage _ _ (Array vector_param) = msg       String focused_uri = V.head vector_param -- only one parameter passed from the client-  debug $ show focused_uri+  logStringStderr <& show focused_uri   tryReCompile state_mvar (uriToFilePath (Uri focused_uri))  goToDefinitionHandler :: IORef State -> Handlers (LspM ())@@ -56,19 +57,17 @@   let RequestMessage _ _ _ (DefinitionParams doc pos _workDone _partial) = req       Position l c = pos       file_path = uriToFilePath $ doc ^. uri-  debug $ "Got goto definition: " <> show (file_path, pos)+  logStringStderr <& ("Got goto definition: " <> show (file_path, pos))   state <- tryTakeStateFromIORef state_mvar file_path   case findDefinitionRange state file_path (fromEnum l + 1) (fromEnum c + 1) of     Nothing -> responder $ Right $ InR $ InL $ List []-    Just loc -> do-      debug $ show loc-      responder $ Right $ InL loc+    Just loc -> responder $ Right $ InL loc  onDocumentSaveHandler :: IORef State -> Handlers (LspM ()) onDocumentSaveHandler state_mvar = notificationHandler STextDocumentDidSave $ \msg -> do   let NotificationMessage _ _ (DidSaveTextDocumentParams doc _text) = msg       file_path = uriToFilePath $ doc ^. uri-  debug $ "Saved document: " ++ show doc+  logStringStderr <& ("Saved document: " ++ show doc)   tryReCompile state_mvar file_path  onDocumentChangeHandler :: IORef State -> Handlers (LspM ())@@ -81,8 +80,9 @@ onDocumentOpenHandler state_mvar = notificationHandler STextDocumentDidOpen $ \msg -> do   let NotificationMessage _ _ (DidOpenTextDocumentParams doc) = msg       file_path = uriToFilePath $ doc ^. uri-  debug $ "Opened document: " ++ show (doc ^. uri)+  logStringStderr <& ("Opened document: " ++ show (doc ^. uri))   tryReCompile state_mvar file_path  onDocumentCloseHandler :: Handlers (LspM ())-onDocumentCloseHandler = notificationHandler STextDocumentDidClose $ \_msg -> debug "Closed document"+onDocumentCloseHandler = notificationHandler STextDocumentDidClose $ \_msg ->+  logStringStderr <& "Closed document"
src/Futhark/Optimise/BlkRegTiling.hs view
@@ -93,7 +93,8 @@      -- inner loop updating this thread's accumulator (loop k in mmm_kernels).     thd_acc <- forLoop tk [thd_res_merge] $ \k [acc_merge] ->-      resultBodyM =<< letTupExp' "foo"+      resultBodyM+        =<< letTupExp' "foo"         =<< eIf           ( toExp $               if epilogue@@ -162,7 +163,8 @@              css <- forLoop ry [css_init] $ \i [css_merge] -> do               css <- forLoop rx [css_merge] $ \j [css_merge'] ->-                resultBodyM =<< letTupExp' "foo"+                resultBodyM+                  =<< letTupExp' "foo"                   =<< eIf                     ( toExp $                         if fits_ij@@ -174,8 +176,8 @@                              le64 iii + le64 i + pe64 ry * le64 ltid_y                               .<. pe64 height_A-                                .&&. le64 jjj + le64 j + pe64 rx * le64 ltid_x-                              .<. pe64 width_B+                              .&&. le64 jjj + le64 j + pe64 rx * le64 ltid_x+                                .<. pe64 width_B                     )                     ( do                         a <- index "a" as [i]@@ -529,7 +531,8 @@           -- build prologue.           full_tiles <-             letExp "full_tiles" $-              BasicOp $ BinOp (SQuot Int64 Unsafe) common_dim tk+              BasicOp $+                BinOp (SQuot Int64 Unsafe) common_dim tk            let ct_arg =                 ( (rx, ry, tx, ty, tk, tk_div_tx, tk_div_ty, tx_rx),@@ -736,7 +739,7 @@    (ty, ry) <- getParTiles ("Ty", "Ry") (ty_name, ry_name) height_A   (tx, rx) <- getParTiles ("Tx", "Rx") (tx_name, rx_name) width_B-  tk <- getSeqTile "Tk" tk_name common_dim ty tx+  tk <- getSeqTile "Tk" tk_name common_dim tx ty    tk_div_tx <- letSubExp "tk_div_tx" =<< ceilDiv tk tx   tk_div_ty <- letSubExp "tk_div_ty" =<< ceilDiv tk ty@@ -874,10 +877,10 @@       if not branch_invariant         then Nothing -- if i or j in branch_variant; return nothing         else-          if nameIn i variant_to && not (nameIn j variant_to)+          if nameIn i variant_to && j `notNameIn` variant_to             then Just 0             else-              if nameIn j variant_to && not (nameIn i variant_to)+              if nameIn j variant_to && i `notNameIn` variant_to                 then Just 1                 else Nothing @@ -891,12 +894,12 @@   | Just (ss, tab) <- acc,     [p] <- patElems patt,     p_nm <- patElemName p,-    nameIn p_nm arrs =+    p_nm `nameIn` arrs =       Just (ss, M.insert p_nm stm tab) processIndirections _ res_red_var acc stm'@(Let patt _ _)   | Just (ss, tab) <- acc,     ps <- patElems patt,-    all (\p -> not (nameIn (patElemName p) res_red_var)) ps =+    all (\p -> patElemName p `notNameIn` res_red_var) ps =       Just (ss Seq.|> stm', tab)   | otherwise = Nothing @@ -915,7 +918,7 @@       pure (t, r)  getSeqTile :: String -> Name -> SubExp -> SubExp -> SubExp -> Builder GPU SubExp-getSeqTile tk_str tk_name len_dim ty tx =+getSeqTile tk_str tk_name len_dim tx ty =   case (tx, ty) of     (Constant (IntValue (Int64Value v_x)), Constant (IntValue (Int64Value v_y))) ->       letSubExp tk_str . BasicOp . SubExp . constant $@@ -1153,7 +1156,9 @@                          res_nms <-                           letTupExp "Y_glb2loc" <=< renameExp $-                            Op $ SegOp $ SegMap segthd_lvl segspace [Prim ptp_Y] body+                            Op $+                              SegOp $+                                SegMap segthd_lvl segspace [Prim ptp_Y] body                         let res_nm : _ = res_nms                         pure res_nm                     resultBodyM $ map Var loc_arr_merge2_nms'@@ -1177,7 +1182,8 @@                               reg_arr_merge_nms' <-                                 forLoop' rz reg_arr_merge_nms_slc $ \i reg_arr_mm_nms -> do                                   letBindNames [gtid_z] =<< toExp (le64 ii + le64 i)-                                  resultBodyM =<< letTupExp' "redomap_lam"+                                  resultBodyM+                                    =<< letTupExp' "redomap_lam"                                     =<< eIf                                       (toExp $ le64 gtid_z .<. pe64 d_M)                                       ( do
src/Futhark/Optimise/CSE.hs view
@@ -235,7 +235,10 @@         local (addNameSubst pat' subpat) $ do           let lets =                 [ Let (Pat [patElem']) (StmAux cs attrs edec) $-                    BasicOp $ SubExp $ Var $ patElemName patElem+                    BasicOp $+                      SubExp $+                        Var $+                          patElemName patElem                   | (name, patElem) <- zip (patNames pat') $ patElems subpat,                     let patElem' = patElem {patElemName = name}                 ]
src/Futhark/Optimise/DoubleBuffer.hs view
@@ -245,7 +245,7 @@        in second (oneStm stm <>) <$> extractAllocOf bound' needle stms'   where     invariant Constant {} = True-    invariant (Var v) = not $ v `nameIn` bound+    invariant (Var v) = v `notNameIn` bound  optimiseLoop :: Constraints rep inner => OptimiseLoop rep optimiseLoop pat merge body = do@@ -315,7 +315,8 @@             MemArray pt shape u (ArrayIn _ arg_ixfun) -> do               arg_copy <- newVName (baseString arg <> "_dbcopy")               letBind (Pat [PatElem arg_copy $ MemArray pt shape u $ ArrayIn mem' arg_ixfun]) $-                BasicOp $ Copy arg+                BasicOp $+                  Copy arg               -- We need to make this parameter unique to avoid invalid               -- hoisting (see #1533), because we are invalidating the               -- underlying memory.@@ -361,8 +362,10 @@   where     params = map fst ctx_and_res     loopVariant v =-      v `nameIn` bound_in_loop-        || v `elem` map (paramName . fst) ctx_and_res+      v+        `nameIn` bound_in_loop+        || v+        `elem` map (paramName . fst) ctx_and_res      loopInvariantSize (Constant v) =       Just (Constant v, True)@@ -467,7 +470,8 @@           summary = MemArray (elemType t) (arrayShape t) NoUniqueness $ ArrayIn bufname ixfun           copystm =             Let (Pat [PatElem copyname summary]) (defAux ()) $-              BasicOp $ Copy v+              BasicOp $+                Copy v        in (Just copystm, SubExpRes cs (Var copyname))     buffer _ _ se =       (Nothing, se)
src/Futhark/Optimise/Fusion.hs view
@@ -1,1135 +1,481 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies #-}---- | Perform horizontal and vertical fusion of SOACs.  See the paper--- /A T2 Graph-Reduction Approach To Fusion/ for the basic idea (some--- extensions discussed in /Design and GPGPU Performance of Futhark’s--- Redomap Construct/).-module Futhark.Optimise.Fusion (fuseSOACs) where--import Control.Monad.Except-import Control.Monad.Reader-import Control.Monad.State-import qualified Data.List as L-import qualified Data.Map.Strict as M-import Data.Maybe-import qualified Data.Set as S-import qualified Futhark.Analysis.Alias as Alias-import qualified Futhark.Analysis.HORep.SOAC as SOAC-import Futhark.Construct-import qualified Futhark.IR.Aliases as Aliases-import Futhark.IR.Prop.Aliases-import Futhark.IR.SOACS hiding (SOAC (..))-import qualified Futhark.IR.SOACS as Futhark-import Futhark.IR.SOACS.Simplify-import Futhark.Optimise.Fusion.LoopKernel-import Futhark.Pass-import Futhark.Transform.Rename-import Futhark.Transform.Substitute-import Futhark.Util (maxinum)--data VarEntry-  = IsArray VName (NameInfo SOACS) Names SOAC.Input-  | IsNotArray (NameInfo SOACS)--varEntryType :: VarEntry -> NameInfo SOACS-varEntryType (IsArray _ dec _ _) =-  dec-varEntryType (IsNotArray dec) =-  dec--varEntryAliases :: VarEntry -> Names-varEntryAliases (IsArray _ _ x _) = x-varEntryAliases _ = mempty--data FusionGEnv = FusionGEnv-  { -- | Mapping from variable name to its entire family.-    soacs :: M.Map VName [VName],-    varsInScope :: M.Map VName VarEntry,-    fusedRes :: FusedRes-  }--lookupArr :: VName -> FusionGEnv -> Maybe SOAC.Input-lookupArr v env = asArray =<< M.lookup v (varsInScope env)-  where-    asArray (IsArray _ _ _ input) = Just input-    asArray IsNotArray {} = Nothing--newtype Error = Error String--instance Show Error where-  show (Error msg) = "Fusion error:\n" ++ msg--newtype FusionGM a = FusionGM (ExceptT Error (StateT VNameSource (Reader FusionGEnv)) a)-  deriving-    ( Monad,-      Applicative,-      Functor,-      MonadError Error,-      MonadState VNameSource,-      MonadReader FusionGEnv-    )--instance MonadFreshNames FusionGM where-  getNameSource = get-  putNameSource = put--instance HasScope SOACS FusionGM where-  askScope = asks $ toScope . varsInScope-    where-      toScope = M.map varEntryType------------------------------------------------------------------------------ Monadic Helpers: bind/new/runFusionGatherM, etc----------------------------------------------------------------------------- | Binds an array name to the set of used-array vars-bindVar :: FusionGEnv -> (Ident, Names) -> FusionGEnv-bindVar env (Ident name t, aliases) =-  env {varsInScope = M.insert name entry $ varsInScope env}-  where-    entry = case t of-      Array {} -> IsArray name (LetName t) aliases' $ SOAC.identInput $ Ident name t-      _ -> IsNotArray $ LetName t-    expand = maybe mempty varEntryAliases . flip M.lookup (varsInScope env)-    aliases' = aliases <> mconcat (map expand $ namesToList aliases)--bindVars :: FusionGEnv -> [(Ident, Names)] -> FusionGEnv-bindVars = foldl bindVar--binding :: [(Ident, Names)] -> FusionGM a -> FusionGM a-binding vs = local (`bindVars` vs)--gatherStmPat :: Pat Type -> Exp SOACS -> FusionGM FusedRes -> FusionGM FusedRes-gatherStmPat pat e = binding $ zip idents aliases-  where-    idents = patIdents pat-    aliases = expAliases (Alias.analyseExp mempty e)--bindingPat :: Pat Type -> FusionGM a -> FusionGM a-bindingPat = binding . (`zip` repeat mempty) . patIdents--bindingParams :: Typed t => [Param t] -> FusionGM a -> FusionGM a-bindingParams = binding . (`zip` repeat mempty) . map paramIdent---- | Binds an array name to the set of soac-produced vars-bindingFamilyVar :: [VName] -> FusionGEnv -> Ident -> FusionGEnv-bindingFamilyVar faml env (Ident nm t) =-  env-    { soacs = M.insert nm faml $ soacs env,-      varsInScope =-        M.insert-          nm-          ( IsArray nm (LetName t) mempty $-              SOAC.identInput $ Ident nm t-          )-          $ varsInScope env-    }--varAliases :: VName -> FusionGM Names-varAliases v =-  asks $-    (oneName v <>) . maybe mempty varEntryAliases-      . M.lookup v-      . varsInScope--varsAliases :: Names -> FusionGM Names-varsAliases = fmap mconcat . mapM varAliases . namesToList--updateKerInPlaces :: FusedRes -> ([VName], [VName]) -> FusionGM FusedRes-updateKerInPlaces res (ip_vs, other_infuse_vs) = do-  res' <- foldM addVarToInfusible res (ip_vs ++ other_infuse_vs)-  aliases <- mconcat <$> mapM varAliases ip_vs-  let inspectKer k = k {inplace = aliases <> inplace k}-  pure res' {kernels = M.map inspectKer $ kernels res'}--checkForUpdates :: FusedRes -> Exp SOACS -> FusionGM FusedRes-checkForUpdates res (BasicOp (Update _ src slice _)) = do-  let ifvs = namesToList $ freeIn slice-  updateKerInPlaces res ([src], ifvs)-checkForUpdates res (BasicOp (FlatUpdate src slice _)) = do-  let ifvs = namesToList $ freeIn slice-  updateKerInPlaces res ([src], ifvs)-checkForUpdates res (Op (Futhark.Scatter _ _ _ written_info)) = do-  let updt_arrs = map (\(_, _, x) -> x) written_info-  updateKerInPlaces res (updt_arrs, [])-checkForUpdates res (BasicOp (UpdateAcc src slice _)) = do-  let ifvs = namesToList $ freeIn slice-  updateKerInPlaces res ([src], ifvs)-checkForUpdates res _ = pure res---- | Updates the environment: (i) the @soacs@ (map) by binding each pattern---   element identifier to all pattern elements (identifiers) and (ii) the---   variables in scope (map) by inserting each (pattern-array) name.---   Finally, if the binding is an in-place update, then the @inplace@ field---   of each (result) kernel is updated with the new in-place updates.-bindingFamily :: Pat Type -> FusionGM FusedRes -> FusionGM FusedRes-bindingFamily pat = local bind-  where-    idents = patIdents pat-    family = patNames pat-    bind env = foldl (bindingFamilyVar family) env idents--bindingTransform :: PatElem Type -> VName -> SOAC.ArrayTransform -> FusionGM a -> FusionGM a-bindingTransform pe srcname trns = local $ \env ->-  case M.lookup srcname $ varsInScope env of-    Just (IsArray src' _ aliases input) ->-      env-        { varsInScope =-            M.insert-              vname-              ( IsArray src' (LetName dec) (oneName srcname <> aliases) $-                  trns `SOAC.addTransform` input-              )-              $ varsInScope env-        }-    _ -> bindVar env (patElemIdent pe, oneName vname)-  where-    vname = patElemName pe-    dec = patElemDec pe---- | Binds the fusion result to the environment.-bindRes :: FusedRes -> FusionGM a -> FusionGM a-bindRes rrr = local (\x -> x {fusedRes = rrr})---- | The fusion transformation runs in this monad.  The mutable--- state refers to the fresh-names engine.--- The reader hides the vtable that associates ... to ... (fill in, please).--- The 'Either' monad is used for error handling.-runFusionGatherM ::-  MonadFreshNames m =>-  FusionGM a ->-  FusionGEnv ->-  m (Either Error a)-runFusionGatherM (FusionGM a) env =-  modifyNameSource $ \src -> runReader (runStateT (runExceptT a) src) env------------------------------------------------------------------------------ Fusion Entry Points: gather the to-be-fused kernels@pgm level    -------    and fuse them in a second pass!                               -------------------------------------------------------------------------------- | The pass definition.-fuseSOACs :: Pass SOACS SOACS-fuseSOACs =-  Pass-    { passName = "Fuse SOACs",-      passDescription = "Perform higher-order optimisation, i.e., fusion.",-      passFunction = \prog ->-        simplifySOACS =<< renameProg-          =<< intraproceduralTransformationWithConsts-            (fuseConsts (freeIn (progFuns prog)))-            fuseFun-            prog-    }--fuseConsts :: Names -> Stms SOACS -> PassM (Stms SOACS)-fuseConsts used_consts consts =-  fuseStms mempty consts $ varsRes $ namesToList used_consts--fuseFun :: Stms SOACS -> FunDef SOACS -> PassM (FunDef SOACS)-fuseFun consts fun = do-  stms <--    fuseStms-      (scopeOf consts <> scopeOfFParams (funDefParams fun))-      (bodyStms $ funDefBody fun)-      (bodyResult $ funDefBody fun)-  let body = (funDefBody fun) {bodyStms = stms}-  pure fun {funDefBody = body}--fuseStms :: Scope SOACS -> Stms SOACS -> Result -> PassM (Stms SOACS)-fuseStms scope stms res = do-  let env =-        FusionGEnv-          { soacs = M.empty,-            varsInScope = mempty,-            fusedRes = mempty-          }-  k <--    cleanFusionResult-      <$> liftEitherM-        ( runFusionGatherM-            (binding scope' $ fusionGatherStms mempty (stmsToList stms) res)-            env-        )-  if not $ rsucc k-    then pure stms-    else liftEitherM $ runFusionGatherM (binding scope' $ bindRes k $ fuseInStms stms) env-  where-    scope' = map toBind $ M.toList scope-    toBind (k, t) = (Ident k $ typeOf t, mempty)-------------------------------------------------------------------------------------------------------------- RESULT's Data Structure------------------------------------------------------------------------------------------------------------ | A type used for (hopefully) uniquely referring a producer SOAC.--- The uniquely identifying value is the name of the first array--- returned from the SOAC.-newtype KernName = KernName {unKernName :: VName}-  deriving (Eq, Ord, Show)--data FusedRes = FusedRes-  { -- | Whether we have fused something anywhere.-    rsucc :: Bool,-    -- | Associates an array to the name of the-    -- SOAC kernel that has produced it.-    outArr :: M.Map VName KernName,-    -- | Associates an array to the names of the-    -- SOAC kernels that uses it. These sets include-    -- only the SOAC input arrays used as full variables, i.e., no `a[i]'.-    inpArr :: M.Map VName (S.Set KernName),-    -- | the (names of) arrays that are not fusible, i.e.,-    ---    --   1. they are either used other than input to SOAC kernels, or-    ---    --   2. are used as input to at least two different kernels that-    --      are not located on disjoint control-flow branches, or-    ---    --   3. are used in the lambda expression of SOACs-    infusible :: Names,-    -- | The map recording the uses-    kernels :: M.Map KernName FusedKer-  }--instance Semigroup FusedRes where-  res1 <> res2 =-    FusedRes-      (rsucc res1 || rsucc res2)-      (outArr res1 `M.union` outArr res2)-      (M.unionWith S.union (inpArr res1) (inpArr res2))-      (infusible res1 <> infusible res2)-      (kernels res1 `M.union` kernels res2)--instance Monoid FusedRes where-  mempty =-    FusedRes-      { rsucc = False,-        outArr = M.empty,-        inpArr = M.empty,-        infusible = mempty,-        kernels = M.empty-      }--isInpArrInResModKers :: FusedRes -> S.Set KernName -> VName -> Bool-isInpArrInResModKers ress kers nm =-  case M.lookup nm (inpArr ress) of-    Nothing -> False-    Just s -> not $ S.null $ s `S.difference` kers--getKersWithInpArrs :: FusedRes -> [VName] -> S.Set KernName-getKersWithInpArrs ress =-  S.unions . mapMaybe (`M.lookup` inpArr ress)---- | extend the set of names to include all the names---     produced via SOACs (by querring the vtable's soac)-expandSoacInpArr :: [VName] -> FusionGM [VName]-expandSoacInpArr =-  foldM-    ( \y nm -> do-        stm <- asks $ M.lookup nm . soacs-        case stm of-          Nothing -> pure (y ++ [nm])-          Just nns -> pure (y ++ nns)-    )-    []-------------------------------------------------------------------------------------------------------------------------------------------------soacInputs :: SOAC -> FusionGM ([VName], [VName])-soacInputs soac = do-  let (inp_idds, other_idds) = getIdentArr $ SOAC.inputs soac-      (inp_nms0, other_nms0) = (inp_idds, other_idds)-  inp_nms <- expandSoacInpArr inp_nms0-  other_nms <- expandSoacInpArr other_nms0-  pure (inp_nms, other_nms)--addNewKerWithInfusible :: FusedRes -> ([Ident], StmAux (), SOAC, Names) -> Names -> FusionGM FusedRes-addNewKerWithInfusible res (idd, aux, soac, consumed) ufs = do-  nm_ker <- KernName <$> newVName "ker"-  scope <- askScope-  let out_nms = map identName idd-      new_ker = newKernel aux soac consumed out_nms scope-      comb = M.unionWith S.union-      os' =-        M.fromList [(arr, nm_ker) | arr <- out_nms]-          `M.union` outArr res-      is' =-        M.fromList-          [ (arr, S.singleton nm_ker)-            | arr <- map SOAC.inputArray $ SOAC.inputs soac-          ]-          `comb` inpArr res-  pure $-    FusedRes-      (rsucc res)-      os'-      is'-      ufs-      (M.insert nm_ker new_ker (kernels res))--lookupInput :: VName -> FusionGM (Maybe SOAC.Input)-lookupInput name = asks $ lookupArr name--inlineSOACInput :: SOAC.Input -> FusionGM SOAC.Input-inlineSOACInput (SOAC.Input ts v t) = do-  maybe_inp <- lookupInput v-  case maybe_inp of-    Nothing ->-      pure $ SOAC.Input ts v t-    Just (SOAC.Input ts2 v2 t2) ->-      pure $ SOAC.Input (ts2 <> ts) v2 t2--inlineSOACInputs :: SOAC -> FusionGM SOAC-inlineSOACInputs soac = do-  inputs' <- mapM inlineSOACInput $ SOAC.inputs soac-  pure $ inputs' `SOAC.setInputs` soac---- | Attempts to fuse between SOACs. Input:---   @rem_stms@ are the bindings remaining in the current body after @orig_soac@.---   @lam_used_nms@ the infusible names---   @res@ the fusion result (before processing the current soac)---   @orig_soac@ and @out_idds@ the current SOAC and its binding pattern---   @consumed@ is the set of names consumed by the SOAC.---   Output: a new Fusion Result (after processing the current SOAC binding)-greedyFuse ::-  [Stm SOACS] ->-  Names ->-  FusedRes ->-  (Pat Type, StmAux (), SOAC, Names) ->-  FusionGM FusedRes-greedyFuse rem_stms lam_used_nms res (out_idds, aux, orig_soac, consumed) = do-  soac <- inlineSOACInputs orig_soac-  (inp_nms, other_nms) <- soacInputs soac-  -- Assumption: the free vars in lambda are already in @infusible res@.-  let out_nms = patNames out_idds-      isInfusible = (`nameIn` infusible res)-      is_screma = case orig_soac of-        SOAC.Screma _ form _ ->-          (isJust (isRedomapSOAC form) || isJust (isScanomapSOAC form))-            && not (isJust (isReduceSOAC form) || isJust (isScanSOAC form))-        _ -> False-  ---  -- Conditions for fusion:-  -- If current soac is a replicate OR (current soac a redomap/scanomap AND-  --    (i) none of @out_idds@ belongs to the infusible set)-  -- THEN try applying producer-consumer fusion-  -- ELSE try applying horizontal        fusion-  -- (without duplicating computation in both cases)--  (ok_kers_compat, fused_kers, fused_nms, old_kers, oldker_nms) <--    if is_screma || any isInfusible out_nms-      then horizontGreedyFuse rem_stms res (out_idds, aux, soac, consumed)-      else prodconsGreedyFuse res (out_idds, aux, soac, consumed)-  ---  -- (ii) check whether fusing @soac@ will violate any in-place update-  --      restriction, e.g., would move an input array past its in-place update.-  all_used_names <--    fmap mconcat . mapM varAliases . namesToList $-      mconcat [lam_used_nms, namesFromList inp_nms, namesFromList other_nms]-  let has_inplace ker = inplace ker `namesIntersect` all_used_names-      ok_inplace = not $ any has_inplace old_kers-  ---  -- (iii)  there are some kernels that use some of `out_idds' as inputs-  -- (iv)   and producer-consumer or horizontal fusion succeeds with those.-  let fusible_ker = not (null old_kers) && ok_inplace && ok_kers_compat-  ---  -- Start constructing the fusion's result:-  --  (i) inparr ids other than vars will be added to infusible list,-  -- (ii) will also become part of the infusible set the inparr vars-  --         that also appear as inparr of another kernel,-  --         BUT which said kernel is not the one we are fusing with (now)!-  let mod_kerS = if fusible_ker then S.fromList oldker_nms else mempty-  let used_inps = filter (isInpArrInResModKers res mod_kerS) inp_nms-  let ufs =-        mconcat-          [ infusible res,-            namesFromList used_inps,-            namesFromList other_nms-              `namesSubtract` namesFromList (map SOAC.inputArray $ SOAC.inputs soac)-          ]-  let comb = M.unionWith S.union--  if not fusible_ker-    then addNewKerWithInfusible res (patIdents out_idds, aux, soac, consumed) ufs-    else do-      -- Need to suitably update `inpArr':-      --   (i) first remove the inpArr bindings of the old kernel-      let inpArr' =-            foldl-              ( \inpa (kold, knm) ->-                  S.foldl'-                    ( \inpp nm ->-                        case M.lookup nm inpp of-                          Nothing -> inpp-                          Just s ->-                            let new_set = S.delete knm s-                             in if S.null new_set-                                  then M.delete nm inpp-                                  else M.insert nm new_set inpp-                    )-                    inpa-                    $ arrInputs kold-              )-              (inpArr res)-              (zip old_kers oldker_nms)-      --  (ii) then add the inpArr bindings of the new kernel-      let fused_ker_nms = zip fused_nms fused_kers-          inpArr'' =-            foldl-              ( \inpa' (knm, knew) ->-                  M.fromList-                    [ (k, S.singleton knm)-                      | k <- S.toList $ arrInputs knew-                    ]-                    `comb` inpa'-              )-              inpArr'-              fused_ker_nms-      -- Update the kernels map (why not delete the ones that have been fused?)-      let kernels' = M.fromList fused_ker_nms `M.union` kernels res-      -- nothing to do for `outArr' (since we have not added a new kernel)-      -- DO IMPROVEMENT: attempt to fuse the resulting kernel AGAIN until it fails,-      --                 but make sure NOT to add a new kernel!-      pure $ FusedRes True (outArr res) inpArr'' ufs kernels'--prodconsGreedyFuse ::-  FusedRes ->-  (Pat Type, StmAux (), SOAC, Names) ->-  FusionGM (Bool, [FusedKer], [KernName], [FusedKer], [KernName])-prodconsGreedyFuse res (out_idds, aux, soac, consumed) = do-  let out_nms = patNames out_idds -- Extract VNames from output patterns-      to_fuse_knmSet = getKersWithInpArrs res out_nms -- Find kernels which consume outputs-      to_fuse_knms = S.toList to_fuse_knmSet-      lookup_kern k = case M.lookup k (kernels res) of-        Nothing ->-          throwError $-            Error-              ( "In Fusion.hs, greedyFuse, comp of to_fuse_kers: "-                  ++ "kernel name not found in kernels field!"-              )-        Just ker -> pure ker-  to_fuse_kers <- mapM lookup_kern to_fuse_knms -- Get all consumer kernels-  -- try producer-consumer fusion-  (ok_kers_compat, fused_kers) <- do-    kers <--      forM to_fuse_kers $-        attemptFusion mempty (patNames out_idds) soac consumed-    case sequence kers of-      Nothing -> pure (False, [])-      Just kers' -> pure (True, map certifyKer kers')-  pure (ok_kers_compat, fused_kers, to_fuse_knms, to_fuse_kers, to_fuse_knms)-  where-    certifyKer k = k {kerAux = kerAux k <> aux}--horizontGreedyFuse ::-  [Stm SOACS] ->-  FusedRes ->-  (Pat Type, StmAux (), SOAC, Names) ->-  FusionGM (Bool, [FusedKer], [KernName], [FusedKer], [KernName])-horizontGreedyFuse rem_stms res (out_idds, aux, soac, consumed) = do-  (inp_nms, _) <- soacInputs soac-  let out_nms = patNames out_idds-      infusible_nms = namesFromList $ filter (`nameIn` infusible res) out_nms-      out_arr_nms = case soac of-        -- the accumulator result cannot be fused!-        SOAC.Screma _ (ScremaForm scans reds _) _ ->-          drop (scanResults scans + redResults reds) out_nms-        SOAC.Stream _ _ _ nes _ -> drop (length nes) out_nms-        _ -> out_nms-      to_fuse_knms1 = S.toList $ getKersWithInpArrs res (out_arr_nms ++ inp_nms)-      to_fuse_knms2 = getKersWithSameInpSize (SOAC.width soac) res-      to_fuse_knms = S.toList $ S.fromList $ to_fuse_knms1 ++ to_fuse_knms2-      lookupKernel k = case M.lookup k (kernels res) of-        Nothing ->-          throwError $-            Error-              ( "In Fusion.hs, greedyFuse, comp of to_fuse_kers: "-                  ++ "kernel name not found in kernels field!"-              )-        Just ker -> pure ker--  -- For each kernel get the index in the bindings where the kernel is-  -- located and sort based on the index so that partial fusion may-  -- succeed.  We use the last position where one of the kernel-  -- outputs occur.-  let stm_nms = map (patNames . stmPat) rem_stms-  kernminds <- forM to_fuse_knms $ \ker_nm -> do-    ker <- lookupKernel ker_nm-    case mapMaybe (\out_nm -> L.findIndex (elem out_nm) stm_nms) (outNames ker) of-      [] -> pure Nothing-      is -> pure $ Just (ker, ker_nm, maxinum is)--  scope <- askScope-  let kernminds' = L.sortBy (\(_, _, i1) (_, _, i2) -> compare i1 i2) $ catMaybes kernminds-      soac_kernel = newKernel aux soac consumed out_nms scope--  -- now try to fuse kernels one by one (in a fold); @ok_ind@ is the index of the-  -- kernel until which fusion succeded, and @fused_ker@ is the resulting kernel.-  (_, ok_ind, _, fused_ker, _) <--    foldM-      ( \(cur_ok, n, prev_ind, cur_ker, ufus_nms) (ker, _ker_nm, stm_ind) -> do-          -- check that we still try fusion and that the intermediate-          -- bindings do not use the results of cur_ker-          let curker_outnms = outNames cur_ker-              curker_outset = namesFromList curker_outnms-              new_ufus_nms = namesFromList $ filter (`notNameIn` fusedConsumed ker) $ outNames ker ++ namesToList ufus_nms-              ker_inp = SOAC.inputs $ fsoac ker-              ker_inp_names = namesFromList (mapMaybe SOAC.isVarInput ker_inp)--              -- disable horizontal fusion in the case when an output array of-              -- producer SOAC is a non-trivially transformed input of the consumer-              out_transf_ok =-                let unfuse1 =-                      namesFromList (map SOAC.inputArray ker_inp)-                        `namesSubtract` ker_inp_names-                    unfuse2 = namesIntersection curker_outset ufus_nms-                 in not $ unfuse1 `namesIntersect` unfuse2-              -- Disable horizontal fusion if consumer has any-              -- output transforms.-              cons_no_out_transf = SOAC.nullTransforms $ outputTransform ker--          -- check that consumer's lambda body does not use-          -- directly the produced arrays (e.g., see noFusion3.fut).-          let consumer_ok =-                not $-                  curker_outset-                    `namesIntersect` freeIn (lambdaBody $ SOAC.lambda $ fsoac ker)--          let interm_stms_ok =-                cur_ok && consumer_ok && out_transf_ok && cons_no_out_transf-                  && foldl-                    ( \ok stm ->-                        ok-                          && not (curker_outset `namesIntersect` freeIn (stmExp stm))-                          -- hardwired to False after first fail-                          -- (i) check that the in-between bindings do-                          --     not use the result of current kernel OR-                          ||-                          -- (ii) that the pattern-binding corresponds to-                          --     the result of the consumer kernel; in the-                          --     latter case it means it corresponds to a-                          --     kernel that has been fused in the consumer,-                          --     hence it should be ignored-                          not-                            ( null $-                                curker_outnms-                                  `L.intersect` patNames (stmPat stm)-                            )-                    )-                    True-                    (drop (prev_ind + 1) $ take stm_ind rem_stms)-          if not interm_stms_ok-            then pure (False, n, stm_ind, cur_ker, mempty)-            else do-              -- Avoid keeping results that are consumed by the-              -- consumer (#1613). The dance here is to still handle-              -- horizontal fusion of scatter-scatter properly-              -- (issue1284.fut).-              let ufus_nms' =-                    ufus_nms `namesSubtract` (fusedConsumed ker `namesIntersection` ker_inp_names)-              new_ker <--                attemptFusion-                  ufus_nms'-                  (outNames cur_ker)-                  (fsoac cur_ker)-                  (fusedConsumed cur_ker)-                  ker-              case new_ker of-                Nothing -> pure (False, n, stm_ind, cur_ker, mempty)-                Just krn -> do-                  let krn' = krn {kerAux = aux <> kerAux krn}-                  pure (True, n + 1, stm_ind, krn', new_ufus_nms)-      )-      (True, 0, 0, soac_kernel, infusible_nms)-      kernminds'--  -- Find the kernels we have fused into and the name of the last such-  -- kernel (if any).-  let (to_fuse_kers', to_fuse_knms', _) = unzip3 $ take ok_ind kernminds'-      new_kernms = drop (ok_ind - 1) to_fuse_knms'--  pure (ok_ind > 0, [fused_ker], new_kernms, to_fuse_kers', to_fuse_knms')-  where-    getKersWithSameInpSize :: SubExp -> FusedRes -> [KernName]-    getKersWithSameInpSize sz ress =-      map fst $ filter (\(_, ker) -> sz == SOAC.width (fsoac ker)) $ M.toList $ kernels ress-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Fusion Gather for EXPRESSIONS and BODIES,                        ------- i.e., where work is being done:                                  -------    i) bottom-up AbSyn traversal (backward analysis)              -------   ii) soacs are fused greedily iff does not duplicate computation------- E.g., (y1, y2, y3) = mapT(f, x1, x2[i])                          -------       (z1, z2)     = mapT(g1, y1, y2)                            -------       (q1, q2)     = mapT(g2, y3, z1, a, y3)                     -------       res          = reduce(op, ne, q1, q2, z2, y1, y3)          ------- can be fused if y1,y2,y3, z1,z2, q1,q2 are not used elsewhere:   -------       res = redomap(op, \(x1,x2i,a)->                            -------                             let (y1,y2,y3) = f (x1, x2i)       in-------                             let (z1,z2)    = g1(y1, y2)        in-------                             let (q1,q2)    = g2(y3, z1, a, y3) in-------                             (q1, q2, z2, y1, y3)                 -------                     x1, x2[i], a)                                --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------fusionGatherBody :: FusedRes -> Body SOACS -> FusionGM FusedRes-fusionGatherBody fres (Body _ stms res) =-  fusionGatherStms fres (stmsToList stms) res--fusionGatherStms :: FusedRes -> [Stm SOACS] -> Result -> FusionGM FusedRes--- Some forms of do-loops can profitably be considered streamSeqs.  We--- are careful to ensure that the generated nested loop cannot itself--- be considered a stream, to avoid infinite recursion.-fusionGatherStms-  fres-  (Let (Pat pes) stmtp (DoLoop merge (ForLoop i it w loop_vars) body) : stms)-  res-    | not $ null loop_vars,-      -- We cannot turn a loop into a stream if it has variant sizes-      -- in its parameters.-      not $ any ((`nameIn` freeIn merge) . paramName . fst) merge = do-        let (merge_params, merge_init) = unzip merge-            (loop_params, loop_arrs) = unzip loop_vars-        chunk_param <- newParam "chunk_size" $ Prim int64-        offset_param <- newParam "offset" $ Prim $ IntType it-        let offset = paramName offset_param-            chunk_size = paramName chunk_param--        acc_params <- forM merge_params $ \p ->-          newParam (baseString (paramName p) ++ "_outer") (paramType p)--        chunked_params <- forM loop_vars $ \(p, arr) ->-          newParam-            (baseString arr ++ "_chunk")-            (paramType p `arrayOfRow` Futhark.Var chunk_size)--        let lam_params = chunk_param : acc_params ++ [offset_param] ++ chunked_params--        lam_body <- runBodyBuilder $-          localScope (scopeOfLParams lam_params) $ do-            let merge' = zip merge_params $ map (Futhark.Var . paramName) acc_params-            j <- newVName "j"-            loop_body <- runBodyBuilder $ do-              forM_ (zip loop_params chunked_params) $ \(p, a_p) ->-                letBindNames [paramName p] $-                  BasicOp $-                    Index (paramName a_p) $-                      fullSlice (paramType a_p) [DimFix $ Futhark.Var j]-              letBindNames [i] $ BasicOp $ BinOp (Add it OverflowUndef) (Futhark.Var offset) (Futhark.Var j)-              pure body-            eBody-              [ pure $-                  DoLoop merge' (ForLoop j it (Futhark.Var chunk_size) []) loop_body,-                pure $-                  BasicOp $ BinOp (Add Int64 OverflowUndef) (Futhark.Var offset) (Futhark.Var chunk_size)-              ]-        let lam =-              Lambda-                { lambdaParams = lam_params,-                  lambdaBody = lam_body,-                  lambdaReturnType = map paramType $ acc_params ++ [offset_param]-                }-            stream = Futhark.Stream w loop_arrs Sequential (merge_init ++ [intConst it 0]) lam--        -- It is important that the (discarded) final-offset is not the-        -- 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 int64--        fusionGatherStms-          fres-          (Let (Pat (pes <> [discard_pe])) stmtp (Op stream) : stms)-          res-fusionGatherStms fres (stm@(Let pat _ e) : stms) res = do-  maybesoac <- SOAC.fromExp e-  case maybesoac of-    Right soac@(SOAC.Scatter _len lam _ivs _as) -> do-      -- We put the variables produced by Scatter into the infusible-      -- set to force horizontal fusion.  It is not possible to-      -- producer/consumer-fuse Scatter anyway.-      fres' <- addNamesToInfusible fres $ namesFromList $ patNames pat-      fres'' <- mapLike fres' soac lam-      checkForUpdates fres'' e-    Right soac@(SOAC.Hist _ _ lam _) -> do-      -- We put the variables produced by Hist into the infusible-      -- set to force horizontal fusion.  It is not possible to-      -- producer/consumer-fuse Hist anyway.-      fres' <- addNamesToInfusible fres $ namesFromList $ patNames pat-      mapLike fres' soac lam-    Right soac@(SOAC.Screma _ (ScremaForm scans reds map_lam) _) ->-      reduceLike soac (map scanLambda scans <> map redLambda reds <> [map_lam]) $-        concatMap scanNeutral scans <> concatMap redNeutral reds-    Right soac@(SOAC.Stream _ form lam nes _) -> do-      -- a redomap does not neccessarily start a new kernel, e.g.,-      -- @let a= reduce(+,0,A) in ... stms ... in let B = map(f,A)@-      -- can be fused into a redomap that replaces the @map@, if @a@-      -- and @B@ are defined in the same scope and @stms@ does not uses @a@.-      -- a redomap always starts a new kernel-      let lambdas = case form of-            Parallel _ _ lout -> [lout, lam]-            Sequential -> [lam]-      reduceLike soac lambdas nes-    _-      | Pat [pe] <- pat,-        Just (src, trns) <- SOAC.transformFromExp (stmCerts stm) e ->-          bindingTransform pe src trns $ fusionGatherStms fres stms res-      | otherwise -> do-          let pat_vars = map (BasicOp . SubExp . Var) $ patNames pat-          bres <- gatherStmPat pat e $ fusionGatherStms fres stms res-          bres' <- checkForUpdates bres e-          foldM fusionGatherExp bres' (e : pat_vars)-  where-    aux = stmAux stm-    rem_stms = stm : stms-    consumed = consumedInExp $ Alias.analyseExp mempty e--    reduceLike soac lambdas nes = do-      (used_lam, lres) <- foldM fusionGatherLam (mempty, fres) lambdas-      bres <- bindingFamily pat $ fusionGatherStms lres stms res-      bres' <- foldM fusionGatherSubExp bres nes-      consumed' <- varsAliases consumed-      greedyFuse rem_stms used_lam bres' (pat, aux, soac, consumed')--    mapLike fres' soac lambda = do-      bres <- bindingFamily pat $ fusionGatherStms fres' stms res-      (used_lam, blres) <- fusionGatherLam (mempty, bres) lambda-      consumed' <- varsAliases consumed-      greedyFuse rem_stms used_lam blres (pat, aux, soac, consumed')-fusionGatherStms fres [] res =-  foldM fusionGatherExp fres $ map (BasicOp . SubExp . resSubExp) res--fusionGatherExp :: FusedRes -> Exp SOACS -> FusionGM FusedRes-fusionGatherExp fres (DoLoop merge form loop_body) = do-  fres' <- addNamesToInfusible fres $ freeIn form <> freeIn merge-  let form_idents =-        case form of-          ForLoop i it _ loopvars ->-            Ident i (Prim (IntType it)) : map (paramIdent . fst) loopvars-          WhileLoop {} -> []--  new_res <--    binding (zip (form_idents ++ map (paramIdent . fst) merge) $ repeat mempty) $-      fusionGatherBody mempty loop_body-  -- make the inpArr infusible, so that they-  -- cannot be fused from outside the loop:-  let (inp_arrs, _) = unzip $ M.toList $ inpArr new_res-  let new_res' = new_res {infusible = infusible new_res <> mconcat (map oneName inp_arrs)}-  -- merge new_res with fres'-  pure $ new_res' <> fres'-fusionGatherExp fres (If cond e_then e_else _) = do-  then_res <- fusionGatherBody mempty e_then-  else_res <- fusionGatherBody mempty e_else-  let both_res = then_res <> else_res-  fres' <- fusionGatherSubExp fres cond-  mergeFusionRes fres' both_res-fusionGatherExp fres (WithAcc inps lam) = do-  (_, fres') <- fusionGatherLam (mempty, fres) lam-  addNamesToInfusible fres' $ freeIn inps----------------------------------------------------------------------------------------- Errors: all SOACs, (because normalization ensures they appear---- directly in let exp, i.e., let x = e)--------------------------------------------------------------------------------------fusionGatherExp _ (Op Futhark.Screma {}) = errorIllegal "screma"-fusionGatherExp _ (Op Futhark.Scatter {}) = errorIllegal "write"-fusionGatherExp fres (Op (Futhark.VJP lam _ _)) =-  snd <$> fusionGatherLam (mempty, fres) lam-fusionGatherExp fres (Op (Futhark.JVP lam _ _)) =-  snd <$> fusionGatherLam (mempty, fres) lam----fusionGatherExp fres e = addNamesToInfusible fres $ freeIn e--fusionGatherSubExp :: FusedRes -> SubExp -> FusionGM FusedRes-fusionGatherSubExp fres (Var idd) = addVarToInfusible fres idd-fusionGatherSubExp fres _ = pure fres--addNamesToInfusible :: FusedRes -> Names -> FusionGM FusedRes-addNamesToInfusible fres = foldM addVarToInfusible fres . namesToList--addVarToInfusible :: FusedRes -> VName -> FusionGM FusedRes-addVarToInfusible fres name = do-  trns <- asks $ lookupArr name-  let name' = case trns of-        Nothing -> name-        Just (SOAC.Input _ orig _) -> orig-  pure fres {infusible = oneName name' <> infusible fres}---- Lambdas create a new scope.  Disallow fusing from outside lambda by--- adding inp_arrs to the infusible set.-fusionGatherLam :: (Names, FusedRes) -> Lambda SOACS -> FusionGM (Names, FusedRes)-fusionGatherLam (u_set, fres) (Lambda idds body _) = do-  new_res <- bindingParams idds $ fusionGatherBody mempty body-  -- make the inpArr infusible, so that they-  -- cannot be fused from outside the lambda:-  let inp_arrs = namesFromList $ M.keys $ inpArr new_res-  let unfus = infusible new_res <> inp_arrs-  stms <- asks $ M.keys . varsInScope-  let unfus' = unfus `namesIntersection` namesFromList stms-  -- merge fres with new_res'-  let new_res' = new_res {infusible = unfus'}-  -- merge new_res with fres'-  pure (u_set <> unfus', new_res' <> fres)--------------------------------------------------------------------------------------------------------------------------------- FINALLY, Substitute the kernels in function------------------------------------------------------------------------------------------------------------------------------fuseInStms :: Stms SOACS -> FusionGM (Stms SOACS)-fuseInStms stms-  | Just (Let pat aux e, stms') <- stmsHead stms = do-      stms'' <- bindingPat pat $ fuseInStms stms'-      soac_stms <- replaceSOAC pat aux e-      pure $ soac_stms <> stms''-  | otherwise =-      pure mempty--fuseInBody :: Body SOACS -> FusionGM (Body SOACS)-fuseInBody (Body _ stms res) =-  Body () <$> fuseInStms stms <*> pure res--fuseInExp :: Exp SOACS -> FusionGM (Exp SOACS)--- Handle loop specially because we need to bind the types of the--- merge variables.-fuseInExp (DoLoop merge form loopbody) =-  binding (zip form_idents $ repeat mempty) $-    bindingParams (map fst merge) $-      DoLoop merge form <$> fuseInBody loopbody-  where-    form_idents = case form of-      WhileLoop {} -> []-      ForLoop i it _ loopvars ->-        Ident i (Prim $ IntType it) :-        map (paramIdent . fst) loopvars-fuseInExp e = mapExpM fuseIn e--fuseIn :: Mapper SOACS SOACS FusionGM-fuseIn =-  identityMapper-    { mapOnBody = const fuseInBody,-      mapOnOp = mapSOACM identitySOACMapper {mapOnSOACLambda = fuseInLambda}-    }--fuseInLambda :: Lambda SOACS -> FusionGM (Lambda SOACS)-fuseInLambda (Lambda params body rtp) = do-  body' <- bindingParams params $ fuseInBody body-  pure $ Lambda params body' rtp--replaceSOAC :: Pat Type -> StmAux () -> Exp SOACS -> FusionGM (Stms SOACS)-replaceSOAC (Pat []) _ _ = pure mempty-replaceSOAC pat@(Pat (patElem : _)) aux e = do-  fres <- asks fusedRes-  let pat_nm = patElemName patElem-      names = patIdents pat-  case M.lookup pat_nm (outArr fres) of-    Nothing ->-      oneStm . Let pat aux <$> fuseInExp e-    Just knm ->-      case M.lookup knm (kernels fres) of-        Nothing ->-          throwError $-            Error-              ( "In Fusion.hs, replaceSOAC, outArr in ker_name "-                  ++ "which is not in Res: "-                  ++ pretty (unKernName knm)-              )-        Just ker -> do-          when (null $ fusedVars ker) $-            throwError $-              Error-                ( "In Fusion.hs, replaceSOAC, unfused kernel "-                    ++ "still in result: "-                    ++ pretty names-                )-          insertKerSOAC aux (outNames ker) ker--insertKerSOAC :: StmAux () -> [VName] -> FusedKer -> FusionGM (Stms SOACS)-insertKerSOAC aux names ker = do-  new_soac' <- finaliseSOAC $ fsoac ker-  runBuilder_ $ do-    f_soac <- SOAC.toSOAC new_soac'-    -- The fused kernel may consume more than the original SOACs (see-    -- issue #224).  We insert copy expressions to fix it.-    f_soac' <- copyNewlyConsumed (fusedConsumed ker) $ addOpAliases mempty f_soac-    validents <- zipWithM newIdent (map baseString names) $ SOAC.typeOf new_soac'-    auxing (kerAux ker <> aux) $ letBind (basicPat validents) $ Op f_soac'-    transformOutput (outputTransform ker) names validents---- | Perform simplification and fusion inside the lambda(s) of a SOAC.-finaliseSOAC :: SOAC.SOAC SOACS -> FusionGM (SOAC.SOAC SOACS)-finaliseSOAC new_soac =-  case new_soac of-    SOAC.Screma w (ScremaForm scans reds map_lam) arrs -> do-      scans' <- forM scans $ \(Scan scan_lam scan_nes) -> do-        scan_lam' <- simplifyAndFuseInLambda scan_lam-        pure $ Scan scan_lam' scan_nes--      reds' <- forM reds $ \(Reduce comm red_lam red_nes) -> do-        red_lam' <- simplifyAndFuseInLambda red_lam-        pure $ Reduce comm red_lam' red_nes--      map_lam' <- simplifyAndFuseInLambda map_lam--      pure $ SOAC.Screma w (ScremaForm scans' reds' map_lam') arrs-    SOAC.Scatter w lam inps dests -> do-      lam' <- simplifyAndFuseInLambda lam-      pure $ SOAC.Scatter w lam' inps dests-    SOAC.Hist w ops lam arrs -> do-      lam' <- simplifyAndFuseInLambda lam-      pure $ SOAC.Hist w ops lam' arrs-    SOAC.Stream w form lam nes inps -> do-      lam' <- simplifyAndFuseInLambda lam-      pure $ SOAC.Stream w form lam' nes inps--simplifyAndFuseInLambda :: Lambda SOACS -> FusionGM (Lambda SOACS)-simplifyAndFuseInLambda lam = do-  lam' <- simplifyLambda lam-  (_, nfres) <- fusionGatherLam (mempty, mkFreshFusionRes) lam'-  let nfres' = cleanFusionResult nfres-  bindRes nfres' $ fuseInLambda lam'--copyNewlyConsumed ::-  Names ->-  Futhark.SOAC (Aliases.Aliases SOACS) ->-  Builder SOACS (Futhark.SOAC SOACS)-copyNewlyConsumed was_consumed soac =-  case soac of-    Futhark.Screma w arrs (Futhark.ScremaForm scans reds map_lam) -> do-      -- Copy any arrays that are consumed now, but were not in the-      -- constituents.-      arrs' <- mapM copyConsumedArr arrs-      -- Any consumed free variables will have to be copied inside the-      -- lambda, and we have to substitute the name of the copy for-      -- the original.-      map_lam' <- copyFreeInLambda map_lam--      let scans' =-            map-              ( \scan ->-                  scan-                    { scanLambda =-                        Aliases.removeLambdaAliases-                          (scanLambda scan)-                    }-              )-              scans--      let reds' =-            map-              ( \red ->-                  red-                    { redLambda =-                        Aliases.removeLambdaAliases-                          (redLambda red)-                    }-              )-              reds--      pure $ Futhark.Screma w arrs' $ Futhark.ScremaForm scans' reds' map_lam'-    _ -> pure $ removeOpAliases soac-  where-    consumed = consumedInOp soac-    newly_consumed = consumed `namesSubtract` was_consumed--    copyConsumedArr a-      | a `nameIn` newly_consumed =-          letExp (baseString a <> "_copy") $ BasicOp $ Copy a-      | otherwise = pure a--    copyFreeInLambda lam = do-      let free_consumed =-            consumedByLambda lam-              `namesSubtract` namesFromList (map paramName $ lambdaParams lam)-      (stms, subst) <--        foldM copyFree (mempty, mempty) $ namesToList free_consumed-      let lam' = Aliases.removeLambdaAliases lam-      pure $-        if null stms-          then lam'-          else-            lam'-              { lambdaBody =-                  insertStms stms $-                    substituteNames subst $ lambdaBody lam'-              }--    copyFree (stms, subst) v = do-      v_copy <- newVName $ baseString v <> "_copy"-      copy <- mkLetNamesM [v_copy] $ BasicOp $ Copy v-      pure (oneStm copy <> stms, M.insert v v_copy subst)-------------------------------------------------------------------------------------------------------------- HELPERS------------------------------------------------------------------------------------------------------------ | Get a new fusion result, i.e., for when entering a new scope,---   e.g., a new lambda or a new loop.-mkFreshFusionRes :: FusedRes-mkFreshFusionRes =-  FusedRes-    { rsucc = False,-      outArr = M.empty,-      inpArr = M.empty,-      infusible = mempty,-      kernels = M.empty-    }--mergeFusionRes :: FusedRes -> FusedRes -> FusionGM FusedRes-mergeFusionRes res1 res2 = do-  let ufus_mres = infusible res1 <> infusible res2-  inp_both <- expandSoacInpArr $ M.keys $ inpArr res1 `M.intersection` inpArr res2-  let m_unfus = ufus_mres <> mconcat (map oneName inp_both)-  pure $-    FusedRes-      (rsucc res1 || rsucc res2)-      (outArr res1 `M.union` outArr res2)-      (M.unionWith S.union (inpArr res1) (inpArr res2))-      m_unfus-      (kernels res1 `M.union` kernels res2)---- | The expression arguments are supposed to be array-type exps.---   Returns a tuple, in which the arrays that are vars are in the---   first element of the tuple, and the one which are indexed or---   transposes (or otherwise transformed) should be in the second.------   E.g., for expression `mapT(f, a, b[i])', the result should be---   `([a],[b])'-getIdentArr :: [SOAC.Input] -> ([VName], [VName])-getIdentArr = foldl comb ([], [])-  where-    comb (vs, os) (SOAC.Input ts idd _)-      | SOAC.nullTransforms ts = (idd : vs, os)-    comb (vs, os) inp =-      (vs, SOAC.inputArray inp : os)--cleanFusionResult :: FusedRes -> FusedRes-cleanFusionResult fres =-  let newks = M.filter (not . null . fusedVars) (kernels fres)-      newoa = M.filter (`M.member` newks) (outArr fres)-      newia = M.map (S.filter (`M.member` newks)) (inpArr fres)-   in fres {outArr = newoa, inpArr = newia, kernels = newks}-------------------- Errors --------------------errorIllegal :: String -> FusionGM FusedRes-errorIllegal soac_name =-  throwError $-    Error-      ("In Fusion.hs, soac " ++ soac_name ++ " appears illegally in pgm!")++-- | Perform horizontal and vertical fusion of SOACs.  See the paper+-- /A T2 Graph-Reduction Approach To Fusion/ for the basic idea (some+-- extensions discussed in /Design and GPGPU Performance of Futhark’s+-- Redomap Construct/).+module Futhark.Optimise.Fusion (fuseSOACs) where++import Control.Monad.Reader+import Control.Monad.State+import qualified Data.Graph.Inductive.Graph as G+import qualified Data.Graph.Inductive.Query.DFS as Q+import qualified Data.List as L+import qualified Data.Map.Strict as M+import Data.Maybe+import qualified Futhark.Analysis.Alias as Alias+import qualified Futhark.Analysis.HORep.SOAC as H+import Futhark.Construct+import Futhark.IR.Prop.Aliases+import Futhark.IR.SOACS hiding (SOAC (..))+import qualified Futhark.IR.SOACS as Futhark+import Futhark.IR.SOACS.Simplify (simplifyLambda)+import Futhark.Optimise.Fusion.GraphRep+import qualified Futhark.Optimise.Fusion.TryFusion as TF+import Futhark.Pass+import Futhark.Transform.Rename+import Futhark.Transform.Substitute++data FusionEnv = FusionEnv+  { vNameSource :: VNameSource,+    fusionCount :: Int,+    fuseScans :: Bool+  }++freshFusionEnv :: FusionEnv+freshFusionEnv =+  FusionEnv+    { vNameSource = blankNameSource,+      fusionCount = 0,+      fuseScans = True+    }++newtype FusionM a = FusionM (ReaderT (Scope SOACS) (State FusionEnv) a)+  deriving+    ( Monad,+      Applicative,+      Functor,+      MonadState FusionEnv,+      HasScope SOACS,+      LocalScope SOACS+    )++instance MonadFreshNames FusionM where+  getNameSource = gets vNameSource+  putNameSource source =+    modify (\env -> env {vNameSource = source})++runFusionM :: MonadFreshNames m => Scope SOACS -> FusionEnv -> FusionM a -> m a+runFusionM scope fenv (FusionM a) = modifyNameSource $ \src ->+  let x = runReaderT a scope+      (y, z) = runState x (fenv {vNameSource = src})+   in (y, vNameSource z)++doFuseScans :: FusionM a -> FusionM a+doFuseScans m = do+  fs <- gets fuseScans+  modify (\s -> s {fuseScans = True})+  r <- m+  modify (\s -> s {fuseScans = fs})+  pure r++dontFuseScans :: FusionM a -> FusionM a+dontFuseScans m = do+  fs <- gets fuseScans+  modify (\s -> s {fuseScans = False})+  r <- m+  modify (\s -> s {fuseScans = fs})+  pure r++unreachableEitherDir :: DepGraph -> G.Node -> G.Node -> Bool+unreachableEitherDir g a b =+  not (reachable g a b || reachable g b a)++isNotVarInput :: [H.Input] -> [H.Input]+isNotVarInput = filter (isNothing . H.isVarInput)++finalizeNode :: (HasScope SOACS m, MonadFreshNames m) => NodeT -> m (Stms SOACS)+finalizeNode nt = case nt of+  StmNode stm -> pure $ oneStm stm+  SoacNode ots outputs soac aux -> runBuilder_ $ do+    untransformed_outputs <- mapM newName $ patNames outputs+    auxing aux $ letBindNames untransformed_outputs . Op =<< H.toSOAC soac+    forM_ (zip (patNames outputs) untransformed_outputs) $ \(output, v) ->+      letBindNames [output] . BasicOp . SubExp . Var =<< H.applyTransforms ots v+  ResNode _ -> pure mempty+  FreeNode _ -> pure mempty+  DoNode stm lst -> do+    lst' <- mapM (finalizeNode . fst) lst+    pure $ mconcat lst' <> oneStm stm+  IfNode stm lst -> do+    lst' <- mapM (finalizeNode . fst) lst+    pure $ mconcat lst' <> oneStm stm+  FinalNode stms1 nt' stms2 -> do+    stms' <- finalizeNode nt'+    pure $ stms1 <> stms' <> stms2++linearizeGraph :: (HasScope SOACS m, MonadFreshNames m) => DepGraph -> m (Stms SOACS)+linearizeGraph dg =+  fmap mconcat $ mapM finalizeNode $ reverse $ Q.topsort' (dgGraph dg)++fusedSomething :: NodeT -> FusionM (Maybe NodeT)+fusedSomething x = do+  modify $ \s -> s {fusionCount = 1 + fusionCount s}+  pure $ Just x++-- | For each node, find what came before, attempt to fuse them+-- horizontally.  This means we only perform horizontal fusion for+-- SOACs that use the same input in some way.+horizontalFusionOnNode :: G.Node -> DepGraphAug FusionM+horizontalFusionOnNode node dg@DepGraph {dgGraph = g} =+  applyAugs (map (uncurry hTryFuseNodesInGraph) pairs) dg+  where+    incoming_nodes = map fst $ filter (isDep . snd) $ G.lpre g node+    pairs = [(x, y) | x <- incoming_nodes, y <- incoming_nodes, x < y]++vFusionFeasability :: DepGraph -> G.Node -> G.Node -> Bool+vFusionFeasability dg@DepGraph {dgGraph = g} n1 n2 =+  not (any isInf (edgesBetween dg n1 n2))+    && not (any (reachable dg n2) (filter (/= n2) (G.pre g n1)))++hFusionFeasability :: DepGraph -> G.Node -> G.Node -> Bool+hFusionFeasability = unreachableEitherDir++tryFuseNodeInGraph :: DepNode -> DepGraphAug FusionM+tryFuseNodeInGraph node_to_fuse dg@DepGraph {dgGraph = g} =+  if G.gelem node_to_fuse_id g+    then applyAugs (map (vTryFuseNodesInGraph node_to_fuse_id) fuses_with) dg+    else pure dg+  where+    fuses_with = map fst $ filter (isDep . snd) $ G.lpre g (nodeFromLNode node_to_fuse)+    node_to_fuse_id = nodeFromLNode node_to_fuse++vTryFuseNodesInGraph :: G.Node -> G.Node -> DepGraphAug FusionM+-- find the neighbors -> verify that fusion causes no cycles -> fuse+vTryFuseNodesInGraph node_1 node_2 dg@DepGraph {dgGraph = g}+  | not (G.gelem node_1 g && G.gelem node_2 g) = pure dg+  | vFusionFeasability dg node_1 node_2 = do+      let (ctx1, ctx2) = (G.context g node_1, G.context g node_2)+      fres <- vFuseContexts edgs infusable_nodes ctx1 ctx2+      case fres of+        Just (inputs, _, nodeT, outputs) -> do+          nodeT' <-+            if null fusedC+              then pure nodeT+              else do+                let (_, _, _, deps_1) = ctx1+                    (_, _, _, deps_2) = ctx2+                    -- make copies of everything that was not+                    -- previously consumed+                    old_cons = map (getName . fst) $ filter (isCons . fst) (deps_1 <> deps_2)+                makeCopiesOfFusedExcept old_cons nodeT+          contractEdge node_2 (inputs, node_1, nodeT', outputs) dg+        Nothing -> pure dg+  | otherwise = pure dg+  where+    edgs = map G.edgeLabel $ edgesBetween dg node_1 node_2+    fusedC = map getName $ filter isCons edgs+    infusable_nodes =+      map+        depsFromEdge+        (concatMap (edgesBetween dg node_1) (filter (/= node_2) $ G.pre g node_1))++hTryFuseNodesInGraph :: G.Node -> G.Node -> DepGraphAug FusionM+hTryFuseNodesInGraph node_1 node_2 dg@DepGraph {dgGraph = g}+  | not (G.gelem node_1 g && G.gelem node_2 g) = pure dg+  | hFusionFeasability dg node_1 node_2 = do+      fres <- hFuseContexts (G.context g node_1) (G.context g node_2)+      case fres of+        Just ctx -> contractEdge node_2 ctx dg+        Nothing -> pure dg+  | otherwise = pure dg++hFuseContexts :: DepContext -> DepContext -> FusionM (Maybe DepContext)+hFuseContexts+  c1@(_, _, nodeT1, _)+  c2@(_, _, nodeT2, _) = do+    fres <- hFuseNodeT nodeT1 nodeT2+    case fres of+      Just nodeT -> pure $ Just (mergedContext nodeT c1 c2)+      Nothing -> pure Nothing++vFuseContexts :: [EdgeT] -> [VName] -> DepContext -> DepContext -> FusionM (Maybe DepContext)+vFuseContexts+  edgs+  infusable+  c1@(i1, n1, nodeT1, o1)+  c2@(_i2, n2, nodeT2, o2) = do+    fres <-+      vFuseNodeT+        edgs+        infusable+        (nodeT1, map fst $ filter ((/=) n2 . snd) i1, map fst o1)+        (nodeT2, map fst $ filter ((/=) n1 . snd) o2)+    case fres of+      Just nodeT -> pure $ Just (mergedContext nodeT c1 c2)+      Nothing -> pure Nothing++makeCopiesOfFusedExcept ::+  (LocalScope SOACS m, MonadFreshNames m) =>+  [VName] ->+  NodeT ->+  m NodeT+makeCopiesOfFusedExcept noCopy (SoacNode ots pats soac aux) = do+  let lam = H.lambda soac+  localScope (scopeOf lam) $ do+    fused_inner <-+      filterM (fmap (not . isAcc) . lookupType) . namesToList . consumedByLambda $+        Alias.analyseLambda mempty lam+    lam' <- makeCopiesInLambda (fused_inner L.\\ noCopy) lam+    pure $ SoacNode ots pats (H.setLambda lam' soac) aux+makeCopiesOfFusedExcept _ nodeT = pure nodeT++makeCopiesInLambda ::+  (LocalScope SOACS m, MonadFreshNames m) =>+  [VName] ->+  Lambda SOACS ->+  m (Lambda SOACS)+makeCopiesInLambda toCopy lam = do+  (copies, nameMap) <- makeCopyStms toCopy+  let l_body = lambdaBody lam+      newBody = insertStms copies (substituteNames nameMap l_body)+      newLambda = lam {lambdaBody = newBody}+  pure newLambda++makeCopyStms ::+  (LocalScope SOACS m, MonadFreshNames m) =>+  [VName] ->+  m (Stms SOACS, M.Map VName VName)+makeCopyStms vs = do+  vs' <- mapM makeNewName vs+  copies <- forM (zip vs vs') $ \(name, name') ->+    mkLetNames [name'] $ BasicOp $ Copy name+  pure (stmsFromList copies, M.fromList $ zip vs vs')+  where+    makeNewName name = newVName $ baseString name <> "_copy"++okToFuseProducer :: H.SOAC SOACS -> FusionM Bool+okToFuseProducer (H.Screma _ form _) = do+  let is_scan = isJust $ Futhark.isScanomapSOAC form+  gets $ (not is_scan ||) . fuseScans+okToFuseProducer _ = pure True++-- First node is producer, second is consumer.+vFuseNodeT :: [EdgeT] -> [VName] -> (NodeT, [EdgeT], [EdgeT]) -> (NodeT, [EdgeT]) -> FusionM (Maybe NodeT)+vFuseNodeT _ infusible (s1, _, e1s) (IfNode stm2 dfused, _)+  | isRealNode s1,+    null infusible =+      pure $ Just $ IfNode stm2 $ (s1, e1s) : dfused+vFuseNodeT _ infusible (StmNode stm1, _, _) (SoacNode ots2 pats2 soac2 aux2, _)+  | null infusible,+    [stm1_out] <- patNames $ stmPat stm1,+    Just (stm1_in, tr) <-+      H.transformFromExp (stmAuxCerts (stmAux stm1)) (stmExp stm1) = do+      stm1_in_t <- lookupType stm1_in+      let onInput inp+            | H.inputArray inp == stm1_out =+                H.Input (tr H.<| H.inputTransforms inp) stm1_in stm1_in_t+            | otherwise =+                inp+          soac2' = map onInput (H.inputs soac2) `H.setInputs` soac2+      pure $ Just $ SoacNode ots2 pats2 soac2' aux2+vFuseNodeT+  _+  _+  (SoacNode ots1 pats1 soac1 aux1, i1s, _e1s)+  (SoacNode ots2 pats2 soac2 aux2, _e2s) = do+    let ker =+          TF.FusedSOAC+            { TF.fsSOAC = soac2,+              TF.fsOutputTransform = ots2,+              TF.fsOutNames = patNames pats2+            }+        preserveEdge InfDep {} = True+        preserveEdge e = isDep e+        preserve = namesFromList $ map getName $ filter preserveEdge i1s+    ok <- okToFuseProducer soac1+    r <-+      if ok && ots1 == mempty+        then TF.attemptFusion preserve (patNames pats1) soac1 ker+        else pure Nothing+    case r of+      Just ker' -> do+        let pats2' =+              zipWith PatElem (TF.fsOutNames ker') (H.typeOf (TF.fsSOAC ker'))+        fusedSomething $+          SoacNode+            (TF.fsOutputTransform ker')+            (Pat pats2')+            (TF.fsSOAC ker')+            (aux1 <> aux2)+      Nothing -> pure Nothing+vFuseNodeT _ _ _ _ = pure Nothing++resFromLambda :: Lambda rep -> Result+resFromLambda = bodyResult . lambdaBody++hasNoDifferingInputs :: [H.Input] -> [H.Input] -> Bool+hasNoDifferingInputs is1 is2 =+  let (vs1, vs2) = (isNotVarInput is1, isNotVarInput $ is2 L.\\ is1)+   in null $ vs1 `L.intersect` vs2++hFuseNodeT :: NodeT -> NodeT -> FusionM (Maybe NodeT)+hFuseNodeT (SoacNode ots1 pats1 soac1 aux1) (SoacNode ots2 pats2 soac2 aux2)+  | ots1 == mempty,+    ots2 == mempty,+    hasNoDifferingInputs (H.inputs soac1) (H.inputs soac2) = do+      let ker =+            TF.FusedSOAC+              { TF.fsSOAC = soac2,+                TF.fsOutputTransform = mempty,+                TF.fsOutNames = patNames pats2+              }+          preserve = namesFromList $ patNames pats1+      r <- TF.attemptFusion preserve (patNames pats1) soac1 ker+      case r of+        Just ker' -> do+          let pats2' =+                zipWith PatElem (TF.fsOutNames ker') (H.typeOf (TF.fsSOAC ker'))+          fusedSomething $ SoacNode mempty (Pat pats2') (TF.fsSOAC ker') (aux1 <> aux2)+        Nothing -> pure Nothing+hFuseNodeT _ _ = pure Nothing++removeOutputsExcept :: [VName] -> NodeT -> NodeT+removeOutputsExcept toKeep s = case s of+  SoacNode ots (Pat pats1) soac@(H.Screma _ (ScremaForm scans_1 red_1 lam_1) _) aux1 ->+    SoacNode ots (Pat $ pats_unchanged <> pats_new) (H.setLambda lam_new soac) aux1+    where+      scan_output_size = Futhark.scanResults scans_1+      red_output_size = Futhark.redResults red_1++      (pats_unchanged, pats_toChange) = splitAt (scan_output_size + red_output_size) pats1+      (res_unchanged, res_toChange) = splitAt (scan_output_size + red_output_size) (zip (resFromLambda lam_1) (lambdaReturnType lam_1))++      (pats_new, other) = unzip $ filter (\(x, _) -> patElemName x `elem` toKeep) (zip pats_toChange res_toChange)+      (results, types) = unzip (res_unchanged ++ other)+      lam_new =+        lam_1+          { lambdaReturnType = types,+            lambdaBody = (lambdaBody lam_1) {bodyResult = results}+          }+  node -> node++vNameFromAdj :: G.Node -> (EdgeT, G.Node) -> VName+vNameFromAdj n1 (edge, n2) = depsFromEdge (n2, n1, edge)++removeUnusedOutputsFromContext :: DepContext -> FusionM DepContext+removeUnusedOutputsFromContext (incoming, n1, nodeT, outgoing) =+  pure (incoming, n1, nodeT', outgoing)+  where+    toKeep = map (vNameFromAdj n1) incoming+    nodeT' = removeOutputsExcept toKeep nodeT++removeUnusedOutputs :: DepGraphAug FusionM+removeUnusedOutputs = mapAcross removeUnusedOutputsFromContext++doVerticalFusion :: DepGraphAug FusionM+doVerticalFusion dg = applyAugs (map tryFuseNodeInGraph $ reverse $ G.labNodes (dgGraph dg)) dg++doHorizontalFusion :: DepGraphAug FusionM+doHorizontalFusion dg = applyAugs (map horizontalFusionOnNode (G.nodes (dgGraph dg))) dg++doInnerFusion :: DepGraphAug FusionM+doInnerFusion = mapAcross runInnerFusionOnContext++-- Fixed-point iteration.+keepTrying :: DepGraphAug FusionM -> DepGraphAug FusionM+keepTrying f g = do+  prev_fused <- gets fusionCount+  g' <- f g+  aft_fused <- gets fusionCount+  if prev_fused /= aft_fused then keepTrying f g' else pure g'++doAllFusion :: DepGraphAug FusionM+doAllFusion =+  applyAugs+    [ keepTrying . applyAugs $+        [ doVerticalFusion,+          doHorizontalFusion,+          doInnerFusion+        ],+      removeUnusedOutputs+    ]++runInnerFusionOnContext :: DepContext -> FusionM DepContext+runInnerFusionOnContext c@(incoming, node, nodeT, outgoing) = case nodeT of+  DoNode (Let pat aux (DoLoop params form body)) to_fuse ->+    doFuseScans . localScope (scopeOfFParams (map fst params) <> scopeOf form) $ do+      b <- doFusionWithDelayed body to_fuse+      pure (incoming, node, DoNode (Let pat aux (DoLoop params form b)) [], outgoing)+  IfNode (Let pat aux (If sz b1 b2 dec)) to_fuse -> doFuseScans $ do+    b1' <- doFusionWithDelayed b1 to_fuse+    b2' <- doFusionWithDelayed b2 to_fuse+    rb2' <- renameBody b2'+    pure (incoming, node, IfNode (Let pat aux (If sz b1' rb2' dec)) [], outgoing)+  StmNode (Let pat aux (Op (Futhark.VJP lam args vec))) -> doFuseScans $ do+    lam' <- doFusionLambda lam+    pure (incoming, node, StmNode (Let pat aux (Op (Futhark.VJP lam' args vec))), outgoing)+  StmNode (Let pat aux (Op (Futhark.JVP lam args vec))) -> doFuseScans $ do+    lam' <- doFusionLambda lam+    pure (incoming, node, StmNode (Let pat aux (Op (Futhark.JVP lam' args vec))), outgoing)+  StmNode (Let pat aux (WithAcc inputs lam)) -> doFuseScans $ do+    lam' <- doFusionLambda lam+    pure (incoming, node, StmNode (Let pat aux (WithAcc inputs lam')), outgoing)+  SoacNode ots pat soac aux -> do+    let lam = H.lambda soac+    lam' <- localScope (scopeOf lam) $ case soac of+      H.Stream _ Sequential {} _ _ _ ->+        dontFuseScans $ doFusionLambda lam+      _ ->+        doFuseScans $ doFusionLambda lam+    let nodeT' = SoacNode ots pat (H.setLambda lam' soac) aux+    pure (incoming, node, nodeT', outgoing)+  _ -> pure c+  where+    doFusionWithDelayed :: Body SOACS -> [(NodeT, [EdgeT])] -> FusionM (Body SOACS)+    doFusionWithDelayed (Body () stms res) extraNodes = localScope (scopeOf stms) $ do+      stm_node <- mapM (finalizeNode . fst) extraNodes+      stms' <- fuseGraph (mkBody (mconcat stm_node <> stms) res)+      pure $ Body () stms' res+    doFusionBody :: Body SOACS -> FusionM (Body SOACS)+    doFusionBody body = do+      stms' <- fuseGraph body+      pure $ body {bodyStms = stms'}+    doFusionLambda :: Lambda SOACS -> FusionM (Lambda SOACS)+    doFusionLambda lam = do+      -- To clean up previous instances of fusion.+      lam' <- simplifyLambda lam+      prev_count <- gets fusionCount+      newbody <- localScope (scopeOf lam') $ doFusionBody $ lambdaBody lam'+      aft_count <- gets fusionCount+      -- To clean up any inner fusion.+      (if prev_count /= aft_count then simplifyLambda else pure)+        lam' {lambdaBody = newbody}++-- main fusion function.+fuseGraph :: Body SOACS -> FusionM (Stms SOACS)+fuseGraph body = localScope (scopeOf (bodyStms body)) $ do+  graph_not_fused <- mkDepGraph body+  graph_fused <- doAllFusion graph_not_fused+  linearizeGraph graph_fused++fuseConsts :: [VName] -> Stms SOACS -> PassM (Stms SOACS)+fuseConsts outputs stms =+  runFusionM+    (scopeOf stms)+    freshFusionEnv+    (fuseGraph (mkBody stms (varsRes outputs)))++fuseFun :: Stms SOACS -> FunDef SOACS -> PassM (FunDef SOACS)+fuseFun consts fun = do+  fun_stms' <-+    runFusionM+      (scopeOf fun <> scopeOf consts)+      freshFusionEnv+      (fuseGraph (funDefBody fun))+  pure fun {funDefBody = (funDefBody fun) {bodyStms = fun_stms'}}++-- | The pass definition.+{-# NOINLINE fuseSOACs #-}+fuseSOACs :: Pass SOACS SOACS+fuseSOACs =+  Pass+    { passName = "Fuse SOACs",+      passDescription = "Perform higher-order optimisation, i.e., fusion.",+      passFunction = \p ->+        intraproceduralTransformationWithConsts+          (fuseConsts (namesToList $ freeIn (progFuns p)))+          fuseFun+          p+    }
src/Futhark/Optimise/Fusion/Composing.hs view
@@ -119,7 +119,8 @@     originputmap = lam1inputmap `M.union` lam2inputmap'     outins =       uncurry (outParams $ map fst out1) $-        unzip $ M.toList lam2inputmap'+        unzip $+          M.toList lam2inputmap'     outstms = filterOutParams out1 outins     (inputmap, makeCopies) =       removeDuplicateInputs $ originputmap `M.difference` outins@@ -259,7 +260,8 @@         res_body' =           res_body             { bodyResult =-                p_lam_scan_res ++ res_lam_scan_res+                p_lam_scan_res+                  ++ res_lam_scan_res                   ++ p_lam_red_res                   ++ res_lam_red_res                   ++ res_lam_map_res@@ -269,7 +271,8 @@             { lambdaParams = accpars ++ lambdaParams res_lam,               lambdaBody = res_body',               lambdaReturnType =-                p_lam_scan_ts ++ res_lam_scan_ts+                p_lam_scan_ts+                  ++ res_lam_scan_ts                   ++ p_lam_red_ts                   ++ res_lam_red_ts                   ++ res_lam_map_ts
+ src/Futhark/Optimise/Fusion/GraphRep.hs view
@@ -0,0 +1,431 @@+{-# LANGUAGE FlexibleContexts #-}++-- | A graph representation of a sequence of Futhark statements+-- (i.e. a 'Body'), built to handle fusion.  Could perhaps be made+-- more general.  An important property is that it does not handle+-- "nested bodies" (e.g. 'If'); these are represented as single nodes.+--+-- This is all implemented on top of the graph representation provided+-- by the @fgl@ package ("Data.Graph.Inductive").  The graph provided+-- by this package allows nodes and edges to have arbitrarily-typed+-- "labels".  It is these labels ('EdgeT', 'NodeT') that we use to+-- contain Futhark-specific information.  An edge goes *from* uses of+-- variables to the node that produces that variable.  There are also+-- edges that do not represent normal data dependencies, but other+-- things.  This means that a node can have multiple edges for the+-- same name, indicating different kinds of dependencies.+module Futhark.Optimise.Fusion.GraphRep+  ( -- * Data structure+    EdgeT (..),+    NodeT (..),+    DepContext,+    DepGraphAug,+    DepGraph (..),+    DepNode,++    -- * Queries+    getName,+    nodeFromLNode,+    mergedContext,+    mapAcross,+    edgesBetween,+    reachable,+    applyAugs,+    depsFromEdge,+    contractEdge,+    isRealNode,+    isCons,+    isDep,+    isInf,++    -- * Construction+    mkDepGraph,+    pprg,+  )+where++import Data.Bifunctor (bimap)+import Data.Foldable (foldlM)+import qualified Data.Graph.Inductive.Dot as G+import qualified Data.Graph.Inductive.Graph as G+import qualified Data.Graph.Inductive.Query.DFS as Q+import qualified Data.Graph.Inductive.Tree as G+import qualified Data.List as L+import qualified Data.Map.Strict as M+import qualified Data.Set as S+import qualified Futhark.Analysis.Alias as Alias+import qualified Futhark.Analysis.HORep.SOAC as H+import Futhark.IR.Prop.Aliases+import Futhark.IR.SOACS hiding (SOAC (..))+import qualified Futhark.IR.SOACS as Futhark+import Futhark.Util (nubOrd)++-- | Information associated with an edge in the graph.+data EdgeT+  = Alias VName+  | InfDep VName+  | Dep VName+  | Cons VName+  | Fake VName+  | Res VName+  deriving (Eq, Ord)++-- | Information associated with a node in the graph.+data NodeT+  = StmNode (Stm SOACS)+  | SoacNode H.ArrayTransforms (Pat Type) (H.SOAC SOACS) (StmAux (ExpDec SOACS))+  | -- | Node corresponding to a result of the entire computation+    -- (i.e. the 'Result' of a body).  Any node that is not+    -- transitively reachable from one of these can be considered+    -- dead.+    ResNode VName+  | -- | Node corresponding to a free variable.+    -- Unclear whether we actually need these.+    FreeNode VName+  | FinalNode (Stms SOACS) NodeT (Stms SOACS)+  | IfNode (Stm SOACS) [(NodeT, [EdgeT])]+  | DoNode (Stm SOACS) [(NodeT, [EdgeT])]+  deriving (Eq)++instance Show EdgeT where+  show (Dep vName) = "Dep " <> pretty vName+  show (InfDep vName) = "iDep " <> pretty vName+  show (Cons _) = "Cons"+  show (Fake _) = "Fake"+  show (Res _) = "Res"+  show (Alias _) = "Alias"++instance Show NodeT where+  show (StmNode (Let pat _ _)) = L.intercalate ", " $ map pretty $ patNames pat+  show (SoacNode _ pat _ _) = pretty pat+  show (FinalNode _ nt _) = show nt+  show (ResNode name) = pretty $ "Res: " ++ pretty name+  show (FreeNode name) = pretty $ "Input: " ++ pretty name+  show (IfNode stm _) = "If: " ++ L.intercalate ", " (map pretty $ stmNames stm)+  show (DoNode stm _) = "Do: " ++ L.intercalate ", " (map pretty $ stmNames stm)++-- | The name that this edge depends on.+getName :: EdgeT -> VName+getName edgeT = case edgeT of+  Alias vn -> vn+  InfDep vn -> vn+  Dep vn -> vn+  Cons vn -> vn+  Fake vn -> vn+  Res vn -> vn++-- | Does the node acutally represent something in the program?  A+-- "non-real" node represents things like fake nodes inserted to+-- express ordering due to consumption.+isRealNode :: NodeT -> Bool+isRealNode ResNode {} = False+isRealNode FreeNode {} = False+isRealNode _ = True++-- | Prettyprint dependency graph.+pprg :: DepGraph -> String+pprg = G.showDot . G.fglToDotString . G.nemap show show . dgGraph++-- | A pair of a 'G.Node' and the node label.+type DepNode = G.LNode NodeT++type DepEdge = G.LEdge EdgeT++-- | A tuple with four parts: inbound links to the node, the node+-- itself, the 'NodeT' "label", and outbound links from the node.+-- This type is used to modify the graph in 'mapAcross'.+type DepContext = G.Context NodeT EdgeT++-- | A dependency graph.  Edges go from *consumers* to *producers*+-- (i.e. from usage to definition).  That means the incoming edges of+-- a node are the dependents of that node, and the outgoing edges are+-- the dependencies of that node.+data DepGraph = DepGraph+  { dgGraph :: G.Gr NodeT EdgeT,+    dgProducerMapping :: ProducerMapping,+    -- | A table mapping VNames to VNames that are aliased to it.+    dgAliasTable :: AliasTable+  }++-- | A "graph augmentation" is a monadic action that modifies the graph.+type DepGraphAug m = DepGraph -> m DepGraph++-- | For each node, what producer should the node depend on and what+-- type is it.+type EdgeGenerator = NodeT -> [(VName, EdgeT)]++-- | A mapping from variable name to the graph node that produces+-- it.+type ProducerMapping = M.Map VName G.Node++makeMapping :: Monad m => DepGraphAug m+makeMapping dg@(DepGraph {dgGraph = g}) =+  pure dg {dgProducerMapping = M.fromList $ concatMap gen_dep_list (G.labNodes g)}+  where+    gen_dep_list :: DepNode -> [(VName, G.Node)]+    gen_dep_list (i, node) = [(name, i) | name <- getOutputs node]++-- make a table to handle transitive aliases+makeAliasTable :: Monad m => Stms SOACS -> DepGraphAug m+makeAliasTable stms dg = do+  let (_, (aliasTable', _)) = Alias.analyseStms mempty stms+  pure $ dg {dgAliasTable = aliasTable'}++-- | Apply several graph augmentations in sequence.+applyAugs :: Monad m => [DepGraphAug m] -> DepGraphAug m+applyAugs augs g = foldlM (flip ($)) g augs++-- | Creates deps for the given nodes on the graph using the 'EdgeGenerator'.+genEdges :: Monad m => [DepNode] -> EdgeGenerator -> DepGraphAug m+genEdges l_stms edge_fun dg =+  depGraphInsertEdges (concatMap (genEdge (dgProducerMapping dg)) l_stms) dg+  where+    -- statements -> mapping from declared array names to soac index+    genEdge :: M.Map VName G.Node -> DepNode -> [G.LEdge EdgeT]+    genEdge name_map (from, node) = do+      (dep, edgeT) <- edge_fun node+      Just to <- [M.lookup dep name_map]+      pure $ G.toLEdge (from, to) edgeT++depGraphInsertEdges :: Monad m => [DepEdge] -> DepGraphAug m+depGraphInsertEdges edgs dg = pure $ dg {dgGraph = G.insEdges edgs $ dgGraph dg}++-- | Monadically modify every node of the graph.+mapAcross :: Monad m => (DepContext -> m DepContext) -> DepGraphAug m+mapAcross f dg = do+  g' <- foldlM (flip helper) (dgGraph dg) (G.nodes (dgGraph dg))+  pure $ dg {dgGraph = g'}+  where+    helper n g' = case G.match n g' of+      (Just c, g_new) -> do+        c' <- f c+        pure $ c' G.& g_new+      (Nothing, _) -> pure g'++stmFromNode :: NodeT -> Stms SOACS -- do not use outside of edge generation+stmFromNode (StmNode x) = oneStm x+stmFromNode _ = mempty++-- | Get the underlying @fgl@ node.+nodeFromLNode :: DepNode -> G.Node+nodeFromLNode = fst++-- | Get the variable name that this edge refers to.+depsFromEdge :: DepEdge -> VName+depsFromEdge = getName . G.edgeLabel++-- | Find all the edges connecting the two nodes.+edgesBetween :: DepGraph -> G.Node -> G.Node -> [DepEdge]+edgesBetween dg n1 n2 = G.labEdges $ G.subgraph [n1, n2] $ dgGraph dg++-- | @reachable dg from to@ is true if @to@ is reachable from @from@.+reachable :: DepGraph -> G.Node -> G.Node -> Bool+reachable dg source target = target `elem` Q.reachable source (dgGraph dg)++-- Utility func for augs+augWithFun :: Monad m => EdgeGenerator -> DepGraphAug m+augWithFun f dg = genEdges (G.labNodes (dgGraph dg)) f dg++addDeps :: Monad m => DepGraphAug m+addDeps = augWithFun toDep+  where+    toDep stmt =+      let (fusible, infusible) =+            bimap (map fst) (map fst)+              . L.partition ((== SOACInput) . snd)+              . S.toList+              $ foldMap stmInputs (stmFromNode stmt)+          mkDep vname = (vname, Dep vname)+          mkInfDep vname = (vname, InfDep vname)+       in map mkDep fusible <> map mkInfDep infusible++addConsAndAliases :: Monad m => DepGraphAug m+addConsAndAliases = augWithFun edges+  where+    edges (StmNode s) = consEdges e <> aliasEdges e+      where+        e = Alias.analyseExp mempty $ stmExp s+    edges _ = mempty+    consEdges e = zip names (map Cons names)+      where+        names = namesToList $ consumedInExp e+    aliasEdges =+      map (\vname -> (vname, Alias vname))+        . namesToList+        . mconcat+        . expAliases++-- extra dependencies mask the fact that consuming nodes "depend" on all other+-- nodes coming before it (now also adds fake edges to aliases - hope this+-- fixes asymptotic complexity guarantees)+addExtraCons :: Monad m => DepGraphAug m+addExtraCons dg =+  depGraphInsertEdges (concatMap makeEdge (G.labEdges g)) dg+  where+    g = dgGraph dg+    alias_table = dgAliasTable dg+    mapping = dgProducerMapping dg+    makeEdge (from, to, Cons cname) = do+      let aliases = namesToList $ M.findWithDefault mempty cname alias_table+          to' = map (mapping M.!) aliases+          p (tonode, toedge) =+            tonode /= from && getName toedge `elem` (cname : aliases)+      (to2, _) <- filter p $ concatMap (G.lpre g) to' <> G.lpre g to+      pure $ G.toLEdge (from, to2) (Fake cname)+    makeEdge _ = []++mapAcrossNodeTs :: Monad m => (NodeT -> m NodeT) -> DepGraphAug m+mapAcrossNodeTs f = mapAcross f'+  where+    f' (ins, n, nodeT, outs) = do+      nodeT' <- f nodeT+      pure (ins, n, nodeT', outs)++nodeToSoacNode :: (HasScope SOACS m, Monad m) => NodeT -> m NodeT+nodeToSoacNode n@(StmNode s@(Let pat aux op)) = case op of+  Op {} -> do+    maybeSoac <- H.fromExp op+    case maybeSoac of+      Right hsoac -> pure $ SoacNode mempty pat hsoac aux+      Left H.NotSOAC -> pure n+  DoLoop {} ->+    pure $ DoNode s []+  If {} ->+    pure $ IfNode s []+  _ -> pure n+nodeToSoacNode n = pure n++convertGraph :: (HasScope SOACS m, Monad m) => DepGraphAug m+convertGraph = mapAcrossNodeTs nodeToSoacNode++initialGraphConstruction :: (HasScope SOACS m, Monad m) => DepGraphAug m+initialGraphConstruction =+  applyAugs+    [ addDeps,+      addConsAndAliases,+      addExtraCons,+      addResEdges,+      convertGraph -- Must be done after adding edges+    ]++-- | Construct a graph with only nodes, but no edges.+emptyGraph :: Body SOACS -> DepGraph+emptyGraph body =+  DepGraph+    { dgGraph = G.mkGraph (labelNodes (stmnodes <> resnodes <> inputnodes)) [],+      dgProducerMapping = mempty,+      dgAliasTable = mempty+    }+  where+    labelNodes = zip [0 ..]+    stmnodes = map StmNode $ stmsToList $ bodyStms body+    resnodes = map ResNode $ namesToList $ freeIn $ bodyResult body+    inputnodes = map FreeNode $ namesToList $ freeIn body++-- | Make a dependency graph corresponding to a 'Body'.+mkDepGraph :: (HasScope SOACS m, Monad m) => Body SOACS -> m DepGraph+mkDepGraph body = applyAugs augs $ emptyGraph body+  where+    augs =+      [ makeMapping,+        makeAliasTable (bodyStms body),+        initialGraphConstruction+      ]++-- | Merges two contexts.+mergedContext :: Ord b => a -> G.Context a b -> G.Context a b -> G.Context a b+mergedContext mergedlabel (inp1, n1, _, out1) (inp2, n2, _, out2) =+  let new_inp = filter (\n -> snd n /= n1 && snd n /= n2) (nubOrd (inp1 <> inp2))+      new_out = filter (\n -> snd n /= n1 && snd n /= n2) (nubOrd (out1 <> out2))+   in (new_inp, n1, mergedlabel, new_out)++-- | Remove the given node, and insert the 'DepContext' into the+-- graph, replacing any existing information about the node contained+-- in the 'DepContext'.+contractEdge :: Monad m => G.Node -> DepContext -> DepGraphAug m+contractEdge n2 ctx dg = do+  let n1 = G.node' ctx -- n1 remains+  pure $ dg {dgGraph = ctx G.& G.delNodes [n1, n2] (dgGraph dg)}++addResEdges :: Monad m => DepGraphAug m+addResEdges = augWithFun getStmRes++-- Utils for fusibility/infusibility+-- find dependencies - either fusible or infusible. edges are generated based on these++-- | A classification of a free variable.+data Classification+  = -- | Used as array input to a SOAC (meaning fusible).+    SOACInput+  | -- | Used in some other way.+    Other+  deriving (Eq, Ord, Show)++type Classifications = S.Set (VName, Classification)++freeClassifications :: FreeIn a => a -> Classifications+freeClassifications =+  S.fromList . (`zip` repeat Other) . namesToList . freeIn++stmInputs :: Stm SOACS -> Classifications+stmInputs (Let pat aux e) =+  freeClassifications (pat, aux) <> expInputs e++bodyInputs :: Body SOACS -> Classifications+bodyInputs (Body _ stms res) = foldMap stmInputs stms <> freeClassifications res++expInputs :: Exp SOACS -> Classifications+expInputs (If cond b1 b2 attr) =+  bodyInputs b1 <> bodyInputs b2 <> freeClassifications (cond, attr)+expInputs (DoLoop params form b1) =+  freeClassifications (params, form) <> bodyInputs b1+expInputs (Op soac) = case soac of+  Futhark.Screma w is form -> inputs is <> freeClassifications (w, form)+  Futhark.Hist w is ops lam -> inputs is <> freeClassifications (w, ops, lam)+  Futhark.Scatter w is lam iws -> inputs is <> freeClassifications (w, lam, iws)+  Futhark.Stream w is form nes lam ->+    inputs is <> freeClassifications (w, form, nes, lam)+  Futhark.JVP {} -> freeClassifications soac+  Futhark.VJP {} -> freeClassifications soac+  where+    inputs = S.fromList . (`zip` repeat SOACInput)+expInputs e+  | Just (arr, _) <- H.transformFromExp mempty e =+      S.singleton (arr, SOACInput)+        <> freeClassifications (freeIn e `namesSubtract` oneName arr)+  | otherwise = freeClassifications e++stmNames :: Stm SOACS -> [VName]+stmNames = patNames . stmPat++getStmRes :: EdgeGenerator+getStmRes (ResNode name) = [(name, Res name)]+getStmRes _ = []++getOutputs :: NodeT -> [VName]+getOutputs node = case node of+  (StmNode stm) -> stmNames stm+  (ResNode _) -> []+  (FreeNode name) -> [name]+  (IfNode stm _) -> stmNames stm+  (DoNode stm _) -> stmNames stm+  FinalNode {} -> error "Final nodes cannot generate edges"+  (SoacNode _ pat _ _) -> patNames pat++-- | Is there a possibility of fusion?+isDep :: EdgeT -> Bool+isDep (Dep _) = True+isDep (Res _) = True+isDep _ = False++-- | Is this an infusible edge?+isInf :: (G.Node, G.Node, EdgeT) -> Bool+isInf (_, _, e) = case e of+  InfDep _ -> True+  Fake _ -> True -- this is infusible to avoid simultaneous cons/dep edges+  _ -> False++-- | Is this a 'Cons' edge?+isCons :: EdgeT -> Bool+isCons (Cons _) = True+isCons _ = False
− src/Futhark/Optimise/Fusion/LoopKernel.hs
@@ -1,937 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE TypeFamilies #-}--module Futhark.Optimise.Fusion.LoopKernel-  ( FusedKer (..),-    newKernel,-    inputs,-    setInputs,-    arrInputs,-    transformOutput,-    attemptFusion,-    SOAC,-    MapNest,-  )-where--import Control.Applicative-import Control.Arrow (first)-import Control.Monad-import Control.Monad.Reader-import Control.Monad.State-import Data.List (find, tails, (\\))-import qualified Data.Map.Strict as M-import Data.Maybe-import qualified Data.Set as S-import qualified Futhark.Analysis.HORep.MapNest as MapNest-import qualified Futhark.Analysis.HORep.SOAC as SOAC-import Futhark.Construct-import Futhark.IR.SOACS hiding (SOAC (..))-import qualified Futhark.IR.SOACS as Futhark-import Futhark.Optimise.Fusion.Composing-import Futhark.Pass.ExtractKernels.ISRWIM (rwimPossible)-import Futhark.Transform.Rename (renameLambda)-import Futhark.Transform.Substitute-import Futhark.Util (splitAt3)--newtype TryFusion a-  = TryFusion-      ( ReaderT-          (Scope SOACS)-          (StateT VNameSource Maybe)-          a-      )-  deriving-    ( Functor,-      Applicative,-      Alternative,-      Monad,-      MonadFail,-      MonadFreshNames,-      HasScope SOACS,-      LocalScope SOACS-    )--tryFusion ::-  MonadFreshNames m =>-  TryFusion a ->-  Scope SOACS ->-  m (Maybe a)-tryFusion (TryFusion m) types = modifyNameSource $ \src ->-  case runStateT (runReaderT m types) src of-    Just (x, src') -> (Just x, src')-    Nothing -> (Nothing, src)--liftMaybe :: Maybe a -> TryFusion a-liftMaybe Nothing = fail "Nothing"-liftMaybe (Just x) = pure x--type SOAC = SOAC.SOAC SOACS--type MapNest = MapNest.MapNest SOACS---- XXX: This function is very gross.-transformOutput ::-  SOAC.ArrayTransforms ->-  [VName] ->-  [Ident] ->-  Builder SOACS ()-transformOutput ts names = descend ts-  where-    descend ts' validents =-      case SOAC.viewf ts' of-        SOAC.EmptyF ->-          forM_ (zip names validents) $ \(k, valident) ->-            letBindNames [k] $ BasicOp $ SubExp $ Var $ identName valident-        t SOAC.:< ts'' -> do-          let (es, css) = unzip $ map (applyTransform t) validents-              mkPat (Ident nm tp) = Pat [PatElem nm tp]-          opts <- concat <$> mapM basicOpType es-          newIds <- forM (zip names opts) $ \(k, opt) ->-            newIdent (baseString k) opt-          forM_ (zip3 css newIds es) $ \(cs, ids, e) ->-            certifying cs $ letBind (mkPat ids) (BasicOp e)-          descend ts'' newIds--applyTransform :: SOAC.ArrayTransform -> Ident -> (BasicOp, Certs)-applyTransform (SOAC.Rearrange cs perm) v =-  (Rearrange perm' $ identName v, cs)-  where-    perm' = perm ++ drop (length perm) [0 .. arrayRank (identType v) - 1]-applyTransform (SOAC.Reshape cs shape) v =-  (Reshape shape $ identName v, cs)-applyTransform (SOAC.ReshapeOuter cs shape) v =-  let shapes = reshapeOuter shape 1 $ arrayShape $ identType v-   in (Reshape shapes $ identName v, cs)-applyTransform (SOAC.ReshapeInner cs shape) v =-  let shapes = reshapeInner shape 1 $ arrayShape $ identType v-   in (Reshape shapes $ identName v, cs)-applyTransform (SOAC.Replicate cs n) v =-  (Replicate n $ Var $ identName v, cs)--inputToOutput :: SOAC.Input -> Maybe (SOAC.ArrayTransform, SOAC.Input)-inputToOutput (SOAC.Input ts ia iat) =-  case SOAC.viewf ts of-    t SOAC.:< ts' -> Just (t, SOAC.Input ts' ia iat)-    SOAC.EmptyF -> Nothing--data FusedKer = FusedKer-  { -- | the SOAC expression, e.g., mapT( f(a,b), x, y )-    fsoac :: SOAC,-    -- | Variables used in in-place updates in the kernel itself, as-    -- well as on the path to the kernel from the current position.-    -- This is used to avoid fusion that would violate in-place-    -- restrictions.-    inplace :: Names,-    -- | whether at least a fusion has been performed.-    fusedVars :: [VName],-    -- | The set of variables that were consumed by the SOACs-    -- contributing to this kernel.  Note that, by the type rules, the-    -- final SOAC may actually consume _more_ than its original-    -- contributors, which implies the need for 'Copy' expressions.-    fusedConsumed :: Names,-    -- | The names in scope at the kernel.-    kernelScope :: Scope SOACS,-    outputTransform :: SOAC.ArrayTransforms,-    outNames :: [VName],-    kerAux :: StmAux ()-  }-  deriving (Show)--newKernel :: StmAux () -> SOAC -> Names -> [VName] -> Scope SOACS -> FusedKer-newKernel aux soac consumed out_nms scope =-  FusedKer-    { fsoac = soac,-      inplace = consumed,-      fusedVars = [],-      fusedConsumed = consumed,-      outputTransform = SOAC.noTransforms,-      outNames = out_nms,-      kernelScope = scope,-      kerAux = aux-    }--arrInputs :: FusedKer -> S.Set VName-arrInputs = S.fromList . map SOAC.inputArray . inputs--inputs :: FusedKer -> [SOAC.Input]-inputs = SOAC.inputs . fsoac--setInputs :: [SOAC.Input] -> FusedKer -> FusedKer-setInputs inps ker = ker {fsoac = inps `SOAC.setInputs` fsoac ker}--tryOptimizeSOAC ::-  Names ->-  [VName] ->-  SOAC ->-  Names ->-  FusedKer ->-  TryFusion FusedKer-tryOptimizeSOAC unfus_nms outVars soac consumed ker = do-  (soac', ots) <- optimizeSOAC Nothing soac mempty-  let ker' = map (addInitialTransformIfRelevant ots) (inputs ker) `setInputs` ker-      outIdents = zipWith Ident outVars $ SOAC.typeOf soac'-      ker'' = fixInputTypes outIdents ker'-  applyFusionRules unfus_nms outVars soac' consumed ker''-  where-    addInitialTransformIfRelevant ots inp-      | SOAC.inputArray inp `elem` outVars =-          SOAC.addInitialTransforms ots inp-      | otherwise =-          inp--tryOptimizeKernel ::-  Names ->-  [VName] ->-  SOAC ->-  Names ->-  FusedKer ->-  TryFusion FusedKer-tryOptimizeKernel unfus_nms outVars soac consumed ker = do-  ker' <- optimizeKernel (Just outVars) ker-  applyFusionRules unfus_nms outVars soac consumed ker'--tryExposeInputs ::-  Names ->-  [VName] ->-  SOAC ->-  Names ->-  FusedKer ->-  TryFusion FusedKer-tryExposeInputs unfus_nms outVars soac consumed ker = do-  (ker', ots) <- exposeInputs outVars ker-  if SOAC.nullTransforms ots-    then fuseSOACwithKer unfus_nms outVars soac consumed ker'-    else do-      (soac', ots') <- pullOutputTransforms soac ots-      let outIdents = zipWith Ident outVars $ SOAC.typeOf soac'-          ker'' = fixInputTypes outIdents ker'-      if SOAC.nullTransforms ots'-        then applyFusionRules unfus_nms outVars soac' consumed ker''-        else fail "tryExposeInputs could not pull SOAC transforms"--fixInputTypes :: [Ident] -> FusedKer -> FusedKer-fixInputTypes outIdents ker =-  ker {fsoac = fixInputTypes' $ fsoac ker}-  where-    fixInputTypes' soac =-      map fixInputType (SOAC.inputs soac) `SOAC.setInputs` soac-    fixInputType (SOAC.Input ts v _)-      | Just v' <- find ((== v) . identName) outIdents =-          SOAC.Input ts v $ identType v'-    fixInputType inp = inp--applyFusionRules ::-  Names ->-  [VName] ->-  SOAC ->-  Names ->-  FusedKer ->-  TryFusion FusedKer-applyFusionRules unfus_nms outVars soac consumed ker =-  tryOptimizeSOAC unfus_nms outVars soac consumed ker-    <|> tryOptimizeKernel unfus_nms outVars soac consumed ker-    <|> fuseSOACwithKer unfus_nms outVars soac consumed ker-    <|> tryExposeInputs unfus_nms outVars soac consumed ker--attemptFusion ::-  MonadFreshNames m =>-  Names ->-  [VName] ->-  SOAC ->-  Names ->-  FusedKer ->-  m (Maybe FusedKer)-attemptFusion unfus_nms outVars soac consumed ker =-  fmap removeUnusedParamsFromKer-    <$> tryFusion-      (applyFusionRules unfus_nms outVars soac consumed ker)-      (kernelScope ker)--removeUnusedParamsFromKer :: FusedKer -> FusedKer-removeUnusedParamsFromKer ker =-  case soac of-    SOAC.Screma {} -> ker {fsoac = soac'}-    _ -> ker-  where-    soac = fsoac ker-    l = SOAC.lambda soac-    inps = SOAC.inputs soac-    (l', inps') = removeUnusedParams l inps-    soac' =-      l'-        `SOAC.setLambda` (inps' `SOAC.setInputs` soac)--removeUnusedParams :: Lambda SOACS -> [SOAC.Input] -> (Lambda SOACS, [SOAC.Input])-removeUnusedParams l inps =-  (l {lambdaParams = ps'}, inps')-  where-    pInps = zip (lambdaParams l) inps-    (ps', inps') = case (unzip $ filter (used . fst) pInps, pInps) of-      (([], []), (p, inp) : _) -> ([p], [inp])-      ((ps_, inps_), _) -> (ps_, inps_)-    used p = paramName p `nameIn` freeVars-    freeVars = freeIn $ lambdaBody l---- | Check that the consumer uses at least one output of the producer--- unmodified.-mapFusionOK :: [VName] -> FusedKer -> Bool-mapFusionOK outVars ker = any (`elem` inpIds) outVars-  where-    inpIds = mapMaybe SOAC.isVarishInput (inputs ker)---- | Check that the consumer uses all the outputs of the producer unmodified.-mapWriteFusionOK :: [VName] -> FusedKer -> Bool-mapWriteFusionOK outVars ker = all (`elem` inpIds) outVars-  where-    inpIds = mapMaybe SOAC.isVarishInput (inputs ker)---- | The brain of this module: Fusing a SOAC with a Kernel.-fuseSOACwithKer ::-  Names ->-  [VName] ->-  SOAC ->-  Names ->-  FusedKer ->-  TryFusion FusedKer-fuseSOACwithKer unfus_set outVars soac_p soac_p_consumed ker = do-  -- We are fusing soac_p into soac_c, i.e, the output of soac_p is going-  -- into soac_c.-  let soac_c = fsoac ker-      inp_p_arr = SOAC.inputs soac_p-      horizFuse =-        unfus_set /= mempty-          && SOAC.width soac_p == SOAC.width soac_c-      inp_c_arr = SOAC.inputs soac_c-      lam_p = SOAC.lambda soac_p-      lam_c = SOAC.lambda soac_c-      w = SOAC.width soac_p-      returned_outvars = filter (`nameIn` unfus_set) outVars-      success res_outnms res_soac = do-        let fusedVars_new = fusedVars ker ++ outVars-        -- Avoid name duplication, because the producer lambda is not-        -- removed from the program until much later.-        uniq_lam <- renameLambda $ SOAC.lambda res_soac-        pure $-          ker-            { fsoac = uniq_lam `SOAC.setLambda` res_soac,-              fusedVars = fusedVars_new,-              inplace = inplace ker <> soac_p_consumed,-              fusedConsumed = fusedConsumed ker <> soac_p_consumed,-              outNames = res_outnms-            }--  outPairs <- forM (zip outVars $ map rowType $ SOAC.typeOf soac_p) $ \(outVar, t) -> do-    outVar' <- newVName $ baseString outVar ++ "_elem"-    pure (outVar, Ident outVar' t)--  let mapLikeFusionCheck =-        let (res_lam, new_inp) = fuseMaps unfus_set lam_p inp_p_arr outPairs lam_c inp_c_arr-            (extra_nms, extra_rtps) =-              unzip $-                filter ((`nameIn` unfus_set) . fst) $-                  zip outVars $ map (stripArray 1) $ SOAC.typeOf soac_p-            res_lam' = res_lam {lambdaReturnType = lambdaReturnType res_lam ++ extra_rtps}-         in (extra_nms, res_lam', new_inp)--  when (horizFuse && not (SOAC.nullTransforms $ outputTransform ker)) $-    fail "Horizontal fusion is invalid in the presence of output transforms."--  case (soac_c, soac_p) of-    _ | SOAC.width soac_p /= SOAC.width soac_c -> fail "SOAC widths must match."-    ( SOAC.Screma _ (ScremaForm scans_c reds_c _) _,-      SOAC.Screma _ (ScremaForm scans_p reds_p _) _-      )-        | mapFusionOK (drop (Futhark.scanResults scans_p + Futhark.redResults reds_p) outVars) ker-            || horizFuse -> do-            let red_nes_p = concatMap redNeutral reds_p-                red_nes_c = concatMap redNeutral reds_c-                scan_nes_p = concatMap scanNeutral scans_p-                scan_nes_c = concatMap scanNeutral scans_c-                (res_lam', new_inp) =-                  fuseRedomap-                    unfus_set-                    outVars-                    lam_p-                    scan_nes_p-                    red_nes_p-                    inp_p_arr-                    outPairs-                    lam_c-                    scan_nes_c-                    red_nes_c-                    inp_c_arr-                (soac_p_scanout, soac_p_redout, _soac_p_mapout) =-                  splitAt3 (length scan_nes_p) (length red_nes_p) outVars-                (soac_c_scanout, soac_c_redout, soac_c_mapout) =-                  splitAt3 (length scan_nes_c) (length red_nes_c) $ outNames ker-                unfus_arrs = returned_outvars \\ (soac_p_scanout ++ soac_p_redout)-            success-              ( soac_p_scanout ++ soac_c_scanout-                  ++ soac_p_redout-                  ++ soac_c_redout-                  ++ soac_c_mapout-                  ++ unfus_arrs-              )-              $ SOAC.Screma-                w-                (ScremaForm (scans_p ++ scans_c) (reds_p ++ reds_c) res_lam')-                new_inp--    -------------------    -- Scatter fusion ---    --------------------    -- Map-Scatter fusion.-    ---    -- The 'inplace' mechanism for kernels already takes care of-    -- checking that the Scatter is not writing to any array used in-    -- the Map.-    ( SOAC.Scatter _len _lam _ivs dests,-      SOAC.Screma _ form _-      )-        | isJust $ isMapSOAC form,-          -- 1. all arrays produced by the map are ONLY used (consumed)-          --    by the scatter, i.e., not used elsewhere.-          not (any (`nameIn` unfus_set) outVars),-          -- 2. all arrays produced by the map are input to the scatter.-          mapWriteFusionOK outVars ker -> do-            let (extra_nms, res_lam', new_inp) = mapLikeFusionCheck-            success (outNames ker ++ extra_nms) $-              SOAC.Scatter w res_lam' new_inp dests--    -- Map-Hist fusion.-    ---    -- The 'inplace' mechanism for kernels already takes care of-    -- checking that the Hist is not writing to any array used in-    -- the Map.-    ( SOAC.Hist _ ops _ _,-      SOAC.Screma _ form _-      )-        | isJust $ isMapSOAC form,-          -- 1. all arrays produced by the map are ONLY used (consumed)-          --    by the hist, i.e., not used elsewhere.-          not (any (`nameIn` unfus_set) outVars),-          -- 2. all arrays produced by the map are input to the scatter.-          mapWriteFusionOK outVars ker -> do-            let (extra_nms, res_lam', new_inp) = mapLikeFusionCheck-            success (outNames ker ++ extra_nms) $-              SOAC.Hist w ops res_lam' new_inp--    -- Hist-Hist fusion-    ( SOAC.Hist _ ops_c _ _,-      SOAC.Hist _ ops_p _ _-      )-        | horizFuse -> do-            let p_num_buckets = length ops_p-                c_num_buckets = length ops_c-                (body_p, body_c) = (lambdaBody lam_p, lambdaBody lam_c)-                body' =-                  Body-                    { bodyDec = bodyDec body_p, -- body_p and body_c have the same decorations-                      bodyStms = bodyStms body_p <> bodyStms body_c,-                      bodyResult =-                        take c_num_buckets (bodyResult body_c)-                          ++ take p_num_buckets (bodyResult body_p)-                          ++ drop c_num_buckets (bodyResult body_c)-                          ++ drop p_num_buckets (bodyResult body_p)-                    }-                lam' =-                  Lambda-                    { lambdaParams = lambdaParams lam_c ++ lambdaParams lam_p,-                      lambdaBody = body',-                      lambdaReturnType =-                        replicate (c_num_buckets + p_num_buckets) (Prim int64)-                          ++ drop c_num_buckets (lambdaReturnType lam_c)-                          ++ drop p_num_buckets (lambdaReturnType lam_p)-                    }-            success (outNames ker ++ returned_outvars) $-              SOAC.Hist w (ops_c <> ops_p) lam' (inp_c_arr <> inp_p_arr)--    -- Scatter-write fusion.-    ( SOAC.Scatter _len_c _lam_c ivs_c as_c,-      SOAC.Scatter _len_p _lam_p ivs_p as_p-      )-        | horizFuse -> do-            let zipW as_xs xs as_ys ys = xs_indices ++ ys_indices ++ xs_vals ++ ys_vals-                  where-                    (xs_indices, xs_vals) = splitScatterResults as_xs xs-                    (ys_indices, ys_vals) = splitScatterResults as_ys ys-            let (body_p, body_c) = (lambdaBody lam_p, lambdaBody lam_c)-            let body' =-                  Body-                    { bodyDec = bodyDec body_p, -- body_p and body_c have the same decorations-                      bodyStms = bodyStms body_p <> bodyStms body_c,-                      bodyResult = zipW as_c (bodyResult body_c) as_p (bodyResult body_p)-                    }-            let lam' =-                  Lambda-                    { lambdaParams = lambdaParams lam_c ++ lambdaParams lam_p,-                      lambdaBody = body',-                      lambdaReturnType = zipW as_c (lambdaReturnType lam_c) as_p (lambdaReturnType lam_p)-                    }-            success (outNames ker ++ returned_outvars) $-              SOAC.Scatter w lam' (ivs_c ++ ivs_p) (as_c ++ as_p)-    (SOAC.Scatter {}, _) ->-      fail "Cannot fuse a write with anything else than a write or a map"-    (_, SOAC.Scatter {}) ->-      fail "Cannot fuse a write with anything else than a write or a map"-    -----------------------------    -- Stream-Stream Fusions: ---    -----------------------------    (SOAC.Stream _ Sequential _ _ _, SOAC.Stream _ Sequential _ nes _)-      | mapFusionOK (drop (length nes) outVars) ker || horizFuse -> do-          -- fuse two SEQUENTIAL streams-          (res_nms, res_stream) <- fuseStreamHelper (outNames ker) unfus_set outVars outPairs soac_c soac_p-          success res_nms res_stream-    (SOAC.Stream _ Sequential _ _ _, SOAC.Stream _ Sequential _ _ _) ->-      fail "Fusion conditions not met for two SEQ streams!"-    (SOAC.Stream _ Sequential _ _ _, SOAC.Stream {}) ->-      fail "Cannot fuse a parallel with a sequential Stream!"-    (SOAC.Stream {}, SOAC.Stream _ Sequential _ _ _) ->-      fail "Cannot fuse a parallel with a sequential Stream!"-    (SOAC.Stream {}, SOAC.Stream _ _ _ nes _)-      | mapFusionOK (drop (length nes) outVars) ker || horizFuse -> do-          -- fuse two PARALLEL streams-          (res_nms, res_stream) <- fuseStreamHelper (outNames ker) unfus_set outVars outPairs soac_c soac_p-          success res_nms res_stream-    (SOAC.Stream {}, SOAC.Stream {}) ->-      fail "Fusion conditions not met for two PAR streams!"-    --------------------------------------------------------------------    --- If one is a stream, translate the other to a stream as well.----    --- This does not get in trouble (infinite computation) because ----    ---   scan's translation to Stream introduces a hindrance to    ----    ---   (horizontal fusion), hence repeated application is for the----    ---   moment impossible. However, if with a dependence-graph rep----    ---   we could run in an infinite recursion, i.e., repeatedly   ----    ---   fusing map o scan into an infinity of Stream levels!      ----    --------------------------------------------------------------------    (SOAC.Stream _ form2 _ _ _, _) -> do-      -- If this rule is matched then soac_p is NOT a stream.-      -- To fuse a stream kernel, we transform soac_p to a stream, which-      -- borrows the sequential/parallel property of the soac_c Stream,-      -- and recursively perform stream-stream fusion.-      (soac_p', newacc_ids) <- SOAC.soacToStream soac_p-      soac_p'' <- case form2 of-        Sequential {} -> toSeqStream soac_p'-        _ -> pure soac_p'-      if soac_p' == soac_p-        then fail "SOAC could not be turned into stream."-        else fuseSOACwithKer unfus_set (map identName newacc_ids ++ outVars) soac_p'' soac_p_consumed ker-    (_, SOAC.Screma _ form _) | Just _ <- Futhark.isScanSOAC form -> do-      -- A Scan soac can be currently only fused as a (sequential) stream,-      -- hence it is first translated to a (sequential) Stream and then-      -- fusion with a kernel is attempted.-      (soac_p', newacc_ids) <- SOAC.soacToStream soac_p-      if soac_p' /= soac_p-        then fuseSOACwithKer unfus_set (map identName newacc_ids ++ outVars) soac_p' soac_p_consumed ker-        else fail "SOAC could not be turned into stream."-    (_, SOAC.Stream _ form_p _ _ _) -> do-      -- If it reached this case then soac_c is NOT a Stream kernel,-      -- hence transform the kernel's soac to a stream and attempt-      -- stream-stream fusion recursivelly.-      -- The newly created stream corresponding to soac_c borrows the-      -- sequential/parallel property of the soac_p stream.-      (soac_c', newacc_ids) <- SOAC.soacToStream soac_c-      when (soac_c' == soac_c) $ fail "SOAC could not be turned into stream."-      soac_c'' <- case form_p of-        Sequential -> toSeqStream soac_c'-        _ -> pure soac_c'--      fuseSOACwithKer unfus_set outVars soac_p soac_p_consumed $-        ker {fsoac = soac_c'', outNames = map identName newacc_ids ++ outNames ker}--    ----------------------------------    --- DEFAULT, CANNOT FUSE CASE ----    ----------------------------------    _ -> fail "Cannot fuse"--getStreamOrder :: StreamForm rep -> StreamOrd-getStreamOrder (Parallel o _ _) = o-getStreamOrder Sequential = InOrder--fuseStreamHelper ::-  [VName] ->-  Names ->-  [VName] ->-  [(VName, Ident)] ->-  SOAC ->-  SOAC ->-  TryFusion ([VName], SOAC)-fuseStreamHelper-  out_kernms-  unfus_set-  outVars-  outPairs-  (SOAC.Stream w2 form2 lam2 nes2 inp2_arr)-  (SOAC.Stream _ form1 lam1 nes1 inp1_arr) =-    if getStreamOrder form2 /= getStreamOrder form1-      then fail "fusion conditions not met!"-      else do-        -- very similar to redomap o redomap composition, but need-        -- to remove first the `chunk' parameters of streams'-        -- lambdas and put them in the resulting stream lambda.-        let chunk1 = head $ lambdaParams lam1-            chunk2 = head $ lambdaParams lam2-            hmnms = M.fromList [(paramName chunk2, paramName chunk1)]-            lam20 = substituteNames hmnms lam2-            lam1' = lam1 {lambdaParams = tail $ lambdaParams lam1}-            lam2' = lam20 {lambdaParams = tail $ lambdaParams lam20}-            (res_lam', new_inp) =-              fuseRedomap-                unfus_set-                outVars-                lam1'-                []-                nes1-                inp1_arr-                outPairs-                lam2'-                []-                nes2-                inp2_arr-            res_lam'' = res_lam' {lambdaParams = chunk1 : lambdaParams res_lam'}-            unfus_accs = take (length nes1) outVars-            unfus_arrs = filter (`notElem` unfus_accs) $ filter (`nameIn` unfus_set) outVars-        res_form <- mergeForms form2 form1-        pure-          ( unfus_accs ++ out_kernms ++ unfus_arrs,-            SOAC.Stream w2 res_form res_lam'' (nes1 ++ nes2) new_inp-          )-    where-      mergeForms Sequential Sequential = pure Sequential-      mergeForms (Parallel _ comm2 lam2r) (Parallel o1 comm1 lam1r) =-        pure $ Parallel o1 (comm1 <> comm2) (mergeReduceOps lam1r lam2r)-      mergeForms _ _ = fail "Fusing sequential to parallel stream disallowed!"-fuseStreamHelper _ _ _ _ _ _ = fail "Cannot Fuse Streams!"---- | If a Stream is passed as argument then it converts it to a---   Sequential Stream; Otherwise it FAILS!-toSeqStream :: SOAC -> TryFusion SOAC-toSeqStream s@(SOAC.Stream _ Sequential _ _ _) = pure s-toSeqStream (SOAC.Stream w Parallel {} l acc inps) =-  pure $ SOAC.Stream w Sequential l acc inps-toSeqStream _ = fail "toSeqStream expects a stream, but given a SOAC."---- Here follows optimizations and transforms to expose fusability.--optimizeKernel :: Maybe [VName] -> FusedKer -> TryFusion FusedKer-optimizeKernel inp ker = do-  (soac, resTrans) <- optimizeSOAC inp (fsoac ker) startTrans-  pure $-    ker-      { fsoac = soac,-        outputTransform = resTrans-      }-  where-    startTrans = outputTransform ker--optimizeSOAC ::-  Maybe [VName] ->-  SOAC ->-  SOAC.ArrayTransforms ->-  TryFusion (SOAC, SOAC.ArrayTransforms)-optimizeSOAC inp soac os = do-  res <- foldM comb (False, soac, os) optimizations-  case res of-    (False, _, _) -> fail "No optimisation applied"-    (True, soac', os') -> pure (soac', os')-  where-    comb (changed, soac', os') f =-      do-        (soac'', os'') <- f inp soac' os-        pure (True, soac'', os'')-        <|> pure (changed, soac', os')--type Optimization =-  Maybe [VName] ->-  SOAC ->-  SOAC.ArrayTransforms ->-  TryFusion (SOAC, SOAC.ArrayTransforms)--optimizations :: [Optimization]-optimizations = [iswim]--iswim ::-  Maybe [VName] ->-  SOAC ->-  SOAC.ArrayTransforms ->-  TryFusion (SOAC, SOAC.ArrayTransforms)-iswim _ (SOAC.Screma w form arrs) ots-  | Just [Futhark.Scan scan_fun nes] <- Futhark.isScanSOAC form,-    Just (map_pat, map_cs, map_w, map_fun) <- rwimPossible scan_fun,-    Just nes_names <- mapM subExpVar nes = do-      let nes_idents = zipWith Ident nes_names $ lambdaReturnType scan_fun-          map_nes = map SOAC.identInput nes_idents-          map_arrs' = map_nes ++ map (SOAC.transposeInput 0 1) arrs-          (scan_acc_params, scan_elem_params) =-            splitAt (length arrs) $ lambdaParams scan_fun-          map_params =-            map removeParamOuterDim scan_acc_params-              ++ map (setParamOuterDimTo w) scan_elem_params-          map_rettype = map (`setOuterSize` w) $ lambdaReturnType scan_fun--          scan_params = lambdaParams map_fun-          scan_body = lambdaBody map_fun-          scan_rettype = lambdaReturnType map_fun-          scan_fun' = Lambda scan_params scan_body scan_rettype-          nes' = map Var $ take (length map_nes) $ map paramName map_params-          arrs' = drop (length map_nes) $ map paramName map_params--      scan_form <- scanSOAC [Futhark.Scan scan_fun' nes']--      let map_body =-            mkBody-              ( oneStm $-                  Let (setPatOuterDimTo w map_pat) (defAux ()) $-                    Op $ Futhark.Screma w arrs' scan_form-              )-              $ varsRes $ patNames map_pat-          map_fun' = Lambda map_params map_body map_rettype-          perm = case lambdaReturnType map_fun of-            [] -> []-            t : _ -> 1 : 0 : [2 .. arrayRank t]--      pure-        ( SOAC.Screma map_w (ScremaForm [] [] map_fun') map_arrs',-          ots SOAC.|> SOAC.Rearrange map_cs perm-        )-iswim _ _ _ =-  fail "ISWIM does not apply."--removeParamOuterDim :: LParam SOACS -> LParam SOACS-removeParamOuterDim param =-  let t = rowType $ paramType param-   in param {paramDec = t}--setParamOuterDimTo :: SubExp -> LParam SOACS -> LParam SOACS-setParamOuterDimTo w param =-  let t = paramType param `setOuterSize` w-   in param {paramDec = t}--setPatOuterDimTo :: SubExp -> Pat Type -> Pat Type-setPatOuterDimTo w = fmap (`setOuterSize` w)---- Now for fiddling with transpositions...--commonTransforms ::-  [VName] ->-  [SOAC.Input] ->-  (SOAC.ArrayTransforms, [SOAC.Input])-commonTransforms interesting inps = commonTransforms' inps'-  where-    inps' =-      [ (SOAC.inputArray inp `elem` interesting, inp)-        | inp <- inps-      ]--commonTransforms' :: [(Bool, SOAC.Input)] -> (SOAC.ArrayTransforms, [SOAC.Input])-commonTransforms' inps =-  case foldM inspect (Nothing, []) inps of-    Just (Just mot, inps') -> first (mot SOAC.<|) $ commonTransforms' $ reverse inps'-    _ -> (SOAC.noTransforms, map snd inps)-  where-    inspect (mot, prev) (True, inp) =-      case (mot, inputToOutput inp) of-        (Nothing, Just (ot, inp')) -> Just (Just ot, (True, inp') : prev)-        (Just ot1, Just (ot2, inp'))-          | ot1 == ot2 -> Just (Just ot2, (True, inp') : prev)-        _ -> Nothing-    inspect (mot, prev) inp = Just (mot, inp : prev)--mapDepth :: MapNest -> Int-mapDepth (MapNest.MapNest _ lam levels _) =-  min resDims (length levels) + 1-  where-    resDims = minDim $ case levels of-      [] -> lambdaReturnType lam-      nest : _ -> MapNest.nestingReturnType nest-    minDim [] = 0-    minDim (t : ts) = foldl min (arrayRank t) $ map arrayRank ts--pullRearrange ::-  SOAC ->-  SOAC.ArrayTransforms ->-  TryFusion (SOAC, SOAC.ArrayTransforms)-pullRearrange soac ots = do-  nest <- liftMaybe =<< MapNest.fromSOAC soac-  SOAC.Rearrange cs perm SOAC.:< ots' <- pure $ SOAC.viewf ots-  if rearrangeReach perm <= mapDepth nest-    then do-      let -- Expand perm to cover the full extent of the input dimensionality-          perm' inp = take r perm ++ [length perm .. r - 1]-            where-              r = SOAC.inputRank inp-          addPerm inp = SOAC.addTransform (SOAC.Rearrange cs $ perm' inp) inp-          inputs' = map addPerm $ MapNest.inputs nest-      soac' <--        MapNest.toSOAC $-          inputs' `MapNest.setInputs` rearrangeReturnTypes nest perm-      pure (soac', ots')-    else fail "Cannot pull transpose"--pushRearrange ::-  [VName] ->-  SOAC ->-  SOAC.ArrayTransforms ->-  TryFusion (SOAC, SOAC.ArrayTransforms)-pushRearrange inpIds soac ots = do-  nest <- liftMaybe =<< MapNest.fromSOAC soac-  (perm, inputs') <- liftMaybe $ fixupInputs inpIds $ MapNest.inputs nest-  if rearrangeReach perm <= mapDepth nest-    then do-      let invertRearrange = SOAC.Rearrange mempty $ rearrangeInverse perm-      soac' <--        MapNest.toSOAC $-          inputs'-            `MapNest.setInputs` rearrangeReturnTypes nest perm-      pure (soac', invertRearrange SOAC.<| ots)-    else fail "Cannot push transpose"---- | Actually also rearranges indices.-rearrangeReturnTypes :: MapNest -> [Int] -> MapNest-rearrangeReturnTypes nest@(MapNest.MapNest w body nestings inps) perm =-  MapNest.MapNest-    w-    body-    ( zipWith-        setReturnType-        nestings-        $ drop 1 $ iterate (map rowType) ts-    )-    inps-  where-    origts = MapNest.typeOf nest-    -- The permutation may be deeper than the rank of the type,-    -- but it is required that it is an identity permutation-    -- beyond that.  This is supposed to be checked as an-    -- invariant by whoever calls rearrangeReturnTypes.-    rearrangeType' t = rearrangeType (take (arrayRank t) perm) t-    ts = map rearrangeType' origts--    setReturnType nesting t' =-      nesting {MapNest.nestingReturnType = t'}--fixupInputs :: [VName] -> [SOAC.Input] -> Maybe ([Int], [SOAC.Input])-fixupInputs inpIds inps =-  case mapMaybe inputRearrange $ filter exposable inps of-    perm : _ -> do-      inps' <- mapM (fixupInput (rearrangeReach perm) perm) inps-      pure (perm, inps')-    _ -> Nothing-  where-    exposable = (`elem` inpIds) . SOAC.inputArray--    inputRearrange (SOAC.Input ts _ _)-      | _ SOAC.:> SOAC.Rearrange _ perm <- SOAC.viewl ts = Just perm-    inputRearrange _ = Nothing--    fixupInput d perm inp-      | r <- SOAC.inputRank inp,-        r >= d =-          Just $ SOAC.addTransform (SOAC.Rearrange mempty $ take r perm) inp-      | otherwise = Nothing--pullReshape :: SOAC -> SOAC.ArrayTransforms -> TryFusion (SOAC, SOAC.ArrayTransforms)-pullReshape (SOAC.Screma _ form inps) ots-  | Just maplam <- Futhark.isMapSOAC form,-    SOAC.Reshape cs shape SOAC.:< ots' <- SOAC.viewf ots,-    all primType $ lambdaReturnType maplam = do-      let mapw' = case reverse $ newDims shape of-            [] -> intConst Int64 0-            d : _ -> d-          inputs' = map (SOAC.addTransform $ SOAC.ReshapeOuter cs shape) inps-          inputTypes = map SOAC.inputType inputs'--      let outersoac ::-            ([SOAC.Input] -> SOAC) ->-            (SubExp, [SubExp]) ->-            TryFusion ([SOAC.Input] -> SOAC)-          outersoac inner (w, outershape) = do-            let addDims t = arrayOf t (Shape outershape) NoUniqueness-                retTypes = map addDims $ lambdaReturnType maplam--            ps <- forM inputTypes $ \inpt ->-              newParam "pullReshape_param" $-                stripArray (length shape - length outershape) inpt--            inner_body <--              runBodyBuilder $-                eBody [SOAC.toExp $ inner $ map (SOAC.identInput . paramIdent) ps]-            let inner_fun =-                  Lambda-                    { lambdaParams = ps,-                      lambdaReturnType = retTypes,-                      lambdaBody = inner_body-                    }-            pure $ SOAC.Screma w $ Futhark.mapSOAC inner_fun--      op' <--        foldM outersoac (SOAC.Screma mapw' $ Futhark.mapSOAC maplam) $-          zip (drop 1 $ reverse $ newDims shape) $-            drop 1 $ reverse $ drop 1 $ tails $ newDims shape-      pure (op' inputs', ots')-pullReshape _ _ = fail "Cannot pull reshape"---- Tie it all together in exposeInputs (for making inputs to a--- consumer available) and pullOutputTransforms (for moving--- output-transforms of a producer to its inputs instead).--exposeInputs ::-  [VName] ->-  FusedKer ->-  TryFusion (FusedKer, SOAC.ArrayTransforms)-exposeInputs inpIds ker =-  (exposeInputs' =<< pushRearrange')-    <|> (exposeInputs' =<< pullRearrange')-    <|> exposeInputs' ker-  where-    ot = outputTransform ker--    pushRearrange' = do-      (soac', ot') <- pushRearrange inpIds (fsoac ker) ot-      pure-        ker-          { fsoac = soac',-            outputTransform = ot'-          }--    pullRearrange' = do-      (soac', ot') <- pullRearrange (fsoac ker) ot-      unless (SOAC.nullTransforms ot') $-        fail "pullRearrange was not enough"-      pure-        ker-          { fsoac = soac',-            outputTransform = SOAC.noTransforms-          }--    exposeInputs' ker' =-      case commonTransforms inpIds $ inputs ker' of-        (ot', inps')-          | all exposed inps' ->-              pure (ker' {fsoac = inps' `SOAC.setInputs` fsoac ker'}, ot')-        _ -> fail "Cannot expose"--    exposed (SOAC.Input ts _ _)-      | SOAC.nullTransforms ts = True-    exposed inp = SOAC.inputArray inp `notElem` inpIds--outputTransformPullers :: [SOAC -> SOAC.ArrayTransforms -> TryFusion (SOAC, SOAC.ArrayTransforms)]-outputTransformPullers = [pullRearrange, pullReshape]--pullOutputTransforms ::-  SOAC ->-  SOAC.ArrayTransforms ->-  TryFusion (SOAC, SOAC.ArrayTransforms)-pullOutputTransforms = attempt outputTransformPullers-  where-    attempt [] _ _ = fail "Cannot pull anything"-    attempt (p : ps) soac ots =-      do-        (soac', ots') <- p soac ots-        if SOAC.nullTransforms ots'-          then pure (soac', SOAC.noTransforms)-          else pullOutputTransforms soac' ots' <|> pure (soac', ots')-        <|> attempt ps soac ots
+ src/Futhark/Optimise/Fusion/TryFusion.hs view
@@ -0,0 +1,856 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies #-}++-- | Facilities for fusing two SOACs.+--+-- When the fusion algorithm decides that it's worth fusing two SOAC+-- statements, this is the module that tries to see if that's+-- possible.  May involve massaging either producer or consumer in+-- various ways.+module Futhark.Optimise.Fusion.TryFusion+  ( FusedSOAC (..),+    attemptFusion,+  )+where++import Control.Applicative+import Control.Arrow (first)+import Control.Monad+import Control.Monad.Reader+import Control.Monad.State+import Data.List (find, tails, (\\))+import qualified Data.Map.Strict as M+import Data.Maybe+import qualified Futhark.Analysis.HORep.MapNest as MapNest+import qualified Futhark.Analysis.HORep.SOAC as SOAC+import Futhark.Construct+import Futhark.IR.SOACS hiding (SOAC (..))+import qualified Futhark.IR.SOACS as Futhark+import Futhark.Optimise.Fusion.Composing+import Futhark.Pass.ExtractKernels.ISRWIM (rwimPossible)+import Futhark.Transform.Rename (renameLambda)+import Futhark.Transform.Substitute+import Futhark.Util (splitAt3)++newtype TryFusion a+  = TryFusion+      ( ReaderT+          (Scope SOACS)+          (StateT VNameSource Maybe)+          a+      )+  deriving+    ( Functor,+      Applicative,+      Alternative,+      Monad,+      MonadFail,+      MonadFreshNames,+      HasScope SOACS,+      LocalScope SOACS+    )++tryFusion ::+  MonadFreshNames m =>+  TryFusion a ->+  Scope SOACS ->+  m (Maybe a)+tryFusion (TryFusion m) types = modifyNameSource $ \src ->+  case runStateT (runReaderT m types) src of+    Just (x, src') -> (Just x, src')+    Nothing -> (Nothing, src)++liftMaybe :: Maybe a -> TryFusion a+liftMaybe Nothing = fail "Nothing"+liftMaybe (Just x) = pure x++type SOAC = SOAC.SOAC SOACS++type MapNest = MapNest.MapNest SOACS++inputToOutput :: SOAC.Input -> Maybe (SOAC.ArrayTransform, SOAC.Input)+inputToOutput (SOAC.Input ts ia iat) =+  case SOAC.viewf ts of+    t SOAC.:< ts' -> Just (t, SOAC.Input ts' ia iat)+    SOAC.EmptyF -> Nothing++-- | A fused SOAC contains a bit of extra information.+data FusedSOAC = FusedSOAC+  { -- | The actual SOAC.+    fsSOAC :: SOAC,+    -- | A transformation to be applied to *all* results of the SOAC.+    fsOutputTransform :: SOAC.ArrayTransforms,+    -- | The outputs of the SOAC (i.e. the names in the pattern that+    -- the result of this SOAC should be bound to).+    fsOutNames :: [VName]+  }+  deriving (Show)++inputs :: FusedSOAC -> [SOAC.Input]+inputs = SOAC.inputs . fsSOAC++setInputs :: [SOAC.Input] -> FusedSOAC -> FusedSOAC+setInputs inps ker = ker {fsSOAC = inps `SOAC.setInputs` fsSOAC ker}++tryOptimizeSOAC ::+  Names ->+  [VName] ->+  SOAC ->+  FusedSOAC ->+  TryFusion FusedSOAC+tryOptimizeSOAC unfus_nms outVars soac ker = do+  (soac', ots) <- optimizeSOAC Nothing soac mempty+  let ker' = map (addInitialTransformIfRelevant ots) (inputs ker) `setInputs` ker+      outIdents = zipWith Ident outVars $ SOAC.typeOf soac'+      ker'' = fixInputTypes outIdents ker'+  applyFusionRules unfus_nms outVars soac' ker''+  where+    addInitialTransformIfRelevant ots inp+      | SOAC.inputArray inp `elem` outVars =+          SOAC.addInitialTransforms ots inp+      | otherwise =+          inp++tryOptimizeKernel ::+  Names ->+  [VName] ->+  SOAC ->+  FusedSOAC ->+  TryFusion FusedSOAC+tryOptimizeKernel unfus_nms outVars soac ker = do+  ker' <- optimizeKernel (Just outVars) ker+  applyFusionRules unfus_nms outVars soac ker'++tryExposeInputs ::+  Names ->+  [VName] ->+  SOAC ->+  FusedSOAC ->+  TryFusion FusedSOAC+tryExposeInputs unfus_nms outVars soac ker = do+  (ker', ots) <- exposeInputs outVars ker+  if SOAC.nullTransforms ots+    then fuseSOACwithKer unfus_nms outVars soac ker'+    else do+      guard $ unfus_nms == mempty+      (soac', ots') <- pullOutputTransforms soac ots+      let outIdents = zipWith Ident outVars $ SOAC.typeOf soac'+          ker'' = fixInputTypes outIdents ker'+      if SOAC.nullTransforms ots'+        then applyFusionRules unfus_nms outVars soac' ker''+        else fail "tryExposeInputs could not pull SOAC transforms"++fixInputTypes :: [Ident] -> FusedSOAC -> FusedSOAC+fixInputTypes outIdents ker =+  ker {fsSOAC = fixInputTypes' $ fsSOAC ker}+  where+    fixInputTypes' soac =+      map fixInputType (SOAC.inputs soac) `SOAC.setInputs` soac+    fixInputType (SOAC.Input ts v _)+      | Just v' <- find ((== v) . identName) outIdents =+          SOAC.Input ts v $ identType v'+    fixInputType inp = inp++applyFusionRules ::+  Names ->+  [VName] ->+  SOAC ->+  FusedSOAC ->+  TryFusion FusedSOAC+applyFusionRules unfus_nms outVars soac ker =+  tryOptimizeSOAC unfus_nms outVars soac ker+    <|> tryOptimizeKernel unfus_nms outVars soac ker+    <|> fuseSOACwithKer unfus_nms outVars soac ker+    <|> tryExposeInputs unfus_nms outVars soac ker++-- | Attempt fusing the producer into the consumer.+attemptFusion ::+  (HasScope SOACS m, MonadFreshNames m) =>+  -- | Outputs of the producer that should still be output by the+  -- fusion result (corresponding to "diagonal fusion").+  Names ->+  -- | The outputs of the SOAC.+  [VName] ->+  SOAC ->+  FusedSOAC ->+  m (Maybe FusedSOAC)+attemptFusion unfus_nms outVars soac ker = do+  scope <- askScope+  tryFusion (applyFusionRules unfus_nms outVars soac ker) scope++-- | Check that the consumer does not use any scan or reduce results.+scremaFusionOK :: ([VName], [VName]) -> FusedSOAC -> Bool+scremaFusionOK (nonmap_outs, _map_outs) ker =+  all (`notElem` nonmap_outs) $ mapMaybe SOAC.isVarishInput (inputs ker)++-- | Check that the consumer uses all the outputs of the producer unmodified.+mapWriteFusionOK :: [VName] -> FusedSOAC -> Bool+mapWriteFusionOK outVars ker = all (`elem` inpIds) outVars+  where+    inpIds = mapMaybe SOAC.isVarishInput (inputs ker)++-- | The brain of this module: Fusing a SOAC with a Kernel.+fuseSOACwithKer ::+  Names ->+  [VName] ->+  SOAC ->+  FusedSOAC ->+  TryFusion FusedSOAC+fuseSOACwithKer unfus_set outVars soac_p ker = do+  -- We are fusing soac_p into soac_c, i.e, the output of soac_p is going+  -- into soac_c.+  let soac_c = fsSOAC ker+      inp_p_arr = SOAC.inputs soac_p+      horizFuse = unfus_set /= mempty+      inp_c_arr = SOAC.inputs soac_c+      lam_p = SOAC.lambda soac_p+      lam_c = SOAC.lambda soac_c+      w = SOAC.width soac_p+      returned_outvars = filter (`nameIn` unfus_set) outVars+      success res_outnms res_soac = do+        -- Avoid name duplication, because the producer lambda is not+        -- removed from the program until much later.+        uniq_lam <- renameLambda $ SOAC.lambda res_soac+        pure $+          ker+            { fsSOAC = uniq_lam `SOAC.setLambda` res_soac,+              fsOutNames = res_outnms+            }++  -- Can only fuse SOACs with same width.+  guard $ SOAC.width soac_p == SOAC.width soac_c++  -- If we are getting rid of a producer output, then it must be used+  -- without any transformation.+  let bare_inputs = mapMaybe SOAC.isVarishInput (inputs ker)+      ker_inputs = map SOAC.inputArray (inputs ker)+      inputOrUnfus v = v `elem` bare_inputs || v `notElem` ker_inputs++  guard $ all inputOrUnfus outVars++  outPairs <- forM (zip outVars $ map rowType $ SOAC.typeOf soac_p) $ \(outVar, t) -> do+    outVar' <- newVName $ baseString outVar ++ "_elem"+    pure (outVar, Ident outVar' t)++  let mapLikeFusionCheck =+        let (res_lam, new_inp) = fuseMaps unfus_set lam_p inp_p_arr outPairs lam_c inp_c_arr+            (extra_nms, extra_rtps) =+              unzip $+                filter ((`nameIn` unfus_set) . fst) $+                  zip outVars $+                    map (stripArray 1) $+                      SOAC.typeOf soac_p+            res_lam' = res_lam {lambdaReturnType = lambdaReturnType res_lam ++ extra_rtps}+         in (extra_nms, res_lam', new_inp)++  when (horizFuse && not (SOAC.nullTransforms $ fsOutputTransform ker)) $+    fail "Horizontal fusion is invalid in the presence of output transforms."++  case (soac_c, soac_p) of+    _ | SOAC.width soac_p /= SOAC.width soac_c -> fail "SOAC widths must match."+    ( SOAC.Screma _ (ScremaForm scans_c reds_c _) _,+      SOAC.Screma _ (ScremaForm scans_p reds_p _) _+      )+        | scremaFusionOK (splitAt (Futhark.scanResults scans_p + Futhark.redResults reds_p) outVars) ker -> do+            let red_nes_p = concatMap redNeutral reds_p+                red_nes_c = concatMap redNeutral reds_c+                scan_nes_p = concatMap scanNeutral scans_p+                scan_nes_c = concatMap scanNeutral scans_c+                (res_lam', new_inp) =+                  fuseRedomap+                    unfus_set+                    outVars+                    lam_p+                    scan_nes_p+                    red_nes_p+                    inp_p_arr+                    outPairs+                    lam_c+                    scan_nes_c+                    red_nes_c+                    inp_c_arr+                (soac_p_scanout, soac_p_redout, _soac_p_mapout) =+                  splitAt3 (length scan_nes_p) (length red_nes_p) outVars+                (soac_c_scanout, soac_c_redout, soac_c_mapout) =+                  splitAt3 (length scan_nes_c) (length red_nes_c) $ fsOutNames ker+                unfus_arrs = returned_outvars \\ (soac_p_scanout ++ soac_p_redout)+            success+              ( soac_p_scanout+                  ++ soac_c_scanout+                  ++ soac_p_redout+                  ++ soac_c_redout+                  ++ soac_c_mapout+                  ++ unfus_arrs+              )+              $ SOAC.Screma+                w+                (ScremaForm (scans_p ++ scans_c) (reds_p ++ reds_c) res_lam')+                new_inp++    ------------------+    -- Scatter fusion --+    ------------------++    -- Map-Scatter fusion.+    --+    -- The 'inplace' mechanism for kernels already takes care of+    -- checking that the Scatter is not writing to any array used in+    -- the Map.+    ( SOAC.Scatter _len _lam _ivs dests,+      SOAC.Screma _ form _+      )+        | isJust $ isMapSOAC form,+          -- 1. all arrays produced by the map are ONLY used (consumed)+          --    by the scatter, i.e., not used elsewhere.+          all (`notNameIn` unfus_set) outVars,+          -- 2. all arrays produced by the map are input to the scatter.+          mapWriteFusionOK outVars ker -> do+            let (extra_nms, res_lam', new_inp) = mapLikeFusionCheck+            success (fsOutNames ker ++ extra_nms) $+              SOAC.Scatter w res_lam' new_inp dests++    -- Map-Hist fusion.+    --+    -- The 'inplace' mechanism for kernels already takes care of+    -- checking that the Hist is not writing to any array used in+    -- the Map.+    ( SOAC.Hist _ ops _ _,+      SOAC.Screma _ form _+      )+        | isJust $ isMapSOAC form,+          -- 1. all arrays produced by the map are ONLY used (consumed)+          --    by the hist, i.e., not used elsewhere.+          all (`notNameIn` unfus_set) outVars,+          -- 2. all arrays produced by the map are input to the scatter.+          mapWriteFusionOK outVars ker -> do+            let (extra_nms, res_lam', new_inp) = mapLikeFusionCheck+            success (fsOutNames ker ++ extra_nms) $+              SOAC.Hist w ops res_lam' new_inp++    -- Hist-Hist fusion+    ( SOAC.Hist _ ops_c _ _,+      SOAC.Hist _ ops_p _ _+      )+        | horizFuse -> do+            let p_num_buckets = length ops_p+                c_num_buckets = length ops_c+                (body_p, body_c) = (lambdaBody lam_p, lambdaBody lam_c)+                body' =+                  Body+                    { bodyDec = bodyDec body_p, -- body_p and body_c have the same decorations+                      bodyStms = bodyStms body_p <> bodyStms body_c,+                      bodyResult =+                        take c_num_buckets (bodyResult body_c)+                          ++ take p_num_buckets (bodyResult body_p)+                          ++ drop c_num_buckets (bodyResult body_c)+                          ++ drop p_num_buckets (bodyResult body_p)+                    }+                lam' =+                  Lambda+                    { lambdaParams = lambdaParams lam_c ++ lambdaParams lam_p,+                      lambdaBody = body',+                      lambdaReturnType =+                        replicate (c_num_buckets + p_num_buckets) (Prim int64)+                          ++ drop c_num_buckets (lambdaReturnType lam_c)+                          ++ drop p_num_buckets (lambdaReturnType lam_p)+                    }+            success (fsOutNames ker ++ returned_outvars) $+              SOAC.Hist w (ops_c <> ops_p) lam' (inp_c_arr <> inp_p_arr)++    -- Scatter-write fusion.+    ( SOAC.Scatter _len_c _lam_c ivs_c as_c,+      SOAC.Scatter _len_p _lam_p ivs_p as_p+      )+        | horizFuse -> do+            let zipW as_xs xs as_ys ys = xs_indices ++ ys_indices ++ xs_vals ++ ys_vals+                  where+                    (xs_indices, xs_vals) = splitScatterResults as_xs xs+                    (ys_indices, ys_vals) = splitScatterResults as_ys ys+            let (body_p, body_c) = (lambdaBody lam_p, lambdaBody lam_c)+            let body' =+                  Body+                    { bodyDec = bodyDec body_p, -- body_p and body_c have the same decorations+                      bodyStms = bodyStms body_p <> bodyStms body_c,+                      bodyResult = zipW as_c (bodyResult body_c) as_p (bodyResult body_p)+                    }+            let lam' =+                  Lambda+                    { lambdaParams = lambdaParams lam_c ++ lambdaParams lam_p,+                      lambdaBody = body',+                      lambdaReturnType = zipW as_c (lambdaReturnType lam_c) as_p (lambdaReturnType lam_p)+                    }+            success (fsOutNames ker ++ returned_outvars) $+              SOAC.Scatter w lam' (ivs_c ++ ivs_p) (as_c ++ as_p)+    (SOAC.Scatter {}, _) ->+      fail "Cannot fuse a write with anything else than a write or a map"+    (_, SOAC.Scatter {}) ->+      fail "Cannot fuse a write with anything else than a write or a map"+    ----------------------------+    -- Stream-Stream Fusions: --+    ----------------------------+    (SOAC.Stream _ Sequential _ _ _, SOAC.Stream _ Sequential _ _ _) -> do+      -- fuse two SEQUENTIAL streams+      (res_nms, res_stream) <- fuseStreamHelper (fsOutNames ker) unfus_set outVars outPairs soac_c soac_p+      success res_nms res_stream+    (SOAC.Stream {}, SOAC.Stream {}) -> do+      -- fuse two PARALLEL streams+      (res_nms, res_stream) <- fuseStreamHelper (fsOutNames ker) unfus_set outVars outPairs soac_c soac_p+      success res_nms res_stream+    -------------------------------------------------------------------+    --- If one is a stream, translate the other to a stream as well.---+    --- This does not get in trouble (infinite computation) because ---+    ---   scan's translation to Stream introduces a hindrance to    ---+    ---   (horizontal fusion), hence repeated application is for the---+    ---   moment impossible. However, if with a dependence-graph rep---+    ---   we could run in an infinite recursion, i.e., repeatedly   ---+    ---   fusing map o scan into an infinity of Stream levels!      ---+    -------------------------------------------------------------------+    (SOAC.Stream _ form2 _ _ _, _) -> do+      -- If this rule is matched then soac_p is NOT a stream.+      -- To fuse a stream kernel, we transform soac_p to a stream, which+      -- borrows the sequential/parallel property of the soac_c Stream,+      -- and recursively perform stream-stream fusion.+      (soac_p', newacc_ids) <- SOAC.soacToStream soac_p+      soac_p'' <- case form2 of+        Sequential {} -> maybe (fail "not a stream") pure (toSeqStream soac_p')+        _ -> pure soac_p'+      if soac_p' == soac_p+        then fail "SOAC could not be turned into stream."+        else+          fuseSOACwithKer+            (namesFromList (map identName newacc_ids) <> unfus_set)+            (map identName newacc_ids ++ outVars)+            soac_p''+            ker+    (_, SOAC.Screma _ form _) | Just _ <- Futhark.isScanomapSOAC form -> do+      -- A Scan soac can be currently only fused as a (sequential) stream,+      -- hence it is first translated to a (sequential) Stream and then+      -- fusion with a kernel is attempted.+      (soac_p', newacc_ids) <- SOAC.soacToStream soac_p+      if soac_p' /= soac_p+        then+          fuseSOACwithKer+            (namesFromList (map identName newacc_ids) <> unfus_set)+            (map identName newacc_ids ++ outVars)+            soac_p'+            ker+        else fail "SOAC could not be turned into stream."+    (_, SOAC.Stream _ form_p _ _ _) -> do+      -- If it reached this case then soac_c is NOT a Stream kernel,+      -- hence transform the kernel's soac to a stream and attempt+      -- stream-stream fusion recursivelly.+      -- The newly created stream corresponding to soac_c borrows the+      -- sequential/parallel property of the soac_p stream.+      (soac_c', newacc_ids) <- SOAC.soacToStream soac_c+      when (soac_c' == soac_c) $ fail "SOAC could not be turned into stream."+      soac_c'' <- case form_p of+        Sequential -> maybe (fail "not a stream") pure (toSeqStream soac_c')+        _ -> pure soac_c'++      fuseSOACwithKer+        (namesFromList (map identName newacc_ids) <> unfus_set)+        outVars+        soac_p+        $ ker {fsSOAC = soac_c'', fsOutNames = map identName newacc_ids ++ fsOutNames ker}++    ---------------------------------+    --- DEFAULT, CANNOT FUSE CASE ---+    ---------------------------------+    _ -> fail "Cannot fuse"++getStreamOrder :: StreamForm rep -> StreamOrd+getStreamOrder (Parallel o _ _) = o+getStreamOrder Sequential = InOrder++fuseStreamHelper ::+  [VName] ->+  Names ->+  [VName] ->+  [(VName, Ident)] ->+  SOAC ->+  SOAC ->+  TryFusion ([VName], SOAC)+fuseStreamHelper+  out_kernms+  unfus_set+  outVars+  outPairs+  (SOAC.Stream w2 form2 lam2 nes2 inp2_arr)+  (SOAC.Stream _ form1 lam1 nes1 inp1_arr) =+    if getStreamOrder form2 /= getStreamOrder form1+      then fail "fusion conditions not met!"+      else do+        -- very similar to redomap o redomap composition, but need+        -- to remove first the `chunk' parameters of streams'+        -- lambdas and put them in the resulting stream lambda.+        let chunk1 = head $ lambdaParams lam1+            chunk2 = head $ lambdaParams lam2+            hmnms = M.fromList [(paramName chunk2, paramName chunk1)]+            lam20 = substituteNames hmnms lam2+            lam1' = lam1 {lambdaParams = tail $ lambdaParams lam1}+            lam2' = lam20 {lambdaParams = tail $ lambdaParams lam20}+            (res_lam', new_inp) =+              fuseRedomap+                unfus_set+                outVars+                lam1'+                []+                nes1+                inp1_arr+                outPairs+                lam2'+                []+                nes2+                inp2_arr+            res_lam'' = res_lam' {lambdaParams = chunk1 : lambdaParams res_lam'}+            unfus_accs = take (length nes1) outVars+            unfus_arrs = filter (`notElem` unfus_accs) $ filter (`nameIn` unfus_set) outVars+        let res_form = mergeForms form2 form1+        pure+          ( unfus_accs ++ out_kernms ++ unfus_arrs,+            SOAC.Stream w2 res_form res_lam'' (nes1 ++ nes2) new_inp+          )+fuseStreamHelper _ _ _ _ _ _ = fail "Cannot Fuse Streams!"++mergeForms :: StreamForm SOACS -> StreamForm SOACS -> StreamForm SOACS+mergeForms Sequential Sequential = Sequential+mergeForms (Parallel _ comm2 lam2r) (Parallel o1 comm1 lam1r) =+  Parallel o1 (comm1 <> comm2) (mergeReduceOps lam1r lam2r)+mergeForms _ _ = error "Fusing sequential to parallel stream disallowed!"++-- | If a Stream is passed as argument then it converts it to a+--   Sequential Stream.+toSeqStream :: SOAC -> Maybe SOAC+toSeqStream s@(SOAC.Stream _ Sequential _ _ _) = Just s+toSeqStream (SOAC.Stream w Parallel {} l acc inps) =+  Just $ SOAC.Stream w Sequential l acc inps+toSeqStream _ = Nothing++-- Here follows optimizations and transforms to expose fusability.++optimizeKernel :: Maybe [VName] -> FusedSOAC -> TryFusion FusedSOAC+optimizeKernel inp ker = do+  (soac, resTrans) <- optimizeSOAC inp (fsSOAC ker) (fsOutputTransform ker)+  pure $ ker {fsSOAC = soac, fsOutputTransform = resTrans}++optimizeSOAC ::+  Maybe [VName] ->+  SOAC ->+  SOAC.ArrayTransforms ->+  TryFusion (SOAC, SOAC.ArrayTransforms)+optimizeSOAC inp soac os = do+  res <- foldM comb (False, soac, os) optimizations+  case res of+    (False, _, _) -> fail "No optimisation applied"+    (True, soac', os') -> pure (soac', os')+  where+    comb (changed, soac', os') f =+      do+        (soac'', os'') <- f inp soac' os+        pure (True, soac'', os'')+        <|> pure (changed, soac', os')++type Optimization =+  Maybe [VName] ->+  SOAC ->+  SOAC.ArrayTransforms ->+  TryFusion (SOAC, SOAC.ArrayTransforms)++optimizations :: [Optimization]+optimizations = [iswim]++iswim ::+  Maybe [VName] ->+  SOAC ->+  SOAC.ArrayTransforms ->+  TryFusion (SOAC, SOAC.ArrayTransforms)+iswim _ (SOAC.Screma w form arrs) ots+  | Just [Futhark.Scan scan_fun nes] <- Futhark.isScanSOAC form,+    Just (map_pat, map_cs, map_w, map_fun) <- rwimPossible scan_fun,+    Just nes_names <- mapM subExpVar nes = do+      let nes_idents = zipWith Ident nes_names $ lambdaReturnType scan_fun+          map_nes = map SOAC.identInput nes_idents+          map_arrs' = map_nes ++ map (SOAC.transposeInput 0 1) arrs+          (scan_acc_params, scan_elem_params) =+            splitAt (length arrs) $ lambdaParams scan_fun+          map_params =+            map removeParamOuterDim scan_acc_params+              ++ map (setParamOuterDimTo w) scan_elem_params+          map_rettype = map (`setOuterSize` w) $ lambdaReturnType scan_fun++          scan_params = lambdaParams map_fun+          scan_body = lambdaBody map_fun+          scan_rettype = lambdaReturnType map_fun+          scan_fun' = Lambda scan_params scan_body scan_rettype+          nes' = map Var $ take (length map_nes) $ map paramName map_params+          arrs' = drop (length map_nes) $ map paramName map_params++      scan_form <- scanSOAC [Futhark.Scan scan_fun' nes']++      let map_body =+            mkBody+              ( oneStm $+                  Let (setPatOuterDimTo w map_pat) (defAux ()) $+                    Op $+                      Futhark.Screma w arrs' scan_form+              )+              $ varsRes+              $ patNames map_pat+          map_fun' = Lambda map_params map_body map_rettype+          perm = case lambdaReturnType scan_fun of -- instead of map_fun+            [] -> []+            t : _ -> 1 : 0 : [2 .. arrayRank t]++      pure+        ( SOAC.Screma map_w (ScremaForm [] [] map_fun') map_arrs',+          ots SOAC.|> SOAC.Rearrange map_cs perm+        )+iswim _ _ _ =+  fail "ISWIM does not apply."++removeParamOuterDim :: LParam SOACS -> LParam SOACS+removeParamOuterDim param =+  let t = rowType $ paramType param+   in param {paramDec = t}++setParamOuterDimTo :: SubExp -> LParam SOACS -> LParam SOACS+setParamOuterDimTo w param =+  let t = paramType param `setOuterSize` w+   in param {paramDec = t}++setPatOuterDimTo :: SubExp -> Pat Type -> Pat Type+setPatOuterDimTo w = fmap (`setOuterSize` w)++-- Now for fiddling with transpositions...++commonTransforms ::+  [VName] ->+  [SOAC.Input] ->+  (SOAC.ArrayTransforms, [SOAC.Input])+commonTransforms interesting inps = commonTransforms' inps'+  where+    inps' =+      [ (SOAC.inputArray inp `elem` interesting, inp)+        | inp <- inps+      ]++commonTransforms' :: [(Bool, SOAC.Input)] -> (SOAC.ArrayTransforms, [SOAC.Input])+commonTransforms' inps =+  case foldM inspect (Nothing, []) inps of+    Just (Just mot, inps') -> first (mot SOAC.<|) $ commonTransforms' $ reverse inps'+    _ -> (SOAC.noTransforms, map snd inps)+  where+    inspect (mot, prev) (True, inp) =+      case (mot, inputToOutput inp) of+        (Nothing, Just (ot, inp')) -> Just (Just ot, (True, inp') : prev)+        (Just ot1, Just (ot2, inp'))+          | ot1 == ot2 -> Just (Just ot2, (True, inp') : prev)+        _ -> Nothing+    inspect (mot, prev) inp = Just (mot, inp : prev)++mapDepth :: MapNest -> Int+mapDepth (MapNest.MapNest _ lam levels _) =+  min resDims (length levels) + 1+  where+    resDims = minDim $ case levels of+      [] -> lambdaReturnType lam+      nest : _ -> MapNest.nestingReturnType nest+    minDim [] = 0+    minDim (t : ts) = foldl min (arrayRank t) $ map arrayRank ts++pullRearrange ::+  SOAC ->+  SOAC.ArrayTransforms ->+  TryFusion (SOAC, SOAC.ArrayTransforms)+pullRearrange soac ots = do+  nest <- liftMaybe =<< MapNest.fromSOAC soac+  SOAC.Rearrange cs perm SOAC.:< ots' <- pure $ SOAC.viewf ots+  if rearrangeReach perm <= mapDepth nest+    then do+      let -- Expand perm to cover the full extent of the input dimensionality+          perm' inp = take r perm ++ [length perm .. r - 1]+            where+              r = SOAC.inputRank inp+          addPerm inp = SOAC.addTransform (SOAC.Rearrange cs $ perm' inp) inp+          inputs' = map addPerm $ MapNest.inputs nest+      soac' <-+        MapNest.toSOAC $+          inputs' `MapNest.setInputs` rearrangeReturnTypes nest perm+      pure (soac', ots')+    else fail "Cannot pull transpose"++pushRearrange ::+  [VName] ->+  SOAC ->+  SOAC.ArrayTransforms ->+  TryFusion (SOAC, SOAC.ArrayTransforms)+pushRearrange inpIds soac ots = do+  nest <- liftMaybe =<< MapNest.fromSOAC soac+  (perm, inputs') <- liftMaybe $ fixupInputs inpIds $ MapNest.inputs nest+  if rearrangeReach perm <= mapDepth nest+    then do+      let invertRearrange = SOAC.Rearrange mempty $ rearrangeInverse perm+      soac' <-+        MapNest.toSOAC $+          inputs'+            `MapNest.setInputs` rearrangeReturnTypes nest perm+      pure (soac', invertRearrange SOAC.<| ots)+    else fail "Cannot push transpose"++-- | Actually also rearranges indices.+rearrangeReturnTypes :: MapNest -> [Int] -> MapNest+rearrangeReturnTypes nest@(MapNest.MapNest w body nestings inps) perm =+  MapNest.MapNest+    w+    body+    ( zipWith+        setReturnType+        nestings+        $ drop 1+        $ iterate (map rowType) ts+    )+    inps+  where+    origts = MapNest.typeOf nest+    -- The permutation may be deeper than the rank of the type,+    -- but it is required that it is an identity permutation+    -- beyond that.  This is supposed to be checked as an+    -- invariant by whoever calls rearrangeReturnTypes.+    rearrangeType' t = rearrangeType (take (arrayRank t) perm) t+    ts = map rearrangeType' origts++    setReturnType nesting t' =+      nesting {MapNest.nestingReturnType = t'}++fixupInputs :: [VName] -> [SOAC.Input] -> Maybe ([Int], [SOAC.Input])+fixupInputs inpIds inps =+  case mapMaybe inputRearrange $ filter exposable inps of+    perm : _ -> do+      inps' <- mapM (fixupInput (rearrangeReach perm) perm) inps+      pure (perm, inps')+    _ -> Nothing+  where+    exposable = (`elem` inpIds) . SOAC.inputArray++    inputRearrange (SOAC.Input ts _ _)+      | _ SOAC.:> SOAC.Rearrange _ perm <- SOAC.viewl ts = Just perm+    inputRearrange _ = Nothing++    fixupInput d perm inp+      | r <- SOAC.inputRank inp,+        r >= d =+          Just $ SOAC.addTransform (SOAC.Rearrange mempty $ take r perm) inp+      | otherwise = Nothing++pullReshape :: SOAC -> SOAC.ArrayTransforms -> TryFusion (SOAC, SOAC.ArrayTransforms)+pullReshape (SOAC.Screma _ form inps) ots+  | Just maplam <- Futhark.isMapSOAC form,+    SOAC.Reshape cs shape SOAC.:< ots' <- SOAC.viewf ots,+    all primType $ lambdaReturnType maplam = do+      let mapw' = case reverse $ newDims shape of+            [] -> intConst Int64 0+            d : _ -> d+          trInput inp+            | arrayRank (SOAC.inputType inp) == 1 =+                SOAC.addTransform (SOAC.Reshape cs shape) inp+            | otherwise =+                SOAC.addTransform (SOAC.ReshapeOuter cs shape) inp+          inputs' = map trInput inps+          inputTypes = map SOAC.inputType inputs'++      let outersoac ::+            ([SOAC.Input] -> SOAC) ->+            (SubExp, [SubExp]) ->+            TryFusion ([SOAC.Input] -> SOAC)+          outersoac inner (w, outershape) = do+            let addDims t = arrayOf t (Shape outershape) NoUniqueness+                retTypes = map addDims $ lambdaReturnType maplam++            ps <- forM inputTypes $ \inpt ->+              newParam "pullReshape_param" $+                stripArray (length shape - length outershape) inpt++            inner_body <-+              runBodyBuilder $+                eBody [SOAC.toExp $ inner $ map (SOAC.identInput . paramIdent) ps]+            let inner_fun =+                  Lambda+                    { lambdaParams = ps,+                      lambdaReturnType = retTypes,+                      lambdaBody = inner_body+                    }+            pure $ SOAC.Screma w $ Futhark.mapSOAC inner_fun++      op' <-+        foldM outersoac (SOAC.Screma mapw' $ Futhark.mapSOAC maplam) $+          zip (drop 1 $ reverse $ newDims shape) $+            drop 1 $+              reverse $+                drop 1 $+                  tails $+                    newDims shape+      pure (op' inputs', ots')+pullReshape _ _ = fail "Cannot pull reshape"++-- Tie it all together in exposeInputs (for making inputs to a+-- consumer available) and pullOutputTransforms (for moving+-- output-transforms of a producer to its inputs instead).++exposeInputs ::+  [VName] ->+  FusedSOAC ->+  TryFusion (FusedSOAC, SOAC.ArrayTransforms)+exposeInputs inpIds ker =+  (exposeInputs' =<< pushRearrange')+    <|> (exposeInputs' =<< pullRearrange')+    <|> exposeInputs' ker+  where+    ot = fsOutputTransform ker++    pushRearrange' = do+      (soac', ot') <- pushRearrange inpIds (fsSOAC ker) ot+      pure+        ker+          { fsSOAC = soac',+            fsOutputTransform = ot'+          }++    pullRearrange' = do+      (soac', ot') <- pullRearrange (fsSOAC ker) ot+      unless (SOAC.nullTransforms ot') $+        fail "pullRearrange was not enough"+      pure+        ker+          { fsSOAC = soac',+            fsOutputTransform = SOAC.noTransforms+          }++    exposeInputs' ker' =+      case commonTransforms inpIds $ inputs ker' of+        (ot', inps')+          | all exposed inps' ->+              pure (ker' {fsSOAC = inps' `SOAC.setInputs` fsSOAC ker'}, ot')+        _ -> fail "Cannot expose"++    exposed (SOAC.Input ts _ _)+      | SOAC.nullTransforms ts = True+    exposed inp = SOAC.inputArray inp `notElem` inpIds++outputTransformPullers :: [SOAC -> SOAC.ArrayTransforms -> TryFusion (SOAC, SOAC.ArrayTransforms)]+outputTransformPullers = [pullRearrange, pullReshape]++pullOutputTransforms ::+  SOAC ->+  SOAC.ArrayTransforms ->+  TryFusion (SOAC, SOAC.ArrayTransforms)+pullOutputTransforms = attempt outputTransformPullers+  where+    attempt [] _ _ = fail "Cannot pull anything"+    attempt (p : ps) soac ots =+      do+        (soac', ots') <- p soac ots+        if SOAC.nullTransforms ots'+          then pure (soac', SOAC.noTransforms)+          else pullOutputTransforms soac' ots' <|> pure (soac', ots')+        <|> attempt ps soac ots
src/Futhark/Optimise/GenRedOpt.hs view
@@ -210,7 +210,7 @@     -- is a subexp invariant to a gid of a parallel dimension?     isSeInvar2 variance gid (Var x) =       let x_deps = M.findWithDefault mempty x variance-       in gid /= x && not (nameIn gid x_deps)+       in gid /= x && gid `notNameIn` x_deps     isSeInvar2 _ _ _ = True     -- is a DimIndex invar to a gid of a parallel dimension?     isDimIdxInvar2 variance gid (DimFix d) =@@ -224,7 +224,7 @@     isTileable :: VName -> [(VName, SubExp)] -> VarianceTable -> VName -> Stm GPU -> Bool     isTileable seq_gid gid_dims variance acc_nm (Let (Pat [pel]) _ (BasicOp (Index _ slc)))       | acc_deps <- M.findWithDefault mempty acc_nm variance,-        nameIn (patElemName pel) acc_deps =+        patElemName pel `nameIn` acc_deps =           let invar_par = isSliceInvar2 variance slc (map fst gid_dims)               invar_seq = isSliceInvar2 variance slc [seq_gid]            in invar_par || invar_seq@@ -261,7 +261,7 @@     transposeFV (tab, Let pat aux (BasicOp (Index arr slc)))       | dims <- unSlice slc,         all isFixDim dims,-        nameIn arr fvs,+        arr `nameIn` fvs,         iis <- L.findIndices depOnGid dims,         [ii] <- iis,         -- generalize below: treat any rearange and add to tab if not there.@@ -318,7 +318,7 @@   Maybe (VName, Int) isInvarToParDim branch_variant kspace variance acc_inds =   let ker_gids = map fst $ unSegSpace kspace-      branch_invariant = not $ any (`nameIn` branch_variant) ker_gids+      branch_invariant = all (`notNameIn` branch_variant) ker_gids       allvar2 = allvariant2 acc_inds ker_gids       last_invar_dim =         foldl (lastNotIn allvar2) Nothing $@@ -336,7 +336,7 @@     allvariant2 ind_ses kids =       namesFromList $ concatMap (`variant2` kids) ind_ses     lastNotIn allvar2 acc (kid, k) =-      if nameIn kid allvar2 then acc else Just (kid, k)+      if kid `nameIn` allvar2 then acc else Just (kid, k)  allGoodReturns :: [KernelResult] -> Maybe ([VName], [SubExp]) allGoodReturns kres@@ -405,7 +405,9 @@ costBody :: Body GPU -> Cost costBody bdy =   foldl addCosts (Small 0) $-    map costRedundantStmt $ stmsToList $ bodyStms bdy+    map costRedundantStmt $+      stmsToList $+        bodyStms bdy  costRedundantStmt :: Stm GPU -> Cost costRedundantStmt (Let _ _ (Op _)) = Big
src/Futhark/Optimise/HistAccs.hs view
@@ -75,9 +75,13 @@     vs <- forM arrs $ \arr -> do       arr_t <- lookupType arr       letSubExp (baseString arr <> "_elem") $-        BasicOp $ Index arr $ fullSlice arr_t $ map (DimFix . Var) gtids+        BasicOp $+          Index arr $+            fullSlice arr_t $+              map (DimFix . Var) gtids     letExp (baseString acc <> "_upd") $-      BasicOp $ UpdateAcc acc (map Var gtids) vs+      BasicOp $+        UpdateAcc acc (map Var gtids) vs    acc_t <- lookupType acc   pure . Op . SegOp . SegMap lvl space [acc_t] $
src/Futhark/Optimise/InPlaceLowering.hs view
@@ -148,7 +148,7 @@   -- XXX: unfortunate that we cannot handle duplicate update values.   -- Would be good to improve this.  See inplacelowering6.fut.   case nubByOrd (comparing updateValue)-    . filter (not . (`nameIn` bottomUpSeen bup) . updateSource) -- (9)+    . filter ((`notNameIn` bottomUpSeen bup) . updateSource) -- (9)     . filter ((`elem` boundHere) . updateValue)     $ forwardThese bup of     [] -> do@@ -213,7 +213,10 @@           stms <-             deepen $               optimiseStms (stmsToList (kernelBodyStms kbody)) $-                mapM_ seenVar $ namesToList $ freeIn $ kernelBodyResult kbody+                mapM_ seenVar $+                  namesToList $+                    freeIn $+                      kernelBodyResult kbody           pure kbody {kernelBodyStms = stmsFromList stms}     mapSegOpM mapper op 
src/Futhark/Optimise/InPlaceLowering/LowerIntoStm.hs view
@@ -58,7 +58,8 @@     pure $       prestms         ++ [ certify (stmAuxCerts aux) $-               mkLet pat' $ DoLoop merge' form body'+               mkLet pat' $+                 DoLoop merge' form body'            ]         ++ poststms lowerUpdate@@ -70,7 +71,9 @@          in Just . pure $               [ certify (stmAuxCerts aux <> cs) $                   mkLet [Ident bindee_nm $ typeOf bindee_dec] $-                    BasicOp $ Update Unsafe v is' $ Var val+                    BasicOp $+                      Update Unsafe v is' $+                        Var val               ] lowerUpdate _ _ _ =   Nothing@@ -87,8 +90,8 @@           (pat', kbody', poststms) <- mk           let cs = stmAuxCerts aux <> foldMap updateCerts updates           pure $-            certify cs (Let pat' aux $ Op $ SegOp $ SegMap lvl space ts kbody') :-            stmsToList poststms+            certify cs (Let pat' aux $ Op $ SegOp $ SegMap lvl space ts kbody')+              : stmsToList poststms     where       -- This check is a bit more conservative than ideal.  In a perfect       -- world, we would allow indexing a[i,j] if the update is also@@ -148,7 +151,8 @@             (slice', bodystms) <-               flip runBuilderT scope $                 traverse (toSubExp "index") $-                  fixSlice (fmap pe64 slice) $ map (pe64 . Var) gtids+                  fixSlice (fmap pe64 slice) $+                    map (pe64 . Var) gtids              let res_dims = take (length slice') $ arrayDims $ snd bindee_dec                 ret' = WriteReturns cs (Shape res_dims) src [(Slice $ map DimFix slice', se)]@@ -218,7 +222,7 @@    -- Safety condition (8).   forM_ (zip val $ bodyAliases body) $ \((p, _), als) ->-    guard $ not $ paramName p `nameIn` als+    guard $ paramName p `notNameIn` als    mk_in_place_map <- summariseLoop scope updates usedInBody resmap val @@ -252,12 +256,13 @@           let source_t = snd $ updateType update               elm_t = source_t `setArrayDims` sliceDims (updateIndices update)           tell-            ( [ mkLet [Ident source source_t] . BasicOp $-                  Update+            ( [ mkLet [Ident source source_t] . BasicOp+                  $ Update                     Unsafe                     (updateSource update)                     (fullSlice source_t $ unSlice $ updateIndices update)-                    $ snd $ mergeParam summary+                  $ snd+                  $ mergeParam summary               ],               [ mkLet [Ident precopy elm_t] . BasicOp $                   Index
src/Futhark/Optimise/InPlaceLowering/SubstituteIndices.hs view
@@ -68,7 +68,8 @@     [v'] <- patNames pat = do       src' <-         letExp (baseString v' <> "_subst") $-          BasicOp $ Rotate (replicate (arrayRank src_t - length rots) zero ++ rots) src+          BasicOp $+            Rotate (replicate (arrayRank src_t - length rots) zero ++ rots) src       src_t' <- lookupType src'       pure $ (v', (cs, src', src_t', is)) : substs   where@@ -99,7 +100,9 @@       v' <-         certifying cs $           letExp (baseString src <> "_op_idx") $-            BasicOp $ Index src $ fullSlice (typeOf src_dec) is+            BasicOp $+              Index src $+                fullSlice (typeOf src_dec) is       pure $ M.singleton v v'   pure $ Op $ substituteNames var_substs op substituteIndicesInExp substs e = do@@ -119,7 +122,9 @@                 row <-                   certifying cs2 $                     letExp (baseString v ++ "_row") $-                      BasicOp $ Index src2 $ fullSlice (typeOf src2dec) (unSlice is2)+                      BasicOp $+                        Index src2 $+                          fullSlice (typeOf src2dec) (unSlice is2)                 row_copy <-                   letExp (baseString v ++ "_row_copy") $ BasicOp $ Copy row                 pure $@@ -157,11 +162,16 @@ substituteIndicesInVar substs v   | Just (cs2, src2, _, Slice []) <- lookup v substs =       certifying cs2 $-        letExp (baseString src2) $ BasicOp $ SubExp $ Var src2+        letExp (baseString src2) $+          BasicOp $+            SubExp $+              Var src2   | Just (cs2, src2, src2_dec, Slice is2) <- lookup v substs =       certifying cs2 $         letExp (baseString src2 <> "_v_idx") $-          BasicOp $ Index src2 $ fullSlice (typeOf src2_dec) is2+          BasicOp $+            Index src2 $+              fullSlice (typeOf src2_dec) is2   | otherwise =       pure v @@ -173,10 +183,12 @@ substituteIndicesInBody substs (Body _ stms res) = do   (substs', stms') <-     inScopeOf stms $-      collectStms $ substituteIndicesInStms substs stms+      collectStms $+        substituteIndicesInStms substs stms   (res', res_stms) <-     inScopeOf stms' $-      collectStms $ mapM (onSubExpRes substs') res+      collectStms $+        mapM (onSubExpRes substs') res   mkBodyM (stms' <> res_stms) res'   where     onSubExpRes substs' (SubExpRes cs se) =
src/Futhark/Optimise/InliningDeadFun.hs view
@@ -59,10 +59,12 @@   Prog SOACS ->   m (Prog SOACS) inlineFunctions simplify_rate cg what_should_be_inlined prog = do-  let Prog consts funs = prog+  let consts = progConsts prog+      funs = progFuns prog       vtable = ST.fromScope (addScopeWisdom (scopeOf consts)) -  uncurry Prog <$> recurse (1, vtable) (consts, funs) what_should_be_inlined+  (consts', funs') <- recurse (1, vtable) (consts, funs) what_should_be_inlined+  pure $ prog {progConsts = consts', progFuns = funs'}   where     fdmap fds = M.fromList $ zip (map funDefName fds) fds @@ -112,8 +114,10 @@ inlineBecauseTiny = foldMap onFunDef . progFuns   where     onFunDef fd-      | length (bodyStms (funDefBody fd)) < 2-          || "inline" `inAttrs` funDefAttrs fd =+      | length (bodyStms (funDefBody fd))+          < 2+          || "inline"+          `inAttrs` funDefAttrs fd =           S.singleton (funDefName fd)       | otherwise = mempty @@ -164,7 +168,8 @@      body_stms =       addLocations (stmAuxAttrs aux) safety (filter notmempty (loc : locs)) $-        bodyStms $ funDefBody fun+        bodyStms $+          funDefBody fun      -- Note that the sizes of arrays may not be correct at this     -- point - it is crucial that we run copy propagation before
src/Futhark/Optimise/ReduceDeviceSyncs.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+ -- | This module implements an optimization that migrates host -- statements into 'GPUBody' kernels to reduce the number of -- host-device synchronizations that occur when a scalar variable is@@ -8,10 +10,9 @@ module Futhark.Optimise.ReduceDeviceSyncs (reduceDeviceSyncs) where  import Control.Monad-import Control.Monad.Trans.Class-import qualified Control.Monad.Trans.Reader as R-import Control.Monad.Trans.State.Strict hiding (State)-import Control.Parallel.Strategies (parMap, rpar)+import Control.Monad.Reader+import Control.Monad.State hiding (State)+import Data.Bifunctor (second) import Data.Foldable import qualified Data.IntMap.Strict as IM import Data.List (unzip4, zip4)@@ -20,9 +21,8 @@ import qualified Data.Text as T import Futhark.Construct (fullSlice, sliceDim) import Futhark.Error-import qualified Futhark.FreshNames as FN import Futhark.IR.GPU-import Futhark.MonadFreshNames (VNameSource, getNameSource, putNameSource)+import Futhark.MonadFreshNames import Futhark.Optimise.ReduceDeviceSyncs.MigrationTable import Futhark.Pass import Futhark.Transform.Substitute@@ -34,28 +34,23 @@   Pass     "reduce device synchronizations"     "Move host statements to device to reduce blocking memory operations."-    run+    $ \prog -> do+      let hof = hostOnlyFunDefs $ progFuns prog+          consts_mt = analyseConsts hof (progFuns prog) (progConsts prog)+      consts <- onConsts consts_mt $ progConsts prog+      funs <- parPass (onFun hof consts_mt) (progFuns prog)+      pure $ prog {progConsts = consts, progFuns = funs}   where-    run prog = do-      ns <- getNameSource-      let mt = analyseProg prog-      let st = initialState ns-      let (prog', st') = R.runReader (runStateT (optimizeProgram prog) st) mt-      putNameSource (stateNameSource st')-      pure prog'+    onConsts consts_mt stms =+      runReduceM consts_mt (optimizeStms stms)+    onFun hof consts_mt fd = do+      let mt = consts_mt <> analyseFunDef hof fd+      runReduceM mt (optimizeFunDef fd)  -------------------------------------------------------------------------------- --                            AD HOC OPTIMIZATION                             -- -------------------------------------------------------------------------------- --- | Optimize a whole program. The type signatures of top-level functions will--- remain unchanged.-optimizeProgram :: Prog GPU -> ReduceM (Prog GPU)-optimizeProgram (Prog consts funs) = do-  consts' <- optimizeStms consts-  funs' <- sequence $ parMap rpar optimizeFunDef funs-  pure (Prog consts' funs')- -- | Optimize a function definition. Its type signature will remain unchanged. optimizeFunDef :: FunDef GPU -> ReduceM (FunDef GPU) optimizeFunDef fd = do@@ -372,8 +367,23 @@ --------------------------------------------------------------------------------  -- | The monad used to perform migration-based synchronization reductions.-type ReduceM = StateT State (R.Reader MigrationTable)+newtype ReduceM a = ReduceM (StateT State (Reader MigrationTable) a)+  deriving+    ( Functor,+      Applicative,+      Monad,+      MonadState State,+      MonadReader MigrationTable+    ) +runReduceM :: MonadFreshNames m => MigrationTable -> ReduceM a -> m a+runReduceM mt (ReduceM m) = modifyNameSource $ \src ->+  second stateNameSource (runReader (runStateT m (initialState src)) mt)++instance MonadFreshNames ReduceM where+  getNameSource = gets stateNameSource+  putNameSource src = modify $ \s -> s {stateNameSource = src}+ -- | The state used by a 'ReduceM' monad. data State = State   { -- | A source to generate new 'VName's from.@@ -403,14 +413,6 @@       stateGPUBodyOk = True     } --- | Retrieve a function of the current environment.-asks :: (MigrationTable -> a) -> ReduceM a-asks = lift . R.asks---- | Fetch the value of the environment.-ask :: ReduceM MigrationTable-ask = lift R.ask- -- | Perform non-migration optimizations without introducing any GPUBody -- kernels. noGPUBody :: ReduceM a -> ReduceM a@@ -421,15 +423,6 @@   modify $ \st -> st {stateGPUBodyOk = prev}   pure res --- | Produce a fresh name, using the given name as a template.-newName :: VName -> ReduceM VName-newName n = do-  st <- get-  let ns = stateNameSource st-  let (n', ns') = FN.newName ns n-  put (st {stateNameSource = ns'})-  pure n'- -- | Create a 'PatElem' that binds the array of a migrated variable binding. arrayizePatElem :: PatElem Type -> ReduceM (PatElem Type) arrayizePatElem (PatElem n t) = do@@ -474,7 +467,7 @@ -- provided statements and be returned. useScalar :: Stms GPU -> VName -> ReduceM (Stms GPU, VName) useScalar stms n = do-  entry <- IM.lookup (baseTag n) <$> gets stateMigrated+  entry <- gets $ IM.lookup (baseTag n) . stateMigrated   case entry of     Nothing ->       pure (stms, n)@@ -499,7 +492,7 @@ storedScalar :: SubExp -> ReduceM (Maybe VName) storedScalar (Constant _) = pure Nothing storedScalar (Var n) = do-  entry <- IM.lookup (baseTag n) <$> gets stateMigrated+  entry <- gets $ IM.lookup (baseTag n) . stateMigrated   pure $ fmap (\(_, _, arr, _) -> arr) entry  -- | @storeScalar stms se t@ returns a variable that binds a single element@@ -510,7 +503,7 @@ storeScalar :: Stms GPU -> SubExp -> Type -> ReduceM (Stms GPU, VName) storeScalar stms se t = do   entry <- case se of-    Var n -> IM.lookup (baseTag n) <$> gets stateMigrated+    Var n -> gets $ IM.lookup (baseTag n) . stateMigrated     _ -> pure Nothing   case entry of     Just (_, _, arr, _) -> pure (stms, arr)@@ -553,7 +546,7 @@ -- host, the name of a single element array containing its value. resolveName :: VName -> ReduceM VName resolveName n = do-  entry <- IM.lookup (baseTag n) <$> gets stateMigrated+  entry <- gets $ IM.lookup (baseTag n) . stateMigrated   case entry of     Nothing -> pure n     Just (_, _, _, True) -> pure n
src/Futhark/Optimise/ReduceDeviceSyncs/MigrationTable.hs view
@@ -32,7 +32,9 @@ -- Børgesen (2022). module Futhark.Optimise.ReduceDeviceSyncs.MigrationTable   ( -- * Analysis-    analyseProg,+    analyseFunDef,+    analyseConsts,+    hostOnlyFunDefs,      -- * Types     MigrationTable,@@ -56,7 +58,6 @@ import qualified Control.Monad.Trans.Reader as R import Control.Monad.Trans.State.Strict () import Control.Monad.Trans.State.Strict hiding (State)-import Control.Parallel.Strategies (parMap, rpar) import Data.Bifunctor (first, second) import Data.Foldable import qualified Data.IntMap.Strict as IM@@ -104,6 +105,9 @@ --         all such statements have been moved. newtype MigrationTable = MigrationTable (IM.IntMap MigrationStatus) +instance Semigroup MigrationTable where+  MigrationTable a <> MigrationTable b = MigrationTable (a `IM.union` b)+ -- | Where should the value bound by this name be computed? statusOf :: VName -> MigrationTable -> MigrationStatus statusOf n (MigrationTable mt) =@@ -141,10 +145,6 @@ usedOnHost :: VName -> MigrationTable -> Bool usedOnHost n mt = statusOf n mt /= MoveToDevice --- | Merges two migration tables that are assumed to be disjoint.-merge :: MigrationTable -> MigrationTable -> MigrationTable-merge (MigrationTable a) (MigrationTable b) = MigrationTable (a `IM.union` b)- -------------------------------------------------------------------------------- --                         HOST-ONLY FUNCTION ANALYSIS                        -- --------------------------------------------------------------------------------@@ -232,15 +232,6 @@  nameToId :: VName -> Id nameToId = baseTag---- | Analyses a program to return a migration table that covers all its--- statements and variables.-analyseProg :: Prog GPU -> MigrationTable-analyseProg (Prog consts funs) =-  let hof = hostOnlyFunDefs funs-      mt = analyseConsts hof funs consts-      mts = parMap rpar (analyseFunDef hof) funs-   in foldl' merge mt mts  -- | Analyses top-level constants. analyseConsts :: HostOnlyFuns -> [FunDef GPU] -> Stms GPU -> MigrationTable
src/Futhark/Optimise/Simplify.hs view
@@ -39,7 +39,9 @@   Engine.HoistBlockers rep ->   Prog rep ->   PassM (Prog rep)-simplifyProg simpl rules blockers (Prog consts funs) = do+simplifyProg simpl rules blockers prog = do+  let consts = progConsts prog+      funs = progFuns prog   (consts_vtable, consts') <-     simplifyConsts (UT.usages $ foldMap freeIn funs) (mempty, informStms consts) @@ -51,7 +53,11 @@    (_, consts'') <- simplifyConsts funs_uses (mempty, consts') -  pure $ Prog (fmap removeStmWisdom consts'') (fmap removeFunDefWisdom funs')+  pure $+    prog+      { progConsts = fmap removeStmWisdom consts'',+        progFuns = fmap removeFunDefWisdom funs'+      }   where     simplifyFun' consts_vtable =       simplifySomething
src/Futhark/Optimise/Simplify/Engine.hs view
@@ -320,7 +320,8 @@           | otherwise -> pure $ constant True -- infinite loop         ForLoop _ it bound _ ->           letSubExp "loop_nonempty" $-            BasicOp $ CmpOp (CmpSlt it) (intConst it 0) bound+            BasicOp $+              CmpOp (CmpSlt it) (intConst it 0) bound  protectIf ::   MonadBuilder m =>@@ -332,7 +333,8 @@ protectIf _ _ taken (Let pat aux (If cond taken_body untaken_body (IfDec if_ts IfFallback))) = do   cond' <- letSubExp "protect_cond_conj" $ BasicOp $ BinOp LogAnd taken cond   auxing aux . letBind pat $-    If cond' taken_body untaken_body $ IfDec if_ts IfFallback+    If cond' taken_body untaken_body $+      IfDec if_ts IfFallback protectIf _ _ taken (Let pat aux (BasicOp (Assert cond msg loc))) = do   not_taken <- letSubExp "loop_not_taken" $ BasicOp $ UnOp Not taken   cond' <- letSubExp "protect_assert_disj" $ BasicOp $ BinOp LogOr not_taken cond@@ -351,7 +353,8 @@             eBody $ map (emptyOfType $ patNames pat) (patTypes pat)           if_ts <- expTypesFromPat pat           auxing aux . letBind pat $-            If taken taken_body untaken_body $ IfDec if_ts IfFallback+            If taken taken_body untaken_body $+              IfDec if_ts IfFallback protectIf _ _ _ stm =   addStm stm @@ -386,7 +389,7 @@   let dims = map zeroIfContext $ shapeDims shape   pure $ BasicOp $ Scratch et dims   where-    zeroIfContext (Var v) | v `elem` ctx_names = intConst Int32 0+    zeroIfContext (Var v) | v `elem` ctx_names = intConst Int64 0     zeroIfContext se = se  -- | Statements that are not worth hoisting out of loops, because they@@ -529,13 +532,13 @@   UT.UsageTable ->   Stm rep ->   UT.UsageTable-expandUsage usageInStm vtable utable stm@(Let pat _ e) =+expandUsage usageInStm vtable utable stm@(Let pat aux e) =   stmUsages <> utable   where     stmUsages =       UT.expand (`ST.lookupAliases` vtable) (usageInStm stm <> usageThroughAliases)         <> ( if any (`UT.isSize` utable) (patNames pat)-               then UT.sizeUsages (freeIn e)+               then UT.sizeUsages (freeIn (stmAuxCerts aux) <> freeIn e)                else mempty            )     usageThroughAliases =@@ -544,7 +547,8 @@     usageThroughBindeeAliases (name, aliases) = do       uses <- UT.lookup name utable       pure . mconcat $-        map (`UT.usage` (uses `UT.withoutU` UT.presentU)) $ namesToList aliases+        map (`UT.usage` (uses `UT.withoutU` UT.presentU)) $+          namesToList aliases  type BlockPred rep = ST.SymbolTable rep -> UT.UsageTable -> Stm rep -> Bool @@ -613,8 +617,10 @@ cheapExp (BasicOp UnOp {}) = True cheapExp (BasicOp CmpOp {}) = True cheapExp (BasicOp ConvOp {}) = True+cheapExp (BasicOp Assert {}) = True cheapExp (BasicOp Copy {}) = False cheapExp (BasicOp Replicate {}) = False+cheapExp (BasicOp Concat {}) = False cheapExp (BasicOp Manifest {}) = False cheapExp DoLoop {} = False cheapExp (If _ tbranch fbranch _) =@@ -624,9 +630,6 @@ cheapExp _ = True -- Used to be False, but -- let's try it out. -stmIs :: (Stm rep -> Bool) -> BlockPred rep-stmIs f _ _ = f- loopInvariantStm :: ASTRep rep => ST.SymbolTable rep -> Stm rep -> Bool loopInvariantStm vtable =   all (`nameIn` ST.availableAtClosestLoop vtable) . namesToList . freeIn@@ -660,7 +663,7 @@       cond_loop_invariant =         all (`nameIn` ST.availableAtClosestLoop vtable) $ namesToList $ freeIn cond -      desirableToHoist stm =+      desirableToHoist usage stm =         is_alloc_fun stm           || ( ST.loopDepth vtable > 0                  && cond_loop_invariant@@ -670,6 +673,11 @@                  -- asymptotics of the program.                  && all primType (patTypes (stmPat stm))              )+          || ( ifsort /= IfFallback+                 && any (`UT.isSize` usage) (patNames (stmPat stm))+                 && all primType (patTypes (stmPat stm))+             )+      notDesirableToHoist _ usage stm = not $ desirableToHoist usage stm        -- No matter what, we always want to hoist constants as much as       -- possible.@@ -682,9 +690,6 @@       isNotHoistableBnd _ _ (Let _ _ (BasicOp (Index _ slice))) =         null $ sliceDims slice       ---      isNotHoistableBnd _ usage (Let pat _ _)-        | any (`UT.isSize` usage) $ patNames pat =-            False       isNotHoistableBnd _ _ stm         | is_alloc_fun stm = False       isNotHoistableBnd _ _ _ =@@ -694,7 +699,7 @@       block =         branch_blocker           `orIf` ( (isNotSafe `orIf` isNotCheap `orIf` isNotHoistableBnd)-                     `andAlso` stmIs (not . desirableToHoist)+                     `andAlso` notDesirableToHoist                  )           `orIf` isConsuming @@ -830,21 +835,22 @@         )   seq_blocker <- asksEngineEnv $ blockHoistSeq . envHoistBlockers   (loopres, loopstms, hoisted) <--    enterLoop . consumeMerge $-      bindMerge (zipWith withRes merge' (bodyResult loopbody)) . wrapbody $-        blockIf-          ( hasFree boundnames `orIf` isConsumed-              `orIf` seq_blocker-              `orIf` notWorthHoisting-          )-          (bodyStms loopbody)-          $ do-            let params_usages =-                  map-                    (\p -> if unique (paramDeclType p) then UT.consumedU else mempty)-                    params'-            (res, uses) <- simplifyResult params_usages $ bodyResult loopbody-            pure (res, uses <> isDoLoopResult res)+    enterLoop . consumeMerge+      $ bindMerge (zipWith withRes merge' (bodyResult loopbody)) . wrapbody+      $ blockIf+        ( hasFree boundnames+            `orIf` isConsumed+            `orIf` seq_blocker+            `orIf` notWorthHoisting+        )+        (bodyStms loopbody)+      $ do+        let params_usages =+              map+                (\p -> if unique (paramDeclType p) then UT.consumedU else mempty)+                params'+        (res, uses) <- simplifyResult params_usages $ bodyResult loopbody+        pure (res, uses <> isDoLoopResult res)   loopbody' <- constructBody loopstms loopres   pure (DoLoop merge' form' loopbody', hoisted)   where
src/Futhark/Optimise/Simplify/Rules.hs view
@@ -72,7 +72,8 @@     -- simplifier applies bottom-up rules in a kind of deepest-first     -- order.     not (patElemName d `UT.isInResult` used)-      || patElemName d `UT.isConsumed` used+      || patElemName d+      `UT.isConsumed` used       -- Always OK to remove the copy if 'v' has no aliases and is never       -- used again.       || (v_is_fresh && v_not_used_again),@@ -104,7 +105,10 @@       Simplify $         certifying cs $           attributing attrs $-            letBind pat $ BasicOp $ SubExp $ Constant result+            letBind pat $+              BasicOp $+                SubExp $+                  Constant result   where     isConst (Constant v) = Just v     isConst _ = Nothing@@ -117,10 +121,14 @@       attributing attrs $ case res of         SubExpResult cs' se ->           certifying (cs <> cs') $-            letBindNames (patNames pat) $ BasicOp $ SubExp se+            letBindNames (patNames pat) $+              BasicOp $+                SubExp se         IndexResult extra_cs idd' inds' ->           certifying (cs <> extra_cs) $-            letBindNames (patNames pat) $ BasicOp $ Index idd' inds'+            letBindNames (patNames pat) $+              BasicOp $+                Index idd' inds'   where     consumed = patElemName pe `UT.isConsumed` used     seType (Var v) = ST.lookupType v vtable@@ -193,7 +201,9 @@       if oneIshInt t && zeroIshInt f && tcs == mempty && fcs == mempty         then           Simplify $-            letBind pat $ BasicOp $ ConvOp (BToI (intValueType t)) cond+            letBind pat $+              BasicOp $+                ConvOp (BToI (intValueType t)) cond         else           if zeroIshInt t && oneIshInt f             then Simplify $ do@@ -219,7 +229,9 @@     matches x y || matches y x =       Simplify $         certifying (stmAuxCerts aux <> xcs <> ycs) $-          letBind (Pat [pe]) $ BasicOp $ SubExp y+          letBind (Pat [pe]) $+            BasicOp $+              SubExp y   where     z = patElemName pe     matches (Var x) y@@ -256,13 +268,16 @@       namesFromList . concatMap (patNames . stmPat) $         bodyStms tb <> bodyStms fb     invariant Constant {} = True-    invariant (Var v) = not $ v `nameIn` bound_in_branches+    invariant (Var v) = v `notNameIn` bound_in_branches      branchInvariant (i, pe, t, (tse, fse))       -- Do both branches return the same value?       | tse == fse = do           certifying (resCerts tse <> resCerts fse) $-            letBindNames [patElemName pe] $ BasicOp $ SubExp $ resSubExp tse+            letBindNames [patElemName pe] $+              BasicOp $+                SubExp $+                  resSubExp tse           hoisted i pe        -- Do both branches return values that are free in the@@ -274,7 +289,8 @@         Prim _ <- patElemType pe = do           bt <- expTypesFromPat $ Pat [pe]           letBindNames [patElemName pe]-            =<< ( If cond <$> resultBodyM [resSubExp tse]+            =<< ( If cond+                    <$> resultBodyM [resSubExp tse]                     <*> resultBodyM [resSubExp fse]                     <*> pure (IfDec bt ifsort)                 )@@ -305,7 +321,7 @@ removeDeadBranchResult :: BuilderOps rep => BottomUpRuleIf rep removeDeadBranchResult (_, used) pat _ (e1, tb, fb, IfDec rettype ifsort)   | -- Only if there is no existential binding...-    not $ any (`nameIn` foldMap freeIn (patElems pat)) (patNames pat),+    all (`notNameIn` foldMap freeIn (patElems pat)) (patNames pat),     -- Figure out which of the names in 'pat' are used...     patused <- map (`UT.isUsedDirectly` used) $ patNames pat,     -- If they are not all used, then this rule applies.@@ -357,7 +373,8 @@    lam' <-     mkLambda (cert_params' ++ acc_params') $-      bodyBind $ (lambdaBody lam) {bodyResult = acc_res' <> nonacc_res'}+      bodyBind $+        (lambdaBody lam) {bodyResult = acc_res' <> nonacc_res'}    letBind (Pat (concat acc_pes' <> nonacc_pes')) $ WithAcc inputs' lam'   where@@ -420,10 +437,10 @@        -- Eliminate unused accumulator results       let get_rid_of =-            map snd . filter getRidOf $-              zip+            map snd . filter getRidOf+              $ zip                 (chunks (map inputArrs inputs) acc_pes)-                $ map paramName cert_params+              $ map paramName cert_params        -- Eliminate unused non-accumulator results       let (nonacc_pes', nonacc_res') =
src/Futhark/Optimise/Simplify/Rules/BasicOp.hs view
@@ -21,7 +21,6 @@ import Futhark.Optimise.Simplify.Rule import Futhark.Optimise.Simplify.Rules.Loop import Futhark.Optimise.Simplify.Rules.Simple-import Futhark.Util  isCt1 :: SubExp -> Bool isCt1 (Constant v) = oneIsh v@@ -89,7 +88,9 @@     Just (xs', xs_cs) <- unzip <$> mapM (transposedBy perm) xs = Simplify $ do       concat_rearrange <-         certifying (x_cs <> mconcat xs_cs) $-          letExp "concat_rearrange" $ BasicOp $ Concat 0 (x' :| xs') new_d+          letExp "concat_rearrange" $+            BasicOp $+              Concat 0 (x' :| xs') new_d       letBind pat $ BasicOp $ Rearrange perm concat_rearrange   where     transposedBy perm1 v =@@ -103,7 +104,10 @@ simplifyConcat _ pat aux (Concat _ (x :| []) _) =   Simplify $     -- Still need a copy because Concat produces a fresh array.-    auxing aux $ letBind pat $ BasicOp $ Copy x+    auxing aux $+      letBind pat $+        BasicOp $+          Copy x -- concat xs (concat ys zs) == concat xs ys zs simplifyConcat (vtable, _) pat (StmAux cs attrs _) (Concat i (x :| xs) new_d)   | x' /= x || concat xs' /= xs =@@ -111,7 +115,8 @@         certifying (cs <> x_cs <> mconcat xs_cs) $           attributing attrs $             letBind pat $-              BasicOp $ Concat i (x' :| zs ++ concat xs') new_d+              BasicOp $+                Concat i (x' :| zs ++ concat xs') new_d   where     (x' : zs, x_cs) = isConcat x     (xs', xs_cs) = unzip $ map isConcat xs@@ -128,7 +133,8 @@       forSingleArray $         reverse $           foldl' fuseConcatArg mempty $-            map (toConcatArg vtable) $ x : xs,+            map (toConcatArg vtable) $+              x : xs,     length xs /= length ys =       Simplify $ do         elem_type <- lookupType x@@ -164,7 +170,9 @@       Simplify $ do         e' <- toSubExp "update_elem" e         auxing aux . certifying cs $-          letBind pat $ BasicOp $ Update safety src (Slice [DimFix i]) e'+          letBind pat $+            BasicOp $+              Update safety src (Slice [DimFix i]) e' ruleBasicOp vtable pat _ (Update _ dest destis (Var v))   | Just (e, _) <- ST.lookupExp v vtable,     arrayFrom e =@@ -189,7 +197,8 @@         Var v | not $ null $ sliceDims is -> do           v_reshaped <-             letExp (baseString v ++ "_reshaped") $-              BasicOp $ Reshape (map DimNew $ arrayDims dest_t) v+              BasicOp $+                Reshape (map DimNew $ arrayDims dest_t) v           letBind pat $ BasicOp $ Copy v_reshaped         _ -> letBind pat $ BasicOp $ ArrayLit [se] $ rowType dest_t ruleBasicOp vtable pat (StmAux cs1 attrs _) (Update safety1 dest1 is1 (Var v1))@@ -224,7 +233,8 @@           not_p_and_eq_x_z <-             letSubExp "p_and_eq_x_y" $ BasicOp $ BinOp LogAnd not_p eq_x_z           letBind pat $-            BasicOp $ BinOp LogOr p_and_eq_x_y not_p_and_eq_x_z+            BasicOp $+              BinOp LogOr p_and_eq_x_y not_p_and_eq_x_z     simplifyWith _ _ =       Nothing @@ -261,7 +271,9 @@           Just _ ->             certifying idd_cs $               auxing aux $-                letBind pat $ BasicOp $ Index idd2 slice+                letBind pat $+                  BasicOp $+                    Index idd2 slice           Nothing -> do             -- Linearise indices and map to old index space.             oldshape <- arrayDims <$> lookupType idd2@@ -273,13 +285,19 @@             new_inds' <-               mapM (toSubExp "new_index") new_inds             certifying idd_cs . auxing aux $-              letBind pat $ BasicOp $ Index idd2 $ Slice $ map DimFix new_inds'+              letBind pat $+                BasicOp $+                  Index idd2 $+                    Slice $+                      map DimFix new_inds'  -- Copying an iota is pointless; just make it an iota instead. ruleBasicOp vtable pat aux (Copy v)   | Just (Iota n x s it, v_cs) <- ST.lookupBasicOp v vtable =       Simplify . certifying v_cs . auxing aux $-        letBind pat $ BasicOp $ Iota n x s it+        letBind pat $+          BasicOp $+            Iota n x s it -- Handle identity permutation. ruleBasicOp _ pat _ (Rearrange perm v)   | sort perm == perm =@@ -288,7 +306,9 @@   | Just (BasicOp (Rearrange perm2 e), v_cs) <- ST.lookupExp v vtable =       -- Rearranging a rearranging: compose the permutations.       Simplify . certifying v_cs . auxing aux $-        letBind pat $ BasicOp $ Rearrange (perm `rearrangeCompose` perm2) e+        letBind pat $+          BasicOp $+            Rearrange (perm `rearrangeCompose` perm2) e ruleBasicOp vtable pat aux (Rearrange perm v)   | Just (BasicOp (Rotate offsets v2), v_cs) <- ST.lookupExp v vtable,     Just (BasicOp (Rearrange perm3 v3), v2_cs) <- ST.lookupExp v2 vtable = Simplify $ do@@ -296,7 +316,9 @@       rearrange_rotate <- letExp "rearrange_rotate" $ BasicOp $ Rotate offsets' v3       certifying (v_cs <> v2_cs) $         auxing aux $-          letBind pat $ BasicOp $ Rearrange (perm `rearrangeCompose` perm3) rearrange_rotate+          letBind pat $+            BasicOp $+              Rearrange (perm `rearrangeCompose` perm3) rearrange_rotate  -- Rearranging a replicate where the outer dimension is left untouched. ruleBasicOp vtable pat aux (Rearrange perm v1)@@ -310,7 +332,8 @@           auxing aux $ do             v <-               letSubExp "rearrange_replicate" $-                BasicOp $ Rearrange (map (subtract num_dims) rest_perm) v2+                BasicOp $+                  Rearrange (map (subtract num_dims) rest_perm) v2             letBind pat $ BasicOp $ Replicate dims v  -- A zero-rotation is identity.@@ -325,7 +348,9 @@       rotate_rearrange <-         auxing aux $ letExp "rotate_rearrange" $ BasicOp $ Rearrange perm v3       certifying (v_cs <> v2_cs) $-        letBind pat $ BasicOp $ Rotate offsets' rotate_rearrange+        letBind pat $+          BasicOp $+            Rotate offsets' rotate_rearrange  -- Combining Rotates. ruleBasicOp vtable pat aux (Rotate offsets1 v)@@ -333,28 +358,12 @@       offsets <- zipWithM add offsets1 offsets2       certifying v_cs $         auxing aux $-          letBind pat $ BasicOp $ Rotate offsets v2+          letBind pat $+            BasicOp $+              Rotate offsets v2   where     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--- Update with a slice of that array.  This matters when the arrays--- are far away (on the GPU, say), because it avoids a copy of the--- scalar to and from the host.-ruleBasicOp vtable pat aux (Update safety arr_x (Slice slice_x) (Var v))-  | Just _ <- sliceIndices (Slice slice_x),-    Just (Index arr_y (Slice slice_y), cs_y) <- ST.lookupBasicOp v vtable,-    ST.available arr_y vtable,-    not $ ST.aliases arr_x arr_y vtable,-    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 $ slice_x_bef ++ [DimSlice i (intConst Int64 1) (intConst Int64 1)]-          slice_y' = Slice $ 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 $-        letBind pat $ BasicOp $ Update safety arr_x slice_x' $ Var v'- -- 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 (Int64Value 0)) <- x,@@ -381,7 +390,10 @@     cs' <- filter (`notElem` v_cs) cs,     cs' /= cs =       Simplify . certifying (Certs cs') $-        letBind pat $ BasicOp $ SubExp $ Var v+        letBind pat $+          BasicOp $+            SubExp $+              Var v -- Remove UpdateAccs that contribute the neutral value, which is -- always a no-op. ruleBasicOp vtable pat aux (UpdateAcc acc _ vs)@@ -396,7 +408,9 @@   | Just (Copy v2, cs) <- ST.lookupBasicOp v1 vtable,     ST.available v2 vtable =       Simplify . auxing aux . certifying cs $-        letBind pat $ BasicOp $ Manifest perm v2+        letBind pat $+          BasicOp $+            Manifest perm v2 ruleBasicOp _ _ _ _ =   Skip 
src/Futhark/Optimise/Simplify/Rules/ClosedForm.hs view
@@ -65,7 +65,8 @@       accs   isEmpty <- newVName "fold_input_is_empty"   letBindNames [isEmpty] $-    BasicOp $ CmpOp (CmpEq int64) inputsize (intConst Int64 0)+    BasicOp $+      CmpOp (CmpEq int64) inputsize (intConst Int64 0)   letBind pat     =<< ( If (Var isEmpty)             <$> resultBodyM accs@@ -103,7 +104,8 @@       mergeexp   isEmpty <- newVName "bound_is_zero"   letBindNames [isEmpty] $-    BasicOp $ CmpOp (CmpSlt it) bound (intConst it 0)+    BasicOp $+      CmpOp (CmpSlt it) bound (intConst it 0)    letBind pat     =<< ( If (Var isEmpty)@@ -183,7 +185,8 @@     properFloatSize t =       Just $         letSubExp "converted_size" $-          BasicOp $ ConvOp (SIToFP it t) size+          BasicOp $+            ConvOp (SIToFP it t) size  determineKnownBindings ::   VarLookup rep ->
src/Futhark/Optimise/Simplify/Rules/Index.hs view
@@ -88,10 +88,12 @@                   `add` primExpFromSubExp (IntType to_it) i_offset'             i_stride'' <-               letSubExp "iota_offset" $-                BasicOp $ BinOp (Mul Int64 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+                BasicOp $+                  Iota i_n i_offset'' i_stride'' to_it      -- A rotate cannot be simplified away if we are slicing a rotated dimension.     Just (Rotate offsets a, cs)@@ -195,7 +197,8 @@                 (thisres, thisstms) <- collectStms $ do                   i' <- letSubExp "index_concat_i" $ BasicOp $ BinOp (Sub Int64 OverflowWrap) i start                   letSubExp "index_concat" . BasicOp . Index x' $-                    Slice $ ibef ++ DimFix i' : iaft+                    Slice $+                      ibef ++ DimFix i' : iaft                 thisbody <- mkBodyM thisstms [subExpRes thisres]                 (altres, altstms) <- collectStms $ mkBranch xs_and_starts'                 altbody <- mkBodyM altstms [subExpRes altres]
src/Futhark/Optimise/Simplify/Rules/Loop.hs view
@@ -37,13 +37,16 @@            resIsNecessary ((v, _), _) =             usedAfterLoop v-              || paramName v `nameIn` necessaryForReturned+              || paramName v+              `nameIn` necessaryForReturned               || referencedInPat v               || referencedInForm v            (keep_valpart, discard_valpart) =             partition (resIsNecessary . snd) $-              zip (patElems pat) $ zip merge $ bodyResult body+              zip (patElems pat) $+                zip merge $+                  bodyResult body            (keep_valpatelems, keep_val) = unzip keep_valpart           (_discard_valpatelems, discard_val) = unzip discard_valpart@@ -119,7 +122,7 @@       (invariant, explpat', merge', resExps)         | isInvariant,           -- Also do not remove the condition in a while-loop.-          not $ paramName mergeParam `nameIn` freeIn form =+          paramName mergeParam `notNameIn` freeIn form =             let (stm, explpat'') =                   removeFromResult (mergeParam, mergeInit) explpat'              in ( maybe id (:) stm $ (paramIdent mergeParam, mergeInit) : invariant,@@ -163,8 +166,8 @@         namesToList $           freeIn mergeParam `namesSubtract` oneName (paramName mergeParam)     invariantOrNotMergeParam namesOfInvariant name =-      not (name `nameIn` namesOfMergeParams)-        || name `nameIn` namesOfInvariant+      (name `notNameIn` namesOfMergeParams)+        || (name `nameIn` namesOfInvariant)  simplifyClosedFormLoop :: BuilderOps rep => TopDownRuleDoLoop rep simplifyClosedFormLoop _ pat _ (val, ForLoop i it bound [], body) =@@ -216,7 +219,7 @@           | not $ any ((i `nameIn`) . freeIn) x_stms,             DimFix (Var j) : slice' <- slice,             j == i,-            not $ i `nameIn` freeIn slice -> do+            i `notNameIn` freeIn slice -> do               addStms x_stms               w <- arraySize 0 <$> lookupType arr'               for_in_partial <-
src/Futhark/Optimise/Simplify/Rules/Simple.hs view
@@ -10,8 +10,10 @@  import Control.Monad import Data.List (isSuffixOf)+import qualified Data.List.NonEmpty as NE import Futhark.Analysis.PrimExp.Convert import Futhark.IR+import Futhark.Util (focusNth)  -- | A function that, given a variable name, returns its definition. type VarLookup rep = VName -> Maybe (Exp rep, Certs)@@ -300,6 +302,17 @@       Just (Iota n offset stride it, v_cs) simplifyReshapeIota _ _ _ = Nothing +simplifyReshapeConcat :: SimpleRule rep+simplifyReshapeConcat defOf seType (Reshape newshape v) = do+  (BasicOp (Concat d arrs _), v_cs) <- defOf v+  (bef, w', aft) <- focusNth d =<< shapeCoercion newshape+  (arr_bef, _, arr_aft) <-+    focusNth d <=< fmap arrayDims $ seType $ Var $ NE.head arrs+  guard $ arr_bef == bef+  guard $ arr_aft == aft+  Just (Concat d arrs w', v_cs)+simplifyReshapeConcat _ _ _ = Nothing+ reshapeSlice :: [DimIndex d] -> [d] -> [DimIndex d] reshapeSlice (DimFix i : slice') scs =   DimFix i : reshapeSlice slice' scs@@ -369,6 +382,7 @@     simplifyReshapeScratch,     simplifyReshapeReplicate,     simplifyReshapeIota,+    simplifyReshapeConcat,     simplifyReshapeIndex,     simplifyUpdateReshape,     improveReshape
src/Futhark/Optimise/Sink.hs view
@@ -104,7 +104,8 @@     (sinking_here, sinking') = M.partitionWithKey sunkHere sinking     sunk_stms = stmsFromList $ M.elems sinking_here     sunkHere v stm =-      v `nameIn` free_in_stms+      v+        `nameIn` free_in_stms         && all (`ST.available` vtable) (namesToList (freeIn stm))     sunk = namesFromList $ foldMap (patNames . stmPat) sunk_stms @@ -120,7 +121,7 @@       let stms' = foldr (inline i) (bodyStms body0) loop_vars           body1 = body0 {bodyStms = stms'}           (body2, sunk) = optimiseBody onOp vtable' sinking body1-          notSunk (x, _) = not $ paramName x `nameIn` sunk+          notSunk (x, _) = paramName x `notNameIn` sunk           loop_vars' = filter notSunk loop_vars           form' = ForLoop i it bound loop_vars'           body3 = body2 {bodyStms = SQ.drop (length loop_vars') (bodyStms body2)}@@ -279,7 +280,9 @@       pure $         fst $           optimiseStms onOp mempty mempty consts $-            namesFromList $ M.keys $ scopeOf consts+            namesFromList $+              M.keys $+                scopeOf consts  -- | Sinking in GPU kernels. sinkGPU :: Pass GPU GPU
src/Futhark/Optimise/TileLoops.hs view
@@ -148,7 +148,7 @@         Just (w, arrs, form) <- tileable stm_to_tile,         inputs <- map (is1DTileable gtid variance) arrs,         not $ null $ tiledInputs inputs,-        not $ gtid `nameIn` branch_variant,+        gtid `notNameIn` branch_variant,         (prestms', poststms') <-           preludeToPostlude variance prestms stm_to_tile (stmsFromList poststms),         used <- freeIn stm_to_tile <> freeIn poststms' <> freeIn stms_res =@@ -180,14 +180,14 @@               merge_params = map fst merge            maybe_tiled <--            localScope (M.insert i (IndexName it) $ scopeOfFParams merge_params) $-              tileInBody+            localScope (M.insert i (IndexName it) $ scopeOfFParams merge_params)+              $ tileInBody                 branch_variant'                 variance                 initial_lvl                 initial_space                 (map paramType merge_params)-                $ mkBody (bodyStms loopbody) (bodyResult loopbody)+              $ mkBody (bodyStms loopbody) (bodyResult loopbody)            case maybe_tiled of             Nothing -> next@@ -235,7 +235,8 @@      used stm =       any (`nameIn` used_in_stm_variant) $-        patNames $ stmPat stm+        patNames $+          stmPat stm      (prelude_used, prelude_not_used) =       Seq.partition used prelude@@ -268,7 +269,7 @@     invariantTo names stm =       case patNames (stmPat stm) of         [] -> True -- Does not matter.-        v : _ -> not $ any (`nameIn` names) $ namesToList $ M.findWithDefault mempty v variance+        v : _ -> all (`notNameIn` names) (namesToList $ M.findWithDefault mempty v variance)      consumed v = v `nameIn` consumed_in_prestms     consumedStm stm = any consumed (patNames (stmPat stm))@@ -276,11 +277,12 @@     later_consumed =       namesFromList $         concatMap (patNames . stmPat) $-          stmsToList $ Seq.filter consumedStm prestms+          stmsToList $+            Seq.filter consumedStm prestms      groupInvariant stm =       invariantTo private stm-        && not (any (`nameIn` later_consumed) (patNames (stmPat stm)))+        && all (`notNameIn` later_consumed) (patNames (stmPat stm))         && invariantTo later_consumed stm     (invariant_prestms, variant_prestms) =       Seq.partition groupInvariant prestms@@ -301,7 +303,8 @@     must_be_inlined =       namesFromList $         concatMap (patNames . stmPat) $-          stmsToList $ Seq.filter mustBeInlined variant_prestms+          stmsToList $+            Seq.filter mustBeInlined variant_prestms     recompute stm =       any (`nameIn` must_be_inlined) (patNames (stmPat stm))         || not (invariantTo must_be_inlined stm)@@ -519,7 +522,9 @@     letSubExp "slice_offset" =<< toExp (pe64 tile_id * pe64 full_tile_size)   let slice = DimSlice slice_offset this_tile_size (intConst Int64 1)   letExp "untiled_slice" $-    BasicOp $ Index arr $ fullSlice arr_t [slice]+    BasicOp $+      Index arr $+        fullSlice arr_t [slice]  -- | Statements that we insert directly into every thread-private -- SegMaps.  This is for things that cannot efficiently be computed@@ -868,7 +873,8 @@   -- the whole tiles.   residual_input <-     letSubExp "residual_input" $-      BasicOp $ BinOp (SRem Int64 Unsafe) w tile_size+      BasicOp $+        BinOp (SRem Int64 Unsafe) w tile_size    letTupExp "acc_after_residual"     =<< eIf@@ -932,12 +938,14 @@       else do         group_size <-           letSubExp "computed_group_size" $-            BasicOp $ BinOp (SMin Int64) (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 Int64 Unsafe) kdim group_size+            BasicOp $+              BinOp (SDivUp Int64 Unsafe) kdim group_size          num_groups <-           letSubExp "computed_num_groups"@@ -965,7 +973,8 @@         tilingTileShape = Shape [tile_size],         tilingNumWholeTiles =           letSubExp "num_whole_tiles" $-            BasicOp $ BinOp (SQuot Int64 Unsafe) w tile_size,+            BasicOp $+              BinOp (SQuot Int64 Unsafe) w tile_size,         tilingLevel = lvl,         tilingSpace = space       }@@ -980,10 +989,10 @@   j : i : _ <- Just $ reverse dims   let variant_to = M.findWithDefault mempty arr variance       branch_invariant = not $ nameIn j branch_variant || nameIn i branch_variant-  if branch_invariant && i `nameIn` variant_to && not (j `nameIn` variant_to)+  if branch_invariant && i `nameIn` variant_to && j `notNameIn` variant_to     then Just $ InputTile [0, 1] arr     else-      if branch_invariant && j `nameIn` variant_to && not (i `nameIn` variant_to)+      if branch_invariant && j `nameIn` variant_to && i `notNameIn` variant_to         then Just $ InputTile [1, 0] arr         else Just $ InputDontTile arr @@ -1118,7 +1127,9 @@             tile_t <- lookupType tile             let idx = DimFix $ Var $ head $ rearrangeShape perm [ltid_x, ltid_y]             letExp "tile" $-              BasicOp $ Index tile $ sliceAt tile_t (head perm) [idx]+              BasicOp $+                Index tile $+                  sliceAt tile_t (head perm) [idx]        tiles' <- mapM sliceTile tiles @@ -1151,7 +1162,8 @@     -- the whole tiles.     residual_input <-       letSubExp "residual_input" $-        BasicOp $ BinOp (SRem Int64 Unsafe) w tile_size+        BasicOp $+          BinOp (SRem Int64 Unsafe) w tile_size      letTupExp "acc_after_residual"       =<< eIf@@ -1219,10 +1231,12 @@    num_groups_x <-     letSubExp "num_groups_x" $-      BasicOp $ BinOp (SDivUp Int64 Unsafe) kdim_x tile_size+      BasicOp $+        BinOp (SDivUp Int64 Unsafe) kdim_x tile_size   num_groups_y <-     letSubExp "num_groups_y" $-      BasicOp $ BinOp (SDivUp Int64 Unsafe) kdim_y tile_size+      BasicOp $+        BinOp (SDivUp Int64 Unsafe) kdim_y tile_size    num_groups <-     letSubExp "num_groups_top"@@ -1254,7 +1268,8 @@         tilingTileShape = Shape [tile_size, tile_size],         tilingNumWholeTiles =           letSubExp "num_whole_tiles" $-            BasicOp $ BinOp (SQuot Int64 Unsafe) w tile_size,+            BasicOp $+              BinOp (SQuot Int64 Unsafe) w tile_size,         tilingLevel = lvl,         tilingSpace = space       }
src/Futhark/Optimise/TileLoops/Shared.hs view
@@ -68,7 +68,8 @@    loop_body <-     runBodyBuilder . inScopeOf loop_form . localScope (scopeOfFParams loop_inits) $-      body i $ map paramName loop_inits+      body i $+        map paramName loop_inits    letTupExp "loop" $     DoLoop (zip loop_inits $ map Var merge) loop_form loop_body@@ -101,7 +102,10 @@    let ret (SubExpRes cs se) = Returns manifest cs se   letTupExp desc $-    Op . SegOp $ SegMap lvl space ts $ KernelBody () stms' $ map ret res'+    Op . SegOp $+      SegMap lvl space ts $+        KernelBody () stms' $+          map ret res'  segMap2D ::   String -> -- desc@@ -125,7 +129,10 @@    let ret (SubExpRes cs se) = Returns manifest cs se   letTupExp desc <=< renameExp $-    Op . SegOp $ SegMap lvl segspace ts $ KernelBody () stms $ map ret res+    Op . SegOp $+      SegMap lvl segspace ts $+        KernelBody () stms $+          map ret res  segMap3D ::   String -> -- desc@@ -150,7 +157,10 @@    let ret (SubExpRes cs se) = Returns manifest cs se   letTupExp desc <=< renameExp $-    Op . SegOp $ SegMap lvl segspace ts $ KernelBody () stms $ map ret res+    Op . SegOp $+      SegMap lvl segspace ts $+        KernelBody () stms $+          map ret res  segScatter2D ::   String ->
src/Futhark/Optimise/Unstream.hs view
@@ -140,7 +140,8 @@       stms <- runBuilder_ $ FOT.transformSOAC pat soac       fmap concat $         localScope (scopeOf stms) $-          mapM (optimiseStm (onMCOp stage)) $ stmsToList stms+          mapM (optimiseStm (onMCOp stage)) $+            stmsToList stms   | otherwise =       -- Still sequentialise whatever's inside.       pure <$> (Let pat aux . Op . MC.OtherOp <$> mapSOACM optimise soac)@@ -161,7 +162,8 @@       stms <- runBuilder_ $ FOT.transformSOAC pat soac       fmap concat $         localScope (scopeOf stms) $-          mapM (optimiseStm (onHostOp stage)) $ stmsToList stms+          mapM (optimiseStm (onHostOp stage)) $+            stmsToList stms   | otherwise =       -- Still sequentialise whatever's inside.       pure <$> (Let pat aux . Op . GPU.OtherOp <$> mapSOACM optimise soac)
src/Futhark/Pass.hs view
@@ -7,8 +7,6 @@ module Futhark.Pass   ( PassM,     runPassM,-    liftEither,-    liftEitherM,     Pass (..),     passLongOption,     parPass,@@ -21,8 +19,6 @@ import Control.Monad.Writer.Strict import Control.Parallel.Strategies import Data.Char-import Data.Either-import Futhark.Error import Futhark.IR import Futhark.MonadFreshNames import Futhark.Util.Log@@ -47,17 +43,6 @@   m (a, Log) runPassM (PassM m) = modifyNameSource $ runState (runWriterT m) --- | Turn an 'Either' computation into a 'PassM'.  If the 'Either' is--- 'Left', the result is a 'CompilerBug'.-liftEither :: Show err => Either err a -> PassM a-liftEither (Left e) = compilerBugS $ show e-liftEither (Right v) = pure v---- | Turn an 'Either' monadic computation into a 'PassM'.  If the 'Either' is--- 'Left', the result is an exception.-liftEitherM :: Show err => PassM (Either err a) -> PassM a-liftEitherM m = liftEither =<< m- -- | A compiler pass transforming a 'Prog' of a given rep to a 'Prog' -- of another rep. data Pass fromrep torep = Pass@@ -105,10 +90,10 @@   (Stms torep -> FunDef fromrep -> PassM (FunDef torep)) ->   Prog fromrep ->   PassM (Prog torep)-intraproceduralTransformationWithConsts ct ft (Prog consts funs) = do-  consts' <- ct consts-  funs' <- parPass (ft consts') funs-  pure $ Prog consts' funs'+intraproceduralTransformationWithConsts ct ft prog = do+  consts' <- ct (progConsts prog)+  funs' <- parPass (ft consts') (progFuns prog)+  pure $ prog {progConsts = consts', progFuns = funs'}  -- | Like 'intraproceduralTransformationWithConsts', but do not change -- the top-level constants, and simply pass along their 'Scope'.
src/Futhark/Pass/ExpandAllocations.hs view
@@ -36,10 +36,13 @@ expandAllocations :: Pass GPUMem GPUMem expandAllocations =   Pass "expand allocations" "Expand allocations" $-    \(Prog consts funs) -> do+    \prog -> do       consts' <--        modifyNameSource $ limitationOnLeft . runStateT (runReaderT (transformStms consts) mempty)-      Prog consts' <$> mapM (transformFunDef $ scopeOf consts') funs+        modifyNameSource $+          limitationOnLeft+            . runStateT (runReaderT (transformStms (progConsts prog)) mempty)+      funs' <- mapM (transformFunDef $ scopeOf consts') (progFuns prog)+      pure $ prog {progConsts = consts', progFuns = funs'}  -- Cannot use intraproceduralTransformation because it might create -- duplicate size keys (which are not fixed by renamer, and size@@ -64,7 +67,8 @@     m =       localScope scope $         inScopeOf fundec $-          transformBody $ funDefBody fundec+          transformBody $+            funDefBody fundec  transformBody :: Body GPUMem -> ExpandM (Body GPUMem) transformBody (Body () stms res) = Body () <$> transformStms stms <*> pure res@@ -162,14 +166,15 @@           lvl = SegThread (Count $ intConst Int64 0) (Count $ intConst Int64 0) SegNoVirt           (op_lam', lam_allocs) =             extractLambdaAllocations (lvl, [0]) bound_outside mempty op_lam-          variantAlloc (_, Var v, _) = not $ v `nameIn` bound_outside+          variantAlloc (_, Var v, _) = v `notNameIn` bound_outside           variantAlloc _ = False           (variant_allocs, invariant_allocs) = M.partition variantAlloc lam_allocs        case M.elems variant_allocs of         (_, v, _) : _ ->           throwError $-            "Cannot handle un-sliceable allocation size: " ++ pretty v+            "Cannot handle un-sliceable allocation size: "+              ++ pretty v               ++ "\nLikely cause: irregular nested operations inside accumulator update operator."         [] ->           pure ()@@ -200,17 +205,18 @@       (kbody', kbody_allocs) =         extractKernelBodyAllocations user bound_outside bound_in_kernel kbody       (ops', ops_allocs) = unzip $ map (extractLambdaAllocations user bound_outside mempty) ops-      variantAlloc (_, Var v, _) = not $ v `nameIn` bound_outside+      variantAlloc (_, Var v, _) = v `notNameIn` bound_outside       variantAlloc _ = False       (variant_allocs, invariant_allocs) =         M.partition variantAlloc $ kbody_allocs <> mconcat ops_allocs-      badVariant (_, Var v, _) = not $ v `nameIn` bound_in_kernel+      badVariant (_, Var v, _) = v `notNameIn` bound_in_kernel       badVariant _ = False    case find badVariant $ M.elems variant_allocs of     Just v ->       throwError $-        "Cannot handle un-sliceable allocation size: " ++ pretty v+        "Cannot handle un-sliceable allocation size: "+          ++ pretty v           ++ "\nLikely cause: irregular nested operations inside parallel constructs."     Nothing ->       pure ()@@ -350,7 +356,8 @@         runWriter $           fmap catMaybes $             mapM (extractStmAllocations user bound_outside bound_kernel') $-              stmsToList $ get_stms body+              stmsToList $+                get_stms body    in (set_stms (stmsFromList stms) body, allocs)  expandable, notScalar :: Space -> Bool@@ -445,7 +452,8 @@           permuted_ixfun = IxFun.permute root_ixfun perm           offset_ixfun =             IxFun.slice permuted_ixfun $-              Slice $ map DimFix user_ids ++ map untouched old_shape+              Slice $+                map DimFix user_ids ++ map untouched old_shape        in offset_ixfun     newBase user@(SegGroup {}, _) (old_shape, _) =       let (users_shape, user_ids) = getNumUsers user@@ -809,7 +817,8 @@     params <- replicateM num_sizes $ newParam "x" (Prim int64)     (zs, stms) <- localScope       (scopeOfLParams params <> scopeOfLParams [flat_gtid_lparam])-      $ collectStms $ do+      $ collectStms+      $ do         -- Even though this SegRed is one-dimensional, we need to         -- provide indexes corresponding to the original potentially         -- multi-dimensional construct.@@ -836,7 +845,8 @@      thread_space_iota <-       letExp "thread_space_iota" $-        BasicOp $ Iota w (intConst Int64 0) (intConst Int64 1) Int64+        BasicOp $+          Iota w (intConst Int64 0) (intConst Int64 1) Int64     let red_op =           SegBinOp             Commutative@@ -845,12 +855,14 @@             mempty     lvl <- segThread "segred" -    addStms =<< mapM renameStm+    addStms+      =<< mapM renameStm       =<< nonSegRed lvl pat w [red_op] size_lam' [thread_space_iota]      size_sums <- forM (patNames pat) $ \threads_max ->       letExp "size_sum" $-        BasicOp $ BinOp (Mul Int64 OverflowUndef) (Var threads_max) num_threads+        BasicOp $+          BinOp (Mul Int64 OverflowUndef) (Var threads_max) num_threads      pure (patNames pat, size_sums) 
src/Futhark/Pass/ExplicitAllocations.hs view
@@ -178,7 +178,8 @@       elm_size_i64 = elemSize t   pure $     BinOpExp (SMax Int64) (ValueExp $ IntValue $ Int64Value 0) $-      untyped $ dim_prod_i64 * elm_size_i64+      untyped $+        dim_prod_i64 * elm_size_i64  arraySizeInBytes :: MonadBuilder m => ChunkMap -> Type -> m SubExp arraySizeInBytes chunkmap = letSubExp "bytes" <=< toExp <=< arraySizeInBytesExpM chunkmap@@ -628,7 +629,10 @@ explicitAllocationsInStmsGeneric handleOp hints stms = do   scope <- askScope   runAllocM handleOp hints $-    localScope scope $ collectStms_ $ allocInStms stms $ pure ()+    localScope scope $+      collectStms_ $+        allocInStms stms $+          pure ()  memoryInDeclExtType :: Int -> [DeclExtType] -> [FunReturns] memoryInDeclExtType k dets = evalState (mapM addMem dets) 0@@ -639,7 +643,9 @@       i <- get <* modify (+ 1)       let shape' = fmap shift shape       pure . MemArray pt shape' u . ReturnsNewBlock DefaultSpace i $-        IxFun.iota $ map convert $ shapeDims shape'+        IxFun.iota $+          map convert $+            shapeDims shape'     addMem (Acc acc ispace ts u) = pure $ MemAcc acc ispace ts u      convert (Ext i) = le64 $ Ext i@@ -851,7 +857,9 @@      mkP attrs p pt shape u mem ixfun is =       Param attrs p . MemArray pt shape u . ArrayIn mem . IxFun.slice ixfun $-        fmap pe64 $ Slice $ is ++ map sliceDim (shapeDims shape)+        fmap pe64 $+          Slice $+            is ++ map sliceDim (shapeDims shape)      onXParam _ (Param attrs p (Prim t)) _ =       pure $ Param attrs p (MemPrim t)@@ -962,7 +970,9 @@           shape' = fmap (adjustExt num_new_ctx) shape           bodyret =             MemArray pt shape' u . ReturnsNewBlock space' k $-              IxFun.iota $ map convert $ shapeDims shape'+              IxFun.iota $+                map convert $+                  shapeDims shape'        in bodyret     inspect _ _ (Acc acc ispace ts u) _ = MemAcc acc ispace ts u     inspect _ _ (Prim pt) _ = MemPrim pt@@ -1105,7 +1115,8 @@       fbody <- resultBodyM [intConst Int64 0]       size' <-         letSubExp "hoisted_alloc_size" $-          If taken tbody fbody $ IfDec [MemPrim int64] IfFallback+          If taken tbody fbody $+            IfDec [MemPrim int64] IfFallback       letBind pat $ Op $ Alloc size' space     protectOp _ _ _ = Nothing 
src/Futhark/Pass/ExplicitAllocations/GPU.hs view
@@ -161,9 +161,11 @@                   nilSlice d = DimSlice 0 d 0                in Hint                     ( IxFun.slice (IxFun.iota dims) $-                        fullSliceNum dims $ map nilSlice seg_dims+                        fullSliceNum dims $+                          map nilSlice seg_dims                     )-                    $ ScalarSpace (arrayDims t) $ elemType t+                    $ ScalarSpace (arrayDims t)+                    $ elemType t             else NoHint   where     private (Returns ResultPrivate _ _) = True
src/Futhark/Pass/ExplicitAllocations/SegOp.hs view
@@ -31,7 +31,8 @@   AllocM fromrep torep (Lambda torep) allocInLambda params body =   mkLambda params . allocInStms (bodyStms body) $-    pure $ bodyResult body+    pure $+      bodyResult body  allocInBinOpParams ::   Allocable fromrep torep inner =>@@ -48,7 +49,9 @@         Array pt shape u -> do           twice_num_threads <-             letSubExp "twice_num_threads" $-              BasicOp $ BinOp (Mul Int64 OverflowUndef) num_threads $ intConst Int64 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
src/Futhark/Pass/ExtractKernels.hs view
@@ -194,10 +194,14 @@     }  transformProg :: Prog SOACS -> PassM (Prog GPU)-transformProg (Prog consts funs) = do-  consts' <- runDistribM $ transformStms mempty $ stmsToList consts-  funs' <- mapM (transformFunDef $ scopeOf consts') funs-  pure $ Prog consts' funs'+transformProg prog = do+  consts' <- runDistribM $ transformStms mempty $ stmsToList $ progConsts prog+  funs' <- mapM (transformFunDef $ scopeOf consts') $ progFuns prog+  pure $+    prog+      { progConsts = consts',+        progFuns = funs'+      }  -- In order to generate more stable threshold names, we keep track of -- the numbers used for thresholds separately from the ordinary name@@ -286,7 +290,8 @@     unbalancedStm bound (WithAcc _ lam) =       unbalancedBody bound (lambdaBody lam)     unbalancedStm bound (If cond tbranch fbranch _) =-      cond `subExpBound` bound+      cond+        `subExpBound` bound         && (unbalancedBody bound tbranch || unbalancedBody bound fbranch)     unbalancedStm _ (BasicOp _) =       False@@ -338,7 +343,8 @@   let alt_body = mkBody alt_stms $ varsRes $ patNames alts_pat    letBind pat $-    If cond alt alt_body $ IfDec (staticShapes (patTypes pat)) IfEquiv+    If cond alt alt_body $+      IfDec (staticShapes (patTypes pat)) IfEquiv  transformLambda :: KernelPath -> Lambda SOACS -> DistribM (Lambda GPU) transformLambda path (Lambda params body ret) =@@ -432,7 +438,8 @@               =<< (mkBody <$> paralleliseInner path' <*> pure (varsRes (patNames pat)))        if not (lambdaContainsParallelism map_lam)-        || "sequential_inner" `inAttrs` stmAuxAttrs aux+        || "sequential_inner"+        `inAttrs` stmAuxAttrs aux         then paralleliseOuter         else do           ((outer_suff, outer_suff_key), suff_stms) <-@@ -647,7 +654,8 @@       | WithAcc _ withacc_lam <- stmExp stm =           bodyInterest (lambdaBody withacc_lam)       | Op (Screma _ _ form@(ScremaForm _ _ lam')) <- stmExp stm =-          1 + bodyInterest (lambdaBody lam')+          1+            + bodyInterest (lambdaBody lam')             +             -- Give this a bigger score if it's a redomap, as these             -- are often tileable and thus benefit more from@@ -710,14 +718,18 @@ mayExploitOuter :: Attrs -> Bool mayExploitOuter attrs =   not $-    AttrComp "incremental_flattening" ["no_outer"] `inAttrs` attrs-      || AttrComp "incremental_flattening" ["only_inner"] `inAttrs` attrs+    AttrComp "incremental_flattening" ["no_outer"]+      `inAttrs` attrs+      || AttrComp "incremental_flattening" ["only_inner"]+      `inAttrs` attrs  mayExploitIntra :: Attrs -> Bool mayExploitIntra attrs =   not $-    AttrComp "incremental_flattening" ["no_intra"] `inAttrs` attrs-      || AttrComp "incremental_flattening" ["only_inner"] `inAttrs` attrs+    AttrComp "incremental_flattening" ["no_intra"]+      `inAttrs` attrs+      || AttrComp "incremental_flattening" ["only_inner"]+      `inAttrs` attrs  -- The minimum amount of inner parallelism we require (by default) in -- intra-group versions.  Less than this is usually pointless on a GPU@@ -755,8 +767,10 @@       | Just m <- mkSeqAlts -> do           (outer_suff, outer_suff_key, outer_suff_stms, seq_body) <- m           par_body <--            renameBody =<< mkBody-              <$> mk_par_stms ((outer_suff_key, False) : path) <*> pure res+            renameBody+              =<< mkBody+                <$> mk_par_stms ((outer_suff_key, False) : path)+                <*> pure res           (outer_suff_stms <>) <$> kernelAlternatives pat par_body [(outer_suff, seq_body)]       --       | otherwise -> do@@ -778,8 +792,10 @@                 checkSuffIntraPar path intra'                par_body <--                renameBody =<< mkBody-                  <$> mk_par_stms ((intra_suff_key, False) : path) <*> pure res+                renameBody+                  =<< mkBody+                    <$> mk_par_stms ((intra_suff_key, False) : path)+                    <*> pure res                (intra_suff_stms <>)                 <$> kernelAlternatives pat par_body [(intra_ok, group_par_body)]@@ -790,13 +806,14 @@                 checkSuffIntraPar ((outer_suff_key, False) : path) intra'                par_body <--                renameBody =<< mkBody-                  <$> mk_par_stms-                    ( [ (outer_suff_key, False),-                        (intra_suff_key, False)-                      ]-                        ++ path-                    )+                renameBody+                  =<< mkBody+                    <$> mk_par_stms+                      ( [ (outer_suff_key, False),+                          (intra_suff_key, False)+                        ]+                          ++ path+                      )                     <*> pure res                ((outer_suff_stms <> intra_suff_stms) <>)@@ -815,8 +832,10 @@         mayExploitOuter attrs = Just $ do           ((outer_suff, outer_suff_key), outer_suff_stms) <- checkSuffOuterPar           seq_body <--            renameBody =<< mkBody-              <$> mk_seq_stms ((outer_suff_key, True) : path) <*> pure res+            renameBody+              =<< mkBody+                <$> mk_seq_stms ((outer_suff_key, True) : path)+                <*> pure res           pure (outer_suff, outer_suff_key, outer_suff_stms, seq_body)       | otherwise =           Nothing@@ -914,7 +933,8 @@           -- order instead.           let lam_res' =                 rearrangeShape (rearrangeInverse perm) $-                  bodyResult $ lambdaBody lam'+                  bodyResult $+                    lambdaBody lam'               lam'' = lam' {lambdaBody = (lambdaBody lam') {bodyResult = lam_res'}}               map_nesting = MapNesting pat' aux w $ zip (lambdaParams lam') arrs               nest' = pushInnerKernelNesting (pat', lam_res') map_nesting nest
src/Futhark/Pass/ExtractKernels/BlockedKernel.hs view
@@ -192,7 +192,9 @@         forM_ (zip (lambdaParams lam) arrs) $ \(p, arr) -> do           arr_t <- lookupType arr           letBindNames [paramName p] $-            BasicOp $ Index arr $ fullSlice arr_t [DimFix $ Var gtid]+            BasicOp $+              Index arr $+                fullSlice arr_t [DimFix $ Var gtid]         res <- bodyBind (lambdaBody lam)         forM res $ \(SubExpRes cs se) ->           pure $ Returns ResultMaySimplify cs se
src/Futhark/Pass/ExtractKernels/DistributeNests.hs view
@@ -251,7 +251,8 @@                   }           stms <-             runBuilder_ . auxing aux . FOT.transformSOAC pat $-              Screma w used_arrs $ mapSOAC lam'+              Screma w used_arrs $+                mapSOAC lam'            pure $ acc {distTargets = newtargets, distStms = stms}       | otherwise -> do@@ -381,7 +382,7 @@         Nothing -> addStmToAcc stm acc         Just acc' -> distribute =<< onInnerMap (MapLoop pat (stmAux stm) w lam arrs) acc' maybeDistributeStm stm@(Let pat aux (DoLoop merge form@ForLoop {} body)) acc-  | not $ any (`nameIn` freeIn pat) $ patNames pat,+  | all (`notNameIn` freeIn pat) (patNames pat),     bodyContainsParallelism body =       distributeSingleStm acc stm >>= \case         Just (kernels, res, nest, acc')@@ -413,8 +414,9 @@         _ ->           addStmToAcc stm acc maybeDistributeStm stm@(Let pat _ (If cond tbranch fbranch ret)) acc-  | not $ any (`nameIn` freeIn pat) $ patNames pat,-    bodyContainsParallelism tbranch || bodyContainsParallelism fbranch+  | all (`notNameIn` freeIn pat) (patNames pat),+    bodyContainsParallelism tbranch+      || bodyContainsParallelism fbranch       || not (all primType (ifReturns ret)) =       distributeSingleStm acc stm >>= \case         Just (kernels, res, nest, acc')@@ -657,7 +659,8 @@       | map resSubExp res == map Var (patNames $ stmPat stm),         (outer, _) <- nest,         [(arr_p, arr)] <- loopNestingParamsAndArrs outer,-        boundInKernelNest nest `namesIntersection` freeIn stm+        boundInKernelNest nest+          `namesIntersection` freeIn stm           == oneName (paramName arr_p),         perfectlyMapped arr nest -> do           addPostStms kernels@@ -783,7 +786,8 @@   let rts =         concatMap (take 1) $           chunks as_ns $-            drop (sum indexes) $ lambdaReturnType lam+            drop (sum indexes) $+              lambdaReturnType lam       (is, vs) = splitAt (sum indexes) $ bodyResult $ lambdaBody lam    (is', k_body_stms) <- runBuilder $ do@@ -806,7 +810,9 @@      let pat =           Pat . rearrangeShape perm $-            patElems $ loopNestingPat $ fst nest+            patElems $+              loopNestingPat $+                fst nest      letBind pat $ Op $ segOp k   where@@ -847,10 +853,15 @@     -- Compute indexes into full array.     v' <-       certifying cs $-        letSubExp "v" $ BasicOp $ Index v $ Slice $ map (DimFix . Var) slice_gtids+        letSubExp "v" $+          BasicOp $+            Index v $+              Slice $+                map (DimFix . Var) slice_gtids     slice_is <-       traverse (toSubExp "index") $-        fixSlice (fmap pe64 slice) $ map (pe64 . Var) slice_gtids+        fixSlice (fmap pe64 slice) $+          map (pe64 . Var) slice_gtids      let write_is = map (Var . fst) base_ispace ++ slice_is         arr' =@@ -878,7 +889,9 @@      let pat =           Pat . rearrangeShape perm $-            patElems $ loopNestingPat $ fst nest+            patElems $+              loopNestingPat $+                fst nest      letBind pat $ Op $ segOp k @@ -900,7 +913,9 @@     -- Compute indexes into full array.     slice'' <-       subExpSlice . sliceSlice (primExpSlice slice) $-        primExpSlice $ Slice $ map (DimFix . Var) slice_gtids+        primExpSlice $+          Slice $+            map (DimFix . Var) slice_gtids     v' <- certifying cs $ letSubExp "v" $ BasicOp $ Index arr slice''     v_t <- subExpType v'     pure (v_t, Returns ResultMaySimplify mempty v')@@ -934,7 +949,9 @@   (ispace, inputs) <- flatKernel nest   let orig_pat =         Pat . rearrangeShape perm $-          patElems $ loopNestingPat $ fst nest+          patElems $+            loopNestingPat $+              fst nest    -- The input/output arrays _must_ correspond to some kernel input,   -- or else the original nested Hist would have been ill-typed.@@ -984,7 +1001,8 @@       inputs' = filter (not . isDest . kernelInputArray) inputs    certifying cs $-    addStms =<< traverse renameStm+    addStms+      =<< traverse renameStm       =<< segHist lvl orig_pat hist_w ispace inputs' ops' lam arrs  determineReduceOp ::@@ -1004,7 +1022,9 @@           BasicOp $             Index ne_v $               fullSlice ne_v_t $-                replicate (shapeRank shape) $ DimFix $ intConst Int64 0+                replicate (shapeRank shape) $+                  DimFix $+                    intConst Int64 0       pure (lam', nes', shape)     Nothing ->       pure (lam, nes, mempty)@@ -1041,7 +1061,8 @@       lam'' <- onLambda' lam'       let scan_op = SegBinOp Noncommutative lam'' nes'' shape       lvl <- mk_lvl (segment_size : map snd ispace) "segscan" $ NoRecommendation SegNoVirt-      addStms =<< traverse renameStm+      addStms+        =<< traverse renameStm         =<< segScan lvl pat cs segment_size [scan_op] map_lam arrs ispace inps  regularSegmentedRedomapKernel ::@@ -1062,7 +1083,8 @@     \pat ispace inps nes' _ -> do       let red_op = SegBinOp comm lam nes' mempty       lvl <- mk_lvl (segment_size : map snd ispace) "segred" $ NoRecommendation SegNoVirt-      addStms =<< traverse renameStm+      addStms+        =<< traverse renameStm         =<< segRed lvl pat cs segment_size [red_op] map_lam arrs ispace inps  isSegmentedOp ::@@ -1110,7 +1132,7 @@             | kernelInputIndices inp == map Var indices ->                 pure $ pure $ kernelInputArray inp           Nothing-            | not (arr `nameIn` bound_by_nest) ->+            | arr `notNameIn` bound_by_nest ->                 -- This input is something that is free inside                 -- the loop nesting. We will have to replicate                 -- it.@@ -1132,7 +1154,9 @@          let pat =               Pat . rearrangeShape perm $-                patElems $ loopNestingPat $ fst nest+                patElems $+                  loopNestingPat $+                    fst nest          m pat ispace kernel_inps nes' nested_arrs @@ -1150,8 +1174,8 @@   MonadFreshNames m => [PatElem Type] -> KernelNest -> m KernelNest expandKernelNest pes (outer_nest, inner_nests) = do   let outer_size =-        loopNestingWidth outer_nest :-        map loopNestingWidth inner_nests+        loopNestingWidth outer_nest+          : map loopNestingWidth inner_nests       inner_sizes = tails $ map loopNestingWidth inner_nests   outer_nest' <- expandWith outer_nest outer_size   inner_nests' <- zipWithM expandWith inner_nests inner_sizes
src/Futhark/Pass/ExtractKernels/Distribution.hs view
@@ -434,7 +434,8 @@              nest'' =               removeUnusedNestingParts free_in_kernel $-                MapNesting pat aux w $ zip actual_params actual_arrs+                MapNesting pat aux w $+                  zip actual_params actual_arrs              free_in_kernel'' =               (freeIn nest'' <> free_in_kernel) `namesSubtract` actual_param_names@@ -515,7 +516,7 @@       )   where     isIdentity (patElem, SubExpRes cs (Var v))-      | not (v `nameIn` bound) = Left (patElem, (cs, v))+      | v `notNameIn` bound = Left (patElem, (cs, v))     isIdentity x = Right x  removeIdentityMappingFromNesting ::@@ -553,7 +554,8 @@       Just (targets', distributed) -> do         (kernel_stm, w_stms) <-           localScope (targetsScope targets') $-            constructKernel mk_lvl distributed $ mkBody stms inner_body_res+            constructKernel mk_lvl distributed $+              mkBody stms inner_body_res         distributed' <- renameStm kernel_stm         logMsg $           "distributing\n"
src/Futhark/Pass/ExtractKernels/ISRWIM.hs view
@@ -44,7 +44,9 @@           scan_fun' = Lambda scan_params scan_body scan_rettype           scan_input' =             map (first Var) $-              uncurry zip $ splitAt (length arrs') $ map paramName map_params+              uncurry zip $+                splitAt (length arrs') $+                  map paramName map_params           (nes', scan_arrs) = unzip scan_input'        scan_soac <- scanSOAC [Scan scan_fun' nes']@@ -52,9 +54,11 @@             mkBody               ( oneStm $                   Let (setPatOuterDimTo w map_pat) (defAux ()) $-                    Op $ Screma w scan_arrs scan_soac+                    Op $+                      Screma w scan_arrs scan_soac               )-              $ varsRes $ patNames map_pat+              $ varsRes+              $ patNames map_pat           map_fun' = Lambda map_params map_body map_rettype        res_pat' <-@@ -64,13 +68,16 @@        addStm $         Let res_pat' (StmAux map_cs mempty ()) $-          Op $ Screma map_w map_arrs' (mapSOAC map_fun')+          Op $+            Screma map_w map_arrs' (mapSOAC map_fun')        forM_ (zip (patIdents res_pat) (patIdents res_pat')) $ \(to, from) -> do         let perm = [1, 0] ++ [2 .. arrayRank (identType from) - 1]         addStm $           Let (basicPat [to]) (defAux ()) $-            BasicOp $ Rearrange perm $ identName from+            BasicOp $+              Rearrange perm $+                identName from   | otherwise = Nothing  -- | Interchange Reduce With Inner Map. Tries to turn a @reduce(map)@ into a@@ -115,13 +122,15 @@         case irwim red_pat w comm red_fun' red_input' of           Nothing -> do             reduce_soac <- reduceSOAC [Reduce comm red_fun' $ map fst red_input']-            pure $-              mkBody+            pure+              $ mkBody                 ( oneStm $                     Let red_pat (defAux ()) $-                      Op $ Screma w (map snd red_input') reduce_soac+                      Op $+                        Screma w (map snd red_input') reduce_soac                 )-                $ varsRes $ patNames map_pat+              $ varsRes+              $ patNames map_pat           Just m -> localScope (scopeOfLParams map_params) $ do             map_body_stms <- collectStms_ m             pure $ mkBody map_body_stms $ varsRes $ patNames map_pat@@ -130,7 +139,9 @@        addStm $         Let res_pat (StmAux map_cs mempty ()) $-          Op $ Screma map_w arrs' $ mapSOAC map_fun'+          Op $+            Screma map_w arrs' $+              mapSOAC map_fun'   | otherwise = Nothing  -- | Does this reduce operator contain an inner map, and if so, what
src/Futhark/Pass/ExtractKernels/Interchange.hs view
@@ -79,7 +79,8 @@     let lam = Lambda (params' <> new_params) body rettype         map_stm =           Let loop_pat_expanded aux $-            Op $ Screma w (arrs' <> new_arrs) (mapSOAC lam)+            Op $+              Screma w (arrs' <> new_arrs) (mapSOAC lam)         res = varsRes $ patNames loop_pat_expanded         pat' = Pat $ rearrangeShape perm $ patElems pat @@ -90,7 +91,7 @@       free_in_body = freeIn body        copyOrRemoveParam (param, arr)-        | not (paramName param `nameIn` free_in_body) =+        | paramName param `notNameIn` free_in_body =             pure Nothing         | otherwise =             pure $ Just (param, arr)@@ -100,7 +101,8 @@             pure $ Var arr       expandedInit param_name se =         letSubExp (param_name <> "_expanded_init") $-          BasicOp $ Replicate (Shape [w]) se+          BasicOp $+            Replicate (Shape [w]) se        expand (merge_param, merge_init) = do         expanded_param <-@@ -148,7 +150,8 @@    in ( patNames $ loopNestingPat n,         oneStm $           Let (loopNestingPat n) (loopNestingAux n) $-            Op $ Screma (loopNestingWidth n) arrs (mapSOAC lam)+            Op $+              Screma (loopNestingWidth n) arrs (mapSOAC lam)       )  -- | Given a (parallel) map nesting and an inner sequential loop, move@@ -261,7 +264,8 @@           maplam_ret = lambdaReturnType acc_lam           maplam = Lambda (iota_p : orig_acc_params ++ params) (lambdaBody acc_lam) maplam_ret       auxing map_aux . fmap subExpsRes . letTupExp' "withacc_inter" $-        Op $ Screma w (iota_w : map paramName acc_params ++ arrs) (mapSOAC maplam)+        Op $+          Screma w (iota_w : map paramName acc_params ++ arrs) (mapSOAC maplam)     let pat = Pat $ rearrangeShape perm $ patElems map_pat     pure $ WithAccStm perm pat inputs' acc_lam'     where
src/Futhark/Pass/ExtractKernels/Intragroup.hs view
@@ -122,7 +122,9 @@       lvl = SegGroup (Count num_groups) (Count $ Var group_size) SegNoVirt       kstm =         Let nested_pat aux $-          Op $ SegOp $ SegMap lvl kspace rts kbody'+          Op $+            SegOp $+              SegMap lvl kspace rts kbody'    let intra_min_par = intra_avail_par   pure@@ -201,7 +203,8 @@         localScope (scopeOfFParams $ map fst merge) $ do           loopbody' <- intraGroupBody lvl loopbody           certifying (stmAuxCerts aux) $-            letBind pat $ DoLoop merge form' loopbody'+            letBind pat $+              DoLoop merge form' loopbody'       where         form' = case form of           ForLoop i it bound inps -> ForLoop i it bound inps@@ -210,7 +213,8 @@       tbody' <- intraGroupBody lvl tbody       fbody' <- intraGroupBody lvl fbody       certifying (stmAuxCerts aux) $-        letBind pat $ If cond tbody' fbody' ifdec+        letBind pat $+          If cond tbody' fbody' ifdec     Op soac       | "sequential_outer" `inAttrs` stmAuxAttrs aux ->           intraGroupStms lvl . fmap (certify (stmAuxCerts aux))
src/Futhark/Pass/ExtractKernels/StreamKernel.hs view
@@ -52,10 +52,13 @@   max_num_groups_key <- nameFromString . pretty <$> newVName (desc ++ "_num_groups")   num_groups <-     letSubExp "num_groups" $-      Op $ SizeOp $ CalcNumGroups w max_num_groups_key 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+      BasicOp $+        BinOp (Mul Int64 OverflowUndef) num_groups group_size   pure (num_groups, num_threads)  blockedKernelSize ::
src/Futhark/Pass/ExtractMulticore.hs view
@@ -173,14 +173,17 @@   body <- runBodyBuilder $     localScope (scopeOfLParams inp_params) $ do       letBindNames [paramName chunk_param] $-        BasicOp $ SubExp $ intConst Int64 1+        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)+          BasicOp $+            ArrayLit [Var $ paramName v] (paramType v)        (red_res, map_res) <- splitAt (length nes) <$> bodyBind (lambdaBody lam) @@ -188,7 +191,8 @@         v <- letExp "map_res" $ BasicOp $ SubExp se         v_t <- lookupType v         certifying cs . letSubExp "chunk" . BasicOp $-          Index v $ fullSlice v_t [DimFix $ intConst Int64 0]+          Index v $+            fullSlice v_t [DimFix $ intConst Int64 0]        pure $ mkBody mempty $ red_res <> subExpsRes map_res' @@ -381,7 +385,8 @@           (par_red_stms, par_op) <-             transformParStream DoRename transformBody w comm red_lam red_nes map_lam arrs           pure $-            seq_red_stms <> par_red_stms+            seq_red_stms+              <> par_red_stms               <> oneStm (Let pat (defAux ()) $ Op $ ParOp (Just par_op) seq_op)         else           pure $@@ -396,13 +401,17 @@   transformStms stream_stms  transformProg :: Prog SOACS -> PassM (Prog MC)-transformProg (Prog consts funs) =+transformProg prog =   modifyNameSource $ runState (runReaderT m mempty)   where     ExtractM m = do-      consts' <- transformStms consts-      funs' <- inScopeOf consts' $ mapM transformFunDef funs-      pure $ Prog consts' funs'+      consts' <- transformStms $ progConsts prog+      funs' <- inScopeOf consts' $ mapM transformFunDef $ progFuns prog+      pure $+        prog+          { progConsts = consts',+            progFuns = funs'+          }  -- | Transform a program using SOACs to a program in the 'MC' -- representation, using some amount of flattening.
src/Futhark/Pass/KernelBabysitting.hs view
@@ -287,7 +287,7 @@           not $ tooSmallSlice (primByteSize pt) rem_slice,           is /= map Var (take (length is) thread_gids) || length is == length thread_gids,           not (null thread_gids || null is),-          not (last thread_gids `nameIn` (freeIn is <> freeIn rem_slice)) ->+          last thread_gids `notNameIn` (freeIn is <> freeIn rem_slice) ->             pure Nothing         -- We are not fully indexing the array, and the indices are not         -- a proper prefix of the thread indices, and some indices are@@ -439,7 +439,8 @@   -- will hopefully be removed by the simplifier.   manifested <- if isJust manifest then rowMajorArray arr else pure arr   letExp (baseString arr ++ "_coalesced") $-    BasicOp $ Manifest perm manifested+    BasicOp $+      Manifest perm manifested  rowMajorArray ::   MonadBuilder m =>@@ -463,7 +464,8 @@    per_chunk <-     letSubExp "per_chunk" $-      BasicOp $ BinOp (SQuot Int64 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@@ -473,9 +475,11 @@           padding_shape = setDim d arr_shape padding       arr_padding <-         letExp (baseString arr <> "_padding") $-          BasicOp $ Scratch (elemType arr_t) (shapeDims padding_shape)+          BasicOp $+            Scratch (elemType arr_t) (shapeDims padding_shape)       letExp (baseString arr <> "_padded") $-        BasicOp $ Concat d (arr :| [arr_padding]) w_padded+        BasicOp $+          Concat d (arr :| [arr_padding]) w_padded      rearrange num_chunks' w_padded per_chunk arr_name arr_padded arr_t = do       let arr_dims = arrayDims arr_t@@ -485,10 +489,12 @@           tr_perm = [0 .. d - 1] ++ map (+ d) ([1] ++ [2 .. shapeRank extradim_shape - 1 - d] ++ [0])       arr_extradim <-         letExp (arr_name <> "_extradim") $-          BasicOp $ Reshape (map DimNew $ shapeDims extradim_shape) arr_padded+          BasicOp $+            Reshape (map DimNew $ shapeDims extradim_shape) arr_padded       arr_extradim_tr <-         letExp (arr_name <> "_extradim_tr") $-          BasicOp $ Manifest tr_perm arr_extradim+          BasicOp $+            Manifest tr_perm arr_extradim       arr_inv_tr <-         letExp (arr_name <> "_inv_tr") $           BasicOp $
src/Futhark/Passes.hs view
@@ -58,13 +58,9 @@       simplifySOACS,       performCSE True,       simplifySOACS,-      -- We run fusion twice       fuseSOACs,       performCSE True,       simplifySOACS,-      fuseSOACs,-      performCSE True,-      simplifySOACS,       removeDeadFunctions     ]     >>> condPipeline usesAD adPipeline@@ -79,8 +75,6 @@       performCSE True,       fuseSOACs,       performCSE True,-      simplifySOACS,-      fuseSOACs,       simplifySOACS     ] 
src/Futhark/Pkg/Info.hs view
@@ -209,7 +209,10 @@    let path =         T.unpack $-          owner <> "/" <> repo <> "@"+          owner+            <> "/"+            <> repo+            <> "@"             <> tag             <> "/"             <> T.pack futharkPkg@@ -258,7 +261,8 @@    head_ref <-     maybe (fail $ "Cannot find HEAD ref for " <> T.unpack repo_url) pure $-      maybeHead $ mapMaybe isHeadRef remote_lines+      maybeHead $+        mapMaybe isHeadRef remote_lines   let def = fromMaybe head_ref    rev_info <- M.fromList . catMaybes <$> mapM revInfo remote_lines@@ -347,14 +351,17 @@     base_url = "https://gitlab.com/" <> owner <> "/" <> repo     repo_url = base_url <> ".git"     mk_archive_url r =-      base_url <> "/-/archive/" <> r+      base_url+        <> "/-/archive/"+        <> r         <> "/"         <> repo         <> "-"         <> r         <> ".zip"     mk_manifest_url r =-      base_url <> "/raw/"+      base_url+        <> "/raw/"         <> r         <> "/"         <> T.pack futharkPkg@@ -444,7 +451,8 @@               major                 | (_, vs) <- majorRevOfPkg p,                   _svMajor v `notElem` vs =-                    "\nFor major version " <> T.pack (show (_svMajor v))+                    "\nFor major version "+                      <> T.pack (show (_svMajor v))                       <> ", use package path "                       <> p                       <> "@"@@ -452,7 +460,11 @@                 | otherwise = mempty            in fail $                 T.unpack $-                  "package " <> p <> " does not have a version " <> prettySemVer v <> ".\n"+                  "package "+                    <> p+                    <> " does not have a version "+                    <> prettySemVer v+                    <> ".\n"                     <> versions                     <> major         Just v' -> pure v'
src/Futhark/Pkg/Solve.hs view
@@ -101,7 +101,10 @@       | otherwise =           fail $             T.unpack $-              "Package " <> p <> " " <> prettySemVer v+              "Package "+                <> p+                <> " "+                <> prettySemVer v                 <> " has commit hash "                 <> pkgRevCommit pinfo                 <> ", but expected "
src/Futhark/Pkg/Types.hs view
@@ -194,7 +194,9 @@ -- | The required packages listed in a package manifest. pkgRevDeps :: PkgManifest -> PkgRevDeps pkgRevDeps =-  PkgRevDeps . M.fromList . mapMaybe onR+  PkgRevDeps+    . M.fromList+    . mapMaybe onR     . commented     . manifestRequire   where@@ -206,7 +208,8 @@ pkgDir :: PkgManifest -> Maybe Posix.FilePath pkgDir =   fmap-    ( Posix.addTrailingPathSeparator . ("lib" Posix.</>)+    ( Posix.addTrailingPathSeparator+        . ("lib" Posix.</>)         . T.unpack     )     . commented@@ -280,12 +283,14 @@     spaceNoEol = many $ oneOf (" \t" :: String)      pPkgPath =-      T.pack <$> some (alphaNumChar <|> oneOf ("@-/.:" :: String))+      T.pack+        <$> some (alphaNumChar <|> oneOf ("@-/.:" :: String))         <?> "package path"      pRequired =       space-        *> ( Required <$> lexeme' pPkgPath+        *> ( Required+               <$> lexeme' pPkgPath                <*> lexeme' semver'                <*> optional (lexeme' pHash)            )
src/Futhark/Script.hs view
@@ -35,6 +35,7 @@ where  import Control.Monad.Except+import Data.Bifunctor (bimap) import Data.Char import Data.Foldable (toList) import Data.Functor@@ -51,20 +52,44 @@ import qualified Futhark.Test.Values as V import Futhark.Util (nubOrd) import Futhark.Util.Pretty hiding (float, line, sep, space, string, (</>), (<|>))+import Language.Futhark.Core (Name, nameFromText, nameToText)+import Language.Futhark.Tuple (areTupleFields) import Text.Megaparsec import Text.Megaparsec.Char (space) import Text.Megaparsec.Char.Lexer (charLiteral) +type TypeMap = M.Map TypeName (Maybe [(Name, TypeName)])++typeMap :: MonadIO m => Server -> m TypeMap+typeMap server = do+  liftIO $ either (pure mempty) onTypes =<< cmdTypes server+  where+    onTypes types = M.fromList . zip types <$> mapM onType types+    onType t =+      either (const Nothing) (Just . map onField) <$> cmdFields server t+    onField = bimap nameFromText (T.drop 1) . T.breakOn " "++isRecord :: TypeName -> TypeMap -> Maybe [(Name, TypeName)]+isRecord t m = join $ M.lookup t m++isTuple :: TypeName -> TypeMap -> Maybe [TypeName]+isTuple t m = areTupleFields . M.fromList =<< isRecord t m+ -- | Like a 'Server', but keeps a bit more state to make FutharkScript -- more convenient.-data ScriptServer = ScriptServer Server (IORef Int)+data ScriptServer = ScriptServer+  { scriptServer :: Server,+    scriptCounter :: IORef Int,+    scriptTypes :: TypeMap+  }  -- | Run an action with a 'ScriptServer' produced by an existing -- 'Server', without shutting it down at the end. withScriptServer' :: MonadIO m => Server -> (ScriptServer -> m a) -> m a withScriptServer' server f = do   counter <- liftIO $ newIORef 0-  f $ ScriptServer server counter+  types <- typeMap server+  f $ ScriptServer server counter types  -- | Start a server, execute an action, then shut down the server. -- Similar to 'withServer'.@@ -132,9 +157,12 @@ parseExp :: Parsec Void T.Text () -> Parsec Void T.Text Exp parseExp sep =   choice-    [ lexeme sep "let" $> Let-        <*> pPat <* lexeme sep "="-        <*> parseExp sep <* lexeme sep "in"+    [ lexeme sep "let"+        $> Let+        <*> pPat+        <* lexeme sep "="+        <*> parseExp sep+        <* lexeme sep "in"         <*> parseExp sep,       try $ Call <$> parseFunc <*> many pAtom,       pAtom@@ -276,15 +304,26 @@   ScriptServer ->   Exp ->   m ExpValue-evalExp builtin (ScriptServer server counter) top_level_e = do+evalExp builtin sserver top_level_e = do   vars <- liftIO $ newIORef []-  let newVar base = liftIO $ do+  let ( ScriptServer+          { scriptServer = server,+            scriptCounter = counter,+            scriptTypes = types+          }+        ) = sserver+      newVar base = liftIO $ do         x <- readIORef counter         modifyIORef counter (+ 1)         let v = base <> prettyText x         modifyIORef vars (v :)         pure v +      mkRecord t vs = do+        v <- newVar "record"+        cmdMaybe $ cmdNew server v t vs+        pure v+       toVal :: ValOrVar -> m V.Value       toVal (VVal v) = pure v       toVal (VVar v) = readVar server v@@ -310,17 +349,25 @@       interValToVal :: ExpValue -> m V.CompoundValue       interValToVal = traverse scriptValueToVal -      interValToVar :: ExpValue -> m VarName-      interValToVar (V.ValueAtom v) = scriptValueToVar v-      interValToVar _ = throwError "Unexpected tuple or record value."+      -- Apart from type checking, this function also converts+      -- FutharkScript tuples/records to Futhark-level tuples/records.+      interValToVar :: m VarName -> TypeName -> ExpValue -> m VarName+      interValToVar _ t (V.ValueAtom v)+        | STValue t == scriptValueType v = scriptValueToVar v+      interValToVar bad t (V.ValueTuple vs)+        | Just ts <- isTuple t types,+          length vs == length ts =+            mkRecord t =<< zipWithM (interValToVar bad) ts vs+      interValToVar bad t (V.ValueRecord vs)+        | Just fs <- isRecord t types,+          Just vs' <- mapM ((`M.lookup` vs) . nameToText . fst) fs =+            mkRecord t =<< zipWithM (interValToVar bad) (map snd fs) vs'+      interValToVar bad _ _ = bad        valToInterVal :: V.CompoundValue -> ExpValue       valToInterVal = fmap $ \v ->         SValue (V.valueTypeTextNoDims (V.valueType v)) $ VVal v -      simpleType (V.ValueAtom (STValue _)) = True-      simpleType _ = False-       letMatch :: [VarName] -> ExpValue -> m VTable       letMatch vs val         | vals <- V.unCompound val,@@ -328,7 +375,8 @@             pure $ M.fromList (zip vs vals)         | otherwise =             throwError $-              "Pat: " <> prettyTextOneLine vs+              "Pat: "+                <> prettyTextOneLine vs                 <> "\nDoes not match value of type: "                 <> prettyTextOneLine (fmap scriptValueType val) @@ -341,7 +389,8 @@       evalExp' vtable (Call (FuncFut name) es)         | Just e <- M.lookup name vtable = do             unless (null es) $-              throwError $ "Locally bound name cannot be invoked as a function: " <> prettyText name+              throwError $+                "Locally bound name cannot be invoked as a function: " <> prettyText name             pure e       evalExp' vtable (Call (FuncFut name) es) = do         in_types <- fmap (map inputType) $ cmdEither $ cmdInputs server name@@ -350,22 +399,19 @@         es' <- mapM (evalExp' vtable) es         let es_types = map (fmap scriptValueType) es' -        unless (all simpleType es_types) $-          throwError $-            "Literate Futhark does not support passing script-constructed records, tuples, or functions to entry points.\n"-              <> "Create a Futhark wrapper function."+        let cannotApply =+              throwError $+                "Function \""+                  <> name+                  <> "\" expects arguments of types:\n"+                  <> prettyText (V.mkCompound $ map V.ValueAtom in_types)+                  <> "\nBut called with arguments of types:\n"+                  <> prettyText (V.mkCompound $ map V.ValueAtom es_types)          -- Careful to not require saturated application, but do still         -- check for over-saturation.-        let too_many = length es_types > length in_types-            too_wrong = zipWith (/=) es_types (map (V.ValueAtom . STValue) in_types)-        when (or $ too_many : too_wrong) . throwError $-          "Function \"" <> name <> "\" expects arguments of types:\n"-            <> prettyText (V.mkCompound $ map V.ValueAtom in_types)-            <> "\nBut called with arguments of types:\n"-            <> prettyText (V.mkCompound $ map V.ValueAtom es_types)--        ins <- mapM (interValToVar <=< evalExp' vtable) es+        when (length es_types > length in_types) cannotApply+        ins <- zipWithM (interValToVar cannotApply) in_types es'          if length in_types == length ins           then do@@ -374,7 +420,8 @@             pure $ V.mkCompound $ map V.ValueAtom $ zipWith SValue out_types $ map VVar outs           else             pure . V.ValueAtom . SFun name in_types out_types $-              zipWith SValue in_types $ map VVar ins+              zipWith SValue in_types $+                map VVar ins       evalExp' _ (StringLit s) =         case V.putValue s of           Just s' ->@@ -386,7 +433,8 @@         V.ValueTuple <$> mapM (evalExp' vtable) es       evalExp' vtable e@(Record m) = do         when (length (nubOrd (map fst m)) /= length (map fst m)) $-          throwError $ "Record " <> prettyText e <> " has duplicate fields."+          throwError $+            "Record " <> prettyText e <> " has duplicate fields."         V.ValueRecord <$> traverse (evalExp' vtable) (M.fromList m)       evalExp' vtable (Let pat e1 e2) = do         v <- evalExp' vtable e1@@ -412,10 +460,10 @@ -- no well-defined external representation. getExpValue ::   (MonadError T.Text m, MonadIO m) => ScriptServer -> ExpValue -> m V.CompoundValue-getExpValue (ScriptServer server _) e =+getExpValue server e =   traverse toGround =<< traverse (traverse onLeaf) e   where-    onLeaf (VVar v) = readVar server v+    onLeaf (VVar v) = readVar (scriptServer server) v     onLeaf (VVal v) = pure v     toGround (SFun fname _ _ _) =       throwError $ "Function " <> fname <> " not fully applied."@@ -453,5 +501,5 @@ -- | Release all the server-side variables in the value.  Yes, -- FutharkScript has manual memory management... freeValue :: (MonadError T.Text m, MonadIO m) => ScriptServer -> ExpValue -> m ()-freeValue (ScriptServer server _) =-  cmdMaybe . cmdFree server . S.toList . serverVarsInValue+freeValue server =+  cmdMaybe . cmdFree (scriptServer server) . S.toList . serverVarsInValue
src/Futhark/Test.hs view
@@ -272,7 +272,9 @@       pure stdout     ExitFailure e ->       fail $-        "'futhark dataset' failed with exit code " ++ show e ++ " and stderr:\n"+        "'futhark dataset' failed with exit code "+          ++ show e+          ++ " and stderr:\n"           ++ map (chr . fromIntegral) (SBS.unpack stderr)   where     args = "-b" : concatMap argForGen gens@@ -289,7 +291,8 @@     header_size = 1 + 1 + 1 + 4 -- 'b' <version> <num_dims> <type>     genSize (GenValue (V.ValueType ds t)) =       toInteger $-        header_size + length ds * 8+        header_size+          + length ds * 8           + product ds * V.primTypeBytes t     genSize (GenPrim v) =       toInteger $ header_size + product (V.valueShape v) * V.primTypeBytes (V.valueElemType v)@@ -300,11 +303,11 @@ testRunReferenceOutput prog entry tr =   "data"     </> takeBaseName prog-    <> ":"-    <> T.unpack entry-    <> "-"-    <> map clean (runDescription tr)-    <.> "out"+      <> ":"+      <> T.unpack entry+      <> "-"+      <> map clean (runDescription tr)+        <.> "out"   where     clean '/' = '_' -- Would this ever happen?     clean ' ' = '_'@@ -492,7 +495,9 @@       liftIO $ BS.writeFile actualf $ mconcat $ map Bin.encode actual_vs       liftIO $ BS.writeFile expectedf $ mconcat $ map Bin.encode expected_vs       throwError $-        T.pack actualf <> " and " <> T.pack expectedf+        T.pack actualf+          <> " and "+          <> T.pack expectedf           <> " do not match:\n"           <> T.pack (show mismatch)           <> if null mismatches
src/Futhark/Test/Spec.hs view
@@ -212,7 +212,8 @@ parseAction sep =   choice     [ CompileTimeFailure <$> (lexstr' "error:" *> parseExpectedError sep),-      RunCases <$> parseInputOutputs sep+      RunCases+        <$> parseInputOutputs sep         <*> many (parseExpectedStructure sep)         <*> many (parseWarning sep)     ]@@ -373,7 +374,9 @@           cases <- many $ pInputOutputs <* many pNonTestLine           pure spec {testAction = RunCases (old_cases ++ concat cases) structures warnings}       | otherwise ->-          many pNonTestLine *> notFollowedBy "-- ==" *> pure spec+          many pNonTestLine+            *> notFollowedBy "-- =="+            *> pure spec             <?> "no more test blocks, since first test block specifies type error."     Nothing ->       eof $> noTest
src/Futhark/Tools.hs view
@@ -94,7 +94,8 @@    let scanomap = scanomapSOAC scans map_lam   letBindNames (scan_res <> to_red <> map_res) $-    Op $ Screma w arrs scanomap+    Op $+      Screma w arrs scanomap    reduce <- reduceSOAC reds   letBindNames red_res $ Op $ Screma w to_red reduce
src/Futhark/Transform/FirstOrderTransform.hs view
@@ -171,16 +171,21 @@         case paramForAcc arr_t of           Just acc_out_p ->             letBindNames [paramName p] . BasicOp $-              SubExp $ Var $ paramName acc_out_p+              SubExp $+                Var $+                  paramName acc_out_p           Nothing             | paramName p `nameIn` lam_cons -> do                 p' <-                   letExp (baseString (paramName p)) . BasicOp $-                    Index arr $ fullSlice arr_t [DimFix $ Var i]+                    Index arr $+                      fullSlice arr_t [DimFix $ Var i]                 letBindNames [paramName p] $ BasicOp $ Copy p'             | otherwise ->                 letBindNames [paramName p] $-                  BasicOp $ Index arr $ fullSlice arr_t [DimFix $ Var i]+                  BasicOp $+                    Index arr $+                      fullSlice arr_t [DimFix $ Var i]        -- Insert the statements of the lambda.  We have taken care to       -- ensure that the parameters are bound at this point.@@ -188,7 +193,8 @@       -- Split into scan results, reduce results, and map results.       let (scan_res, red_res, map_res) =             splitAt3 (length scan_nes) (length red_nes) $-              bodyResult $ lambdaBody map_lam+              bodyResult $+                lambdaBody map_lam        scan_res' <-         eLambda scan_lam $@@ -202,12 +208,14 @@       -- Write the scan accumulator to the scan result arrays.       scan_outarrs <-         certifying (foldMap resCerts scan_res) $-          letwith (map paramName scanout_params) (Var i) $ map resSubExp scan_res'+          letwith (map paramName scanout_params) (Var i) $+            map resSubExp scan_res'        -- Write the map results to the map result arrays.       map_outarrs <-         certifying (foldMap resCerts map_res) $-          letwith (map paramName mapout_params) (Var i) $ map resSubExp map_res+          letwith (map paramName mapout_params) (Var i) $+            map resSubExp map_res        pure . mkBody mempty . concat $         [ scan_res',@@ -255,8 +263,8 @@    let loop_form = ForLoop i Int64 w [] -  letBindNames [paramName chunk_size_param] $-    BasicOp $ SubExp $ intConst Int64 1+  letBindNames [paramName chunk_size_param] . BasicOp . SubExp $+    intConst Int64 1    loop_body <- runBodyBuilder $     localScope (scopeOf loop_form <> scopeOfFParams merge_params) $ do@@ -267,11 +275,13 @@        (res, mapout_res) <- splitAt (length nes) <$> bodyBind (lambdaBody lam) +      res' <- mapM (copyIfArray . resSubExp) res+       mapout_res' <- forM (zip mapout_params mapout_res) $ \(p, SubExpRes cs se) ->         certifying cs . letSubExp "mapout_res" . BasicOp $           Update Unsafe (paramName p) (fullSlice (paramType p) slice) se -      mkBodyM mempty $ res ++ subExpsRes mapout_res'+      mkBodyM mempty $ subExpsRes $ res' ++ mapout_res'    letBind pat $ DoLoop merge loop_form loop_body transformSOAC pat (Scatter len ivs lam as) = do@@ -296,7 +306,8 @@         arr_t <- lookupType arr         let saveInArray arr' (indexCur, SubExpRes value_cs valueCur) =               certifying (foldMap resCerts indexCur <> value_cs) . letExp "write_out" $-                BasicOp $ Update Safe arr' (fullSlice arr_t $ map (DimFix . resSubExp) indexCur) valueCur+                BasicOp $+                  Update Safe arr' (fullSlice arr_t $ map (DimFix . resSubExp) indexCur) valueCur          foldM saveInArray arr indexes'       pure $ resultBody (map Var ress)@@ -348,7 +359,8 @@           hist' <- forM (zip hist h_val') $ \(arr, SubExpRes cs v) -> do             arr_t <- lookupType arr             certifying cs . letInPlace "hist_out" arr (fullSlice arr_t $ map DimFix idxs) $-              BasicOp $ SubExp v+              BasicOp $+                SubExp v            pure $ varsRes hist' 
src/Futhark/Util.hs view
@@ -20,7 +20,6 @@     dropAt,     takeLast,     dropLast,-    debug,     mapEither,     maybeNth,     maybeHead,@@ -72,7 +71,6 @@ import Control.Concurrent import Control.Exception import Control.Monad-import Control.Monad.IO.Class (MonadIO, liftIO) import Crypto.Hash.MD5 as MD5 import qualified Data.ByteString as BS import qualified Data.ByteString.Base16 as Base16@@ -99,7 +97,6 @@ import System.IO (hIsTerminalDevice, stdout) import System.IO.Error (isDoesNotExistError) import System.IO.Unsafe-import System.Log.Logger (debugM) import System.Process.ByteString import Text.Read (readMaybe) @@ -515,10 +512,10 @@  encodeAsUnicodeCharar :: Char -> EncodedString encodeAsUnicodeCharar c =-  'z' :-  if isDigit (head hex_str)-    then hex_str-    else '0' : hex_str+  'z'+    : if isDigit (head hex_str)+      then hex_str+      else '0' : hex_str   where     hex_str = showHex (ord c) "U" @@ -546,7 +543,3 @@ fixPoint f x =   let x' = f x    in if x' == x then x else fixPoint f x'---- | Issue a debugging statement to the log.-debug :: MonadIO m => String -> m ()-debug msg = liftIO $ debugM "futhark" msg
src/Language/Futhark.hs view
@@ -2,6 +2,7 @@ module Language.Futhark   ( module Language.Futhark.Syntax,     module Language.Futhark.Prop,+    module Language.Futhark.FreeVars,     module Language.Futhark.Pretty,     Ident,     DimIndex,@@ -26,6 +27,7 @@   ) where +import Language.Futhark.FreeVars import Language.Futhark.Pretty import Language.Futhark.Prop import Language.Futhark.Syntax@@ -79,7 +81,7 @@ type Prog = ProgBase Info VName  -- | A known type arg with shape annotations.-type StructTypeArg = TypeArg (DimDecl VName)+type StructTypeArg = TypeArg Size  -- | A type-checked type parameter. type TypeParam = TypeParamBase VName
src/Language/Futhark/Core.hs view
@@ -30,9 +30,6 @@     quote,     pquote, -    -- * Special identifiers-    defaultEntryPoint,-     -- * Number re-export     Int8,     Int16,@@ -76,10 +73,6 @@   ppr Unique = star   ppr Nonunique = empty --- | The name of the default program entry point (main).-defaultEntryPoint :: Name-defaultEntryPoint = nameFromString "main"- -- | The abstract (not really) type representing names in the Futhark -- compiler.  'String's, being lists of characters, are very slow, -- while 'T.Text's are based on byte-arrays.@@ -156,8 +149,8 @@     -- beyond that would require a truly perverse program.     f i x =       (if cur == i then "-> " else "   ")-        ++ '#' :-      show i+        ++ '#'+        : show i         ++ (if i > 9 then "" else " ")         ++ " "         ++ x
+ src/Language/Futhark/FreeVars.hs view
@@ -0,0 +1,164 @@+-- | Facilities for computing free term variables in various syntactic+-- constructs.+module Language.Futhark.FreeVars+  ( freeInExp,+    freeInPat,+    freeInType,+    freeWithout,+    FV (..),+  )+where++import qualified Data.Map.Strict as M+import qualified Data.Set as S+import Futhark.IR.Pretty ()+import Language.Futhark.Prop+import Language.Futhark.Syntax++-- | A set of names where we also track their type.+newtype FV = FV {unFV :: M.Map VName StructType}+  deriving (Show)++instance Semigroup FV where+  FV x <> FV y = FV $ M.unionWith max x y++instance Monoid FV where+  mempty = FV mempty++-- | Set subtraction.  Do not consider those variables as free.+freeWithout :: FV -> S.Set VName -> FV+freeWithout (FV x) y = FV $ M.filterWithKey keep x+  where+    keep k _ = k `S.notMember` y++ident :: IdentBase Info VName -> FV+ident v = FV $ M.singleton (identName v) (toStruct $ unInfo (identType v))++size :: VName -> FV+size v = FV $ M.singleton v $ Scalar $ Prim $ Signed Int64++-- | A 'FV' with these names, considered to be sizes.+sizes :: S.Set VName -> FV+sizes = foldMap size++-- | Compute the set of free variables of an expression.+freeInExp :: ExpBase Info VName -> FV+freeInExp expr = case expr of+  Literal {} -> mempty+  IntLit {} -> mempty+  FloatLit {} -> mempty+  StringLit {} -> mempty+  Hole {} -> mempty+  Parens e _ -> freeInExp e+  QualParens _ e _ -> freeInExp e+  TupLit es _ -> foldMap freeInExp es+  RecordLit fs _ -> foldMap freeInExpField fs+    where+      freeInExpField (RecordFieldExplicit _ e _) = freeInExp e+      freeInExpField (RecordFieldImplicit vn t _) = ident $ Ident vn t mempty+  ArrayLit es t _ ->+    foldMap freeInExp es <> sizes (freeInType $ unInfo t)+  AppExp (Range e me incl _) _ ->+    freeInExp e <> foldMap freeInExp me <> foldMap freeInExp incl+  Var qn (Info t) _ -> FV $ M.singleton (qualLeaf qn) $ toStruct t+  Ascript e _ _ -> freeInExp e+  AppExp (Coerce e _ _) (Info ar) ->+    freeInExp e <> sizes (freeInType (appResType ar))+  AppExp (LetPat let_sizes pat e1 e2 _) _ ->+    freeInExp e1+      <> ( (sizes (freeInPat pat) <> freeInExp e2)+             `freeWithout` (patNames pat <> S.fromList (map sizeName let_sizes))+         )+  AppExp (LetFun vn (tparams, pats, _, _, e1) e2 _) _ ->+    ( (freeInExp e1 <> sizes (foldMap freeInPat pats))+        `freeWithout` ( foldMap patNames pats+                          <> S.fromList (map typeParamName tparams)+                      )+    )+      <> (freeInExp e2 `freeWithout` S.singleton vn)+  AppExp (If e1 e2 e3 _) _ -> freeInExp e1 <> freeInExp e2 <> freeInExp e3+  AppExp (Apply e1 e2 _ _) _ -> freeInExp e1 <> freeInExp e2+  Negate e _ -> freeInExp e+  Not e _ -> freeInExp e+  Lambda pats e0 _ (Info (_, RetType dims t)) _ ->+    (sizes (foldMap freeInPat pats) <> freeInExp e0 <> sizes (freeInType t))+      `freeWithout` (foldMap patNames pats <> S.fromList dims)+  OpSection {} -> mempty+  OpSectionLeft _ _ e _ _ _ -> freeInExp e+  OpSectionRight _ _ e _ _ _ -> freeInExp e+  ProjectSection {} -> mempty+  IndexSection idxs _ _ -> foldMap freeInDimIndex idxs+  AppExp (DoLoop sparams pat e1 form e3 _) _ ->+    let (e2fv, e2ident) = formVars form+     in freeInExp e1+          <> ( (e2fv <> freeInExp e3)+                 `freeWithout` (S.fromList sparams <> patNames pat <> e2ident)+             )+    where+      formVars (For v e2) = (freeInExp e2, S.singleton $ identName v)+      formVars (ForIn p e2) = (freeInExp e2, patNames p)+      formVars (While e2) = (freeInExp e2, mempty)+  AppExp (BinOp (qn, _) (Info qn_t) (e1, _) (e2, _) _) _ ->+    FV (M.singleton (qualLeaf qn) $ toStruct qn_t)+      <> freeInExp e1+      <> freeInExp e2+  Project _ e _ _ -> freeInExp e+  AppExp (LetWith id1 id2 idxs e1 e2 _) _ ->+    ident id2+      <> foldMap freeInDimIndex idxs+      <> freeInExp e1+      <> (freeInExp e2 `freeWithout` S.singleton (identName id1))+  AppExp (Index e idxs _) _ -> freeInExp e <> foldMap freeInDimIndex idxs+  Update e1 idxs e2 _ -> freeInExp e1 <> foldMap freeInDimIndex idxs <> freeInExp e2+  RecordUpdate e1 _ e2 _ _ -> freeInExp e1 <> freeInExp e2+  Assert e1 e2 _ _ -> freeInExp e1 <> freeInExp e2+  Constr _ es _ _ -> foldMap freeInExp es+  Attr _ e _ -> freeInExp e+  AppExp (Match e cs _) _ -> freeInExp e <> foldMap caseFV cs+    where+      caseFV (CasePat p eCase _) =+        (sizes (freeInPat p) <> freeInExp eCase)+          `freeWithout` patNames p++freeInDimIndex :: DimIndexBase Info VName -> FV+freeInDimIndex (DimFix e) = freeInExp e+freeInDimIndex (DimSlice me1 me2 me3) =+  foldMap (foldMap freeInExp) [me1, me2, me3]++-- | Free variables in pattern (including types of the bound identifiers).+freeInPat :: PatBase Info VName -> S.Set VName+freeInPat (TuplePat ps _) = foldMap freeInPat ps+freeInPat (RecordPat fs _) = foldMap (freeInPat . snd) fs+freeInPat (PatParens p _) = freeInPat p+freeInPat (Id _ (Info tp) _) = freeInType tp+freeInPat (Wildcard (Info tp) _) = freeInType tp+freeInPat (PatAscription p _ _) = freeInPat p+freeInPat (PatLit _ (Info tp) _) = freeInType tp+freeInPat (PatConstr _ _ ps _) = foldMap freeInPat ps+freeInPat (PatAttr _ p _) = freeInPat p++-- | Free variables in the type (meaning those that are used in size expression).+freeInType :: TypeBase Size as -> S.Set VName+freeInType t =+  case t of+    Array _ _ s a ->+      freeInType (Scalar a) <> foldMap onSize (shapeDims s)+    Scalar (Record fs) ->+      foldMap freeInType fs+    Scalar Prim {} ->+      mempty+    Scalar (Sum cs) ->+      foldMap (foldMap freeInType) cs+    Scalar (Arrow _ v t1 (RetType dims t2)) ->+      S.filter (notV v) $ S.filter (`notElem` dims) $ freeInType t1 <> freeInType t2+    Scalar (TypeVar _ _ _ targs) ->+      foldMap typeArgDims targs+  where+    typeArgDims (TypeArgDim d _) = onSize d+    typeArgDims (TypeArgType at _) = freeInType at++    notV Unnamed = const True+    notV (Named v) = (/= v)++    onSize (NamedSize qn) = S.singleton $ qualLeaf qn+    onSize _ = mempty
src/Language/Futhark/Interpreter.hs view
@@ -45,13 +45,13 @@ import qualified Data.Map as M import Data.Maybe import Data.Monoid hiding (Sum)-import Futhark.IR.Primitive (floatValue, intValue)-import qualified Futhark.IR.Primitive as P import Futhark.Util (chunk, maybeHead, splitFromEnd) import Futhark.Util.Loc import Futhark.Util.Pretty hiding (apply, bool)-import Language.Futhark hiding (Value, matchDims)+import Language.Futhark hiding (Shape, Value, matchDims) import qualified Language.Futhark as F+import Language.Futhark.Primitive (floatValue, intValue)+import qualified Language.Futhark.Primitive as P import qualified Language.Futhark.Semantic as T import Prelude hiding (break, mod) @@ -140,7 +140,7 @@     field (k, v) = ppr k <+> equals <+> ppr v  valueStructType :: ValueType -> StructType-valueStructType = first (ConstDim . fromIntegral)+valueStructType = first (ConstSize . fromIntegral)  -- | A shape is a tree to accomodate the case of records.  It is -- parameterised over the representation of dimensions.@@ -177,7 +177,7 @@       ShapeRecord $ M.map go fs     go (Scalar (Sum cs)) =       ShapeSum $ M.map (map go) cs-    go (Scalar (TypeVar _ _ (TypeName [] v) []))+    go (Scalar (TypeVar _ _ (QualName [] v) []))       | Just shape <- M.lookup v shapes =           shape     go _ =@@ -186,16 +186,16 @@ structTypeShape :: M.Map VName ValueShape -> StructType -> Shape (Maybe Int64) structTypeShape shapes = fmap dim . typeShape shapes'   where-    dim (ConstDim d) = Just $ fromIntegral d+    dim (ConstSize d) = Just $ fromIntegral d     dim _ = Nothing-    shapes' = M.map (fmap $ ConstDim . fromIntegral) shapes+    shapes' = M.map (fmap $ ConstSize . fromIntegral) shapes  resolveTypeParams :: [VName] -> StructType -> StructType -> Env resolveTypeParams names = match   where     match (Scalar (TypeVar _ _ tn _)) t-      | typeLeaf tn `elem` names =-          typeEnv $ M.singleton (typeLeaf tn) t+      | qualLeaf tn `elem` names =+          typeEnv $ M.singleton (qualLeaf tn) t     match (Scalar (Record poly_fields)) (Scalar (Record fields)) =       mconcat $         M.elems $@@ -215,7 +215,7 @@           matchDims d1 d2 <> match (stripArray 1 poly_t) (stripArray 1 t)     match _ _ = mempty -    matchDims (NamedDim (QualName _ d1)) (ConstDim d2)+    matchDims (NamedSize (QualName _ d1)) (ConstSize d2)       | d1 `elem` names =           i64Env $ M.singleton d1 $ fromIntegral d2     matchDims _ _ = mempty@@ -237,7 +237,7 @@           matchDims d1 d2 <> match (stripArray 1 poly_t) rowshape     match _ _ = mempty -    matchDims (NamedDim (QualName _ d1)) d2+    matchDims (NamedSize (QualName _ d1)) d2       | d1 `elem` names = M.singleton d1 d2     matchDims _ _ = mempty @@ -549,12 +549,14 @@ instance Pretty Indexing where   ppr (IndexingFix i) = ppr i   ppr (IndexingSlice i j (Just s)) =-    maybe mempty ppr i <> text ":"+    maybe mempty ppr i+      <> text ":"       <> maybe mempty ppr j       <> text ":"       <> ppr s   ppr (IndexingSlice i (Just j) s) =-    maybe mempty ppr i <> text ":"+    maybe mempty ppr i+      <> text ":"       <> ppr j       <> maybe mempty ((text ":" <>) . ppr) s   ppr (IndexingSlice i Nothing Nothing) =@@ -663,7 +665,8 @@ evalDimIndex env (DimFix x) =   IndexingFix . asInt64 <$> eval env x evalDimIndex env (DimSlice start end stride) =-  IndexingSlice <$> traverse (fmap asInt64 . eval env) start+  IndexingSlice+    <$> traverse (fmap asInt64 . eval env) start     <*> traverse (fmap asInt64 . eval env) end     <*> traverse (fmap asInt64 . eval env) stride @@ -671,7 +674,8 @@ evalIndex loc env is arr = do   let oob =         bad loc env $-          "Index [" <> intercalate ", " (map pretty is)+          "Index ["+            <> intercalate ", " (map pretty is)             <> "] out of bounds for array of shape "             <> pretty (valueShape arr)             <> "."@@ -690,26 +694,26 @@       shape' = fmap evalDim shape    in arrayOf u shape' et'   where-    evalDim (NamedDim qn)+    evalDim (NamedSize qn)       | Just (TermValue _ (ValuePrim (SignedValue (Int64Value x)))) <-           lookupVar qn env =-          ConstDim $ fromIntegral x+          ConstSize $ fromIntegral x     evalDim d = d evalType env t@(Scalar (TypeVar () _ tn args)) =-  case lookupType (qualNameFromTypeName tn) env of+  case lookupType tn env of     Just (T.TypeAbbr _ ps (RetType _ t')) ->       let (substs, types) = mconcat $ zipWith matchPtoA ps args-          onDim (NamedDim v) = fromMaybe (NamedDim v) $ M.lookup (qualLeaf v) substs+          onDim (NamedSize v) = fromMaybe (NamedSize v) $ M.lookup (qualLeaf v) substs           onDim d = d        in if null ps             then first onDim t'             else evalType (Env mempty types mempty <> env) $ first onDim t'     Nothing -> t   where-    matchPtoA (TypeParamDim p _) (TypeArgDim (NamedDim qv) _) =-      (M.singleton p $ NamedDim qv, mempty)-    matchPtoA (TypeParamDim p _) (TypeArgDim (ConstDim k) _) =-      (M.singleton p $ ConstDim k, mempty)+    matchPtoA (TypeParamDim p _) (TypeArgDim (NamedSize qv) _) =+      (M.singleton p $ NamedSize qv, mempty)+    matchPtoA (TypeParamDim p _) (TypeArgDim (ConstSize k) _) =+      (M.singleton p $ ConstSize k, mempty)     matchPtoA (TypeParamType l p _) (TypeArgType t' _) =       let t'' = evalType env t'        in (mempty, M.singleton p $ T.TypeAbbr l [] $ RetType [] t'')@@ -733,7 +737,7 @@     Nothing -> error $ "typeValueShape: failed to fully evaluate type " ++ pretty t'     Just shape -> pure shape   where-    dim (ConstDim x) = Just $ fromIntegral x+    dim (ConstSize x) = Just $ fromIntegral x     dim _ = Nothing  evalFunction :: Env -> [VName] -> [Pat] -> Exp -> StructType -> EvalM Value@@ -808,12 +812,13 @@     Nothing -> pure ()   pure v -returned :: Env -> TypeBase (DimDecl VName) als -> [VName] -> Value -> EvalM Value+returned :: Env -> TypeBase Size als -> [VName] -> Value -> EvalM Value returned _ _ [] v = pure v returned env ret retext v = do   mapM_ (uncurry putExtSize) $     M.toList $-      resolveExistentials retext (evalType env $ toStruct ret) $ valueShape v+      resolveExistentials retext (evalType env $ toStruct ret) $+        valueShape v   pure v  evalAppExp :: Env -> StructType -> AppExp -> EvalM Value@@ -853,7 +858,8 @@         t -> error $ "Nonsensical range type: " ++ show t      badRange start' maybe_second' end' =-      "Range " ++ pretty start'+      "Range "+        ++ pretty start'         ++ ( case maybe_second' of                Nothing -> ""                Just second' -> ".." ++ pretty second'@@ -870,12 +876,13 @@     Just _ -> pure v     Nothing ->       bad loc env $-        "Value `" <> pretty v <> "` of shape `" ++ pretty (valueShape v)+        "Value `" <> pretty v <> "` of shape `"+          ++ pretty (valueShape v)           ++ "` cannot match shape of type `"-          <> pretty te-          <> "` (`"-          <> pretty t-          <> "`)"+            <> pretty te+            <> "` (`"+            <> pretty t+            <> "`)" evalAppExp env _ (LetPat sizes p e body _) = do   v <- eval env e   env' <- matchPat env p v@@ -922,9 +929,10 @@   let Ident src_vn (Info src_t) _ = src   dest' <-     maybe oob pure-      =<< writeArray <$> mapM (evalDimIndex env) is-      <*> evalTermVar env (qualName src_vn) (toStruct src_t)-      <*> eval env v+      =<< writeArray+        <$> mapM (evalDimIndex env) is+        <*> evalTermVar env (qualName src_vn) (toStruct src_t)+        <*> eval env v   let t = T.BoundV [] $ toStruct $ unInfo $ identType dest   eval (valEnv (M.singleton (identName dest) (Just t, dest')) <> env) body   where@@ -1165,9 +1173,9 @@     onTerm (TermPoly t v) = TermPoly t v     onTerm (TermModule m) = TermModule $ onModule m     onType (T.TypeAbbr l ps t) = T.TypeAbbr l ps $ first onDim t-    onDim (NamedDim v) = NamedDim $ replaceQ v-    onDim (ConstDim x) = ConstDim x-    onDim (AnyDim v) = AnyDim v+    onDim (NamedSize v) = NamedSize $ replaceQ v+    onDim (ConstSize x) = ConstSize x+    onDim (AnySize v) = AnySize v  evalModuleVar :: Env -> QualName VName -> EvalM Module evalModuleVar env qv =@@ -1522,27 +1530,31 @@     def "<" =       Just $         bopDef $-          sintCmp P.CmpSlt ++ uintCmp P.CmpUlt+          sintCmp P.CmpSlt+            ++ uintCmp P.CmpUlt             ++ floatCmp P.FCmpLt             ++ boolCmp P.CmpLlt     def ">" =       Just $         bopDef $           flipCmps $-            sintCmp P.CmpSlt ++ uintCmp P.CmpUlt+            sintCmp P.CmpSlt+              ++ uintCmp P.CmpUlt               ++ floatCmp P.FCmpLt               ++ boolCmp P.CmpLlt     def "<=" =       Just $         bopDef $-          sintCmp P.CmpSle ++ uintCmp P.CmpUle+          sintCmp P.CmpSle+            ++ uintCmp P.CmpUle             ++ floatCmp P.FCmpLe             ++ boolCmp P.CmpLle     def ">=" =       Just $         bopDef $           flipCmps $-            sintCmp P.CmpSle ++ uintCmp P.CmpUle+            sintCmp P.CmpSle+              ++ uintCmp P.CmpUle               ++ floatCmp P.FCmpLe               ++ boolCmp P.CmpLle     def s@@ -1892,7 +1904,8 @@             ShapeDim _ ys_rowshape = valueShape ys         pure $           toArray' (ShapeRecord (tupleFields [xs_rowshape, ys_rowshape])) $-            map toTuple $ transpose [snd $ fromArray xs, snd $ fromArray ys]+            map toTuple $+              transpose [snd $ fromArray xs, snd $ fromArray ys]     def "concat" = Just $       fun2t $ \xs ys -> do         let (ShapeDim _ rowshape, xs') = fromArray xs@@ -1903,7 +1916,9 @@         let (ShapeDim n (ShapeDim m shape), xs') = fromArray xs         pure $           toArray (ShapeDim m (ShapeDim n shape)) $-            map (toArray (ShapeDim n shape)) $ transpose $ map (snd . fromArray) xs'+            map (toArray (ShapeDim n shape)) $+              transpose $+                map (snd . fromArray) xs'     def "rotate" = Just $       fun2t $ \i xs -> do         let (shape, xs') = fromArray xs@@ -1928,7 +1943,8 @@         if asInt64 n * asInt64 m /= xs_size           then             bad mempty mempty $-              "Cannot unflatten array of shape [" <> pretty xs_size+              "Cannot unflatten array of shape ["+                <> pretty xs_size                 <> "] to array of shape ["                 <> pretty (asInt64 n)                 <> "]["@@ -1936,9 +1952,11 @@                 <> "]"           else pure $ toArray shape $ map (toArray rowshape) $ chunk (asInt m) xs'     def "vjp2" = Just $-      fun3t $ \_ _ _ -> bad noLoc mempty "Interpreter does not support autodiff."+      fun3t $+        \_ _ _ -> bad noLoc mempty "Interpreter does not support autodiff."     def "jvp2" = Just $-      fun3t $ \_ _ _ -> bad noLoc mempty "Interpreter does not support autodiff."+      fun3t $+        \_ _ _ -> bad noLoc mempty "Interpreter does not support autodiff."     def "acc" = Nothing     def s | nameFromString s `M.member` namesToPrimTypes = Nothing     def s = error $ "Missing intrinsic: " ++ s@@ -2037,8 +2055,10 @@     badPrim vt pt =       Left . pretty $         "Invalid argument type."-          </> "Expected:" <+> align (ppr pt)-          </> "Got:     " <+> align (ppr vt)+          </> "Expected:"+          <+> align (ppr pt)+          </> "Got:     "+          <+> align (ppr vt)      convertValue (F.PrimValue p) = Just $ ValuePrim p     convertValue (F.ArrayValue arr t) = mkArray t =<< mapM convertValue (elems arr)
src/Language/Futhark/Parser/Monad.hs view
@@ -91,7 +91,7 @@     "Only the keyword '" <> expected <> "' may appear here."  mustBeEmpty :: Located loc => loc -> ValueType -> ParserMonad ()-mustBeEmpty _ (Array _ _ (ShapeDecl dims) _)+mustBeEmpty _ (Array _ _ (Shape dims) _)   | 0 `elem` dims = pure () mustBeEmpty loc t =   parseErrorAt loc $ Just $ pretty t ++ " is not an empty array."@@ -139,7 +139,9 @@       | valueType x == valueType y = Right x       | otherwise =           Left . SyntaxError NoLoc $-            "Elements " <> pretty x <> " and "+            "Elements "+              <> pretty x+              <> " and "               <> pretty y               <> " cannot exist in same array." @@ -155,7 +157,8 @@     op (AppExp (Index e is floc) _) (ArrayLit xs _ xloc) =       parseErrorAt (srcspan floc xloc) . Just . pretty $         "Incorrect syntax for multi-dimensional indexing."-          </> "Use" <+> align (ppr index)+          </> "Use"+          <+> align (ppr index)       where         index = AppExp (Index e (is ++ map DimFix xs) xloc) NoInfo     op f x =
src/Language/Futhark/Parser/Parser.y view
@@ -457,12 +457,12 @@ TypeExpTerm :: { UncheckedTypeExp }          : '*' TypeExpTerm            { TEUnique $2 (srcspan $1 $>) }-         | '[' DimExp ']' TypeExpTerm %prec indexprec+         | '[' SizeExp ']' TypeExpTerm %prec indexprec            { TEArray $2 $4 (srcspan $1 $>) }          | TypeExpApply %prec sumprec { $1 }           -- Errors-         | '[' DimExp ']' %prec bottom+         | '[' SizeExp ']' %prec bottom            {% parseErrorAt (srcspan $1 $>) $ Just $                 unlines ["missing array row type.",                          "Did you mean []"  ++ pretty $2 ++ "?"]@@ -487,12 +487,12 @@ TypeExpApply :: { UncheckedTypeExp }               : TypeExpApply TypeArg                 { TEApply $1 $2 (srcspan $1 $>) }-              | 'id[' DimExp ']'+              | 'id[' SizeExp ']'                 { let L loc (INDEXING v) = $1                   in TEApply (TEVar (qualName v) (srclocOf (backOneCol loc)))                              (TypeArgExpDim $2 (srclocOf loc))                              (srcspan $1 $>) }-              | 'qid[' DimExp ']'+              | 'qid[' SizeExp ']'                 { let L loc (QUALINDEXING qs v) = $1                   in TEApply (TEVar (QualName qs v) (srclocOf (backOneCol loc)))                              (TypeArgExpDim $2 (srclocOf loc))@@ -513,7 +513,7 @@         : constructor { let L _ (CONSTRUCTOR c) = $1 in (c, locOf $1) }  TypeArg :: { TypeArgExp Name }-         : '[' DimExp ']' { TypeArgExpDim $2 (srcspan $1 $>) }+         : '[' SizeExp ']' { TypeArgExpDim $2 (srcspan $1 $>) }          | TypeExpAtom     { TypeArgExpType $1 }  FieldType :: { (Name, UncheckedTypeExp) }@@ -527,14 +527,14 @@             : TypeExp                { [$1] }             | TypeExp ',' TupleTypes { $1 : $3 } -DimExp :: { DimExp Name }+SizeExp :: { SizeExp Name }         : QualName-          { DimExpNamed (fst $1) (srclocOf (snd $1)) }+          { SizeExpNamed (fst $1) (srclocOf (snd $1)) }         | intlit           { let L loc (INTLIT n) = $1-            in DimExpConst (fromIntegral n) (srclocOf loc) }+            in SizeExpConst (fromIntegral n) (srclocOf loc) }         |-          { DimExpAny }+          { SizeExpAny }  FunParam :: { PatBase NoInfo Name } FunParam : InnerPat { $1 }@@ -1000,13 +1000,13 @@ ArrayValue :: { Value } ArrayValue :  '[' Value ']'              {% pure $ ArrayValue (arrayFromList [$2]) $-                arrayOf Unique (ShapeDecl [1]) (valueType $2)+                arrayOf Unique (Shape [1]) (valueType $2)              }            |  '[' Value ',' Values ']'              {% case combArrayElements $2 $4 of                   Left e -> throwError e                   Right v -> pure $ ArrayValue (arrayFromList $ $2:$4) $-                             arrayOf Unique (ShapeDecl [1+fromIntegral (length $4)]) (valueType v)+                             arrayOf Unique (Shape [1+fromIntegral (length $4)]) (valueType v)              }            | id '(' ValueType ')'              {% ($1 `mustBe` "empty") >> mustBeEmpty (srcspan $2 $4) $3 >> pure (ArrayValue (listArray (0,-1) []) $3) }@@ -1019,8 +1019,8 @@ Dim : intlit { let L _ (INTLIT num) = $1 in fromInteger num }  ValueType :: { ValueType }-ValueType : '[' Dim ']' ValueType  { arrayOf Nonunique (ShapeDecl [$2]) $4 }-          | '[' Dim ']' PrimType { arrayOf Nonunique (ShapeDecl [$2]) (Scalar (Prim $4)) }+ValueType : '[' Dim ']' ValueType  { arrayOf Nonunique (Shape [$2]) $4 }+          | '[' Dim ']' PrimType { arrayOf Nonunique (Shape [$2]) (Scalar (Prim $4)) }  Values :: { [Value] } Values : Value ',' Values { $1 : $3 }
src/Language/Futhark/Pretty.hs view
@@ -94,41 +94,41 @@   ppr (BoolValue False) = text "false"   ppr (FloatValue v) = ppr v -instance IsName vn => Pretty (DimDecl vn) where-  ppr (AnyDim Nothing) = mempty-  ppr (AnyDim (Just v)) = text "?" <> pprName v-  ppr (NamedDim v) = ppr v-  ppr (ConstDim n) = ppr n+instance Pretty Size where+  ppr (AnySize Nothing) = mempty+  ppr (AnySize (Just v)) = text "?" <> pprName v+  ppr (NamedSize v) = ppr v+  ppr (ConstSize n) = ppr n -instance IsName vn => Pretty (DimExp vn) where-  ppr DimExpAny = mempty-  ppr (DimExpNamed v _) = ppr v-  ppr (DimExpConst n _) = ppr n+instance IsName vn => Pretty (SizeExp vn) where+  ppr SizeExpAny = mempty+  ppr (SizeExpNamed v _) = ppr v+  ppr (SizeExpConst n _) = ppr n -instance IsName vn => Pretty (ShapeDecl (DimDecl vn)) where-  ppr (ShapeDecl ds) = mconcat (map (brackets . ppr) ds)+instance Pretty (Shape Size) where+  ppr (Shape ds) = mconcat (map (brackets . ppr) ds) -instance Pretty (ShapeDecl ()) where-  ppr (ShapeDecl ds) = mconcat $ replicate (length ds) $ text "[]"+instance Pretty (Shape ()) where+  ppr (Shape ds) = mconcat $ replicate (length ds) $ text "[]" -instance Pretty (ShapeDecl Int64) where-  ppr (ShapeDecl ds) = mconcat (map (brackets . ppr) ds)+instance Pretty (Shape Int64) where+  ppr (Shape ds) = mconcat (map (brackets . ppr) ds) -instance Pretty (ShapeDecl Bool) where-  ppr (ShapeDecl ds) = mconcat (map (brackets . ppr) ds)+instance Pretty (Shape Bool) where+  ppr (Shape ds) = mconcat (map (brackets . ppr) ds) -instance Pretty (ShapeDecl dim) => Pretty (RetTypeBase dim as) where+instance Pretty (Shape dim) => Pretty (RetTypeBase dim as) where   ppr = pprPrec 0   pprPrec p (RetType [] t) = pprPrec p t   pprPrec _ (RetType dims t) =     text "?" <> mconcat (map (brackets . pprName) dims) <> text "." <> ppr t -instance Pretty (ShapeDecl dim) => Pretty (ScalarTypeBase dim as) where+instance Pretty (Shape dim) => Pretty (ScalarTypeBase dim as) where   ppr = pprPrec 0   pprPrec _ (Prim et) = ppr et-  pprPrec p (TypeVar _ u et targs) =+  pprPrec p (TypeVar _ u v targs) =     parensIf (not (null targs) && p > 3) $-      ppr u <> ppr (qualNameFromTypeName et) <+> spread (map (pprPrec 3) targs)+      ppr u <> ppr v <+> spread (map (pprPrec 3) targs)   pprPrec _ (Record fs)     | Just ts <- areTupleFields fs =         oneLine (parens $ commasep $ map ppr ts)@@ -152,14 +152,14 @@       ppConstr (name, fs) = sep $ (text "#" <> ppr name) : map (pprPrec 2) fs       cs' = map ppConstr $ M.toList cs -instance Pretty (ShapeDecl dim) => Pretty (TypeBase dim as) where+instance Pretty (Shape dim) => Pretty (TypeBase dim as) where   ppr = pprPrec 0   pprPrec _ (Array _ u shape at) = ppr u <> ppr shape <> align (pprPrec 1 at)   pprPrec p (Scalar t) = pprPrec p t -instance Pretty (ShapeDecl dim) => Pretty (TypeArg dim) where+instance Pretty (Shape dim) => Pretty (TypeArg dim) where   ppr = pprPrec 0-  pprPrec _ (TypeArgDim d _) = ppr $ ShapeDecl [d]+  pprPrec _ (TypeArgDim d _) = ppr $ Shape [d]   pprPrec p (TypeArgType t _) = pprPrec p t  instance (Eq vn, IsName vn) => Pretty (TypeExp vn) where@@ -201,12 +201,14 @@ instance (Eq vn, IsName vn, Annot f) => Pretty (DimIndexBase f vn) where   ppr (DimFix e) = ppr e   ppr (DimSlice i j (Just s)) =-    maybe mempty ppr i <> text ":"+    maybe mempty ppr i+      <> text ":"       <> maybe mempty ppr j       <> text ":"       <> ppr s   ppr (DimSlice i (Just j) s) =-    maybe mempty ppr i <> text ":"+    maybe mempty ppr i+      <> text ":"       <> ppr j       <> maybe mempty ((text ":" <>) . ppr) s   ppr (DimSlice i Nothing Nothing) =@@ -230,9 +232,11 @@     text "loop"       <+> align         ( spread (map (brackets . pprName) sizeparams)-            <+/> ppr pat <+> equals+            <+/> ppr pat+            <+> equals             <+/> ppr initexp-            <+/> ppr form <+> text "do"+            <+/> ppr form+            <+> text "do"         )       </> indent 2 (ppr loopbody)   pprPrec _ (Index e idxs _) =@@ -240,7 +244,9 @@   pprPrec p (LetPat sizes pat e body _) =     parensIf (p /= -1) $       align $-        text "let" <+> spread (map ppr sizes) <+> align (ppr pat)+        text "let"+          <+> spread (map ppr sizes)+          <+> align (ppr pat)           <+> ( if linebreak                   then equals </> indent 2 (ppr e)                   else equals <+> align (ppr e)@@ -253,8 +259,11 @@         ArrayLit {} -> False         _ -> hasArrayLit e   pprPrec _ (LetFun fname (tparams, params, retdecl, rettype, e) body _) =-    text "let" <+> pprName fname <+> spread (map ppr tparams ++ map ppr params)-      <> retdecl' <+> equals+    text "let"+      <+> pprName fname+      <+> spread (map ppr tparams ++ map ppr params)+        <> retdecl'+      <+> equals       </> indent 2 (ppr e)       </> letBody body     where@@ -263,12 +272,16 @@         Nothing -> mempty   pprPrec _ (LetWith dest src idxs ve body _)     | dest == src =-        text "let" <+> ppr dest <> list (map ppr idxs)+        text "let"+          <+> ppr dest <> list (map ppr idxs)           <+> equals           <+> align (ppr ve)           </> letBody body     | otherwise =-        text "let" <+> ppr dest <+> equals <+> ppr src+        text "let"+          <+> ppr dest+          <+> equals+          <+> ppr src           <+> text "with"           <+> brackets (commasep (map ppr idxs))           <+> text "="@@ -283,9 +296,12 @@           ToInclusive end' -> text "..." <> ppr end'           UpToExclusive end' -> text "..<" <> ppr end'   pprPrec _ (If c t f _) =-    text "if" <+> ppr c-      </> text "then" <+> align (ppr t)-      </> text "else" <+> align (ppr f)+    text "if"+      <+> ppr c+      </> text "then"+      <+> align (ppr t)+      </> text "else"+      <+> align (ppr f)   pprPrec p (Apply f arg _ _) =     parensIf (p >= 10) $ pprPrec 0 f <+/> pprPrec 10 arg @@ -335,12 +351,14 @@   pprPrec _ (Negate e _) = text "-" <> ppr e   pprPrec _ (Not e _) = text "-" <> ppr e   pprPrec _ (Update src idxs ve _) =-    ppr src <+> text "with"+    ppr src+      <+> text "with"       <+> brackets (commasep (map ppr idxs))       <+> text "="       <+> align (ppr ve)   pprPrec _ (RecordUpdate src fs ve _ _) =-    ppr src <+> text "with"+    ppr src+      <+> text "with"       <+> mconcat (intersperse (text ".") (map ppr fs))       <+> text "="       <+> align (ppr ve)@@ -348,7 +366,8 @@   pprPrec p (Lambda params body rettype _ _) =     parensIf (p /= -1) $       text "\\" <> spread (map ppr params) <> ppAscription rettype-        <+> text "->" </> indent 2 (ppr body)+        <+> text "->"+        </> indent 2 (ppr body)   pprPrec _ (OpSection binop _ _) =     parens $ ppr binop   pprPrec _ (OpSectionLeft binop _ x _ _ _) =@@ -436,7 +455,8 @@   ppr (ModAscript me se _ _) = ppr me <> colon <+> ppr se   ppr (ModLambda param maybe_sig body _) =     text "\\" <> ppr param <> maybe_sig'-      <+> text "->" </> indent 2 (ppr body)+      <+> text "->"+      </> indent 2 (ppr body)     where       maybe_sig' = case maybe_sig of         Nothing -> mempty@@ -449,7 +469,8 @@  instance (Eq vn, IsName vn, Annot f) => Pretty (TypeBindBase f vn) where   ppr (TypeBind name l params te rt _ _) =-    text "type" <> ppr l <+> pprName name+    text "type" <> ppr l+      <+> pprName name       <+> spread (map ppr params)       <+> equals       <+> maybe (ppr te) ppr (unAnnot rt)@@ -464,8 +485,8 @@       <> text fun       <+> pprName name       <+> align (sep (map ppr tparams ++ map ppr args))-      <> retdecl'-      <> text " ="+        <> retdecl'+        <> text " ="       </> indent 2 (ppr body)     where       fun
+ src/Language/Futhark/Primitive.hs view
@@ -0,0 +1,1873 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}++-- | Definitions of primitive types, the values that inhabit these+-- types, and operations on these values.  A primitive value can also+-- be called a scalar.+--+-- This module diverges from the actual Futhark language in that it+-- does not distinguish signed and unsigned types.  Further, we allow+-- a "unit" type that is only indirectly present in source Futhark in+-- the form of empty tuples.+module Language.Futhark.Primitive+  ( -- * Types+    IntType (..),+    allIntTypes,+    FloatType (..),+    allFloatTypes,+    PrimType (..),+    allPrimTypes,+    module Data.Int,+    module Data.Word,+    Half,++    -- * Values+    IntValue (..),+    intValue,+    intValueType,+    valueIntegral,+    FloatValue (..),+    floatValue,+    floatValueType,+    PrimValue (..),+    primValueType,+    blankPrimValue,++    -- * Operations+    Overflow (..),+    Safety (..),+    UnOp (..),+    allUnOps,+    BinOp (..),+    allBinOps,+    ConvOp (..),+    allConvOps,+    CmpOp (..),+    allCmpOps,++    -- ** Unary Operations+    doUnOp,+    doComplement,+    doAbs,+    doFAbs,+    doSSignum,+    doUSignum,++    -- ** Binary Operations+    doBinOp,+    doAdd,+    doMul,+    doSDiv,+    doSMod,+    doPow,++    -- ** Conversion Operations+    doConvOp,+    doZExt,+    doSExt,+    doFPConv,+    doFPToUI,+    doFPToSI,+    doUIToFP,+    doSIToFP,+    intToInt64,+    intToWord64,+    flipConvOp,++    -- * Comparison Operations+    doCmpOp,+    doCmpEq,+    doCmpUlt,+    doCmpUle,+    doCmpSlt,+    doCmpSle,+    doFCmpLt,+    doFCmpLe,++    -- * Type Of+    binOpType,+    unOpType,+    cmpOpType,+    convOpType,++    -- * Primitive functions+    primFuns,++    -- * Utility+    zeroIsh,+    zeroIshInt,+    oneIsh,+    oneIshInt,+    negativeIsh,+    primBitSize,+    primByteSize,+    intByteSize,+    floatByteSize,+    commutativeBinOp,+    associativeBinOp,++    -- * Prettyprinting+    convOpFun,+    prettySigned,+  )+where++import Control.Category+import qualified Data.Binary.Get as G+import qualified Data.Binary.Put as P+import Data.Bits+  ( complement,+    countLeadingZeros,+    countTrailingZeros,+    popCount,+    shift,+    shiftR,+    xor,+    (.&.),+    (.|.),+  )+import Data.Fixed (mod') -- Weird location.+import Data.Int (Int16, Int32, Int64, Int8)+import qualified Data.Map as M+import Data.Word (Word16, Word32, Word64, Word8)+import Foreign.C.Types (CUShort (..))+import Futhark.Util+  ( cbrt,+    cbrtf,+    ceilDouble,+    ceilFloat,+    convFloat,+    erf,+    erfc,+    erfcf,+    erff,+    floorDouble,+    floorFloat,+    hypot,+    hypotf,+    lgamma,+    lgammaf,+    roundDouble,+    roundFloat,+    tgamma,+    tgammaf,+  )+import Futhark.Util.Pretty+import Numeric.Half+import Prelude hiding (id, (.))++-- | An integer type, ordered by size.  Note that signedness is not a+-- property of the type, but a property of the operations performed on+-- values of these types.+data IntType+  = Int8+  | Int16+  | Int32+  | Int64+  deriving (Eq, Ord, Show, Enum, Bounded)++instance Pretty IntType where+  ppr Int8 = text "i8"+  ppr Int16 = text "i16"+  ppr Int32 = text "i32"+  ppr Int64 = text "i64"++-- | A list of all integer types.+allIntTypes :: [IntType]+allIntTypes = [minBound .. maxBound]++-- | A floating point type.+data FloatType+  = Float16+  | Float32+  | Float64+  deriving (Eq, Ord, Show, Enum, Bounded)++instance Pretty FloatType where+  ppr Float16 = text "f16"+  ppr Float32 = text "f32"+  ppr Float64 = text "f64"++-- | A list of all floating-point types.+allFloatTypes :: [FloatType]+allFloatTypes = [minBound .. maxBound]++-- | Low-level primitive types.+data PrimType+  = IntType IntType+  | FloatType FloatType+  | Bool+  | -- | An informationless type - An array of this type takes up no space.+    Unit+  deriving (Eq, Ord, Show)++instance Enum PrimType where+  toEnum 0 = IntType Int8+  toEnum 1 = IntType Int16+  toEnum 2 = IntType Int32+  toEnum 3 = IntType Int64+  toEnum 4 = FloatType Float16+  toEnum 5 = FloatType Float32+  toEnum 6 = FloatType Float64+  toEnum 7 = Bool+  toEnum _ = Unit++  fromEnum (IntType Int8) = 0+  fromEnum (IntType Int16) = 1+  fromEnum (IntType Int32) = 2+  fromEnum (IntType Int64) = 3+  fromEnum (FloatType Float16) = 4+  fromEnum (FloatType Float32) = 5+  fromEnum (FloatType Float64) = 6+  fromEnum Bool = 7+  fromEnum Unit = 8++instance Bounded PrimType where+  minBound = IntType Int8+  maxBound = Unit++instance Pretty PrimType where+  ppr (IntType t) = ppr t+  ppr (FloatType t) = ppr t+  ppr Bool = text "bool"+  ppr Unit = text "unit"++-- | A list of all primitive types.+allPrimTypes :: [PrimType]+allPrimTypes =+  map IntType allIntTypes+    ++ map FloatType allFloatTypes+    ++ [Bool, Unit]++-- | An integer value.+data IntValue+  = Int8Value !Int8+  | Int16Value !Int16+  | Int32Value !Int32+  | Int64Value !Int64+  deriving (Eq, Ord, Show)++instance Pretty IntValue where+  ppr (Int8Value v) = text $ show v ++ "i8"+  ppr (Int16Value v) = text $ show v ++ "i16"+  ppr (Int32Value v) = text $ show v ++ "i32"+  ppr (Int64Value v) = text $ show v ++ "i64"++-- | Create an t'IntValue' from a type and an 'Integer'.+intValue :: Integral int => IntType -> int -> IntValue+intValue Int8 = Int8Value . fromIntegral+intValue Int16 = Int16Value . fromIntegral+intValue Int32 = Int32Value . fromIntegral+intValue Int64 = Int64Value . fromIntegral++-- | The type of an integer value.+intValueType :: IntValue -> IntType+intValueType Int8Value {} = Int8+intValueType Int16Value {} = Int16+intValueType Int32Value {} = Int32+intValueType Int64Value {} = Int64++-- | Convert an t'IntValue' to any 'Integral' type.+valueIntegral :: Integral int => IntValue -> int+valueIntegral (Int8Value v) = fromIntegral v+valueIntegral (Int16Value v) = fromIntegral v+valueIntegral (Int32Value v) = fromIntegral v+valueIntegral (Int64Value v) = fromIntegral v++-- | A floating-point value.+data FloatValue+  = Float16Value !Half+  | Float32Value !Float+  | Float64Value !Double+  deriving (Show)++instance Eq FloatValue where+  Float16Value x == Float16Value y = isNaN x && isNaN y || x == y+  Float32Value x == Float32Value y = isNaN x && isNaN y || x == y+  Float64Value x == Float64Value y = isNaN x && isNaN y || x == y+  _ == _ = False++-- The derived Ord instance does not handle NaNs correctly.+instance Ord FloatValue where+  Float16Value x <= Float16Value y = x <= y+  Float32Value x <= Float32Value y = x <= y+  Float64Value x <= Float64Value y = x <= y+  Float16Value _ <= Float32Value _ = True+  Float16Value _ <= Float64Value _ = True+  Float32Value _ <= Float16Value _ = False+  Float32Value _ <= Float64Value _ = True+  Float64Value _ <= Float16Value _ = False+  Float64Value _ <= Float32Value _ = False++  Float16Value x < Float16Value y = x < y+  Float32Value x < Float32Value y = x < y+  Float64Value x < Float64Value y = x < y+  Float16Value _ < Float32Value _ = True+  Float16Value _ < Float64Value _ = True+  Float32Value _ < Float16Value _ = False+  Float32Value _ < Float64Value _ = True+  Float64Value _ < Float16Value _ = False+  Float64Value _ < Float32Value _ = False++  (>) = flip (<)+  (>=) = flip (<=)++instance Pretty FloatValue where+  ppr (Float16Value v)+    | isInfinite v, v >= 0 = text "f16.inf"+    | isInfinite v, v < 0 = text "-f16.inf"+    | isNaN v = text "f16.nan"+    | otherwise = text $ show v ++ "f16"+  ppr (Float32Value v)+    | isInfinite v, v >= 0 = text "f32.inf"+    | isInfinite v, v < 0 = text "-f32.inf"+    | isNaN v = text "f32.nan"+    | otherwise = text $ show v ++ "f32"+  ppr (Float64Value v)+    | isInfinite v, v >= 0 = text "f64.inf"+    | isInfinite v, v < 0 = text "-f64.inf"+    | isNaN v = text "f64.nan"+    | otherwise = text $ show v ++ "f64"++-- | Create a t'FloatValue' from a type and a 'Rational'.+floatValue :: Real num => FloatType -> num -> FloatValue+floatValue Float16 = Float16Value . fromRational . toRational+floatValue Float32 = Float32Value . fromRational . toRational+floatValue Float64 = Float64Value . fromRational . toRational++-- | The type of a floating-point value.+floatValueType :: FloatValue -> FloatType+floatValueType Float16Value {} = Float16+floatValueType Float32Value {} = Float32+floatValueType Float64Value {} = Float64++-- | Non-array values.+data PrimValue+  = IntValue !IntValue+  | FloatValue !FloatValue+  | BoolValue !Bool+  | -- | The only value of type 'Unit'.+    UnitValue+  deriving (Eq, Ord, Show)++instance Pretty PrimValue where+  ppr (IntValue v) = ppr v+  ppr (BoolValue True) = text "true"+  ppr (BoolValue False) = text "false"+  ppr (FloatValue v) = ppr v+  ppr UnitValue = text "()"++-- | The type of a basic value.+primValueType :: PrimValue -> PrimType+primValueType (IntValue v) = IntType $ intValueType v+primValueType (FloatValue v) = FloatType $ floatValueType v+primValueType BoolValue {} = Bool+primValueType UnitValue = Unit++-- | A "blank" value of the given primitive type - this is zero, or+-- whatever is close to it.  Don't depend on this value, but use it+-- for e.g. creating arrays to be populated by do-loops.+blankPrimValue :: PrimType -> PrimValue+blankPrimValue (IntType Int8) = IntValue $ Int8Value 0+blankPrimValue (IntType Int16) = IntValue $ Int16Value 0+blankPrimValue (IntType Int32) = IntValue $ Int32Value 0+blankPrimValue (IntType Int64) = IntValue $ Int64Value 0+blankPrimValue (FloatType Float16) = FloatValue $ Float16Value 0.0+blankPrimValue (FloatType Float32) = FloatValue $ Float32Value 0.0+blankPrimValue (FloatType Float64) = FloatValue $ Float64Value 0.0+blankPrimValue Bool = BoolValue False+blankPrimValue Unit = UnitValue++-- | Various unary operators.  It is a bit ad-hoc what is a unary+-- operator and what is a built-in function.  Perhaps these should all+-- go away eventually.+data UnOp+  = -- | E.g., @! True == False@.+    Not+  | -- | E.g., @~(~1) = 1@.+    Complement IntType+  | -- | @abs(-2) = 2@.+    Abs IntType+  | -- | @fabs(-2.0) = 2.0@.+    FAbs FloatType+  | -- | Signed sign function: @ssignum(-2)@ = -1.+    SSignum IntType+  | -- | Unsigned sign function: @usignum(2)@ = 1.+    USignum IntType+  | -- | Floating-point sign function.+    FSignum FloatType+  deriving (Eq, Ord, Show)++-- | What to do in case of arithmetic overflow.  Futhark's semantics+-- are that overflow does wraparound, but for generated code (like+-- address arithmetic), it can be beneficial for overflow to be+-- undefined behaviour, as it allows better optimisation of things+-- such as GPU kernels.+--+-- Note that all values of this type are considered equal for 'Eq' and+-- 'Ord'.+data Overflow = OverflowWrap | OverflowUndef+  deriving (Show)++instance Eq Overflow where+  _ == _ = True++instance Ord Overflow where+  _ `compare` _ = EQ++-- | Whether something is safe or unsafe (mostly function calls, and+-- in the context of whether operations are dynamically checked).+-- When we inline an 'Unsafe' function, we remove all safety checks in+-- its body.  The 'Ord' instance picks 'Unsafe' as being less than+-- 'Safe'.+--+-- For operations like integer division, a safe division will not+-- explode the computer in case of division by zero, but instead+-- return some unspecified value.  This always involves a run-time+-- check, so generally the unsafe variant is what the compiler will+-- insert, but guarded by an explicit assertion elsewhere.  Safe+-- operations are useful when the optimiser wants to move e.g. a+-- division to a location where the divisor may be zero, but where the+-- result will only be used when it is non-zero (so it doesn't matter+-- what result is provided with a zero divisor, as long as the program+-- keeps running).+data Safety = Unsafe | Safe deriving (Eq, Ord, Show)++-- | Binary operators.  These correspond closely to the binary operators in+-- LLVM.  Most are parametrised by their expected input and output+-- types.+data BinOp+  = -- | Integer addition.+    Add IntType Overflow+  | -- | Floating-point addition.+    FAdd FloatType+  | -- | Integer subtraction.+    Sub IntType Overflow+  | -- | Floating-point subtraction.+    FSub FloatType+  | -- | Integer multiplication.+    Mul IntType Overflow+  | -- | Floating-point multiplication.+    FMul FloatType+  | -- | Unsigned integer division.  Rounds towards+    -- negativity infinity.  Note: this is different+    -- from LLVM.+    UDiv IntType Safety+  | -- | Unsigned integer division.  Rounds towards positive+    -- infinity.+    UDivUp IntType Safety+  | -- | Signed integer division.  Rounds towards+    -- negativity infinity.  Note: this is different+    -- from LLVM.+    SDiv IntType Safety+  | -- | Signed integer division.  Rounds towards positive+    -- infinity.+    SDivUp IntType Safety+  | -- | Floating-point division.+    FDiv FloatType+  | -- | Floating-point modulus.+    FMod FloatType+  | -- | Unsigned integer modulus; the countepart to 'UDiv'.+    UMod IntType Safety+  | -- | Signed integer modulus; the countepart to 'SDiv'.+    SMod IntType Safety+  | -- | Signed integer division.  Rounds towards zero.  This+    -- corresponds to the @sdiv@ instruction in LLVM and+    -- integer division in C.+    SQuot IntType Safety+  | -- | Signed integer division.  Rounds towards zero.  This+    -- corresponds to the @srem@ instruction in LLVM and+    -- integer modulo in C.+    SRem IntType Safety+  | -- | Returns the smallest of two signed integers.+    SMin IntType+  | -- | Returns the smallest of two unsigned integers.+    UMin IntType+  | -- | Returns the smallest of two floating-point numbers.+    FMin FloatType+  | -- | Returns the greatest of two signed integers.+    SMax IntType+  | -- | Returns the greatest of two unsigned integers.+    UMax IntType+  | -- | Returns the greatest of two floating-point numbers.+    FMax FloatType+  | -- | Left-shift.+    Shl IntType+  | -- | Logical right-shift, zero-extended.+    LShr IntType+  | -- | Arithmetic right-shift, sign-extended.+    AShr IntType+  | -- | Bitwise and.+    And IntType+  | -- | Bitwise or.+    Or IntType+  | -- | Bitwise exclusive-or.+    Xor IntType+  | -- | Integer exponentiation.+    Pow IntType+  | -- | Floating-point exponentiation.+    FPow FloatType+  | -- | Boolean and - not short-circuiting.+    LogAnd+  | -- | Boolean or - not short-circuiting.+    LogOr+  deriving (Eq, Ord, Show)++-- | Comparison operators are like 'BinOp's, but they always return a+-- boolean value.  The somewhat ugly constructor names are straight+-- out of LLVM.+data CmpOp+  = -- | All types equality.+    CmpEq PrimType+  | -- | Unsigned less than.+    CmpUlt IntType+  | -- | Unsigned less than or equal.+    CmpUle IntType+  | -- | Signed less than.+    CmpSlt IntType+  | -- | Signed less than or equal.+    CmpSle IntType+  | -- Comparison operators for floating-point values.  TODO: extend+    -- this to handle NaNs and such, like the LLVM fcmp instruction.++    -- | Floating-point less than.+    FCmpLt FloatType+  | -- | Floating-point less than or equal.+    FCmpLe FloatType+  | -- Boolean comparison.++    -- | Boolean less than.+    CmpLlt+  | -- | Boolean less than or equal.+    CmpLle+  deriving (Eq, Ord, Show)++-- | Conversion operators try to generalise the @from t0 x to t1@+-- instructions from LLVM.+data ConvOp+  = -- | Zero-extend the former integer type to the latter.+    -- If the new type is smaller, the result is a+    -- truncation.+    ZExt IntType IntType+  | -- | Sign-extend the former integer type to the latter.+    -- If the new type is smaller, the result is a+    -- truncation.+    SExt IntType IntType+  | -- | Convert value of the former floating-point type to+    -- the latter.  If the new type is smaller, the result+    -- is a truncation.+    FPConv FloatType FloatType+  | -- | Convert a floating-point value to the nearest+    -- unsigned integer (rounding towards zero).+    FPToUI FloatType IntType+  | -- | Convert a floating-point value to the nearest+    -- signed integer (rounding towards zero).+    FPToSI FloatType IntType+  | -- | Convert an unsigned integer to a floating-point value.+    UIToFP IntType FloatType+  | -- | Convert a signed integer to a floating-point value.+    SIToFP IntType FloatType+  | -- | Convert an integer to a boolean value.  Zero+    -- becomes false; anything else is true.+    IToB IntType+  | -- | Convert a boolean to an integer.  True is converted+    -- to 1 and False to 0.+    BToI IntType+  | -- | Convert a float to a boolean value.  Zero becomes false;+    -- | anything else is true.+    FToB FloatType+  | -- | Convert a boolean to a float.  True is converted+    -- to 1 and False to 0.+    BToF FloatType+  deriving (Eq, Ord, Show)++-- | A list of all unary operators for all types.+allUnOps :: [UnOp]+allUnOps =+  Not+    : map Complement [minBound .. maxBound]+    ++ map Abs [minBound .. maxBound]+    ++ map FAbs [minBound .. maxBound]+    ++ map SSignum [minBound .. maxBound]+    ++ map USignum [minBound .. maxBound]+    ++ map FSignum [minBound .. maxBound]++-- | A list of all binary operators for all types.+allBinOps :: [BinOp]+allBinOps =+  concat+    [ Add <$> allIntTypes <*> [OverflowWrap, OverflowUndef],+      map FAdd allFloatTypes,+      Sub <$> allIntTypes <*> [OverflowWrap, OverflowUndef],+      map FSub allFloatTypes,+      Mul <$> allIntTypes <*> [OverflowWrap, OverflowUndef],+      map FMul allFloatTypes,+      UDiv <$> allIntTypes <*> [Unsafe, Safe],+      UDivUp <$> allIntTypes <*> [Unsafe, Safe],+      SDiv <$> allIntTypes <*> [Unsafe, Safe],+      SDivUp <$> allIntTypes <*> [Unsafe, Safe],+      map FDiv allFloatTypes,+      map FMod allFloatTypes,+      UMod <$> allIntTypes <*> [Unsafe, Safe],+      SMod <$> allIntTypes <*> [Unsafe, Safe],+      SQuot <$> allIntTypes <*> [Unsafe, Safe],+      SRem <$> allIntTypes <*> [Unsafe, Safe],+      map SMin allIntTypes,+      map UMin allIntTypes,+      map FMin allFloatTypes,+      map SMax allIntTypes,+      map UMax allIntTypes,+      map FMax allFloatTypes,+      map Shl allIntTypes,+      map LShr allIntTypes,+      map AShr allIntTypes,+      map And allIntTypes,+      map Or allIntTypes,+      map Xor allIntTypes,+      map Pow allIntTypes,+      map FPow allFloatTypes,+      [LogAnd, LogOr]+    ]++-- | A list of all comparison operators for all types.+allCmpOps :: [CmpOp]+allCmpOps =+  concat+    [ map CmpEq allPrimTypes,+      map CmpUlt allIntTypes,+      map CmpUle allIntTypes,+      map CmpSlt allIntTypes,+      map CmpSle allIntTypes,+      map FCmpLt allFloatTypes,+      map FCmpLe allFloatTypes,+      [CmpLlt, CmpLle]+    ]++-- | A list of all conversion operators for all types.+allConvOps :: [ConvOp]+allConvOps =+  concat+    [ ZExt <$> allIntTypes <*> allIntTypes,+      SExt <$> allIntTypes <*> allIntTypes,+      FPConv <$> allFloatTypes <*> allFloatTypes,+      FPToUI <$> allFloatTypes <*> allIntTypes,+      FPToSI <$> allFloatTypes <*> allIntTypes,+      UIToFP <$> allIntTypes <*> allFloatTypes,+      SIToFP <$> allIntTypes <*> allFloatTypes,+      IToB <$> allIntTypes,+      BToI <$> allIntTypes,+      FToB <$> allFloatTypes,+      BToF <$> allFloatTypes+    ]++-- | Apply an 'UnOp' to an operand.  Returns 'Nothing' if the+-- application is mistyped.+doUnOp :: UnOp -> PrimValue -> Maybe PrimValue+doUnOp Not (BoolValue b) = Just $ BoolValue $ not b+doUnOp Complement {} (IntValue v) = Just $ IntValue $ doComplement v+doUnOp Abs {} (IntValue v) = Just $ IntValue $ doAbs v+doUnOp FAbs {} (FloatValue v) = Just $ FloatValue $ doFAbs v+doUnOp SSignum {} (IntValue v) = Just $ IntValue $ doSSignum v+doUnOp USignum {} (IntValue v) = Just $ IntValue $ doUSignum v+doUnOp FSignum {} (FloatValue v) = Just $ FloatValue $ doFSignum v+doUnOp _ _ = Nothing++-- | E.g., @~(~1) = 1@.+doComplement :: IntValue -> IntValue+doComplement v = intValue (intValueType v) $ complement $ intToInt64 v++-- | @abs(-2) = 2@.+doAbs :: IntValue -> IntValue+doAbs v = intValue (intValueType v) $ abs $ intToInt64 v++-- | @abs(-2.0) = 2.0@.+doFAbs :: FloatValue -> FloatValue+doFAbs (Float16Value x) = Float16Value $ abs x+doFAbs (Float32Value x) = Float32Value $ abs x+doFAbs (Float64Value x) = Float64Value $ abs x++-- | @ssignum(-2)@ = -1.+doSSignum :: IntValue -> IntValue+doSSignum v = intValue (intValueType v) $ signum $ intToInt64 v++-- | @usignum(-2)@ = -1.+doUSignum :: IntValue -> IntValue+doUSignum v = intValue (intValueType v) $ signum $ intToWord64 v++-- | @fsignum(-2.0)@ = -1.0.+doFSignum :: FloatValue -> FloatValue+doFSignum (Float16Value v) = Float16Value $ signum v+doFSignum (Float32Value v) = Float32Value $ signum v+doFSignum (Float64Value v) = Float64Value $ signum v++-- | Apply a 'BinOp' to an operand.  Returns 'Nothing' if the+-- application is mistyped, or outside the domain (e.g. division by+-- zero).+doBinOp :: BinOp -> PrimValue -> PrimValue -> Maybe PrimValue+doBinOp Add {} = doIntBinOp doAdd+doBinOp FAdd {} = doFloatBinOp (+) (+) (+)+doBinOp Sub {} = doIntBinOp doSub+doBinOp FSub {} = doFloatBinOp (-) (-) (-)+doBinOp Mul {} = doIntBinOp doMul+doBinOp FMul {} = doFloatBinOp (*) (*) (*)+doBinOp UDiv {} = doRiskyIntBinOp doUDiv+doBinOp UDivUp {} = doRiskyIntBinOp doUDivUp+doBinOp SDiv {} = doRiskyIntBinOp doSDiv+doBinOp SDivUp {} = doRiskyIntBinOp doSDivUp+doBinOp FDiv {} = doFloatBinOp (/) (/) (/)+doBinOp FMod {} = doFloatBinOp mod' mod' mod'+doBinOp UMod {} = doRiskyIntBinOp doUMod+doBinOp SMod {} = doRiskyIntBinOp doSMod+doBinOp SQuot {} = doRiskyIntBinOp doSQuot+doBinOp SRem {} = doRiskyIntBinOp doSRem+doBinOp SMin {} = doIntBinOp doSMin+doBinOp UMin {} = doIntBinOp doUMin+doBinOp FMin {} = doFloatBinOp fmin fmin fmin+  where+    fmin x y+      | isNaN x = y+      | isNaN y = x+      | otherwise = min x y+doBinOp SMax {} = doIntBinOp doSMax+doBinOp UMax {} = doIntBinOp doUMax+doBinOp FMax {} = doFloatBinOp fmax fmax fmax+  where+    fmax x y+      | isNaN x = y+      | isNaN y = x+      | otherwise = max x y+doBinOp Shl {} = doIntBinOp doShl+doBinOp LShr {} = doIntBinOp doLShr+doBinOp AShr {} = doIntBinOp doAShr+doBinOp And {} = doIntBinOp doAnd+doBinOp Or {} = doIntBinOp doOr+doBinOp Xor {} = doIntBinOp doXor+doBinOp Pow {} = doRiskyIntBinOp doPow+doBinOp FPow {} = doFloatBinOp (**) (**) (**)+doBinOp LogAnd {} = doBoolBinOp (&&)+doBinOp LogOr {} = doBoolBinOp (||)++doIntBinOp ::+  (IntValue -> IntValue -> IntValue) ->+  PrimValue ->+  PrimValue ->+  Maybe PrimValue+doIntBinOp f (IntValue v1) (IntValue v2) =+  Just $ IntValue $ f v1 v2+doIntBinOp _ _ _ = Nothing++doRiskyIntBinOp ::+  (IntValue -> IntValue -> Maybe IntValue) ->+  PrimValue ->+  PrimValue ->+  Maybe PrimValue+doRiskyIntBinOp f (IntValue v1) (IntValue v2) =+  IntValue <$> f v1 v2+doRiskyIntBinOp _ _ _ = Nothing++doFloatBinOp ::+  (Half -> Half -> Half) ->+  (Float -> Float -> Float) ->+  (Double -> Double -> Double) ->+  PrimValue ->+  PrimValue ->+  Maybe PrimValue+doFloatBinOp f16 _ _ (FloatValue (Float16Value v1)) (FloatValue (Float16Value v2)) =+  Just $ FloatValue $ Float16Value $ f16 v1 v2+doFloatBinOp _ f32 _ (FloatValue (Float32Value v1)) (FloatValue (Float32Value v2)) =+  Just $ FloatValue $ Float32Value $ f32 v1 v2+doFloatBinOp _ _ f64 (FloatValue (Float64Value v1)) (FloatValue (Float64Value v2)) =+  Just $ FloatValue $ Float64Value $ f64 v1 v2+doFloatBinOp _ _ _ _ _ = Nothing++doBoolBinOp ::+  (Bool -> Bool -> Bool) ->+  PrimValue ->+  PrimValue ->+  Maybe PrimValue+doBoolBinOp f (BoolValue v1) (BoolValue v2) =+  Just $ BoolValue $ f v1 v2+doBoolBinOp _ _ _ = Nothing++-- | Integer addition.+doAdd :: IntValue -> IntValue -> IntValue+doAdd v1 v2 = intValue (intValueType v1) $ intToInt64 v1 + intToInt64 v2++-- | Integer subtraction.+doSub :: IntValue -> IntValue -> IntValue+doSub v1 v2 = intValue (intValueType v1) $ intToInt64 v1 - intToInt64 v2++-- | Integer multiplication.+doMul :: IntValue -> IntValue -> IntValue+doMul v1 v2 = intValue (intValueType v1) $ intToInt64 v1 * intToInt64 v2++-- | Unsigned integer division.  Rounds towards negativity infinity.+-- Note: this is different from LLVM.+doUDiv :: IntValue -> IntValue -> Maybe IntValue+doUDiv v1 v2+  | zeroIshInt v2 = Nothing+  | otherwise =+      Just . intValue (intValueType v1) $+        intToWord64 v1 `div` intToWord64 v2++-- | Unsigned integer division.  Rounds towards positive infinity.+doUDivUp :: IntValue -> IntValue -> Maybe IntValue+doUDivUp v1 v2+  | zeroIshInt v2 = Nothing+  | otherwise =+      Just . intValue (intValueType v1) $+        (intToWord64 v1 + intToWord64 v2 - 1) `div` intToWord64 v2++-- | Signed integer division.  Rounds towards negativity infinity.+-- Note: this is different from LLVM.+doSDiv :: IntValue -> IntValue -> Maybe IntValue+doSDiv v1 v2+  | zeroIshInt v2 = Nothing+  | otherwise =+      Just $+        intValue (intValueType v1) $+          intToInt64 v1 `div` intToInt64 v2++-- | Signed integer division.  Rounds towards positive infinity.+doSDivUp :: IntValue -> IntValue -> Maybe IntValue+doSDivUp v1 v2+  | zeroIshInt v2 = Nothing+  | otherwise =+      Just . intValue (intValueType v1) $+        (intToInt64 v1 + intToInt64 v2 - 1) `div` intToInt64 v2++-- | Unsigned integer modulus; the countepart to 'UDiv'.+doUMod :: IntValue -> IntValue -> Maybe IntValue+doUMod v1 v2+  | zeroIshInt v2 = Nothing+  | otherwise = Just $ intValue (intValueType v1) $ intToWord64 v1 `mod` intToWord64 v2++-- | Signed integer modulus; the countepart to 'SDiv'.+doSMod :: IntValue -> IntValue -> Maybe IntValue+doSMod v1 v2+  | zeroIshInt v2 = Nothing+  | otherwise = Just $ intValue (intValueType v1) $ intToInt64 v1 `mod` intToInt64 v2++-- | Signed integer division.  Rounds towards zero.+-- This corresponds to the @sdiv@ instruction in LLVM.+doSQuot :: IntValue -> IntValue -> Maybe IntValue+doSQuot v1 v2+  | zeroIshInt v2 = Nothing+  | otherwise = Just $ intValue (intValueType v1) $ intToInt64 v1 `quot` intToInt64 v2++-- | Signed integer division.  Rounds towards zero.+-- This corresponds to the @srem@ instruction in LLVM.+doSRem :: IntValue -> IntValue -> Maybe IntValue+doSRem v1 v2+  | zeroIshInt v2 = Nothing+  | otherwise = Just $ intValue (intValueType v1) $ intToInt64 v1 `rem` intToInt64 v2++-- | Minimum of two signed integers.+doSMin :: IntValue -> IntValue -> IntValue+doSMin v1 v2 = intValue (intValueType v1) $ intToInt64 v1 `min` intToInt64 v2++-- | Minimum of two unsigned integers.+doUMin :: IntValue -> IntValue -> IntValue+doUMin v1 v2 = intValue (intValueType v1) $ intToWord64 v1 `min` intToWord64 v2++-- | Maximum of two signed integers.+doSMax :: IntValue -> IntValue -> IntValue+doSMax v1 v2 = intValue (intValueType v1) $ intToInt64 v1 `max` intToInt64 v2++-- | Maximum of two unsigned integers.+doUMax :: IntValue -> IntValue -> IntValue+doUMax v1 v2 = intValue (intValueType v1) $ intToWord64 v1 `max` intToWord64 v2++-- | Left-shift.+doShl :: IntValue -> IntValue -> IntValue+doShl v1 v2 = intValue (intValueType v1) $ intToInt64 v1 `shift` intToInt v2++-- | Logical right-shift, zero-extended.+doLShr :: IntValue -> IntValue -> IntValue+doLShr v1 v2 = intValue (intValueType v1) $ intToWord64 v1 `shift` negate (intToInt v2)++-- | Arithmetic right-shift, sign-extended.+doAShr :: IntValue -> IntValue -> IntValue+doAShr v1 v2 = intValue (intValueType v1) $ intToInt64 v1 `shift` negate (intToInt v2)++-- | Bitwise and.+doAnd :: IntValue -> IntValue -> IntValue+doAnd v1 v2 = intValue (intValueType v1) $ intToWord64 v1 .&. intToWord64 v2++-- | Bitwise or.+doOr :: IntValue -> IntValue -> IntValue+doOr v1 v2 = intValue (intValueType v1) $ intToWord64 v1 .|. intToWord64 v2++-- | Bitwise exclusive-or.+doXor :: IntValue -> IntValue -> IntValue+doXor v1 v2 = intValue (intValueType v1) $ intToWord64 v1 `xor` intToWord64 v2++-- | Signed integer exponentatation.+doPow :: IntValue -> IntValue -> Maybe IntValue+doPow v1 v2+  | negativeIshInt v2 = Nothing+  | otherwise = Just $ intValue (intValueType v1) $ intToInt64 v1 ^ intToInt64 v2++-- | Apply a 'ConvOp' to an operand.  Returns 'Nothing' if the+-- application is mistyped.+doConvOp :: ConvOp -> PrimValue -> Maybe PrimValue+doConvOp (ZExt _ to) (IntValue v) = Just $ IntValue $ doZExt v to+doConvOp (SExt _ to) (IntValue v) = Just $ IntValue $ doSExt v to+doConvOp (FPConv _ to) (FloatValue v) = Just $ FloatValue $ doFPConv v to+doConvOp (FPToUI _ to) (FloatValue v) = Just $ IntValue $ doFPToUI v to+doConvOp (FPToSI _ to) (FloatValue v) = Just $ IntValue $ doFPToSI v to+doConvOp (UIToFP _ to) (IntValue v) = Just $ FloatValue $ doUIToFP v to+doConvOp (SIToFP _ to) (IntValue v) = Just $ FloatValue $ doSIToFP v to+doConvOp (IToB _) (IntValue v) = Just $ BoolValue $ intToInt64 v /= 0+doConvOp (BToI to) (BoolValue v) = Just $ IntValue $ intValue to $ if v then 1 else 0 :: Int+doConvOp (FToB _) (FloatValue v) = Just $ BoolValue $ floatToDouble v /= 0+doConvOp (BToF to) (BoolValue v) = Just $ FloatValue $ floatValue to $ if v then 1 else 0 :: Double+doConvOp _ _ = Nothing++-- | Turn the conversion the other way around.  Note that most+-- conversions are lossy, so there is no guarantee the value will+-- round-trip.+flipConvOp :: ConvOp -> ConvOp+flipConvOp (ZExt from to) = ZExt to from+flipConvOp (SExt from to) = SExt to from+flipConvOp (FPConv from to) = FPConv to from+flipConvOp (FPToUI from to) = UIToFP to from+flipConvOp (FPToSI from to) = SIToFP to from+flipConvOp (UIToFP from to) = FPToSI to from+flipConvOp (SIToFP from to) = FPToSI to from+flipConvOp (IToB from) = BToI from+flipConvOp (BToI to) = IToB to+flipConvOp (FToB from) = BToF from+flipConvOp (BToF to) = FToB to++-- | Zero-extend the given integer value to the size of the given+-- type.  If the type is smaller than the given value, the result is a+-- truncation.+doZExt :: IntValue -> IntType -> IntValue+doZExt (Int8Value x) t = intValue t $ toInteger (fromIntegral x :: Word8)+doZExt (Int16Value x) t = intValue t $ toInteger (fromIntegral x :: Word16)+doZExt (Int32Value x) t = intValue t $ toInteger (fromIntegral x :: Word32)+doZExt (Int64Value x) t = intValue t $ toInteger (fromIntegral x :: Word64)++-- | Sign-extend the given integer value to the size of the given+-- type.  If the type is smaller than the given value, the result is a+-- truncation.+doSExt :: IntValue -> IntType -> IntValue+doSExt (Int8Value x) t = intValue t $ toInteger x+doSExt (Int16Value x) t = intValue t $ toInteger x+doSExt (Int32Value x) t = intValue t $ toInteger x+doSExt (Int64Value x) t = intValue t $ toInteger x++-- | Convert the former floating-point type to the latter.+doFPConv :: FloatValue -> FloatType -> FloatValue+doFPConv v Float16 = Float16Value $ floatToHalf v+doFPConv v Float32 = Float32Value $ floatToFloat v+doFPConv v Float64 = Float64Value $ floatToDouble v++-- | Convert a floating-point value to the nearest+-- unsigned integer (rounding towards zero).+doFPToUI :: FloatValue -> IntType -> IntValue+doFPToUI v t = intValue t (truncate $ floatToDouble v :: Word64)++-- | Convert a floating-point value to the nearest+-- signed integer (rounding towards zero).+doFPToSI :: FloatValue -> IntType -> IntValue+doFPToSI v t = intValue t (truncate $ floatToDouble v :: Word64)++-- | Convert an unsigned integer to a floating-point value.+doUIToFP :: IntValue -> FloatType -> FloatValue+doUIToFP v t = floatValue t $ intToWord64 v++-- | Convert a signed integer to a floating-point value.+doSIToFP :: IntValue -> FloatType -> FloatValue+doSIToFP v t = floatValue t $ intToInt64 v++-- | Apply a 'CmpOp' to an operand.  Returns 'Nothing' if the+-- application is mistyped.+doCmpOp :: CmpOp -> PrimValue -> PrimValue -> Maybe Bool+doCmpOp CmpEq {} v1 v2 = Just $ doCmpEq v1 v2+doCmpOp CmpUlt {} (IntValue v1) (IntValue v2) = Just $ doCmpUlt v1 v2+doCmpOp CmpUle {} (IntValue v1) (IntValue v2) = Just $ doCmpUle v1 v2+doCmpOp CmpSlt {} (IntValue v1) (IntValue v2) = Just $ doCmpSlt v1 v2+doCmpOp CmpSle {} (IntValue v1) (IntValue v2) = Just $ doCmpSle v1 v2+doCmpOp FCmpLt {} (FloatValue v1) (FloatValue v2) = Just $ doFCmpLt v1 v2+doCmpOp FCmpLe {} (FloatValue v1) (FloatValue v2) = Just $ doFCmpLe v1 v2+doCmpOp CmpLlt {} (BoolValue v1) (BoolValue v2) = Just $ not v1 && v2+doCmpOp CmpLle {} (BoolValue v1) (BoolValue v2) = Just $ not (v1 && not v2)+doCmpOp _ _ _ = Nothing++-- | Compare any two primtive values for exact equality.+doCmpEq :: PrimValue -> PrimValue -> Bool+doCmpEq (FloatValue (Float32Value v1)) (FloatValue (Float32Value v2)) = v1 == v2+doCmpEq (FloatValue (Float64Value v1)) (FloatValue (Float64Value v2)) = v1 == v2+doCmpEq v1 v2 = v1 == v2++-- | Unsigned less than.+doCmpUlt :: IntValue -> IntValue -> Bool+doCmpUlt v1 v2 = intToWord64 v1 < intToWord64 v2++-- | Unsigned less than or equal.+doCmpUle :: IntValue -> IntValue -> Bool+doCmpUle v1 v2 = intToWord64 v1 <= intToWord64 v2++-- | Signed less than.+doCmpSlt :: IntValue -> IntValue -> Bool+doCmpSlt = (<)++-- | Signed less than or equal.+doCmpSle :: IntValue -> IntValue -> Bool+doCmpSle = (<=)++-- | Floating-point less than.+doFCmpLt :: FloatValue -> FloatValue -> Bool+doFCmpLt = (<)++-- | Floating-point less than or equal.+doFCmpLe :: FloatValue -> FloatValue -> Bool+doFCmpLe = (<=)++-- | Translate an t'IntValue' to 'Word64'.  This is guaranteed to fit.+intToWord64 :: IntValue -> Word64+intToWord64 (Int8Value v) = fromIntegral (fromIntegral v :: Word8)+intToWord64 (Int16Value v) = fromIntegral (fromIntegral v :: Word16)+intToWord64 (Int32Value v) = fromIntegral (fromIntegral v :: Word32)+intToWord64 (Int64Value v) = fromIntegral (fromIntegral v :: Word64)++-- | Translate an t'IntValue' to t'Int64'.  This is guaranteed to fit.+intToInt64 :: IntValue -> Int64+intToInt64 (Int8Value v) = fromIntegral v+intToInt64 (Int16Value v) = fromIntegral v+intToInt64 (Int32Value v) = fromIntegral v+intToInt64 (Int64Value v) = fromIntegral v++-- | Careful - there is no guarantee this will fit.+intToInt :: IntValue -> Int+intToInt = fromIntegral . intToInt64++floatToDouble :: FloatValue -> Double+floatToDouble (Float16Value v)+  | isInfinite v, v > 0 = 1 / 0+  | isInfinite v, v < 0 = -1 / 0+  | isNaN v = 0 / 0+  | otherwise = fromRational $ toRational v+floatToDouble (Float32Value v)+  | isInfinite v, v > 0 = 1 / 0+  | isInfinite v, v < 0 = -1 / 0+  | isNaN v = 0 / 0+  | otherwise = fromRational $ toRational v+floatToDouble (Float64Value v) = v++floatToFloat :: FloatValue -> Float+floatToFloat (Float16Value v)+  | isInfinite v, v > 0 = 1 / 0+  | isInfinite v, v < 0 = -1 / 0+  | isNaN v = 0 / 0+  | otherwise = fromRational $ toRational v+floatToFloat (Float32Value v) = v+floatToFloat (Float64Value v)+  | isInfinite v, v > 0 = 1 / 0+  | isInfinite v, v < 0 = -1 / 0+  | isNaN v = 0 / 0+  | otherwise = fromRational $ toRational v++floatToHalf :: FloatValue -> Half+floatToHalf (Float16Value v) = v+floatToHalf (Float32Value v)+  | isInfinite v, v > 0 = 1 / 0+  | isInfinite v, v < 0 = -1 / 0+  | isNaN v = 0 / 0+  | otherwise = fromRational $ toRational v+floatToHalf (Float64Value v)+  | isInfinite v, v > 0 = 1 / 0+  | isInfinite v, v < 0 = -1 / 0+  | isNaN v = 0 / 0+  | otherwise = fromRational $ toRational v++-- | The result type of a binary operator.+binOpType :: BinOp -> PrimType+binOpType (Add t _) = IntType t+binOpType (Sub t _) = IntType t+binOpType (Mul t _) = IntType t+binOpType (SDiv t _) = IntType t+binOpType (SDivUp t _) = IntType t+binOpType (SMod t _) = IntType t+binOpType (SQuot t _) = IntType t+binOpType (SRem t _) = IntType t+binOpType (UDiv t _) = IntType t+binOpType (UDivUp t _) = IntType t+binOpType (UMod t _) = IntType t+binOpType (SMin t) = IntType t+binOpType (UMin t) = IntType t+binOpType (FMin t) = FloatType t+binOpType (SMax t) = IntType t+binOpType (UMax t) = IntType t+binOpType (FMax t) = FloatType t+binOpType (Shl t) = IntType t+binOpType (LShr t) = IntType t+binOpType (AShr t) = IntType t+binOpType (And t) = IntType t+binOpType (Or t) = IntType t+binOpType (Xor t) = IntType t+binOpType (Pow t) = IntType t+binOpType (FPow t) = FloatType t+binOpType LogAnd = Bool+binOpType LogOr = Bool+binOpType (FAdd t) = FloatType t+binOpType (FSub t) = FloatType t+binOpType (FMul t) = FloatType t+binOpType (FDiv t) = FloatType t+binOpType (FMod t) = FloatType t++-- | The operand types of a comparison operator.+cmpOpType :: CmpOp -> PrimType+cmpOpType (CmpEq t) = t+cmpOpType (CmpSlt t) = IntType t+cmpOpType (CmpSle t) = IntType t+cmpOpType (CmpUlt t) = IntType t+cmpOpType (CmpUle t) = IntType t+cmpOpType (FCmpLt t) = FloatType t+cmpOpType (FCmpLe t) = FloatType t+cmpOpType CmpLlt = Bool+cmpOpType CmpLle = Bool++-- | The operand and result type of a unary operator.+unOpType :: UnOp -> PrimType+unOpType (SSignum t) = IntType t+unOpType (USignum t) = IntType t+unOpType Not = Bool+unOpType (Complement t) = IntType t+unOpType (Abs t) = IntType t+unOpType (FAbs t) = FloatType t+unOpType (FSignum t) = FloatType t++-- | The input and output types of a conversion operator.+convOpType :: ConvOp -> (PrimType, PrimType)+convOpType (ZExt from to) = (IntType from, IntType to)+convOpType (SExt from to) = (IntType from, IntType to)+convOpType (FPConv from to) = (FloatType from, FloatType to)+convOpType (FPToUI from to) = (FloatType from, IntType to)+convOpType (FPToSI from to) = (FloatType from, IntType to)+convOpType (UIToFP from to) = (IntType from, FloatType to)+convOpType (SIToFP from to) = (IntType from, FloatType to)+convOpType (IToB from) = (IntType from, Bool)+convOpType (BToI to) = (Bool, IntType to)+convOpType (FToB from) = (FloatType from, Bool)+convOpType (BToF to) = (Bool, FloatType to)++halfToWord :: Half -> Word16+halfToWord (Half (CUShort x)) = x++wordToHalf :: Word16 -> Half+wordToHalf = Half . CUShort++floatToWord :: Float -> Word32+floatToWord = G.runGet G.getWord32le . P.runPut . P.putFloatle++wordToFloat :: Word32 -> Float+wordToFloat = G.runGet G.getFloatle . P.runPut . P.putWord32le++doubleToWord :: Double -> Word64+doubleToWord = G.runGet G.getWord64le . P.runPut . P.putDoublele++wordToDouble :: Word64 -> Double+wordToDouble = G.runGet G.getDoublele . P.runPut . P.putWord64le++-- | A mapping from names of primitive functions to their parameter+-- types, their result type, and a function for evaluating them.+primFuns ::+  M.Map+    String+    ( [PrimType],+      PrimType,+      [PrimValue] -> Maybe PrimValue+    )+primFuns =+  M.fromList+    [ f16 "sqrt16" sqrt,+      f32 "sqrt32" sqrt,+      f64 "sqrt64" sqrt,+      --+      f16 "cbrt16" $ convFloat . cbrtf . convFloat,+      f32 "cbrt32" cbrtf,+      f64 "cbrt64" cbrt,+      --+      f16 "log16" log,+      f32 "log32" log,+      f64 "log64" log,+      --+      f16 "log10_16" (logBase 10),+      f32 "log10_32" (logBase 10),+      f64 "log10_64" (logBase 10),+      --+      f16 "log2_16" (logBase 2),+      f32 "log2_32" (logBase 2),+      f64 "log2_64" (logBase 2),+      --+      f16 "exp16" exp,+      f32 "exp32" exp,+      f64 "exp64" exp,+      --+      f16 "sin16" sin,+      f32 "sin32" sin,+      f64 "sin64" sin,+      --+      f16 "sinh16" sinh,+      f32 "sinh32" sinh,+      f64 "sinh64" sinh,+      --+      f16 "cos16" cos,+      f32 "cos32" cos,+      f64 "cos64" cos,+      --+      f16 "cosh16" cosh,+      f32 "cosh32" cosh,+      f64 "cosh64" cosh,+      --+      f16 "tan16" tan,+      f32 "tan32" tan,+      f64 "tan64" tan,+      --+      f16 "tanh16" tanh,+      f32 "tanh32" tanh,+      f64 "tanh64" tanh,+      --+      f16 "asin16" asin,+      f32 "asin32" asin,+      f64 "asin64" asin,+      --+      f16 "asinh16" asinh,+      f32 "asinh32" asinh,+      f64 "asinh64" asinh,+      --+      f16 "acos16" acos,+      f32 "acos32" acos,+      f64 "acos64" acos,+      --+      f16 "acosh16" acosh,+      f32 "acosh32" acosh,+      f64 "acosh64" acosh,+      --+      f16 "atan16" atan,+      f32 "atan32" atan,+      f64 "atan64" atan,+      --+      f16 "atanh16" atanh,+      f32 "atanh32" atanh,+      f64 "atanh64" atanh,+      --+      f16 "round16" $ convFloat . roundFloat . convFloat,+      f32 "round32" roundFloat,+      f64 "round64" roundDouble,+      --+      f16 "ceil16" $ convFloat . ceilFloat . convFloat,+      f32 "ceil32" ceilFloat,+      f64 "ceil64" ceilDouble,+      --+      f16 "floor16" $ convFloat . floorFloat . convFloat,+      f32 "floor32" floorFloat,+      f64 "floor64" floorDouble,+      --+      f16 "gamma16" $ convFloat . tgammaf . convFloat,+      f32 "gamma32" tgammaf,+      f64 "gamma64" tgamma,+      --+      f16 "lgamma16" $ convFloat . lgammaf . convFloat,+      f32 "lgamma32" lgammaf,+      f64 "lgamma64" lgamma,+      --+      --+      f16 "erf16" $ convFloat . erff . convFloat,+      f32 "erf32" erff,+      f64 "erf64" erf,+      --+      f16 "erfc16" $ convFloat . erfcf . convFloat,+      f32 "erfc32" erfcf,+      f64 "erfc64" erfc,+      --+      i8 "clz8" $ IntValue . Int32Value . fromIntegral . countLeadingZeros,+      i16 "clz16" $ IntValue . Int32Value . fromIntegral . countLeadingZeros,+      i32 "clz32" $ IntValue . Int32Value . fromIntegral . countLeadingZeros,+      i64 "clz64" $ IntValue . Int32Value . fromIntegral . countLeadingZeros,+      i8 "ctz8" $ IntValue . Int32Value . fromIntegral . countTrailingZeros,+      i16 "ctz16" $ IntValue . Int32Value . fromIntegral . countTrailingZeros,+      i32 "ctz32" $ IntValue . Int32Value . fromIntegral . countTrailingZeros,+      i64 "ctz64" $ IntValue . Int32Value . fromIntegral . countTrailingZeros,+      i8 "popc8" $ IntValue . Int32Value . fromIntegral . popCount,+      i16 "popc16" $ IntValue . Int32Value . fromIntegral . popCount,+      i32 "popc32" $ IntValue . Int32Value . fromIntegral . popCount,+      i64 "popc64" $ IntValue . Int32Value . fromIntegral . popCount,+      ( "mad_hi8",+        ( [IntType Int8, IntType Int8, IntType Int8],+          IntType Int8,+          \case+            [IntValue (Int8Value a), IntValue (Int8Value b), IntValue (Int8Value c)] ->+              Just $ IntValue . Int8Value $ mad_hi8 (Int8Value a) (Int8Value b) c+            _ -> Nothing+        )+      ),+      ( "mad_hi16",+        ( [IntType Int16, IntType Int16, IntType Int16],+          IntType Int16,+          \case+            [IntValue (Int16Value a), IntValue (Int16Value b), IntValue (Int16Value c)] ->+              Just $ IntValue . Int16Value $ mad_hi16 (Int16Value a) (Int16Value b) c+            _ -> Nothing+        )+      ),+      ( "mad_hi32",+        ( [IntType Int32, IntType Int32, IntType Int32],+          IntType Int32,+          \case+            [IntValue (Int32Value a), IntValue (Int32Value b), IntValue (Int32Value c)] ->+              Just $ IntValue . Int32Value $ mad_hi32 (Int32Value a) (Int32Value b) c+            _ -> Nothing+        )+      ),+      ( "mad_hi64",+        ( [IntType Int64, IntType Int64, IntType Int64],+          IntType Int64,+          \case+            [IntValue (Int64Value a), IntValue (Int64Value b), IntValue (Int64Value c)] ->+              Just $ IntValue . Int64Value $ mad_hi64 (Int64Value a) (Int64Value b) c+            _ -> Nothing+        )+      ),+      ( "mul_hi8",+        ( [IntType Int8, IntType Int8],+          IntType Int8,+          \case+            [IntValue (Int8Value a), IntValue (Int8Value b)] ->+              Just $ IntValue . Int8Value $ mul_hi8 (Int8Value a) (Int8Value b)+            _ -> Nothing+        )+      ),+      ( "mul_hi16",+        ( [IntType Int16, IntType Int16],+          IntType Int16,+          \case+            [IntValue (Int16Value a), IntValue (Int16Value b)] ->+              Just $ IntValue . Int16Value $ mul_hi16 (Int16Value a) (Int16Value b)+            _ -> Nothing+        )+      ),+      ( "mul_hi32",+        ( [IntType Int32, IntType Int32],+          IntType Int32,+          \case+            [IntValue (Int32Value a), IntValue (Int32Value b)] ->+              Just $ IntValue . Int32Value $ mul_hi32 (Int32Value a) (Int32Value b)+            _ -> Nothing+        )+      ),+      ( "mul_hi64",+        ( [IntType Int64, IntType Int64],+          IntType Int64,+          \case+            [IntValue (Int64Value a), IntValue (Int64Value b)] ->+              Just $ IntValue . Int64Value $ mul_hi64 (Int64Value a) (Int64Value b)+            _ -> Nothing+        )+      ),+      --+      ( "atan2_16",+        ( [FloatType Float16, FloatType Float16],+          FloatType Float16,+          \case+            [FloatValue (Float16Value x), FloatValue (Float16Value y)] ->+              Just $ FloatValue $ Float16Value $ atan2 x y+            _ -> Nothing+        )+      ),+      ( "atan2_32",+        ( [FloatType Float32, FloatType Float32],+          FloatType Float32,+          \case+            [FloatValue (Float32Value x), FloatValue (Float32Value y)] ->+              Just $ FloatValue $ Float32Value $ atan2 x y+            _ -> Nothing+        )+      ),+      ( "atan2_64",+        ( [FloatType Float64, FloatType Float64],+          FloatType Float64,+          \case+            [FloatValue (Float64Value x), FloatValue (Float64Value y)] ->+              Just $ FloatValue $ Float64Value $ atan2 x y+            _ -> Nothing+        )+      ),+      --+      ( "hypot16",+        ( [FloatType Float16, FloatType Float16],+          FloatType Float16,+          \case+            [FloatValue (Float16Value x), FloatValue (Float16Value y)] ->+              Just $ FloatValue $ Float16Value $ convFloat $ hypotf (convFloat x) (convFloat y)+            _ -> Nothing+        )+      ),+      ( "hypot32",+        ( [FloatType Float32, FloatType Float32],+          FloatType Float32,+          \case+            [FloatValue (Float32Value x), FloatValue (Float32Value y)] ->+              Just $ FloatValue $ Float32Value $ hypotf x y+            _ -> Nothing+        )+      ),+      ( "hypot64",+        ( [FloatType Float64, FloatType Float64],+          FloatType Float64,+          \case+            [FloatValue (Float64Value x), FloatValue (Float64Value y)] ->+              Just $ FloatValue $ Float64Value $ hypot x y+            _ -> Nothing+        )+      ),+      ( "isinf16",+        ( [FloatType Float16],+          Bool,+          \case+            [FloatValue (Float16Value x)] -> Just $ BoolValue $ isInfinite x+            _ -> Nothing+        )+      ),+      ( "isinf32",+        ( [FloatType Float32],+          Bool,+          \case+            [FloatValue (Float32Value x)] -> Just $ BoolValue $ isInfinite x+            _ -> Nothing+        )+      ),+      ( "isinf64",+        ( [FloatType Float64],+          Bool,+          \case+            [FloatValue (Float64Value x)] -> Just $ BoolValue $ isInfinite x+            _ -> Nothing+        )+      ),+      ( "isnan16",+        ( [FloatType Float16],+          Bool,+          \case+            [FloatValue (Float16Value x)] -> Just $ BoolValue $ isNaN x+            _ -> Nothing+        )+      ),+      ( "isnan32",+        ( [FloatType Float32],+          Bool,+          \case+            [FloatValue (Float32Value x)] -> Just $ BoolValue $ isNaN x+            _ -> Nothing+        )+      ),+      ( "isnan64",+        ( [FloatType Float64],+          Bool,+          \case+            [FloatValue (Float64Value x)] -> Just $ BoolValue $ isNaN x+            _ -> Nothing+        )+      ),+      ( "to_bits16",+        ( [FloatType Float16],+          IntType Int16,+          \case+            [FloatValue (Float16Value x)] ->+              Just $ IntValue $ Int16Value $ fromIntegral $ halfToWord x+            _ -> Nothing+        )+      ),+      ( "to_bits32",+        ( [FloatType Float32],+          IntType Int32,+          \case+            [FloatValue (Float32Value x)] ->+              Just $ IntValue $ Int32Value $ fromIntegral $ floatToWord x+            _ -> Nothing+        )+      ),+      ( "to_bits64",+        ( [FloatType Float64],+          IntType Int64,+          \case+            [FloatValue (Float64Value x)] ->+              Just $ IntValue $ Int64Value $ fromIntegral $ doubleToWord x+            _ -> Nothing+        )+      ),+      ( "from_bits16",+        ( [IntType Int16],+          FloatType Float16,+          \case+            [IntValue (Int16Value x)] ->+              Just $ FloatValue $ Float16Value $ wordToHalf $ fromIntegral x+            _ -> Nothing+        )+      ),+      ( "from_bits32",+        ( [IntType Int32],+          FloatType Float32,+          \case+            [IntValue (Int32Value x)] ->+              Just $ FloatValue $ Float32Value $ wordToFloat $ fromIntegral x+            _ -> Nothing+        )+      ),+      ( "from_bits64",+        ( [IntType Int64],+          FloatType Float64,+          \case+            [IntValue (Int64Value x)] ->+              Just $ FloatValue $ Float64Value $ wordToDouble $ fromIntegral x+            _ -> Nothing+        )+      ),+      f16_3 "lerp16" (\v0 v1 t -> v0 + (v1 - v0) * max 0 (min 1 t)),+      f32_3 "lerp32" (\v0 v1 t -> v0 + (v1 - v0) * max 0 (min 1 t)),+      f64_3 "lerp64" (\v0 v1 t -> v0 + (v1 - v0) * max 0 (min 1 t)),+      f16_3 "mad16" (\a b c -> a * b + c),+      f32_3 "mad32" (\a b c -> a * b + c),+      f64_3 "mad64" (\a b c -> a * b + c),+      f16_3 "fma16" (\a b c -> a * b + c),+      f32_3 "fma32" (\a b c -> a * b + c),+      f64_3 "fma64" (\a b c -> a * b + c)+    ]+  where+    i8 s f = (s, ([IntType Int8], IntType Int32, i8PrimFun f))+    i16 s f = (s, ([IntType Int16], IntType Int32, i16PrimFun f))+    i32 s f = (s, ([IntType Int32], IntType Int32, i32PrimFun f))+    i64 s f = (s, ([IntType Int64], IntType Int32, i64PrimFun f))+    f16 s f = (s, ([FloatType Float16], FloatType Float16, f16PrimFun f))+    f32 s f = (s, ([FloatType Float32], FloatType Float32, f32PrimFun f))+    f64 s f = (s, ([FloatType Float64], FloatType Float64, f64PrimFun f))+    f16_3 s f =+      ( s,+        ( [FloatType Float16, FloatType Float16, FloatType Float16],+          FloatType Float16,+          f16PrimFun3 f+        )+      )+    f32_3 s f =+      ( s,+        ( [FloatType Float32, FloatType Float32, FloatType Float32],+          FloatType Float32,+          f32PrimFun3 f+        )+      )+    f64_3 s f =+      ( s,+        ( [FloatType Float64, FloatType Float64, FloatType Float64],+          FloatType Float64,+          f64PrimFun3 f+        )+      )++    i8PrimFun f [IntValue (Int8Value x)] =+      Just $ f x+    i8PrimFun _ _ = Nothing++    i16PrimFun f [IntValue (Int16Value x)] =+      Just $ f x+    i16PrimFun _ _ = Nothing++    i32PrimFun f [IntValue (Int32Value x)] =+      Just $ f x+    i32PrimFun _ _ = Nothing++    i64PrimFun f [IntValue (Int64Value x)] =+      Just $ f x+    i64PrimFun _ _ = Nothing++    f16PrimFun f [FloatValue (Float16Value x)] =+      Just $ FloatValue $ Float16Value $ f x+    f16PrimFun _ _ = Nothing++    f32PrimFun f [FloatValue (Float32Value x)] =+      Just $ FloatValue $ Float32Value $ f x+    f32PrimFun _ _ = Nothing++    f64PrimFun f [FloatValue (Float64Value x)] =+      Just $ FloatValue $ Float64Value $ f x+    f64PrimFun _ _ = Nothing++    f16PrimFun3+      f+      [ FloatValue (Float16Value a),+        FloatValue (Float16Value b),+        FloatValue (Float16Value c)+        ] =+        Just $ FloatValue $ Float16Value $ f a b c+    f16PrimFun3 _ _ = Nothing++    f32PrimFun3+      f+      [ FloatValue (Float32Value a),+        FloatValue (Float32Value b),+        FloatValue (Float32Value c)+        ] =+        Just $ FloatValue $ Float32Value $ f a b c+    f32PrimFun3 _ _ = Nothing++    f64PrimFun3+      f+      [ FloatValue (Float64Value a),+        FloatValue (Float64Value b),+        FloatValue (Float64Value c)+        ] =+        Just $ FloatValue $ Float64Value $ f a b c+    f64PrimFun3 _ _ = Nothing++-- | Is the given value kind of zero?+zeroIsh :: PrimValue -> Bool+zeroIsh (IntValue k) = zeroIshInt k+zeroIsh (FloatValue (Float16Value k)) = k == 0+zeroIsh (FloatValue (Float32Value k)) = k == 0+zeroIsh (FloatValue (Float64Value k)) = k == 0+zeroIsh (BoolValue False) = True+zeroIsh _ = False++-- | Is the given value kind of one?+oneIsh :: PrimValue -> Bool+oneIsh (IntValue k) = oneIshInt k+oneIsh (FloatValue (Float16Value k)) = k == 1+oneIsh (FloatValue (Float32Value k)) = k == 1+oneIsh (FloatValue (Float64Value k)) = k == 1+oneIsh (BoolValue True) = True+oneIsh _ = False++-- | Is the given value kind of negative?+negativeIsh :: PrimValue -> Bool+negativeIsh (IntValue k) = negativeIshInt k+negativeIsh (FloatValue (Float16Value k)) = k < 0+negativeIsh (FloatValue (Float32Value k)) = k < 0+negativeIsh (FloatValue (Float64Value k)) = k < 0+negativeIsh (BoolValue _) = False+negativeIsh UnitValue = False++-- | Is the given integer value kind of zero?+zeroIshInt :: IntValue -> Bool+zeroIshInt (Int8Value k) = k == 0+zeroIshInt (Int16Value k) = k == 0+zeroIshInt (Int32Value k) = k == 0+zeroIshInt (Int64Value k) = k == 0++-- | Is the given integer value kind of one?+oneIshInt :: IntValue -> Bool+oneIshInt (Int8Value k) = k == 1+oneIshInt (Int16Value k) = k == 1+oneIshInt (Int32Value k) = k == 1+oneIshInt (Int64Value k) = k == 1++-- | Is the given integer value kind of negative?+negativeIshInt :: IntValue -> Bool+negativeIshInt (Int8Value k) = k < 0+negativeIshInt (Int16Value k) = k < 0+negativeIshInt (Int32Value k) = k < 0+negativeIshInt (Int64Value k) = k < 0++-- | The size of a value of a given primitive type in bits.+primBitSize :: PrimType -> Int+primBitSize = (* 8) . primByteSize++-- | The size of a value of a given primitive type in eight-bit bytes.+primByteSize :: Num a => PrimType -> a+primByteSize (IntType t) = intByteSize t+primByteSize (FloatType t) = floatByteSize t+primByteSize Bool = 1+primByteSize Unit = 0++-- | The size of a value of a given integer type in eight-bit bytes.+intByteSize :: Num a => IntType -> a+intByteSize Int8 = 1+intByteSize Int16 = 2+intByteSize Int32 = 4+intByteSize Int64 = 8++-- | The size of a value of a given floating-point type in eight-bit bytes.+floatByteSize :: Num a => FloatType -> a+floatByteSize Float16 = 2+floatByteSize Float32 = 4+floatByteSize Float64 = 8++-- | True if the given binary operator is commutative.+commutativeBinOp :: BinOp -> Bool+commutativeBinOp Add {} = True+commutativeBinOp FAdd {} = True+commutativeBinOp Mul {} = True+commutativeBinOp FMul {} = True+commutativeBinOp And {} = True+commutativeBinOp Or {} = True+commutativeBinOp Xor {} = True+commutativeBinOp LogOr {} = True+commutativeBinOp LogAnd {} = True+commutativeBinOp SMax {} = True+commutativeBinOp SMin {} = True+commutativeBinOp UMax {} = True+commutativeBinOp UMin {} = True+commutativeBinOp FMax {} = True+commutativeBinOp FMin {} = True+commutativeBinOp _ = False++-- | True if the given binary operator is associative.+associativeBinOp :: BinOp -> Bool+associativeBinOp Add {} = True+associativeBinOp Mul {} = True+associativeBinOp And {} = True+associativeBinOp Or {} = True+associativeBinOp Xor {} = True+associativeBinOp LogOr {} = True+associativeBinOp LogAnd {} = True+associativeBinOp SMax {} = True+associativeBinOp SMin {} = True+associativeBinOp UMax {} = True+associativeBinOp UMin {} = True+associativeBinOp FMax {} = True+associativeBinOp FMin {} = True+associativeBinOp _ = False++-- Prettyprinting instances++instance Pretty BinOp where+  ppr (Add t OverflowWrap) = taggedI "add" t+  ppr (Add t OverflowUndef) = taggedI "add_nw" t+  ppr (Sub t OverflowWrap) = taggedI "sub" t+  ppr (Sub t OverflowUndef) = taggedI "sub_nw" t+  ppr (Mul t OverflowWrap) = taggedI "mul" t+  ppr (Mul t OverflowUndef) = taggedI "mul_nw" t+  ppr (FAdd t) = taggedF "fadd" t+  ppr (FSub t) = taggedF "fsub" t+  ppr (FMul t) = taggedF "fmul" t+  ppr (UDiv t Safe) = taggedI "udiv_safe" t+  ppr (UDiv t Unsafe) = taggedI "udiv" t+  ppr (UDivUp t Safe) = taggedI "udiv_up_safe" t+  ppr (UDivUp t Unsafe) = taggedI "udiv_up" t+  ppr (UMod t Safe) = taggedI "umod_safe" t+  ppr (UMod t Unsafe) = taggedI "umod" t+  ppr (SDiv t Safe) = taggedI "sdiv_safe" t+  ppr (SDiv t Unsafe) = taggedI "sdiv" t+  ppr (SDivUp t Safe) = taggedI "sdiv_up_safe" t+  ppr (SDivUp t Unsafe) = taggedI "sdiv_up" t+  ppr (SMod t Safe) = taggedI "smod_safe" t+  ppr (SMod t Unsafe) = taggedI "smod" t+  ppr (SQuot t Safe) = taggedI "squot_safe" t+  ppr (SQuot t Unsafe) = taggedI "squot" t+  ppr (SRem t Safe) = taggedI "srem_safe" t+  ppr (SRem t Unsafe) = taggedI "srem" t+  ppr (FDiv t) = taggedF "fdiv" t+  ppr (FMod t) = taggedF "fmod" t+  ppr (SMin t) = taggedI "smin" t+  ppr (UMin t) = taggedI "umin" t+  ppr (FMin t) = taggedF "fmin" t+  ppr (SMax t) = taggedI "smax" t+  ppr (UMax t) = taggedI "umax" t+  ppr (FMax t) = taggedF "fmax" t+  ppr (Shl t) = taggedI "shl" t+  ppr (LShr t) = taggedI "lshr" t+  ppr (AShr t) = taggedI "ashr" t+  ppr (And t) = taggedI "and" t+  ppr (Or t) = taggedI "or" t+  ppr (Xor t) = taggedI "xor" t+  ppr (Pow t) = taggedI "pow" t+  ppr (FPow t) = taggedF "fpow" t+  ppr LogAnd = text "logand"+  ppr LogOr = text "logor"++instance Pretty CmpOp where+  ppr (CmpEq t) = text "eq_" <> ppr t+  ppr (CmpUlt t) = taggedI "ult" t+  ppr (CmpUle t) = taggedI "ule" t+  ppr (CmpSlt t) = taggedI "slt" t+  ppr (CmpSle t) = taggedI "sle" t+  ppr (FCmpLt t) = taggedF "lt" t+  ppr (FCmpLe t) = taggedF "le" t+  ppr CmpLlt = text "llt"+  ppr CmpLle = text "lle"++instance Pretty ConvOp where+  ppr op = convOp (convOpFun op) from to+    where+      (from, to) = convOpType op++instance Pretty UnOp where+  ppr Not = text "not"+  ppr (Abs t) = taggedI "abs" t+  ppr (FAbs t) = taggedF "fabs" t+  ppr (SSignum t) = taggedI "ssignum" t+  ppr (USignum t) = taggedI "usignum" t+  ppr (FSignum t) = taggedF "fsignum" t+  ppr (Complement t) = taggedI "complement" t++-- | The human-readable name for a 'ConvOp'.  This is used to expose+-- the 'ConvOp' in the @intrinsics@ module of a Futhark program.+convOpFun :: ConvOp -> String+convOpFun ZExt {} = "zext"+convOpFun SExt {} = "sext"+convOpFun FPConv {} = "fpconv"+convOpFun FPToUI {} = "fptoui"+convOpFun FPToSI {} = "fptosi"+convOpFun UIToFP {} = "uitofp"+convOpFun SIToFP {} = "sitofp"+convOpFun IToB {} = "itob"+convOpFun BToI {} = "btoi"+convOpFun FToB {} = "ftob"+convOpFun BToF {} = "btof"++taggedI :: String -> IntType -> Doc+taggedI s Int8 = text $ s ++ "8"+taggedI s Int16 = text $ s ++ "16"+taggedI s Int32 = text $ s ++ "32"+taggedI s Int64 = text $ s ++ "64"++taggedF :: String -> FloatType -> Doc+taggedF s Float16 = text $ s ++ "16"+taggedF s Float32 = text $ s ++ "32"+taggedF s Float64 = text $ s ++ "64"++convOp :: (Pretty from, Pretty to) => String -> from -> to -> Doc+convOp s from to = text s <> text "_" <> ppr from <> text "_" <> ppr to++-- | True if signed.  Only makes a difference for integer types.+prettySigned :: Bool -> PrimType -> String+prettySigned True (IntType it) = 'u' : drop 1 (pretty it)+prettySigned _ t = pretty t++mul_hi8 :: IntValue -> IntValue -> Int8+mul_hi8 a b =+  let a' = intToWord64 a+      b' = intToWord64 b+   in fromIntegral (shiftR (a' * b') 8)++mul_hi16 :: IntValue -> IntValue -> Int16+mul_hi16 a b =+  let a' = intToWord64 a+      b' = intToWord64 b+   in fromIntegral (shiftR (a' * b') 16)++mul_hi32 :: IntValue -> IntValue -> Int32+mul_hi32 a b =+  let a' = intToWord64 a+      b' = intToWord64 b+   in fromIntegral (shiftR (a' * b') 32)++mul_hi64 :: IntValue -> IntValue -> Int64+mul_hi64 a b =+  let a' = (toInteger . intToWord64) a+      b' = (toInteger . intToWord64) b+   in fromIntegral (shiftR (a' * b') 64)++mad_hi8 :: IntValue -> IntValue -> Int8 -> Int8+mad_hi8 a b c = mul_hi8 a b + c++mad_hi16 :: IntValue -> IntValue -> Int16 -> Int16+mad_hi16 a b c = mul_hi16 a b + c++mad_hi32 :: IntValue -> IntValue -> Int32 -> Int32+mad_hi32 a b c = mul_hi32 a b + c++mad_hi64 :: IntValue -> IntValue -> Int64 -> Int64+mad_hi64 a b c = mul_hi64 a b + c
+ src/Language/Futhark/Primitive/Parse.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Parsers for primitive values and types.+module Language.Futhark.Primitive.Parse+  ( pPrimValue,+    pPrimType,+    pFloatType,+    pIntType,++    -- * Building blocks+    constituent,+    lexeme,+    keyword,+    whitespace,+  )+where++import Data.Char (isAlphaNum)+import Data.Functor+import qualified Data.Text as T+import Data.Void+import Futhark.Util.Pretty hiding (empty)+import Language.Futhark.Primitive+import Text.Megaparsec+import Text.Megaparsec.Char+import qualified Text.Megaparsec.Char.Lexer as L++-- | Is this character a valid member of an identifier?+constituent :: Char -> Bool+constituent c = isAlphaNum c || (c `elem` ("_/'+-=!&^.<>*|" :: String))++-- | Consume whitespace (including skipping line comments).+whitespace :: Parsec Void T.Text ()+whitespace = L.space space1 (L.skipLineComment "--") empty++-- | Consume whitespace after the provided parser, if it succeeds.+lexeme :: Parsec Void T.Text a -> Parsec Void T.Text a+lexeme = try . L.lexeme whitespace++-- | @keyword k@ parses @k@, which must not be immediately followed by+-- a 'constituent' character.  This ensures that @iff@ is not seen as+-- the @if@ keyword followed by @f@.  Sometimes called the "maximum+-- munch" rule.+keyword :: T.Text -> Parsec Void T.Text ()+keyword s = lexeme $ chunk s *> notFollowedBy (satisfy constituent)++-- | Parse an integer value.+pIntValue :: Parsec Void T.Text IntValue+pIntValue = try $ do+  x <- L.signed (pure ()) L.decimal+  t <- pIntType+  pure $ intValue t (x :: Integer)++-- | Parse a floating-point value.+pFloatValue :: Parsec Void T.Text FloatValue+pFloatValue =+  choice+    [ pNum,+      keyword "f16.nan" $> Float16Value (0 / 0),+      keyword "f16.inf" $> Float16Value (1 / 0),+      keyword "-f16.inf" $> Float16Value (-1 / 0),+      keyword "f32.nan" $> Float32Value (0 / 0),+      keyword "f32.inf" $> Float32Value (1 / 0),+      keyword "-f32.inf" $> Float32Value (-1 / 0),+      keyword "f64.nan" $> Float64Value (0 / 0),+      keyword "f64.inf" $> Float64Value (1 / 0),+      keyword "-f64.inf" $> Float64Value (-1 / 0)+    ]+  where+    pNum = try $ do+      x <- L.signed (pure ()) L.float+      t <- pFloatType+      pure $ floatValue t (x :: Double)++-- | Parse a boolean value.+pBoolValue :: Parsec Void T.Text Bool+pBoolValue =+  choice+    [ keyword "true" $> True,+      keyword "false" $> False+    ]++-- | Defined in this module for convenience.+pPrimValue :: Parsec Void T.Text PrimValue+pPrimValue =+  choice+    [ FloatValue <$> pFloatValue,+      IntValue <$> pIntValue,+      BoolValue <$> pBoolValue,+      UnitValue <$ "()"+    ]+    <?> "primitive value"++-- | Parse a floating-point type.+pFloatType :: Parsec Void T.Text FloatType+pFloatType = choice $ map p allFloatTypes+  where+    p t = keyword (prettyText t) $> t++-- | Parse an integer type.+pIntType :: Parsec Void T.Text IntType+pIntType = choice $ map p allIntTypes+  where+    p t = keyword (prettyText t) $> t++-- | Parse a primitive type.+pPrimType :: Parsec Void T.Text PrimType+pPrimType =+  choice [p Bool, p Unit, FloatType <$> pFloatType, IntType <$> pIntType]+  where+    p t = keyword (prettyText t) $> t
src/Language/Futhark/Prop.hs view
@@ -17,7 +17,6 @@     namesToPrimTypes,     qualName,     qualify,-    typeName,     valueType,     primValueType,     leadingOperator,@@ -27,6 +26,7 @@     identifierReference,     prettyStacktrace,     progHoles,+    defaultEntryPoint,      -- * Queries on expressions     typeOf,@@ -42,7 +42,6 @@     patternStructType,     patternParam,     patternOrderZero,-    patternDimNames,      -- * Queries on types     uniqueness,@@ -51,12 +50,10 @@     diet,     arrayRank,     arrayShape,-    nestedDims,     orderZero,     unfoldFunType,     foldFunType,     typeVars,-    typeDimNames,      -- * Operations on types     peelArray,@@ -71,9 +68,6 @@     noSizes,     traverseDims,     DimPos (..),-    mustBeExplicit,-    mustBeExplicitInType,-    determineSizeWitnesses,     tupleRecord,     isTupleRecord,     areTupleFields,@@ -119,13 +113,17 @@ import Data.Maybe import Data.Ord import qualified Data.Set as S-import qualified Data.Text as T-import qualified Futhark.IR.Primitive as Primitive-import Futhark.Util (maxinum, nubOrd)+import Futhark.Util (maxinum) import Futhark.Util.Pretty+import qualified Language.Futhark.Primitive as Primitive import Language.Futhark.Syntax import Language.Futhark.Traversals+import Language.Futhark.Tuple +-- | The name of the default program entry point (@main@).+defaultEntryPoint :: Name+defaultEntryPoint = nameFromString "main"+ -- | Return the dimensionality of a type.  For non-arrays, this is -- zero.  For a one-dimensional array it is one, for a two-dimensional -- it is two, and so forth.@@ -133,38 +131,12 @@ arrayRank = shapeRank . arrayShape  -- | Return the shape of a type - for non-arrays, this is 'mempty'.-arrayShape :: TypeBase dim as -> ShapeDecl dim+arrayShape :: TypeBase dim as -> Shape dim arrayShape (Array _ _ ds _) = ds arrayShape _ = mempty --- | Return any free shape declarations in the type, with duplicates--- removed.-nestedDims :: TypeBase (DimDecl VName) as -> [DimDecl VName]-nestedDims t =-  case t of-    Array _ _ ds a ->-      nubOrd $ nestedDims (Scalar a) <> shapeDims ds-    Scalar (Record fs) ->-      nubOrd $ foldMap nestedDims fs-    Scalar Prim {} ->-      mempty-    Scalar (Sum cs) ->-      nubOrd $ foldMap (foldMap nestedDims) cs-    Scalar (Arrow _ v t1 (RetType dims t2)) ->-      filter (notV v) $ filter (`notElem` dims') $ nestedDims t1 <> nestedDims t2-      where-        dims' = map (NamedDim . qualName) dims-    Scalar (TypeVar _ _ _ targs) ->-      concatMap typeArgDims targs-  where-    typeArgDims (TypeArgDim d _) = [d]-    typeArgDims (TypeArgType at _) = nestedDims at--    notV Unnamed = const True-    notV (Named v) = (/= NamedDim (qualName v))- -- | Change the shape of a type to be just the rank.-noSizes :: TypeBase (DimDecl vn) as -> TypeBase () as+noSizes :: TypeBase Size as -> TypeBase () as noSizes = first $ const ()  -- | Where does this dimension occur?@@ -220,50 +192,6 @@     onTypeArg bound b (TypeArgType t loc) =       TypeArgType <$> go bound b t <*> pure loc -mustBeExplicitAux :: StructType -> M.Map VName Bool-mustBeExplicitAux t =-  execState (traverseDims onDim t) mempty-  where-    onDim bound _ (NamedDim d)-      | qualLeaf d `S.member` bound =-          modify $ \s -> M.insertWith (&&) (qualLeaf d) False s-    onDim _ PosImmediate (NamedDim d) =-      modify $ \s -> M.insertWith (&&) (qualLeaf d) False s-    onDim _ _ (NamedDim d) =-      modify $ M.insertWith (&&) (qualLeaf d) True-    onDim _ _ _ =-      pure ()---- | Determine which of the sizes in a type are used as sizes outside--- of functions in the type, and which are not.  The former are said--- to be "witnessed" by this type, while the latter are not.  In--- practice, the latter means that the actual sizes must come from--- somewhere else.-determineSizeWitnesses :: StructType -> (S.Set VName, S.Set VName)-determineSizeWitnesses t =-  bimap (S.fromList . M.keys) (S.fromList . M.keys) $-    M.partition not $ mustBeExplicitAux t---- | Figure out which of the sizes in a parameter type must be passed--- explicitly, because their first use is as something else than just--- an array dimension.  'mustBeExplicit' is like this function, but--- first decomposes into parameter types.-mustBeExplicitInType :: StructType -> S.Set VName-mustBeExplicitInType = snd . determineSizeWitnesses---- | Figure out which of the sizes in a binding type must be passed--- explicitly, because their first use is as something else than just--- an array dimension.-mustBeExplicit :: StructType -> S.Set VName-mustBeExplicit bind_t =-  let (ts, ret) = unfoldFunType bind_t-      alsoRet =-        M.unionWith (&&) $-          M.fromList $ zip (S.toList $ typeDimNames ret) $ repeat True-   in S.fromList $ M.keys $ M.filter id $ alsoRet $ foldl' onType mempty ts-  where-    onType uses t = uses <> mustBeExplicitAux t -- Left-biased union.- -- | Return the uniqueness of a type. uniqueness :: TypeBase shape as -> Uniqueness uniqueness (Array _ u _ _) = u@@ -332,7 +260,7 @@ arrayOf ::   Monoid as =>   Uniqueness ->-  ShapeDecl dim ->+  Shape dim ->   TypeBase dim as ->   TypeBase dim as arrayOf u s t = arrayOfWithAliases mempty u s (t `setUniqueness` Nonunique)@@ -341,7 +269,7 @@   Monoid as =>   as ->   Uniqueness ->-  ShapeDecl dim ->+  Shape dim ->   TypeBase dim as ->   TypeBase dim as arrayOfWithAliases as2 u shape2 (Array as1 _ shape1 et) =@@ -371,35 +299,6 @@ isTupleRecord (Scalar (Record fs)) = areTupleFields fs isTupleRecord _ = Nothing --- | Does this record map correspond to a tuple?-areTupleFields :: M.Map Name a -> Maybe [a]-areTupleFields fs =-  let fs' = sortFields fs-   in if and $ zipWith (==) (map fst fs') tupleFieldNames-        then Just $ map snd fs'-        else Nothing---- | Construct a record map corresponding to a tuple.-tupleFields :: [a] -> M.Map Name a-tupleFields as = M.fromList $ zip tupleFieldNames as---- | Increasing field names for a tuple (starts at 0).-tupleFieldNames :: [Name]-tupleFieldNames = map (nameFromString . show) [(0 :: Int) ..]---- | Sort fields by their name; taking care to sort numeric fields by--- their numeric value.  This ensures that tuples and tuple-like--- records match.-sortFields :: M.Map Name a -> [(Name, a)]-sortFields l = map snd $ sortOn fst $ zip (map (fieldish . fst) l') l'-  where-    l' = M.toList l-    onDigit Nothing _ = Nothing-    onDigit (Just d) c-      | isDigit c = Just $ d * 10 + ord c - ord '0'-      | otherwise = Nothing-    fieldish s = maybe (Right s) Left $ T.foldl' onDigit (Just 0) $ nameToText s- -- | Sort the constructors of a sum type in some well-defined (but not -- otherwise significant) manner. sortConstrs :: M.Map Name a -> [(Name, a)]@@ -419,10 +318,10 @@ -- expression. This is necessary since the original type may contain additional -- information (e.g., shape restrictions) from the user given annotation. combineTypeShapes ::-  (Monoid as, ArrayDim dim) =>-  TypeBase dim as ->-  TypeBase dim as ->-  TypeBase dim as+  (Monoid as) =>+  TypeBase Size as ->+  TypeBase Size as ->+  TypeBase Size as combineTypeShapes (Scalar (Record ts1)) (Scalar (Record ts2))   | M.keys ts1 == M.keys ts2 =       Scalar $@@ -473,7 +372,7 @@           flip setAliases (als1 <> als2)             <$> ( arrayOf (min u1 u2)                     <$> onShapes bound shape1 shape2-                      <*> matchDims' bound (Scalar et1) (Scalar et2)+                    <*> matchDims' bound (Scalar et1) (Scalar et2)                 )         (Scalar (Record f1), Scalar (Record f2)) ->           Scalar . Record@@ -488,7 +387,8 @@           ) ->             let bound' = mapMaybe maybePName [p1, p2] <> dims1 <> dims2 <> bound              in Scalar-                  <$> ( Arrow (als1 <> als2) p1 <$> matchDims' bound' a1 a2+                  <$> ( Arrow (als1 <> als2) p1+                          <$> matchDims' bound' a1 a2                           <*> (RetType dims1 <$> matchDims' bound' b1 b2)                       )         ( Scalar (TypeVar als1 u v targs1),@@ -507,7 +407,7 @@     maybePName Unnamed = Nothing      onShapes bound shape1 shape2 =-      ShapeDecl <$> zipWithM (onDims bound) (shapeDims shape1) (shapeDims shape2)+      Shape <$> zipWithM (onDims bound) (shapeDims shape1) (shapeDims shape2)  -- | Set the uniqueness attribute of a type.  If the type is a record -- or sum type, the uniqueness of its components will be modified.@@ -581,7 +481,7 @@   Array     mempty     Unique-    (ShapeDecl [ConstDim $ genericLength vs])+    (Shape [ConstSize $ genericLength vs])     (Prim (Unsigned Int8)) typeOf (Project _ _ (Info t) _) = t typeOf (Var _ (Info t) _) = t@@ -596,9 +496,8 @@   let RetType [] t' = foldr (arrow . patternParam) t params    in t' `setAliases` als   where-    arrow (Named v, x) (RetType dims y)-      | v `S.member` typeDimNames y =-          RetType [] $ Scalar $ Arrow () (Named v) x $ RetType (v : dims) y+    arrow (Named v, x) (RetType dims y) =+      RetType [] $ Scalar $ Arrow () (Named v) x $ RetType (v : dims) y     arrow (pn, tx) y =       RetType [] $ Scalar $ Arrow () pn tx y typeOf (OpSection _ (Info t) _) =@@ -648,10 +547,10 @@ -- sizes). valBindBound :: ValBindBase Info VName -> [VName] valBindBound vb =-  valBindName vb :-  case valBindParams vb of-    [] -> retDims (unInfo (valBindRetType vb))-    _ -> []+  valBindName vb+    : case valBindParams vb of+      [] -> retDims (unInfo (valBindRetType vb))+      _ -> []  -- | The type of a function with the given parameters and return type. funType :: [PatBase Info VName] -> StructRetType -> StructType@@ -667,13 +566,12 @@   case t of     Scalar Prim {} -> mempty     Scalar (TypeVar _ _ tn targs) ->-      mconcat $ typeVarFree tn : map typeArgFree targs+      mconcat $ S.singleton (qualLeaf tn) : map typeArgFree targs     Scalar (Arrow _ _ t1 (RetType _ t2)) -> typeVars t1 <> typeVars t2     Scalar (Record fields) -> foldMap typeVars fields     Scalar (Sum cs) -> mconcat $ (foldMap . fmap) typeVars cs     Array _ _ _ rt -> typeVars $ Scalar rt   where-    typeVarFree = S.singleton . typeLeaf     typeArgFree (TypeArgType ta _) = typeVars ta     typeArgFree TypeArgDim {} = mempty @@ -688,25 +586,6 @@ orderZero (Scalar Arrow {}) = False orderZero (Scalar (Sum cs)) = all (all orderZero) cs --- | Extract all the shape names that occur in a given pattern.-patternDimNames :: PatBase Info VName -> S.Set VName-patternDimNames (TuplePat ps _) = foldMap patternDimNames ps-patternDimNames (RecordPat fs _) = foldMap (patternDimNames . snd) fs-patternDimNames (PatParens p _) = patternDimNames p-patternDimNames (Id _ (Info tp) _) = typeDimNames tp-patternDimNames (Wildcard (Info tp) _) = typeDimNames tp-patternDimNames (PatAscription p _ _) = patternDimNames p-patternDimNames (PatLit _ (Info tp) _) = typeDimNames tp-patternDimNames (PatConstr _ _ ps _) = foldMap patternDimNames ps-patternDimNames (PatAttr _ p _) = patternDimNames p---- | Extract all the shape names that occur free in a given type.-typeDimNames :: TypeBase (DimDecl VName) als -> S.Set VName-typeDimNames = foldMap dimName . nestedDims-  where-    dimName (NamedDim qn) = S.singleton $ qualLeaf qn-    dimName _ = mempty- -- | @patternOrderZero pat@ is 'True' if all of the types in the given pattern -- have order 0. patternOrderZero :: PatBase Info vn -> Bool@@ -789,8 +668,8 @@   M.fromList     [ (nameFromString $ pretty t, t)       | t <--          Bool :-          map Signed [minBound .. maxBound]+          Bool+            : map Signed [minBound .. maxBound]             ++ map Unsigned [minBound .. maxBound]             ++ map FloatType [minBound .. maxBound]     ]@@ -803,7 +682,7 @@ data Intrinsic   = IntrinsicMonoFun [PrimType] PrimType   | IntrinsicOverloadedFun [PrimType] [Maybe PrimType] (Maybe PrimType)-  | IntrinsicPolyFun [TypeParamBase VName] [StructType] (RetTypeBase (DimDecl VName) ())+  | IntrinsicPolyFun [TypeParamBase VName] [StructType] (RetTypeBase Size ())   | IntrinsicType Liftedness [TypeParamBase VName] StructType   | IntrinsicEquality -- Special cased. @@ -811,12 +690,13 @@ intrinsicAcc =   ( acc_v,     IntrinsicType SizeLifted [TypeParamType Unlifted t_v mempty] $-      Scalar $ TypeVar () Nonunique (TypeName [] acc_v) [arg]+      Scalar $+        TypeVar () Nonunique (qualName acc_v) [arg]   )   where     acc_v = VName "acc" 10     t_v = VName "t" 11-    arg = TypeArgType (Scalar (TypeVar () Nonunique (TypeName [] t_v) [])) mempty+    arg = TypeArgType (Scalar (TypeVar () Nonunique (qualName t_v) [])) mempty  -- | A map of all built-ins. intrinsics :: M.Map VName Intrinsic@@ -858,7 +738,8 @@                  IntrinsicPolyFun                    [tp_a, sp_n, sp_m]                    [Array () Nonunique (shape [n, m]) t_a]-                   $ RetType [k] $ Array () Nonunique (shape [k]) t_a+                   $ RetType [k]+                   $ Array () Nonunique (shape [k]) t_a                ),                ( "unflatten",                  IntrinsicPolyFun@@ -867,26 +748,32 @@                      Scalar $ Prim $ Signed Int64,                      Array () Nonunique (shape [n]) t_a                    ]-                   $ RetType [k, m] $-                     Array () Nonunique (shape [k, m]) t_a+                   $ RetType [k, m]+                   $ Array () Nonunique (shape [k, m]) t_a                ),                ( "concat",                  IntrinsicPolyFun                    [tp_a, sp_n, sp_m]                    [arr_a $ shape [n], arr_a $ shape [m]]-                   $ RetType [k] $ uarr_a $ shape [k]+                   $ RetType [k]+                   $ uarr_a+                   $ shape [k]                ),                ( "rotate",                  IntrinsicPolyFun                    [tp_a, sp_n]                    [Scalar $ Prim $ Signed Int64, arr_a $ shape [n]]-                   $ RetType [] $ arr_a $ shape [n]+                   $ RetType []+                   $ arr_a+                   $ shape [n]                ),                ( "transpose",                  IntrinsicPolyFun                    [tp_a, sp_n, sp_m]                    [arr_a $ shape [n, m]]-                   $ RetType [] $ arr_a $ shape [m, n]+                   $ RetType []+                   $ arr_a+                   $ shape [m, n]                ),                ( "scatter",                  IntrinsicPolyFun@@ -895,7 +782,8 @@                      Array () Nonunique (shape [l]) (Prim $ Signed Int64),                      Array () Nonunique (shape [l]) t_a                    ]-                   $ RetType [] $ Array () Unique (shape [n]) t_a+                   $ RetType []+                   $ Array () Unique (shape [n]) t_a                ),                ( "scatter_2d",                  IntrinsicPolyFun@@ -904,7 +792,9 @@                      Array () Nonunique (shape [l]) (tupInt64 2),                      Array () Nonunique (shape [l]) t_a                    ]-                   $ RetType [] $ uarr_a $ shape [n, m]+                   $ RetType []+                   $ uarr_a+                   $ shape [n, m]                ),                ( "scatter_3d",                  IntrinsicPolyFun@@ -913,20 +803,24 @@                      Array () Nonunique (shape [l]) (tupInt64 3),                      Array () Nonunique (shape [l]) t_a                    ]-                   $ RetType [] $ uarr_a $ shape [n, m, k]+                   $ RetType []+                   $ uarr_a+                   $ shape [n, m, k]                ),                ( "zip",                  IntrinsicPolyFun                    [tp_a, tp_b, sp_n]                    [arr_a (shape [n]), arr_b (shape [n])]-                   $ RetType [] $ tuple_uarr (Scalar t_a) (Scalar t_b) $ shape [n]+                   $ RetType []+                   $ tuple_uarr (Scalar t_a) (Scalar t_b)+                   $ shape [n]                ),                ( "unzip",                  IntrinsicPolyFun                    [tp_a, tp_b, sp_n]                    [tuple_arr (Scalar t_a) (Scalar t_b) $ shape [n]]-                   $ RetType [] . Scalar . Record . M.fromList $-                     zip tupleFieldNames [arr_a $ shape [n], arr_b $ shape [n]]+                   $ RetType [] . Scalar . Record . M.fromList+                   $ zip tupleFieldNames [arr_a $ shape [n], arr_b $ shape [n]]                ),                ( "hist_1d",                  IntrinsicPolyFun@@ -938,7 +832,9 @@                      Array () Nonunique (shape [n]) (tupInt64 1),                      arr_a (shape [n])                    ]-                   $ RetType [] $ uarr_a $ shape [m]+                   $ RetType []+                   $ uarr_a+                   $ shape [m]                ),                ( "hist_2d",                  IntrinsicPolyFun@@ -950,7 +846,9 @@                      Array () Nonunique (shape [n]) (tupInt64 2),                      arr_a (shape [n])                    ]-                   $ RetType [] $ uarr_a $ shape [m, k]+                   $ RetType []+                   $ uarr_a+                   $ shape [m, k]                ),                ( "hist_3d",                  IntrinsicPolyFun@@ -962,7 +860,9 @@                      Array () Nonunique (shape [n]) (tupInt64 3),                      arr_a (shape [n])                    ]-                   $ RetType [] $ uarr_a $ shape [m, k, l]+                   $ RetType []+                   $ uarr_a+                   $ shape [m, k, l]                ),                ( "map",                  IntrinsicPolyFun@@ -970,7 +870,9 @@                    [ Scalar t_a `arr` Scalar t_b,                      arr_a $ shape [n]                    ]-                   $ RetType [] $ uarr_b $ shape [n]+                   $ RetType []+                   $ uarr_b+                   $ shape [n]                ),                ( "reduce",                  IntrinsicPolyFun@@ -979,7 +881,8 @@                      Scalar t_a,                      arr_a $ shape [n]                    ]-                   $ RetType [] $ Scalar t_a+                   $ RetType []+                   $ Scalar t_a                ),                ( "reduce_comm",                  IntrinsicPolyFun@@ -988,7 +891,8 @@                      Scalar t_a,                      arr_a $ shape [n]                    ]-                   $ RetType [] $ Scalar t_a+                   $ RetType []+                   $ Scalar t_a                ),                ( "scan",                  IntrinsicPolyFun@@ -997,7 +901,9 @@                      Scalar t_a,                      arr_a $ shape [n]                    ]-                   $ RetType [] $ uarr_a $ shape [n]+                   $ RetType []+                   $ uarr_a+                   $ shape [n]                ),                ( "partition",                  IntrinsicPolyFun@@ -1019,7 +925,9 @@                    [ Scalar (Prim $ Signed Int64) `karr` (arr_ka `arr` arr_kb),                      arr_a $ shape [n]                    ]-                   $ RetType [] $ uarr_b $ shape [n]+                   $ RetType []+                   $ uarr_b+                   $ shape [n]                ),                ( "map_stream_per",                  IntrinsicPolyFun@@ -1027,7 +935,9 @@                    [ Scalar (Prim $ Signed Int64) `karr` (arr_ka `arr` arr_kb),                      arr_a $ shape [n]                    ]-                   $ RetType [] $ uarr_b $ shape [n]+                   $ RetType []+                   $ uarr_b+                   $ shape [n]                ),                ( "reduce_stream",                  IntrinsicPolyFun@@ -1036,7 +946,8 @@                      Scalar (Prim $ Signed Int64) `karr` (arr_ka `arr` Scalar t_b),                      arr_a $ shape [n]                    ]-                   $ RetType [] $ Scalar t_b+                   $ RetType []+                   $ Scalar t_b                ),                ( "reduce_stream_per",                  IntrinsicPolyFun@@ -1045,7 +956,8 @@                      Scalar (Prim $ Signed Int64) `karr` (arr_ka `arr` Scalar t_b),                      arr_a $ shape [n]                    ]-                   $ RetType [] $ Scalar t_b+                   $ RetType []+                   $ Scalar t_b                ),                ( "acc_write",                  IntrinsicPolyFun@@ -1054,7 +966,9 @@                      Scalar (Prim $ Signed Int64),                      Scalar t_a                    ]-                   $ RetType [] $ Scalar $ accType arr_ka+                   $ RetType []+                   $ Scalar+                   $ accType arr_ka                ),                ( "scatter_stream",                  IntrinsicPolyFun@@ -1080,7 +994,9 @@                              ),                      arr_b $ shape [n]                    ]-                   $ RetType [] $ uarr_a $ shape [k]+                   $ RetType []+                   $ uarr_a+                   $ shape [k]                ),                ( "jvp2",                  IntrinsicPolyFun@@ -1089,7 +1005,9 @@                      Scalar t_a,                      Scalar t_a                    ]-                   $ RetType [] $ Scalar $ tupleRecord [Scalar t_b, Scalar t_b]+                   $ RetType []+                   $ Scalar+                   $ tupleRecord [Scalar t_b, Scalar t_b]                ),                ( "vjp2",                  IntrinsicPolyFun@@ -1098,7 +1016,9 @@                      Scalar t_a,                      Scalar t_b                    ]-                   $ RetType [] $ Scalar $ tupleRecord [Scalar t_b, Scalar t_a]+                   $ RetType []+                   $ Scalar+                   $ tupleRecord [Scalar t_b, Scalar t_a]                )              ]           ++@@ -1113,7 +1033,9 @@                   Scalar (Prim $ Signed Int64),                   Scalar (Prim $ Signed Int64)                 ]-                $ RetType [m, k] $ arr_a $ shape [m, k]+                $ RetType [m, k]+                $ arr_a+                $ shape [m, k]             ),             ( "flat_update_2d",               IntrinsicPolyFun@@ -1124,7 +1046,9 @@                   Scalar (Prim $ Signed Int64),                   arr_a $ shape [k, l]                 ]-                $ RetType [] $ uarr_a $ shape [n]+                $ RetType []+                $ uarr_a+                $ shape [n]             ),             ( "flat_index_3d",               IntrinsicPolyFun@@ -1138,7 +1062,9 @@                   Scalar (Prim $ Signed Int64),                   Scalar (Prim $ Signed Int64)                 ]-                $ RetType [m, k, l] $ arr_a $ shape [m, k, l]+                $ RetType [m, k, l]+                $ arr_a+                $ shape [m, k, l]             ),             ( "flat_update_3d",               IntrinsicPolyFun@@ -1150,7 +1076,9 @@                   Scalar (Prim $ Signed Int64),                   arr_a $ shape [k, l, p]                 ]-                $ RetType [] $ uarr_a $ shape [n]+                $ RetType []+                $ uarr_a+                $ shape [n]             ),             ( "flat_index_4d",               IntrinsicPolyFun@@ -1166,7 +1094,9 @@                   Scalar (Prim $ Signed Int64),                   Scalar (Prim $ Signed Int64)                 ]-                $ RetType [m, k, l, p] $ arr_a $ shape [m, k, l, p]+                $ RetType [m, k, l, p]+                $ arr_a+                $ shape [m, k, l, p]             ),             ( "flat_update_4d",               IntrinsicPolyFun@@ -1179,25 +1109,27 @@                   Scalar (Prim $ Signed Int64),                   arr_a $ shape [k, l, p, q]                 ]-                $ RetType [] $ uarr_a $ shape [n]+                $ RetType []+                $ uarr_a+                $ shape [n]             )           ]   where     [a, b, n, m, k, l, p, q] = zipWith VName (map nameFromString ["a", "b", "n", "m", "k", "l", "p", "q"]) [0 ..] -    t_a = TypeVar () Nonunique (typeName a) []+    t_a = TypeVar () Nonunique (qualName a) []     arr_a s = Array () Nonunique s t_a     uarr_a s = Array () Unique s t_a     tp_a = TypeParamType Unlifted a mempty -    t_b = TypeVar () Nonunique (typeName b) []+    t_b = TypeVar () Nonunique (qualName b) []     arr_b s = Array () Nonunique s t_b     uarr_b s = Array () Unique s t_b     tp_b = TypeParamType Unlifted b mempty      [sp_n, sp_m, sp_k, sp_l, sp_p, sp_q] = map (`TypeParamDim` mempty) [n, m, k, l, p, q] -    shape = ShapeDecl . map (NamedDim . qualName)+    shape = Shape . map (NamedSize . qualName)      tuple_arr x y s =       Array@@ -1209,13 +1141,13 @@      arr x y = Scalar $ Arrow mempty Unnamed x (RetType [] y) -    arr_ka = Array () Nonunique (ShapeDecl [NamedDim $ qualName k]) t_a-    uarr_ka = Array () Unique (ShapeDecl [NamedDim $ qualName k]) t_a-    arr_kb = Array () Nonunique (ShapeDecl [NamedDim $ qualName k]) t_b+    arr_ka = Array () Nonunique (Shape [NamedSize $ qualName k]) t_a+    uarr_ka = Array () Unique (Shape [NamedSize $ qualName k]) t_a+    arr_kb = Array () Nonunique (Shape [NamedSize $ qualName k]) t_b     karr x y = Scalar $ Arrow mempty (Named k) x (RetType [] y)      accType t =-      TypeVar () Unique (typeName (fst intrinsicAcc)) [TypeArgType t mempty]+      TypeVar () Unique (qualName (fst intrinsicAcc)) [TypeArgType t mempty]      namify i (x, y) = (VName (nameFromString x) i, y) @@ -1318,10 +1250,6 @@ qualify :: v -> QualName v -> QualName v qualify k (QualName ks v) = QualName (k : ks) v --- | Create a type name name with no qualifiers from a 'VName'.-typeName :: VName -> TypeName-typeName = typeNameFromQualName . qualName- -- | The modules imported by a Futhark program. progImports :: ProgBase f vn -> [(String, SrcLoc)] progImports = concatMap decImports . progDecs@@ -1461,7 +1389,7 @@     onExp e = astMap (identityMapper {mapOnExp = onExp}) e  -- | A type with no aliasing information but shape annotations.-type UncheckedType = TypeBase (ShapeDecl Name) ()+type UncheckedType = TypeBase (Shape Name) ()  -- | An expression with no type annotations. type UncheckedTypeExp = TypeExp Name
src/Language/Futhark/Query.hs view
@@ -114,7 +114,8 @@   where     vbind_t =       foldFunType (map patternStructType (valBindParams vbind)) $-        unInfo $ valBindRetType vbind+        unInfo $+          valBindRetType vbind  typeBindDefs :: TypeBind -> Defs typeBindDefs tbind =@@ -232,7 +233,7 @@   where     inArg (TypeArgExpDim dim _) = inDim dim     inArg (TypeArgExpType e2) = atPosInTypeExp e2 pos-    inDim (DimExpNamed qn loc) = do+    inDim (SizeExpNamed qn loc) = do       guard $ loc `contains` pos       Just $ RawAtName qn $ locOf loc     inDim _ = Nothing
src/Language/Futhark/Semantic.hs view
@@ -174,15 +174,21 @@             ]     where       renderTypeBind (name, TypeAbbr l tps tp) =-        p l <+> pprName name <> mconcat (map ((text " " <>) . ppr) tps)-          <> text " =" <+> ppr tp+        p l+          <+> pprName name+            <> mconcat (map ((text " " <>) . ppr) tps)+            <> text " ="+          <+> ppr tp         where           p Lifted = text "type^"           p SizeLifted = text "type~"           p Unlifted = text "type"       renderValBind (name, BoundV tps t) =-        text "val" <+> pprName name <> mconcat (map ((text " " <>) . ppr) tps)-          <> text " =" <+> ppr t+        text "val"+          <+> pprName name+            <> mconcat (map ((text " " <>) . ppr) tps)+            <> text " ="+          <+> ppr t       renderModType (name, _sig) =         text "module type" <+> pprName name       renderMod (name, mod) =
src/Language/Futhark/Syntax.hs view
@@ -10,6 +10,9 @@ -- the functor @f@, and all names are of type @vn@.  See -- https://futhark.readthedocs.org for a language reference, or this -- module may be a little hard to understand.+--+-- The system of primitive types is interesting in itself.  See+-- "Language.Futhark.Primitive". module Language.Futhark.Syntax   ( module Language.Futhark.Core,     pretty,@@ -20,17 +23,13 @@     IntType (..),     FloatType (..),     PrimType (..),-    ArrayDim (..),-    DimDecl (..),-    ShapeDecl (..),+    Size (..),+    Shape (..),     shapeRank,     stripDims,-    TypeName (..),-    typeNameFromQualName,-    qualNameFromTypeName,     TypeBase (..),     TypeArg (..),-    DimExp (..),+    SizeExp (..),     TypeExp (..),     TypeArgExp (..),     PName (..),@@ -112,15 +111,15 @@ import Data.Ord import qualified Data.Set as S import Data.Traversable-import Futhark.IR.Primitive+import Futhark.Util.Loc+import Futhark.Util.Pretty+import Language.Futhark.Core+import Language.Futhark.Primitive   ( FloatType (..),     FloatValue (..),     IntType (..),     IntValue (..),   )-import Futhark.Util.Loc-import Futhark.Util.Pretty-import Language.Futhark.Core import Prelude  -- | No information functor.  Usually used for placeholder type- or@@ -219,105 +218,53 @@   | AttrComp Name [AttrInfo vn] SrcLoc   deriving (Eq, Ord, Show) --- | A type class for things that can be array dimensions.-class Eq dim => ArrayDim dim where-  -- | @unifyDims x y@ combines @x@ and @y@ to contain their maximum-  -- common information, and fails if they conflict.-  unifyDims :: dim -> dim -> Maybe dim--instance ArrayDim () where-  unifyDims () () = Just ()---- | Declaration of a dimension size.-data DimDecl vn+-- | The elaborated size of a dimension.+data Size   = -- | The size of the dimension is this name, which     -- must be in scope.  In a return type, this will     -- give rise to an assertion.-    NamedDim (QualName vn)+    NamedSize (QualName VName)   | -- | The size is a constant.-    ConstDim Int+    ConstSize Int   | -- | No known size.  If @Nothing@, then this is a name distinct     -- from any other.  The type checker should _never_ produce these     -- - they are a (hopefully temporary) thing introduced by     -- defunctorisation and monomorphisation.-    AnyDim (Maybe vn)-  deriving (Show)--deriving instance Eq (DimDecl VName)--deriving instance Ord (DimDecl VName)--instance Functor DimDecl where-  fmap = fmapDefault--instance Foldable DimDecl where-  foldMap = foldMapDefault--instance Traversable DimDecl where-  traverse f (NamedDim qn) = NamedDim <$> traverse f qn-  traverse _ (ConstDim x) = pure $ ConstDim x-  traverse f (AnyDim v) = AnyDim <$> traverse f v---- Note that the notion of unifyDims here is intentionally not what we--- use when we do real type unification in the type checker.-instance ArrayDim (DimDecl VName) where-  unifyDims AnyDim {} y = Just y-  unifyDims x AnyDim {} = Just x-  unifyDims (NamedDim x) (NamedDim y) | x == y = Just $ NamedDim x-  unifyDims (ConstDim x) (ConstDim y) | x == y = Just $ ConstDim x-  unifyDims _ _ = Nothing+    AnySize (Maybe VName)+  deriving (Eq, Ord, Show)  -- | The size of an array type is a list of its dimension sizes.  If -- 'Nothing', that dimension is of a (statically) unknown size.-newtype ShapeDecl dim = ShapeDecl {shapeDims :: [dim]}+newtype Shape dim = Shape {shapeDims :: [dim]}   deriving (Eq, Ord, Show) -instance Foldable ShapeDecl where-  foldr f x (ShapeDecl ds) = foldr f x ds+instance Foldable Shape where+  foldr f x (Shape ds) = foldr f x ds -instance Traversable ShapeDecl where-  traverse f (ShapeDecl ds) = ShapeDecl <$> traverse f ds+instance Traversable Shape where+  traverse f (Shape ds) = Shape <$> traverse f ds -instance Functor ShapeDecl where-  fmap f (ShapeDecl ds) = ShapeDecl $ map f ds+instance Functor Shape where+  fmap f (Shape ds) = Shape $ map f ds -instance Semigroup (ShapeDecl dim) where-  ShapeDecl l1 <> ShapeDecl l2 = ShapeDecl $ l1 ++ l2+instance Semigroup (Shape dim) where+  Shape l1 <> Shape l2 = Shape $ l1 ++ l2 -instance Monoid (ShapeDecl dim) where-  mempty = ShapeDecl []+instance Monoid (Shape dim) where+  mempty = Shape []  -- | The number of dimensions contained in a shape.-shapeRank :: ShapeDecl dim -> Int+shapeRank :: Shape dim -> Int shapeRank = length . shapeDims  -- | @stripDims n shape@ strips the outer @n@ dimensions from -- @shape@, returning 'Nothing' if this would result in zero or -- fewer dimensions.-stripDims :: Int -> ShapeDecl dim -> Maybe (ShapeDecl dim)-stripDims i (ShapeDecl l)-  | i < length l = Just $ ShapeDecl $ drop i l+stripDims :: Int -> Shape dim -> Maybe (Shape dim)+stripDims i (Shape l)+  | i < length l = Just $ Shape $ drop i l   | otherwise = Nothing --- | A type name consists of qualifiers (for error messages) and a--- 'VName' (for equality checking).-data TypeName = TypeName {typeQuals :: [VName], typeLeaf :: VName}-  deriving (Show)--instance Eq TypeName where-  TypeName _ x == TypeName _ y = x == y--instance Ord TypeName where-  TypeName _ x `compare` TypeName _ y = x `compare` y---- | Convert a 'QualName' to a 'TypeName'.-typeNameFromQualName :: QualName VName -> TypeName-typeNameFromQualName (QualName qs x) = TypeName qs x---- | Convert a 'TypeName' to a 'QualName'.-qualNameFromTypeName :: TypeName -> QualName VName-qualNameFromTypeName (TypeName qs x) = QualName qs x- -- | The name (if any) of a function parameter.  The 'Eq' and 'Ord' -- instances always compare values of this type equal. data PName = Named VName | Unnamed@@ -351,7 +298,7 @@ -- convolutes the code too much if we try to statically rule it out. data ScalarTypeBase dim as   = Prim PrimType-  | TypeVar as Uniqueness TypeName [TypeArg dim]+  | TypeVar as Uniqueness (QualName VName) [TypeArg dim]   | Record (M.Map Name (TypeBase dim as))   | Sum (M.Map Name [TypeBase dim as])   | -- | The aliasing corresponds to the lexical@@ -381,7 +328,7 @@ -- out arrays-of-arrays. data TypeBase dim as   = Scalar (ScalarTypeBase dim as)-  | Array as Uniqueness (ShapeDecl dim) (ScalarTypeBase dim ())+  | Array as Uniqueness (Shape dim) (ScalarTypeBase dim ())   deriving (Eq, Ord, Show)  instance Bitraversable TypeBase where@@ -426,39 +373,39 @@  -- | A type with aliasing information and shape annotations, used for -- describing the type patterns and expressions.-type PatType = TypeBase (DimDecl VName) Aliasing+type PatType = TypeBase Size Aliasing  -- | A "structural" type with shape annotations and no aliasing -- information, used for declarations.-type StructType = TypeBase (DimDecl VName) ()+type StructType = TypeBase Size ()  -- | A value type contains full, manifest size information. type ValueType = TypeBase Int64 ()  -- | The return type version of 'StructType'.-type StructRetType = RetTypeBase (DimDecl VName) ()+type StructRetType = RetTypeBase Size ()  -- | The return type version of 'PatType'.-type PatRetType = RetTypeBase (DimDecl VName) Aliasing+type PatRetType = RetTypeBase Size Aliasing --- | A dimension declaration expression for use in a 'TypeExp'.-data DimExp vn+-- | A size expression for use in a 'TypeExp'.+data SizeExp vn   = -- | The size of the dimension is this name, which     -- must be in scope.-    DimExpNamed (QualName vn) SrcLoc+    SizeExpNamed (QualName vn) SrcLoc   | -- | The size is a constant.-    DimExpConst Int SrcLoc+    SizeExpConst Int SrcLoc   | -- | No dimension declaration.-    DimExpAny+    SizeExpAny   deriving (Show) -deriving instance Eq (DimExp Name)+deriving instance Eq (SizeExp Name) -deriving instance Eq (DimExp VName)+deriving instance Eq (SizeExp VName) -deriving instance Ord (DimExp Name)+deriving instance Ord (SizeExp Name) -deriving instance Ord (DimExp VName)+deriving instance Ord (SizeExp VName)  -- | An unstructured type with type variables and possibly shape -- declarations - this is what the user types in the source program.@@ -467,7 +414,7 @@   = TEVar (QualName vn) SrcLoc   | TETuple [TypeExp vn] SrcLoc   | TERecord [(Name, TypeExp vn)] SrcLoc-  | TEArray (DimExp vn) (TypeExp vn) SrcLoc+  | TEArray (SizeExp vn) (TypeExp vn) SrcLoc   | TEUnique (TypeExp vn) SrcLoc   | TEApply (TypeExp vn) (TypeArgExp vn) SrcLoc   | TEArrow (Maybe vn) (TypeExp vn) (TypeExp vn) SrcLoc@@ -496,7 +443,7 @@  -- | A type argument expression passed to a type constructor. data TypeArgExp vn-  = TypeArgExpDim (DimExp vn) SrcLoc+  = TypeArgExpDim (SizeExp vn) SrcLoc   | TypeArgExpType (TypeExp vn)   deriving (Show) @@ -527,7 +474,7 @@   | -- | Only observes value in this position, does     -- not consume.     Observe-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)  -- | Simple Futhark values.  Values are fully evaluated and their type -- is always unambiguous.@@ -636,8 +583,12 @@  deriving instance Eq (DimIndexBase NoInfo VName) +deriving instance Eq (DimIndexBase Info VName)+ deriving instance Ord (DimIndexBase NoInfo VName) +deriving instance Ord (DimIndexBase Info VName)+ -- | A slicing of an array (potentially multiple dimensions). type SliceBase f vn = [DimIndexBase f vn] @@ -749,8 +700,12 @@  deriving instance Eq (AppExpBase NoInfo VName) +deriving instance Eq (AppExpBase Info VName)+ deriving instance Ord (AppExpBase NoInfo VName) +deriving instance Ord (AppExpBase Info VName)+ instance Located (AppExpBase f vn) where   locOf (Range _ _ _ pos) = locOf pos   locOf (BinOp _ _ _ _ loc) = locOf loc@@ -857,6 +812,10 @@  deriving instance Ord (ExpBase NoInfo VName) +deriving instance Eq (ExpBase Info VName)++deriving instance Ord (ExpBase Info VName)+ instance Located (ExpBase f vn) where   locOf (Literal _ loc) = locOf loc   locOf (IntLit _ _ loc) = locOf loc@@ -897,8 +856,12 @@  deriving instance Eq (FieldBase NoInfo VName) +deriving instance Eq (FieldBase Info VName)+ deriving instance Ord (FieldBase NoInfo VName) +deriving instance Ord (FieldBase Info VName)+ instance Located (FieldBase f vn) where   locOf (RecordFieldExplicit _ _ loc) = locOf loc   locOf (RecordFieldImplicit _ _ loc) = locOf loc@@ -912,8 +875,12 @@  deriving instance Eq (CaseBase NoInfo VName) +deriving instance Eq (CaseBase Info VName)+ deriving instance Ord (CaseBase NoInfo VName) +deriving instance Ord (CaseBase Info VName)+ instance Located (CaseBase f vn) where   locOf (CasePat _ _ loc) = locOf loc @@ -929,8 +896,12 @@  deriving instance Eq (LoopFormBase NoInfo VName) +deriving instance Eq (LoopFormBase Info VName)+ deriving instance Ord (LoopFormBase NoInfo VName) +deriving instance Ord (LoopFormBase Info VName)+ -- | A literal in a pattern. data PatLit   = PatLitInt Integer@@ -957,7 +928,11 @@  deriving instance Eq (PatBase NoInfo VName) +deriving instance Eq (PatBase Info VName)+ deriving instance Ord (PatBase NoInfo VName)++deriving instance Ord (PatBase Info VName)  instance Located (PatBase f vn) where   locOf (TuplePat _ loc) = locOf loc
src/Language/Futhark/Traversals.hs view
@@ -39,7 +39,6 @@ data ASTMapper m = ASTMapper   { mapOnExp :: ExpBase Info VName -> m (ExpBase Info VName),     mapOnName :: VName -> m VName,-    mapOnQualName :: QualName VName -> m (QualName VName),     mapOnStructType :: StructType -> m StructType,     mapOnPatType :: PatType -> m PatType,     mapOnStructRetType :: StructRetType -> m StructRetType,@@ -52,7 +51,6 @@   ASTMapper     { mapOnExp = pure,       mapOnName = pure,-      mapOnQualName = pure,       mapOnStructType = pure,       mapOnPatType = pure,       mapOnStructRetType = pure,@@ -67,9 +65,14 @@   -- into subexpressions.  The mapping is done left-to-right.   astMap :: Monad m => ASTMapper m -> x -> m x +instance ASTMappable (QualName VName) where+  astMap tv = traverse (mapOnName tv)+ instance ASTMappable (AppExpBase Info VName) where   astMap tv (Range start next end loc) =-    Range <$> mapOnExp tv start <*> traverse (mapOnExp tv) next+    Range+      <$> mapOnExp tv start+      <*> traverse (mapOnExp tv) next       <*> traverse (mapOnExp tv) end       <*> pure loc   astMap tv (If c texp fexp loc) =@@ -81,8 +84,11 @@   astMap tv (LetPat sizes pat e body loc) =     LetPat <$> astMap tv sizes <*> astMap tv pat <*> mapOnExp tv e <*> mapOnExp tv body <*> pure loc   astMap tv (LetFun name (fparams, params, ret, t, e) body loc) =-    LetFun <$> mapOnName tv name-      <*> ( (,,,,) <$> mapM (astMap tv) fparams <*> mapM (astMap tv) params+    LetFun+      <$> mapOnName tv name+      <*> ( (,,,,)+              <$> mapM (astMap tv) fparams+              <*> mapM (astMap tv) params               <*> traverse (astMap tv) ret               <*> traverse (mapOnStructRetType tv) t               <*> mapOnExp tv e@@ -100,17 +106,22 @@   astMap tv (Coerce e tdecl loc) =     Coerce <$> mapOnExp tv e <*> astMap tv tdecl <*> pure loc   astMap tv (BinOp (fname, fname_loc) t (x, Info (xt, xext)) (y, Info (yt, yext)) loc) =-    BinOp <$> ((,) <$> mapOnQualName tv fname <*> pure fname_loc)+    BinOp+      <$> ((,) <$> astMap tv fname <*> pure fname_loc)       <*> traverse (mapOnPatType tv) t-      <*> ( (,) <$> mapOnExp tv x+      <*> ( (,)+              <$> mapOnExp tv x               <*> (Info <$> ((,) <$> mapOnStructType tv xt <*> pure xext))           )-      <*> ( (,) <$> mapOnExp tv y+      <*> ( (,)+              <$> mapOnExp tv y               <*> (Info <$> ((,) <$> mapOnStructType tv yt <*> pure yext))           )       <*> pure loc   astMap tv (DoLoop sparams mergepat mergeexp form loopbody loc) =-    DoLoop <$> mapM (mapOnName tv) sparams <*> astMap tv mergepat+    DoLoop+      <$> mapM (mapOnName tv) sparams+      <*> astMap tv mergepat       <*> mapOnExp tv mergeexp       <*> astMap tv form       <*> mapOnExp tv loopbody@@ -120,7 +131,9 @@  instance ASTMappable (ExpBase Info VName) where   astMap tv (Var name t loc) =-    Var <$> mapOnQualName tv name <*> traverse (mapOnPatType tv) t+    Var+      <$> astMap tv name+      <*> traverse (mapOnPatType tv) t       <*> pure loc   astMap tv (Hole t loc) =     Hole <$> traverse (mapOnPatType tv) t <*> pure loc@@ -135,7 +148,8 @@   astMap tv (Parens e loc) =     Parens <$> mapOnExp tv e <*> pure loc   astMap tv (QualParens (name, nameloc) e loc) =-    QualParens <$> ((,) <$> mapOnQualName tv name <*> pure nameloc)+    QualParens+      <$> ((,) <$> astMap tv name <*> pure nameloc)       <*> mapOnExp tv e       <*> pure loc   astMap tv (TupLit els loc) =@@ -151,11 +165,15 @@   astMap tv (Not x loc) =     Not <$> mapOnExp tv x <*> pure loc   astMap tv (Update src slice v loc) =-    Update <$> mapOnExp tv src <*> mapM (astMap tv) slice+    Update+      <$> mapOnExp tv src+      <*> mapM (astMap tv) slice       <*> mapOnExp tv v       <*> pure loc   astMap tv (RecordUpdate src fs v (Info t) loc) =-    RecordUpdate <$> mapOnExp tv src <*> pure fs+    RecordUpdate+      <$> mapOnExp tv src+      <*> pure fs       <*> mapOnExp tv v       <*> (Info <$> mapOnPatType tv t)       <*> pure loc@@ -164,17 +182,20 @@   astMap tv (Assert e1 e2 desc loc) =     Assert <$> mapOnExp tv e1 <*> mapOnExp tv e2 <*> pure desc <*> pure loc   astMap tv (Lambda params body ret t loc) =-    Lambda <$> mapM (astMap tv) params+    Lambda+      <$> mapM (astMap tv) params       <*> mapOnExp tv body       <*> traverse (astMap tv) ret       <*> traverse (traverse $ mapOnStructRetType tv) t       <*> pure loc   astMap tv (OpSection name t loc) =-    OpSection <$> mapOnQualName tv name+    OpSection+      <$> astMap tv name       <*> traverse (mapOnPatType tv) t       <*> pure loc   astMap tv (OpSectionLeft name t arg (Info (pa, t1a, argext), Info (pb, t1b)) (ret, retext) loc) =-    OpSectionLeft <$> mapOnQualName tv name+    OpSectionLeft+      <$> astMap tv name       <*> traverse (mapOnPatType tv) t       <*> mapOnExp tv arg       <*> ( (,)@@ -184,7 +205,8 @@       <*> ((,) <$> traverse (mapOnPatRetType tv) ret <*> traverse (mapM (mapOnName tv)) retext)       <*> pure loc   astMap tv (OpSectionRight name t arg (Info (pa, t1a), Info (pb, t1b, argext)) t2 loc) =-    OpSectionRight <$> mapOnQualName tv name+    OpSectionRight+      <$> astMap tv name       <*> traverse (mapOnPatType tv) t       <*> mapOnExp tv arg       <*> ( (,)@@ -196,7 +218,8 @@   astMap tv (ProjectSection fields t loc) =     ProjectSection fields <$> traverse (mapOnPatType tv) t <*> pure loc   astMap tv (IndexSection idxs t loc) =-    IndexSection <$> mapM (astMap tv) idxs+    IndexSection+      <$> mapM (astMap tv) idxs       <*> traverse (mapOnPatType tv) t       <*> pure loc   astMap tv (Constr name es ts loc) =@@ -212,7 +235,7 @@   astMap tv (While e) = While <$> mapOnExp tv e  instance ASTMappable (TypeExp VName) where-  astMap tv (TEVar qn loc) = TEVar <$> mapOnQualName tv qn <*> pure loc+  astMap tv (TEVar qn loc) = TEVar <$> astMap tv qn <*> pure loc   astMap tv (TETuple ts loc) = TETuple <$> traverse (astMap tv) ts <*> pure loc   astMap tv (TERecord ts loc) =     TERecord <$> traverse (traverse $ astMap tv) ts <*> pure loc@@ -234,16 +257,16 @@   astMap tv (TypeArgExpType te) =     TypeArgExpType <$> astMap tv te -instance ASTMappable (DimExp VName) where-  astMap tv (DimExpNamed vn loc) =-    DimExpNamed <$> mapOnQualName tv vn <*> pure loc-  astMap _ (DimExpConst k loc) = pure $ DimExpConst k loc-  astMap _ DimExpAny = pure DimExpAny+instance ASTMappable (SizeExp VName) where+  astMap tv (SizeExpNamed vn loc) =+    SizeExpNamed <$> astMap tv vn <*> pure loc+  astMap _ (SizeExpConst k loc) = pure $ SizeExpConst k loc+  astMap _ SizeExpAny = pure SizeExpAny -instance ASTMappable (DimDecl VName) where-  astMap tv (NamedDim vn) = NamedDim <$> mapOnQualName tv vn-  astMap _ (ConstDim k) = pure $ ConstDim k-  astMap tv (AnyDim vn) = AnyDim <$> traverse (mapOnName tv) vn+instance ASTMappable Size where+  astMap tv (NamedSize vn) = NamedSize <$> astMap tv vn+  astMap _ (ConstSize k) = pure $ ConstSize k+  astMap tv (AnySize vn) = AnySize <$> traverse (mapOnName tv) vn  instance ASTMappable (TypeParamBase VName) where   astMap = traverse . mapOnName@@ -268,7 +291,7 @@     AppRes <$> mapOnPatType tv t <*> pure ext  type TypeTraverser f t dim1 als1 dim2 als2 =-  (TypeName -> f TypeName) ->+  (QualName VName -> f (QualName VName)) ->   (dim1 -> f dim2) ->   (als1 -> f als2) ->   t dim1 als1 ->@@ -282,7 +305,10 @@ traverseScalarType f g h (TypeVar als u t args) =   TypeVar <$> h als <*> pure u <*> f t <*> traverse (traverseTypeArg f g) args traverseScalarType f g h (Arrow als v t1 (RetType dims t2)) =-  Arrow <$> h als <*> pure v <*> traverseType f g pure t1+  Arrow+    <$> h als+    <*> pure v+    <*> traverseType f g pure t1     <*> (RetType dims <$> traverseType f g h t2) traverseScalarType f g h (Sum cs) =   Sum <$> (traverse . traverse) (traverseType f g h) cs@@ -295,7 +321,7 @@  traverseTypeArg ::   Applicative f =>-  (TypeName -> f TypeName) ->+  (QualName VName -> f (QualName VName)) ->   (dim1 -> f dim2) ->   TypeArg dim1 ->   f (TypeArg dim2)@@ -305,14 +331,10 @@   TypeArgType <$> traverseType f g pure t <*> pure loc  instance ASTMappable StructType where-  astMap tv = traverseType f (astMap tv) pure-    where-      f = fmap typeNameFromQualName . mapOnQualName tv . qualNameFromTypeName+  astMap tv = traverseType (astMap tv) (astMap tv) pure  instance ASTMappable PatType where-  astMap tv = traverseType f (astMap tv) (astMap tv)-    where-      f = fmap typeNameFromQualName . mapOnQualName tv . qualNameFromTypeName+  astMap tv = traverseType (astMap tv) (astMap tv) (astMap tv)  instance ASTMappable StructRetType where   astMap tv (RetType ext t) = RetType ext <$> astMap tv t@@ -352,7 +374,8 @@   astMap tv (RecordFieldExplicit name e loc) =     RecordFieldExplicit name <$> mapOnExp tv e <*> pure loc   astMap tv (RecordFieldImplicit name t loc) =-    RecordFieldImplicit <$> mapOnName tv name+    RecordFieldImplicit+      <$> mapOnName tv name       <*> traverse (mapOnPatType tv) t       <*> pure loc 
+ src/Language/Futhark/Tuple.hs view
@@ -0,0 +1,43 @@+-- \* Basic utilities for interpreting tuples as records.+module Language.Futhark.Tuple+  ( areTupleFields,+    tupleFields,+    tupleFieldNames,+    sortFields,+  )+where++import Data.Char (isDigit, ord)+import Data.List (sortOn)+import qualified Data.Map as M+import qualified Data.Text as T+import Language.Futhark.Core (Name, nameFromString, nameToText)++-- | Does this record map correspond to a tuple?+areTupleFields :: M.Map Name a -> Maybe [a]+areTupleFields fs =+  let fs' = sortFields fs+   in if and $ zipWith (==) (map fst fs') tupleFieldNames+        then Just $ map snd fs'+        else Nothing++-- | Construct a record map corresponding to a tuple.+tupleFields :: [a] -> M.Map Name a+tupleFields as = M.fromList $ zip tupleFieldNames as++-- | Increasing field names for a tuple (starts at 0).+tupleFieldNames :: [Name]+tupleFieldNames = map (nameFromString . show) [(0 :: Int) ..]++-- | Sort fields by their name; taking care to sort numeric fields by+-- their numeric value.  This ensures that tuples and tuple-like+-- records match.+sortFields :: M.Map Name a -> [(Name, a)]+sortFields l = map snd $ sortOn fst $ zip (map (fieldish . fst) l') l'+  where+    l' = M.toList l+    onDigit Nothing _ = Nothing+    onDigit (Just d) c+      | isDigit c = Just $ d * 10 + ord c - ord '0'+      | otherwise = Nothing+    fieldish s = maybe (Right s) Left $ T.foldl' onDigit (Just 0) $ nameToText s
src/Language/Futhark/TypeChecker.hs view
@@ -11,6 +11,7 @@     checkExp,     checkDec,     checkModExp,+    Notes,     TypeError (..),     Warnings,     initialEnv,@@ -155,7 +156,8 @@   m a dupDefinitionError space name loc1 loc2 =   typeError loc1 mempty $-    "Duplicate definition of" <+> ppr space+    "Duplicate definition of"+      <+> ppr space       <+> pprName name <> ".  Previously defined at"       <+> text (locStr loc2) <> "." @@ -196,7 +198,7 @@         { envTypeTable =             M.singleton v $               TypeAbbr l [] . RetType [] . Scalar $-                TypeVar () Nonunique (typeName v) []+                TypeVar () Nonunique (qualName v) []         }  checkTypeDecl ::@@ -224,7 +226,8 @@         unless (null ext) $           typeError loc mempty $             "All function parameters must have non-anonymous sizes."-              </> "Hint: add size parameters to" <+> pquote (pprName name') <> "."+              </> "Hint: add size parameters to"+              <+> pquote (pprName name') <> "."          pure (tparams', vtype', vtype_t) @@ -260,7 +263,7 @@                 envTypeTable =                   M.singleton name' $                     TypeAbbr l ps' . RetType [] . Scalar $-                      TypeVar () Nonunique (typeName name') $+                      TypeVar () Nonunique (qualName name') $                         map typeParamToArg ps'               }       (abstypes, env, specs') <- localEnv tenv $ checkSpecs specs@@ -551,7 +554,7 @@     (te', svars, RetType dims t, l') <- bindingTypeParams tps' $ checkTypeExp te     let elab_t = RetType (svars ++ dims) t -    let used_dims = typeDimNames t+    let used_dims = freeInType t     case filter ((`S.notMember` used_dims) . typeParamName) $       filter isSizeParam tps' of       [] -> pure ()@@ -598,7 +601,7 @@      -- Since the entry point type is not a RetType but just a plain     -- StructType, we have to remove any existentially bound sizes.-    extToAny (NamedDim v) | qualLeaf v `elem` ret = AnyDim Nothing+    extToAny (NamedSize v) | qualLeaf v `elem` ret = AnySize Nothing     extToAny d = d      patternEntry (PatParens p _) =@@ -646,8 +649,8 @@           typeError loc mempty "Entry point functions may not be higher-order."       | sizes_only_in_ret <-           S.fromList (map typeParamName tparams')-            `S.intersection` typeDimNames rettype'-            `S.difference` foldMap typeDimNames (map patternStructType params' ++ rettype_params),+            `S.intersection` freeInType rettype'+            `S.difference` foldMap freeInType (map patternStructType params' ++ rettype_params),         not $ S.null sizes_only_in_ret ->           typeError loc mempty "Entry point functions must not be size-polymorphic in their return type."       | p : _ <- filter nastyParameter params' ->@@ -730,7 +733,8 @@ checkOneDec (ImportDec name NoInfo loc) = do   (name', env) <- lookupImport loc name   when (isBuiltin name) $-    typeError loc mempty $ ppr name <+> "may not be explicitly imported."+    typeError loc mempty $+      ppr name <+> "may not be explicitly imported."   pure (mempty, env, ImportDec name (Info name') loc) checkOneDec (ValDec vb) = do   (env, vb') <- checkValBind vb
src/Language/Futhark/TypeChecker/Modules.hs view
@@ -58,7 +58,8 @@ allNamesInEnv :: Env -> S.Set VName allNamesInEnv (Env vtable ttable stable modtable _names) =   S.fromList-    ( M.keys vtable ++ M.keys ttable+    ( M.keys vtable+        ++ M.keys ttable         ++ M.keys stable         ++ M.keys modtable     )@@ -139,9 +140,9 @@           TypeParamType l (substitute p) loc          substituteInType :: StructType -> StructType-        substituteInType (Scalar (TypeVar () u (TypeName qs v) targs)) =+        substituteInType (Scalar (TypeVar () u (QualName qs v) targs)) =           Scalar $-            TypeVar () u (TypeName (map substitute qs) $ substitute v) $+            TypeVar () u (QualName (map substitute qs) $ substitute v) $               map substituteInTypeArg targs         substituteInType (Scalar (Prim t)) =           Scalar $ Prim t@@ -154,18 +155,18 @@         substituteInType (Scalar (Arrow als v t1 (RetType dims t2))) =           Scalar $ Arrow als v (substituteInType t1) $ RetType dims $ substituteInType t2 -        substituteInShape (ShapeDecl ds) =-          ShapeDecl $ map substituteInDim ds-        substituteInDim (NamedDim (QualName qs v)) =-          NamedDim $ QualName (map substitute qs) $ substitute v+        substituteInShape (Shape ds) =+          Shape $ map substituteInDim ds+        substituteInDim (NamedSize (QualName qs v)) =+          NamedSize $ QualName (map substitute qs) $ substitute v         substituteInDim d = d -        substituteInTypeArg (TypeArgDim (NamedDim (QualName qs v)) loc) =-          TypeArgDim (NamedDim $ QualName (map substitute qs) $ substitute v) loc-        substituteInTypeArg (TypeArgDim (ConstDim x) loc) =-          TypeArgDim (ConstDim x) loc-        substituteInTypeArg (TypeArgDim (AnyDim v) loc) =-          TypeArgDim (AnyDim v) loc+        substituteInTypeArg (TypeArgDim (NamedSize (QualName qs v)) loc) =+          TypeArgDim (NamedSize $ QualName (map substitute qs) $ substitute v) loc+        substituteInTypeArg (TypeArgDim (ConstSize x) loc) =+          TypeArgDim (ConstSize x) loc+        substituteInTypeArg (TypeArgDim (AnySize v) loc) =+          TypeArgDim (AnySize v) loc         substituteInTypeArg (TypeArgType t loc) =           TypeArgType (substituteInType t) loc @@ -193,7 +194,7 @@   StructType ->   TypeM (QualName VName, TySet, Env) refineEnv loc tset env tname ps t-  | Just (tname', TypeAbbr _ cur_ps (RetType _ (Scalar (TypeVar () _ (TypeName qs v) _)))) <-+  | Just (tname', TypeAbbr _ cur_ps (RetType _ (Scalar (TypeVar () _ (QualName qs v) _)))) <-       findTypeDef tname (ModEnv env),     QualName (qualQuals tname') v `M.member` tset =       if paramsMatch cur_ps ps@@ -285,7 +286,8 @@       Left . TypeError (locOf loc) mempty $         "Module defines"           </> indent 2 (ppTypeAbbr abs name mod_t)-          </> "but module type requires" <+> text what <> "."+          </> "but module type requires"+          <+> text what <> "."       where         what = case name_l of           Unlifted -> "a non-lifted type"@@ -369,12 +371,14 @@  ppTypeAbbr :: [VName] -> QualName VName -> (Liftedness, [TypeParam], StructRetType) -> Doc ppTypeAbbr abs name (l, ps, RetType [] (Scalar (TypeVar () _ tn args)))-  | typeLeaf tn `elem` abs,+  | qualLeaf tn `elem` abs,     map typeParamToArg ps == args =-      "type" <> ppr l <+> ppr name+      "type" <> ppr l+        <+> ppr name         <+> spread (map ppr ps) ppTypeAbbr _ name (l, ps, t) =-  "type" <> ppr l <+> ppr name+  "type" <> ppr l+    <+> ppr name     <+> spread (map ppr ps)     <+> equals     <+/> nest 2 (align (ppr t))@@ -390,7 +394,7 @@   Either TypeError (M.Map VName VName) matchMTys orig_mty orig_mty_sig =   matchMTys'-    (M.map (SizeSubst . NamedDim) $ resolveMTyNames orig_mty orig_mty_sig)+    (M.map (SizeSubst . NamedSize) $ resolveMTyNames orig_mty orig_mty_sig)     []     orig_mty     orig_mty_sig@@ -585,7 +589,10 @@           | otherwise -> Just Nothing      ppValBind v (BoundV tps t) =-      "val" <+> ppr v <+> spread (map ppr tps) <+> colon+      "val"+        <+> ppr v+        <+> spread (map ppr tps)+        <+> colon         </> indent 2 (align (ppr t))  -- | Apply a parametric module to an argument.@@ -605,7 +612,7 @@   let a_abbrs = mtyTypeAbbrs a_mty       isSub v = case M.lookup v a_abbrs of         Just abbr -> Just $ substFromAbbr abbr-        _ -> Just $ SizeSubst $ NamedDim $ qualName v+        _ -> Just $ SizeSubst $ NamedSize $ qualName v       type_subst = M.mapMaybe isSub p_subst       body_mty' = substituteTypesInMTy (`M.lookup` type_subst) body_mty   (body_mty'', body_subst) <- newNamesForMTy body_mty'
src/Language/Futhark/TypeChecker/Monad.hs view
@@ -145,8 +145,9 @@   m a underscoreUse loc name =   typeError loc mempty $-    "Use of" <+> pquote (ppr name)-      <> ": variables prefixed with underscore may not be accessed."+    "Use of"+      <+> pquote (ppr name)+        <> ": variables prefixed with underscore may not be accessed."  -- | A mapping from import strings to 'Env's.  This is used to resolve -- @import@ declarations.@@ -244,8 +245,10 @@   case M.lookup canonical_import imports of     Nothing ->       typeError loc mempty $-        "Unknown import" <+> dquotes (text canonical_import)-          </> "Known:" <+> commasep (map text (M.keys imports))+        "Unknown import"+          <+> dquotes (text canonical_import)+          </> "Known:"+          <+> commasep (map text (M.keys imports))     Just scope -> pure (canonical_import, scope)  -- | Evaluate a 'TypeM' computation within an extended (/not/@@ -280,14 +283,16 @@   lookupMod :: SrcLoc -> QualName Name -> m (QualName VName, Mod)   lookupVar :: SrcLoc -> QualName Name -> m (QualName VName, PatType) -  checkNamedDim :: SrcLoc -> QualName Name -> m (QualName VName)-  checkNamedDim loc v = do+  checkNamedSize :: SrcLoc -> QualName Name -> m (QualName VName)+  checkNamedSize loc v = do     (v', t) <- lookupVar loc v     case t of       Scalar (Prim (Signed Int64)) -> pure v'       _ ->         typeError loc mempty $-          "Sizes must have type i64, but" <+> pquote (ppr v) <+> "has type:"+          "Sizes must have type i64, but"+            <+> pquote (ppr v)+            <+> "has type:"             </> ppr t    typeError :: Located loc => loc -> Notes -> Doc -> m a@@ -405,24 +410,22 @@   Env ->   [VName] ->   [VName] ->-  TypeBase (DimDecl VName) as ->-  TypeBase (DimDecl VName) as+  TypeBase Size as ->+  TypeBase Size as qualifyTypeVars outer_env orig_except ref_qs = onType (S.fromList orig_except)   where     onType ::       S.Set VName ->-      TypeBase (DimDecl VName) as ->-      TypeBase (DimDecl VName) as+      TypeBase Size as ->+      TypeBase Size as     onType except (Array as u shape et) =       Array as u (fmap (onDim except) shape) (onScalar except et)     onType except (Scalar t) =       Scalar $ onScalar except t      onScalar _ (Prim t) = Prim t-    onScalar except (TypeVar as u tn targs) =-      TypeVar as u tn' $ map (onTypeArg except) targs-      where-        tn' = typeNameFromQualName $ qual except $ qualNameFromTypeName tn+    onScalar except (TypeVar as u qn targs) =+      TypeVar as u (qual except qn) (map (onTypeArg except) targs)     onScalar except (Record m) =       Record $ M.map (onType except) m     onScalar except (Sum m) =@@ -439,7 +442,7 @@     onTypeArg except (TypeArgType t loc) =       TypeArgType (onType except t) loc -    onDim except (NamedDim qn) = NamedDim $ qual except qn+    onDim except (NamedSize qn) = NamedSize $ qual except qn     onDim _ d = d      qual except (QualName orig_qs name)@@ -458,7 +461,7 @@       name `M.member` envVtable env         || isJust (find matches $ M.elems (envTypeTable env))       where-        matches (TypeAbbr _ _ (RetType _ (Scalar (TypeVar _ _ (TypeName x_qs name') _)))) =+        matches (TypeAbbr _ _ (RetType _ (Scalar (TypeVar _ _ (QualName x_qs name') _)))) =           null x_qs && name == name'         matches _ = False     reachable (q : qs') name env
src/Language/Futhark/TypeChecker/Terms.hs view
@@ -27,9 +27,9 @@ import qualified Data.Map.Strict as M import Data.Maybe import qualified Data.Set as S-import Futhark.IR.Primitive (intByteSize) import Futhark.Util.Pretty hiding (bool, group, space) import Language.Futhark+import Language.Futhark.Primitive (intByteSize) import Language.Futhark.Traversals import Language.Futhark.TypeChecker.Match import Language.Futhark.TypeChecker.Monad hiding (BoundV)@@ -66,13 +66,13 @@ sliceShape ::   Maybe (SrcLoc, Rigidity) ->   Slice ->-  TypeBase (DimDecl VName) as ->-  TermTypeM (TypeBase (DimDecl VName) as, [VName])-sliceShape r slice t@(Array als u (ShapeDecl orig_dims) et) =+  TypeBase Size as ->+  TermTypeM (TypeBase Size as, [VName])+sliceShape r slice t@(Array als u (Shape orig_dims) et) =   runStateT (setDims <$> adjustDims slice orig_dims) []   where     setDims [] = stripArray (length orig_dims) t-    setDims dims' = Array als u (ShapeDecl dims') et+    setDims dims' = Array als u (Shape dims') et      -- If the result is supposed to be a nonrigid size variable, then     -- don't bother trying to create non-existential sizes.  This is@@ -91,11 +91,11 @@           modify (maybeToList ext ++)           pure d         Just (loc, Nonrigid) ->-          lift $ NamedDim . qualName <$> newDimVar loc Nonrigid "slice_dim"+          lift $ NamedSize . qualName <$> newDimVar loc Nonrigid "slice_dim"         Nothing -> do           v <- lift $ newID "slice_anydim"           modify (v :)-          pure $ NamedDim $ qualName v+          pure $ NamedSize $ qualName v       where         -- The original size does not matter if the slice is fully specified.         orig_d'@@ -136,7 +136,7 @@  noAliasesIfOverloaded :: PatType -> TermTypeM PatType noAliasesIfOverloaded t@(Scalar (TypeVar _ u tn [])) = do-  subst <- fmap snd . M.lookup (typeLeaf tn) <$> getConstraints+  subst <- fmap snd . M.lookup (qualLeaf tn) <$> getConstraints   case subst of     Just Overloaded {} -> pure $ Scalar $ TypeVar mempty u tn []     _ -> pure t@@ -187,7 +187,7 @@   (t', m) <- runStateT (traverseDims onDim t) mempty   pure (t' `addAliases` S.map unAlias, M.elems m)   where-    onDim bound _ (NamedDim d)+    onDim bound _ (NamedSize d)       | Just loc <- srclocOf <$> M.lookup (qualLeaf d) unscoped,         not $ qualLeaf d `S.member` bound =           inst loc $ qualLeaf d@@ -196,34 +196,15 @@     inst loc d = do       prev <- gets $ M.lookup d       case prev of-        Just d' -> pure $ NamedDim $ qualName d'+        Just d' -> pure $ NamedSize $ qualName d'         Nothing -> do           d' <- lift $ newDimVar tloc (Rigid $ RigidOutOfScope loc d) "d"           modify $ M.insert d d'-          pure $ NamedDim $ qualName d'+          pure $ NamedSize $ qualName d'      unAlias (AliasBound v) | v `M.member` unscoped = AliasFree v     unAlias a = a --- When a function result is not immediately bound to a name, we need--- to invent a name for it so we can track it during aliasing--- (uniqueness-error54.fut, uniqueness-error55.fut).-addResultAliases :: NameReason -> PatType -> TermTypeM PatType-addResultAliases r (Scalar (Record fs)) =-  Scalar . Record <$> traverse (addResultAliases r) fs-addResultAliases r (Scalar (Sum fs)) =-  Scalar . Sum <$> traverse (traverse (addResultAliases r)) fs-addResultAliases r (Scalar (TypeVar as u tn targs)) = do-  v <- newID "internal_app_result"-  modify $ \s -> s {stateNames = M.insert v r $ stateNames s}-  pure $ Scalar $ TypeVar (S.insert (AliasFree v) as) u tn targs-addResultAliases _ (Scalar t@Prim {}) = pure (Scalar t)-addResultAliases _ (Scalar t@Arrow {}) = pure (Scalar t)-addResultAliases r (Array als u t shape) = do-  v <- newID "internal_app_result"-  modify $ \s -> s {stateNames = M.insert v r $ stateNames s}-  pure $ Array (S.insert (AliasFree v) als) u t shape- -- 'checkApplyExp' is like 'checkExp', but tries to find the "root -- function", for better error messages. checkApplyExp :: UncheckedExp -> TermTypeM (Exp, ApplyOp)@@ -232,11 +213,10 @@   (e1', (fname, i)) <- checkApplyExp e1   t <- expType e1'   (t1, rt, argext, exts) <- checkApply loc (fname, i) t arg-  rt' <- addResultAliases (NameAppRes fname loc) rt   pure     ( AppExp         (Apply e1' (argExp arg) (Info (diet t1, argext)) loc)-        (Info $ AppRes rt' exts),+        (Info $ AppRes rt exts),       (fname, i + 1)     ) checkApplyExp e = do@@ -288,7 +268,8 @@       case maybe_sloc of         Just sloc ->           lift . typeError rloc mempty $-            "Field" <+> pquote (ppr f)+            "Field"+              <+> pquote (ppr f)               <+> "previously defined at"               <+> text (locStrRel rloc sloc) <> "."         Nothing -> pure ()@@ -301,14 +282,14 @@   case all_es of     [] -> do       et <- newTypeVar loc "t"-      t <- arrayOfM loc et (ShapeDecl [ConstDim 0]) Unique+      t <- arrayOfM loc et (Shape [ConstSize 0]) Unique       pure $ ArrayLit [] (Info t) loc     e : es -> do       e' <- checkExp e       et <- expType e'       es' <- mapM (unifies "type of first array element" (toStruct et) <=< checkExp) es       et' <- normTypeFully et-      t <- arrayOfM loc et' (ShapeDecl [ConstDim $ length all_es]) Unique+      t <- arrayOfM loc et' (Shape [ConstSize $ length all_es]) Unique       pure $ ArrayLit (e' : es') (Info t) loc checkExp (AppExp (Range start maybe_step end loc) _) = do   start' <- require "use in range expression" anySignedType =<< checkExp start@@ -346,9 +327,9 @@             dimFromBound end''       _ -> do         d <- newDimVar loc (Rigid RigidRange) "range_dim"-        pure (NamedDim $ qualName d, Just d)+        pure (NamedSize $ qualName d, Just d) -  t <- arrayOfM loc start_t (ShapeDecl [dim]) Unique+  t <- arrayOfM loc start_t (Shape [dim]) Unique   let res = AppRes (t `setAliases` mempty) (maybeToList retext)    pure $ AppExp (Range start' maybe_step' end' loc) (Info res)@@ -650,7 +631,7 @@           named (Unnamed, _) = Nothing           param_names = mapMaybe (named . patternParam) params'           pos_sizes =-            typeDimNamesPos . foldFunType (map patternStructType params') $+            sizeNamesPos . foldFunType (map patternStructType params') $               RetType [] ret           hide k (lvl, _) =             lvl >= cur_lvl && k `notElem` param_names && k `S.notMember` pos_sizes@@ -658,11 +639,11 @@       hidden_sizes <-         S.fromList . M.keys . M.filterWithKey hide <$> getConstraints -      let onDim (NamedDim name)-            | qualLeaf name `S.member` hidden_sizes = S.singleton $ qualLeaf name+      let onDim name+            | name `S.member` hidden_sizes = S.singleton name           onDim _ = mempty -      pure $ RetType (S.toList $ foldMap onDim $ nestedDims ret) ret+      pure $ RetType (S.toList $ foldMap onDim $ freeInType ret) ret checkExp (OpSection op _ loc) = do   (op', ftype) <- lookupVar loc op   pure $ OpSection op' (Info ftype) loc@@ -801,20 +782,6 @@       ppr' (PatLit e _ _) = ppr e       ppr' (PatConstr n _ ps _) = "#" <> ppr n <+> sep (map ppr' ps) -checkUnmatched :: Exp -> TermTypeM ()-checkUnmatched e = void $ checkUnmatched' e >> astMap tv e-  where-    checkUnmatched' (AppExp (Match _ cs loc) _) =-      let ps = fmap (\(CasePat p _ _) -> p) cs-       in case unmatched $ NE.toList ps of-            [] -> pure ()-            ps' ->-              typeError loc mempty . withIndexLink "unmatched-cases" $-                "Unmatched cases in match expression:"-                  </> indent 2 (stack (map ppr ps'))-    checkUnmatched' _ = pure ()-    tv = identityMapper {mapOnExp = \e' -> checkUnmatched' e' >> pure e'}- checkIdent :: IdentBase NoInfo Name -> TermTypeM Ident checkIdent (Ident name _ loc) = do   (QualName _ name', vt) <- lookupVar loc (qualName name)@@ -854,8 +821,8 @@ instantiateDimsInReturnType ::   SrcLoc ->   Maybe (QualName VName) ->-  RetTypeBase (DimDecl VName) als ->-  TermTypeM (TypeBase (DimDecl VName) als, [VName])+  RetTypeBase Size als ->+  TermTypeM (TypeBase Size als, [VName]) instantiateDimsInReturnType tloc fname =   instantiateEmptyArrayDims tloc $ Rigid $ RigidRet fname @@ -865,7 +832,7 @@ type ApplyOp = (Maybe (QualName VName), Int)  -- | Extract all those names that are bound inside the type.-boundInsideType :: TypeBase (DimDecl VName) as -> S.Set VName+boundInsideType :: TypeBase Size as -> S.Set VName boundInsideType (Array _ _ _ t) = boundInsideType (Scalar t) boundInsideType (Scalar Prim {}) = mempty boundInsideType (Scalar (TypeVar _ _ _ targs)) = foldMap f targs@@ -886,9 +853,9 @@ dimUses :: StructType -> (Names, Names) dimUses = flip execState mempty . traverseDims f   where-    f bound _ (NamedDim v) | qualLeaf v `S.member` bound = pure ()-    f _ PosImmediate (NamedDim v) = modify ((S.singleton (qualLeaf v), mempty) <>)-    f _ PosParam (NamedDim v) = modify ((mempty, S.singleton (qualLeaf v)) <>)+    f bound _ (NamedSize v) | qualLeaf v `S.member` bound = pure ()+    f _ PosImmediate (NamedSize v) = modify ((S.singleton (qualLeaf v), mempty) <>)+    f _ PosParam (NamedSize v) = modify ((mempty, S.singleton (qualLeaf v)) <>)     f _ _ _ = pure ()  checkApply ::@@ -943,14 +910,22 @@         case pname of           Named pname'             | (Scalar (Prim (Signed Int64))) <- tp1' -> do-                (d, argext) <- dimFromArg fname argexp+                (d, argext) <- sizeFromArg fname argexp                 pure                   ( argext,                     (`M.lookup` M.singleton pname' (SizeSubst d))                   )           _ -> pure (Nothing, const Nothing)-      let tp2'' = applySubst parsubst $ returnType tp2' (diet tp1') argtype' +      -- In case a function result is not immediately bound to a name,+      -- we need to invent a name for it so we can track it during+      -- aliasing (uniqueness-error54.fut, uniqueness-error55.fut,+      -- uniqueness-error60.fut).+      v <- newID "internal_app_result"+      modify $ \s -> s {stateNames = M.insert v (NameAppRes fname loc) $ stateNames s}+      let appres = S.singleton $ AliasFree v+      let tp2'' = applySubst parsubst $ returnType appres tp2' (diet tp1') argtype'+       pure (tp1', tp2'', argext, ext) checkApply loc fname tfun@(Scalar TypeVar {}) arg = do   tv <- newTypeVar loc "b"@@ -958,7 +933,9 @@   -- to infer that a function is consuming.   let argt_nonunique = toStruct (argType arg) `setUniqueness` Nonunique   unify (mkUsage loc "use as function") (toStruct tfun) $-    Scalar $ Arrow mempty Unnamed argt_nonunique $ RetType [] tv+    Scalar $+      Arrow mempty Unnamed argt_nonunique $+        RetType [] tv   tfun' <- normPatType tfun   checkApply loc fname tfun' arg checkApply loc (fname, prev_applied) ftype (argexp, _, _, _) = do@@ -967,10 +944,14 @@   typeError loc mempty $     if prev_applied == 0       then-        "Cannot apply" <+> fname' <+> "as function, as it has type:"+        "Cannot apply"+          <+> fname'+          <+> "as function, as it has type:"           </> indent 2 (ppr ftype)       else-        "Cannot apply" <+> fname' <+> "to argument #" <> ppr (prev_applied + 1)+        "Cannot apply"+          <+> fname'+          <+> "to argument #" <> ppr (prev_applied + 1)           <+> pquote (shorten $ pretty $ flatten $ ppr argexp) <> ","           <+/> "as"           <+> fname'@@ -982,39 +963,40 @@       | prev_applied == 1 = "argument"       | otherwise = "arguments" --- | @returnType ret_type arg_diet arg_type@ gives result of applying+-- | @returnType appres ret_type arg_diet arg_type@ gives result of applying -- an argument the given types to a function with the given return -- type, consuming the argument with the given diet. returnType ::+  Aliasing ->   PatType ->   Diet ->   PatType ->   PatType-returnType (Array _ Unique et shape) _ _ =+returnType _ (Array _ Unique et shape) _ _ =   Array mempty Nonunique et shape -- Intentional!-returnType (Array als Nonunique et shape) d arg =-  Array (als <> arg_als) Nonunique et shape+returnType appres (Array als Nonunique et shape) d arg =+  Array (appres <> als <> arg_als) Nonunique et shape   where     arg_als = aliases $ maskAliases arg d-returnType (Scalar (Record fs)) d arg =-  Scalar $ Record $ fmap (\et -> returnType et d arg) fs-returnType (Scalar (Prim t)) _ _ =+returnType appres (Scalar (Record fs)) d arg =+  Scalar $ Record $ fmap (\et -> returnType appres et d arg) fs+returnType _ (Scalar (Prim t)) _ _ =   Scalar $ Prim t-returnType (Scalar (TypeVar _ Unique t targs)) _ _ =+returnType _ (Scalar (TypeVar _ Unique t targs)) _ _ =   Scalar $ TypeVar mempty Nonunique t targs -- Intentional!-returnType (Scalar (TypeVar als Nonunique t targs)) d arg =-  Scalar $ TypeVar (als <> arg_als) Unique t targs+returnType appres (Scalar (TypeVar als Nonunique t targs)) d arg =+  Scalar $ TypeVar (appres <> als <> arg_als) Unique t targs   where     arg_als = aliases $ maskAliases arg d-returnType (Scalar (Arrow old_als v t1 (RetType dims t2))) d arg =+returnType _ (Scalar (Arrow old_als v t1 (RetType dims t2))) d arg =   Scalar $ Arrow als v (t1 `setAliases` mempty) $ RetType dims $ t2 `setAliases` als   where     -- Make sure to propagate the aliases of an existing closure.     als = old_als <> aliases (maskAliases arg d)-returnType (Scalar (Sum cs)) d arg =-  Scalar $ Sum $ (fmap . fmap) (\et -> returnType et d arg) cs+returnType appres (Scalar (Sum cs)) d arg =+  Scalar $ Sum $ (fmap . fmap) (\et -> returnType appres et d arg) cs --- | @t `maskAliases` d@ removes aliases (sets them to 'mempty') from+-- @t `maskAliases` d@ removes aliases (sets them to 'mempty') from -- the parts of @t@ that are denoted as consumed by the 'Diet' @d@. maskAliases ::   Monoid as =>@@ -1064,9 +1046,8 @@     letGeneralise (nameFromString "<exp>") (srclocOf e) [] [] t   fixOverloadedTypes $ typeVars t   e'' <- updateTypes e'-  checkUnmatched e''+  localChecks e''   causalityCheck e''-  literalOverflowCheck e''   pure (tparams, e'')  -- Verify that all sum type constructors and empty array literals have@@ -1079,7 +1060,9 @@   let checkCausality what known t loc         | (d, dloc) : _ <-             mapMaybe (unknown constraints known) $-              S.toList $ typeDimNames $ toStruct t =+              S.toList $+                freeInType $+                  toStruct t =             Just $ lift $ causality what (locOf loc) d dloc t         | otherwise = Nothing @@ -1162,7 +1145,8 @@      causality what loc d dloc t =       Left . TypeError loc mempty . withIndexLink "causality-check" $-        "Causality check: size" <+/> pquote (pprName d)+        "Causality check: size"+          <+/> pquote (pprName d)           <+/> "needed for type of"           <+> what <> colon           </> indent 2 (ppr t)@@ -1173,31 +1157,53 @@           </> ""           </> "Hint:"           <+> align-            ( textwrap "Bind the expression producing" <+> pquote (pprName d)+            ( textwrap "Bind the expression producing"+                <+> pquote (pprName d)                 <+> "with 'let' beforehand."             ) --- | Traverse the expression, emitting warnings if any of the literals overflow--- their inferred types+-- | Traverse the expression, emitting warnings and errors for various+-- problems: ----- Note: currently unable to detect float underflow (such as 1e-400 -> 0)-literalOverflowCheck :: Exp -> TermTypeM ()-literalOverflowCheck = void . check+-- * Unmatched cases.+--+-- * If any of the literals overflow their inferred types. Note:+--  currently unable to detect float underflow (such as 1e-400 -> 0)+localChecks :: Exp -> TermTypeM ()+localChecks = void . check   where+    check e@(AppExp (Match _ cs loc) _) = do+      let ps = fmap (\(CasePat p _ _) -> p) cs+      case unmatched $ NE.toList ps of+        [] -> recurse e+        ps' ->+          typeError loc mempty . withIndexLink "unmatched-cases" $+            "Unmatched cases in match expression:"+              </> indent 2 (stack (map ppr ps'))     check e@(IntLit x ty loc) =       e <$ case ty of-        Info (Scalar (Prim t)) -> warnBounds (inBoundsI x t) x t loc+        Info (Scalar (Prim t)) -> errorBounds (inBoundsI x t) x t loc         _ -> error "Inferred type of int literal is not a number"     check e@(FloatLit x ty loc) =       e <$ case ty of-        Info (Scalar (Prim (FloatType t))) -> warnBounds (inBoundsF x t) x t loc+        Info (Scalar (Prim (FloatType t))) -> errorBounds (inBoundsF x t) x t loc         _ -> error "Inferred type of float literal is not a float"     check e@(Negate (IntLit x ty loc1) loc2) =       e <$ case ty of-        Info (Scalar (Prim t)) -> warnBounds (inBoundsI (-x) t) (-x) t (loc1 <> loc2)+        Info (Scalar (Prim t)) -> errorBounds (inBoundsI (-x) t) (-x) t (loc1 <> loc2)         _ -> error "Inferred type of int literal is not a number"-    check e = astMap identityMapper {mapOnExp = check} e+    check e@(AppExp (BinOp (QualName [] v, _) _ (_, Info (Array {}, _)) _ loc) _)+      | baseName v == "==",+        baseTag v <= maxIntrinsicTag = do+          warn loc $+            textwrap+              "Comparing arrays with \"==\" is deprecated and will stop working in a future revision of the language."+          recurse e+    check e = recurse e+    recurse = astMap identityMapper {mapOnExp = check}+     bitWidth ty = 8 * intByteSize ty :: Int+     inBoundsI x (Signed t) = x >= -2 ^ (bitWidth t - 1) && x < 2 ^ (bitWidth t - 1)     inBoundsI x (Unsigned t) = x >= 0 && x < 2 ^ bitWidth t     inBoundsI x (FloatType Float16) = not $ isInfinite (fromIntegral x :: Half)@@ -1207,10 +1213,12 @@     inBoundsF x Float16 = not $ isInfinite (realToFrac x :: Float)     inBoundsF x Float32 = not $ isInfinite (realToFrac x :: Float)     inBoundsF x Float64 = not $ isInfinite x-    warnBounds inBounds x ty loc =++    errorBounds inBounds x ty loc =       unless inBounds $         typeError loc mempty . withIndexLink "literal-out-of-bounds" $-          "Literal " <> ppr x+          "Literal "+            <> ppr x             <> " out of bounds for inferred type "             <> ppr ty             <> "."@@ -1250,14 +1258,11 @@     maybe_retdecl'' <- traverse updateTypes maybe_retdecl'     rettype'' <- normTypeFully rettype' -    -- Check if pattern matches are exhaustive and yield-    -- errors if not.-    checkUnmatched body''-     -- Check if the function body can actually be evaluated.     causalityCheck body'' -    literalOverflowCheck body''+    -- Check for various problems.+    localChecks body''      bindSpaced [(Term, fname)] $ do       fname' <- checkName Term fname loc@@ -1275,23 +1280,29 @@   where     fixOverloaded (v, Overloaded ots usage)       | Signed Int32 `elem` ots = do-          unify usage (Scalar (TypeVar () Nonunique (typeName v) [])) $-            Scalar $ Prim $ Signed Int32+          unify usage (Scalar (TypeVar () Nonunique (qualName v) [])) $+            Scalar $+              Prim $+                Signed Int32           when (v `S.member` tyvars_at_toplevel) $             warn usage "Defaulting ambiguous type to i32."       | FloatType Float64 `elem` ots = do-          unify usage (Scalar (TypeVar () Nonunique (typeName v) [])) $-            Scalar $ Prim $ FloatType Float64+          unify usage (Scalar (TypeVar () Nonunique (qualName v) [])) $+            Scalar $+              Prim $+                FloatType Float64           when (v `S.member` tyvars_at_toplevel) $             warn usage "Defaulting ambiguous type to f64."       | otherwise =           typeError usage mempty . withIndexLink "ambiguous-type" $-            "Type is ambiguous (could be one of" <+> commasep (map ppr ots) <> ")."+            "Type is ambiguous (could be one of"+              <+> commasep (map ppr ots) <> ")."               </> "Add a type annotation to disambiguate the type."     fixOverloaded (v, NoConstraint _ usage) = do       -- See #1552.-      unify usage (Scalar (TypeVar () Nonunique (typeName v) [])) $-        Scalar $ tupleRecord []+      unify usage (Scalar (TypeVar () Nonunique (qualName v) [])) $+        Scalar $+          tupleRecord []       when (v `S.member` tyvars_at_toplevel) $         warn usage "Defaulting ambiguous type to ()."     fixOverloaded (_, Equality usage) =@@ -1335,7 +1346,8 @@   -- These we must turn into fresh type variables, which will be   -- existential in the return type.   fmap (toStruct . fst) $-    unscopeType loc hidden_params $ inferReturnUniqueness params t+    unscopeType loc hidden_params $+      inferReturnUniqueness params t   where     hidden_params = M.filterWithKey (const . (`S.member` hidden)) $ foldMap patternMap params     hidden = hiddenParamNames params@@ -1429,18 +1441,18 @@  -- | Extract all the shape names that occur in positive position -- (roughly, left side of an arrow) in a given type.-typeDimNamesPos :: TypeBase (DimDecl VName) als -> S.Set VName-typeDimNamesPos (Scalar (Arrow _ _ t1 (RetType _ t2))) = onParam t1 <> typeDimNamesPos t2+sizeNamesPos :: TypeBase Size als -> S.Set VName+sizeNamesPos (Scalar (Arrow _ _ t1 (RetType _ t2))) = onParam t1 <> sizeNamesPos t2   where-    onParam :: TypeBase (DimDecl VName) als -> S.Set VName+    onParam :: TypeBase Size als -> S.Set VName     onParam (Scalar Arrow {}) = mempty     onParam (Scalar (Record fs)) = mconcat $ map onParam $ M.elems fs     onParam (Scalar (TypeVar _ _ _ targs)) = mconcat $ map onTypeArg targs-    onParam t = typeDimNames t-    onTypeArg (TypeArgDim (NamedDim d) _) = S.singleton $ qualLeaf d+    onParam t = freeInType t+    onTypeArg (TypeArgDim (NamedSize d) _) = S.singleton $ qualLeaf d     onTypeArg (TypeArgDim _ _) = mempty     onTypeArg (TypeArgType t _) = onParam t-typeDimNamesPos _ = mempty+sizeNamesPos _ = mempty  checkGlobalAliases :: [Pat] -> PatType -> SrcLoc -> TermTypeM () checkGlobalAliases params body_t loc = do@@ -1457,7 +1469,9 @@         "Function result aliases the free variable "           <> pquote (pprName v)           <> "."-          </> "Use" <+> pquote "copy" <+> "to break the aliasing."+          </> "Use"+          <+> pquote "copy"+          <+> "to break the aliasing."     _ ->       pure () @@ -1521,17 +1535,19 @@     verifyParams (foldMap patNames params) =<< mapM updateTypes params   where     verifyParams forbidden (p : ps)-      | d : _ <- S.toList $ patternDimNames p `S.intersection` forbidden =+      | d : _ <- S.toList $ freeInPat p `S.intersection` forbidden =           typeError p mempty . withIndexLink "inaccessible-size" $-            "Parameter" <+> pquote (ppr p)-              <+/> "refers to size" <+> pquote (pprName d)-              <> comma+            "Parameter"+              <+> pquote (ppr p)+              <+/> "refers to size"+              <+> pquote (pprName d)+                <> comma               <+/> textwrap "which will not be accessible to the caller"-              <> comma+                <> comma               <+/> textwrap "possibly because it is nested in a tuple or record."               <+/> textwrap "Consider ascribing an explicit type that does not reference "-              <> pquote (pprName d)-              <> "."+                <> pquote (pprName d)+                <> "."       | otherwise = verifyParams forbidden' ps       where         forbidden' =@@ -1587,20 +1603,18 @@   (more_tparams, retext) <-     partitionEithers . catMaybes       <$> mapM closeOver (M.toList $ M.map snd to_close_over)-  let mkExt (NamedDim v) =-        case M.lookup (qualLeaf v) substs of-          Just (_, UnknowableSize {}) -> Just $ qualLeaf v+  let mkExt v =+        case M.lookup v substs of+          Just (_, UnknowableSize {}) -> Just v           _ -> Nothing-      mkExt ConstDim {} = Nothing-      mkExt AnyDim {} = error "closeOverTypes: AnyDim"   pure     ( tparams ++ more_tparams,-      injectExt (retext ++ mapMaybe mkExt (nestedDims ret)) ret+      injectExt (retext ++ mapMaybe mkExt (S.toList $ freeInType ret)) ret     )   where     t = foldFunType paramts $ RetType [] ret     to_close_over = M.filterWithKey (\k _ -> k `S.member` visible) substs-    visible = typeVars t <> typeDimNames t+    visible = typeVars t <> freeInType t      (produced_sizes, param_sizes) = dimUses t @@ -1617,12 +1631,13 @@     closeOver (k, UnknowableSize _ _)       | k `S.member` param_sizes,         k `S.notMember` produced_sizes = do-          notes <- dimNotes defloc $ NamedDim $ qualName k+          notes <- dimNotes defloc $ NamedSize $ qualName k           typeError defloc notes . withIndexLink "unknowable-param-def" $-            "Unknowable size" <+> pquote (pprName k)+            "Unknowable size"+              <+> pquote (pprName k)               <+> "in parameter of"               <+> pquote (pprName defname)-              <> ", which is inferred as:"+                <> ", which is inferred as:"               </> indent 2 (ppr t)       | k `S.member` produced_sizes =           pure $ Just $ Right k@@ -1672,7 +1687,7 @@     rettype'' <- updateTypes rettype'      let used_sizes =-          foldMap typeDimNames $ rettype'' : map patternStructType params+          foldMap freeInType $ rettype'' : map patternStructType params     case filter ((`S.notMember` used_sizes) . typeParamName) $       filter isSizeParam tparams' of       [] -> pure ()@@ -1710,16 +1725,17 @@        let usage = mkUsage (srclocOf body) "return type annotation"       onFailure (CheckingReturn rettype (toStruct body_t')) $-        expect usage rettype $ toStruct body_t'+        expect usage rettype $+          toStruct body_t'     Nothing -> pure ()    pure body'  arrayOfM ::-  (Pretty (ShapeDecl dim), Monoid as) =>+  (Pretty (Shape dim), Monoid as) =>   SrcLoc ->   TypeBase dim as ->-  ShapeDecl dim ->+  Shape dim ->   Uniqueness ->   TermTypeM (TypeBase dim as) arrayOfM loc t shape u = do
src/Language/Futhark/TypeChecker/Terms/DoLoop.hs view
@@ -36,14 +36,14 @@   Rigidity ->   Name ->   S.Set VName ->-  TypeBase (DimDecl VName) als ->-  TermTypeM (TypeBase (DimDecl VName) als)+  TypeBase Size als ->+  TermTypeM (TypeBase Size als) someDimsFreshInType loc r desc sizes = bitraverse onDim pure   where-    onDim (NamedDim d)+    onDim (NamedSize d)       | qualLeaf d `S.member` sizes = do           v <- newDimVar loc r desc-          pure $ NamedDim $ qualName v+          pure $ NamedSize $ qualName v     onDim d = pure d  -- | Replace the specified sizes with fresh size variables of the@@ -53,20 +53,20 @@   Rigidity ->   Name ->   S.Set VName ->-  TypeBase (DimDecl VName) als ->-  TermTypeM (TypeBase (DimDecl VName) als, [VName])+  TypeBase Size als ->+  TermTypeM (TypeBase Size als, [VName]) freshDimsInType loc r desc sizes t =   second M.elems <$> runStateT (bitraverse onDim pure t) mempty   where-    onDim (NamedDim d)+    onDim (NamedSize d)       | qualLeaf d `S.member` sizes = do           prev_subst <- gets $ M.lookup $ qualLeaf d           case prev_subst of-            Just d' -> pure $ NamedDim $ qualName d'+            Just d' -> pure $ NamedSize $ qualName d'             Nothing -> do               v <- lift $ newDimVar loc r desc               modify $ M.insert (qualLeaf d) v-              pure $ NamedDim $ qualName v+              pure $ NamedSize $ qualName v     onDim d = pure d  -- | Mark bindings of names in "consumed" as Unique.@@ -132,10 +132,10 @@               ( unique pat_v_t                   && not (S.null (aliases t `S.intersection` (cons <> obs)))               )-              $ lift . typeError loop_loc mempty $-                "Return value for consuming loop parameter"-                  <+> pquote (pprName pat_v)-                  <+> "aliases previously returned value."+              $ lift . typeError loop_loc mempty+              $ "Return value for consuming loop parameter"+                <+> pquote (pprName pat_v)+                <+> "aliases previously returned value."             if unique pat_v_t               then put (cons <> aliases t, obs)               else put (cons, obs <> aliases t)@@ -171,7 +171,8 @@ wellTypedLoopArg src sparams pat arg = do   (merge_t, _) <-     freshDimsInType (srclocOf arg) Nonrigid "loop" (S.fromList sparams) $-      toStruct $ patternType pat+      toStruct $+        patternType pat   arg_t <- toStruct <$> expTypeFully arg   onFailure (checking merge_t arg_t) $     unify@@ -255,7 +256,7 @@           -- new_dims in the pattern is unique and distinct.           let onDims _ x y                 | x == y = pure x-              onDims _ (NamedDim v) d+              onDims _ (NamedSize v) d                 | qualLeaf v `elem` new_dims = do                     case M.lookup (qualLeaf v) new_dims_to_initial_dim of                       Just d'@@ -263,7 +264,7 @@                             modify $ first $ M.insert (qualLeaf v) (SizeSubst d)                       _ ->                         modify $ second (qualLeaf v :)-                    pure $ NamedDim v+                    pure $ NamedSize v               onDims _ x _ = pure x           loopbody_t' <- normTypeFully loopbody_t           merge_t' <- normTypeFully merge_t@@ -345,7 +346,8 @@                       <+> ppr t         While cond ->           noUnique . bindingPat [] mergepat (Ascribed merge_t) $ \mergepat' ->-            onlySelfAliasing . tapOccurrences+            onlySelfAliasing+              . tapOccurrences               . sequentially                 ( checkExp cond                     >>= unifies "being the condition of a 'while' loop" (Scalar $ Prim Bool)
src/Language/Futhark/TypeChecker/Terms/Monad.hs view
@@ -45,7 +45,7 @@     isInt64,     maybeDimFromExp,     dimFromExp,-    dimFromArg,+    sizeFromArg,     noSizeEscape,      -- * Control flow@@ -241,7 +241,8 @@ useAfterConsume name rloc wloc = do   name' <- describeVar rloc name   typeError rloc mempty . withIndexLink "use-after-consume" $-    "Using" <+> name' <> ", but this was consumed at"+    "Using"+      <+> name' <> ", but this was consumed at"       <+> text (locStrRel rloc wloc) <> ".  (Possibly through aliasing.)"  badLetWithValue :: (Pretty arr, Pretty src) => arr -> src -> SrcLoc -> TermTypeM a@@ -251,7 +252,9 @@       </> indent 2 (ppr arre)       </> "might alias update value"       </> indent 2 (ppr vale)-      </> "Hint: use" <+> pquote "copy" <+> "to remove aliases from the value."+      </> "Hint: use"+      <+> pquote "copy"+      <+> "to remove aliases from the value."  returnAliased :: Name -> SrcLoc -> TermTypeM () returnAliased name loc =@@ -296,8 +299,10 @@ instance Pretty Checking where   ppr (CheckingApply f e expected actual) =     header-      </> "Expected:" <+> align (ppr expected)-      </> "Actual:  " <+> align (ppr actual)+      </> "Expected:"+      <+> align (ppr expected)+      </> "Actual:  "+      <+> align (ppr actual)     where       header =         case f of@@ -305,16 +310,22 @@             "Cannot apply function to"               <+> pquote (shorten $ pretty $ flatten $ ppr e) <> " (invalid type)."           Just fname ->-            "Cannot apply" <+> pquote (ppr fname) <+> "to"+            "Cannot apply"+              <+> pquote (ppr fname)+              <+> "to"               <+> pquote (shorten $ pretty $ flatten $ ppr e) <> " (invalid type)."   ppr (CheckingReturn expected actual) =     "Function body does not have expected type."-      </> "Expected:" <+> align (ppr expected)-      </> "Actual:  " <+> align (ppr actual)+      </> "Expected:"+      <+> align (ppr expected)+      </> "Actual:  "+      <+> align (ppr actual)   ppr (CheckingAscription expected actual) =     "Expression does not have expected type from explicit ascription."-      </> "Expected:" <+> align (ppr expected)-      </> "Actual:  " <+> align (ppr actual)+      </> "Expected:"+      <+> align (ppr expected)+      </> "Actual:  "+      <+> align (ppr actual)   ppr (CheckingLetGeneralise fname) =     "Cannot generalise type of" <+> pquote (ppr fname) <> "."   ppr (CheckingParams fname) =@@ -324,35 +335,49 @@   ppr (CheckingPat pat NoneInferred) =     "Invalid pattern" <+> pquote (ppr pat) <> "."   ppr (CheckingPat pat (Ascribed t)) =-    "Pat" <+> pquote (ppr pat)+    "Pat"+      <+> pquote (ppr pat)       <+> "cannot match value of type"       </> indent 2 (ppr t)   ppr (CheckingLoopBody expected actual) =     "Loop body does not have expected type."-      </> "Expected:" <+> align (ppr expected)-      </> "Actual:  " <+> align (ppr actual)+      </> "Expected:"+      <+> align (ppr expected)+      </> "Actual:  "+      <+> align (ppr actual)   ppr (CheckingLoopInitial expected actual) =     "Initial loop values do not have expected type."-      </> "Expected:" <+> align (ppr expected)-      </> "Actual:  " <+> align (ppr actual)+      </> "Expected:"+      <+> align (ppr expected)+      </> "Actual:  "+      <+> align (ppr actual)   ppr (CheckingRecordUpdate fs expected actual) =-    "Type mismatch when updating record field" <+> pquote fs' <> "."-      </> "Existing:" <+> align (ppr expected)-      </> "New:     " <+> align (ppr actual)+    "Type mismatch when updating record field"+      <+> pquote fs' <> "."+      </> "Existing:"+      <+> align (ppr expected)+      </> "New:     "+      <+> align (ppr actual)     where       fs' = mconcat $ punctuate "." $ map ppr fs   ppr (CheckingRequired [expected] actual) =-    "Expression must must have type" <+> ppr expected <> "."-      </> "Actual type:" <+> align (ppr actual)+    "Expression must must have type"+      <+> ppr expected <> "."+      </> "Actual type:"+      <+> align (ppr actual)   ppr (CheckingRequired expected actual) =-    "Type of expression must must be one of " <+> expected' <> "."-      </> "Actual type:" <+> align (ppr actual)+    "Type of expression must must be one of "+      <+> expected' <> "."+      </> "Actual type:"+      <+> align (ppr actual)     where       expected' = commasep (map ppr expected)   ppr (CheckingBranches t1 t2) =     "Branches differ in type."-      </> "Former:" <+> ppr t1-      </> "Latter:" <+> ppr t2+      </> "Former:"+      <+> ppr t1+      </> "Latter:"+      <+> ppr t2  -- | Type checking happens with access to this environment.  The -- 'TermScope' will be extended during type-checking as bindings come into@@ -413,7 +438,7 @@   = SourceArg FName (ExpBase NoInfo VName)   | SourceBound (ExpBase NoInfo VName)   | SourceSlice-      (Maybe (DimDecl VName))+      (Maybe Size)       (Maybe (ExpBase NoInfo VName))       (Maybe (ExpBase NoInfo VName))       (Maybe (ExpBase NoInfo VName))@@ -429,7 +454,8 @@ nameReason loc (NameAppRes Nothing apploc) =   "result of application at" <+> text (locStrRel loc apploc) nameReason loc (NameAppRes fname apploc) =-  "result of applying" <+> pquote (ppr fname)+  "result of applying"+    <+> pquote (ppr fname)     <+> parens ("at" <+> text (locStrRel loc apploc))  -- | The state is a set of constraints and a counter for generating@@ -481,7 +507,7 @@     i <- incCounter     v <- newID $ mkTypeVarName desc i     constrain v $ NoConstraint Lifted $ mkUsage' loc-    pure $ Scalar $ TypeVar mempty Nonunique (typeName v) []+    pure $ Scalar $ TypeVar mempty Nonunique (qualName v) []    curLevel = asks termLevel @@ -556,11 +582,11 @@     TypeParamType x _ _ -> do       constrain v . NoConstraint x . mkUsage loc $         "instantiated type parameter of " <> quote (pretty qn) <> "."-      pure (v, Subst [] $ RetType [] $ Scalar $ TypeVar mempty Nonunique (typeName v) [])+      pure (v, Subst [] $ RetType [] $ Scalar $ TypeVar mempty Nonunique (qualName v) [])     TypeParamDim {} -> do       constrain v . Size Nothing . mkUsage loc $         "instantiated size parameter of " <> quote (pretty qn) <> "."-      pure (v, SizeSubst $ NamedDim $ qualName v)+      pure (v, SizeSubst $ NamedSize $ qualName v)  checkQualNameWithEnv :: Namespace -> QualName Name -> SrcLoc -> TermTypeM (TermScope, QualName VName) checkQualNameWithEnv space qn@(QualName quals name) loc = do@@ -660,7 +686,11 @@         equalityType usage argtype         pure $           Scalar . Arrow mempty Unnamed argtype . RetType [] $-            Scalar $ Arrow mempty Unnamed argtype $ RetType [] $ Scalar $ Prim Bool+            Scalar $+              Arrow mempty Unnamed argtype $+                RetType [] $+                  Scalar $+                    Prim Bool       Just (OverloadedF ts pts rt) -> do         argtype <- newTypeVar loc "t"         mustBeOneOf ts usage argtype@@ -676,11 +706,13 @@           maybe (toStruct argtype) (Scalar . Prim) rt         ) -  checkNamedDim loc v = do+  checkNamedSize loc v = do     (v', t) <- lookupVar loc v     onFailure (CheckingRequired [Scalar $ Prim $ Signed Int64] (toStruct t)) $       unify (mkUsage loc "use as array size") (toStruct t) $-        Scalar $ Prim $ Signed Int64+        Scalar $+          Prim $+            Signed Int64     pure v'    typeError loc notes s = do@@ -694,7 +726,7 @@ onFailure :: Checking -> TermTypeM a -> TermTypeM a onFailure c = local $ \env -> env {termChecking = Just c} -extSize :: SrcLoc -> SizeSource -> TermTypeM (DimDecl VName, Maybe VName)+extSize :: SrcLoc -> SizeSource -> TermTypeM (Size, Maybe VName) extSize loc e = do   prev <- gets $ M.lookup e . stateDimTable   case prev of@@ -709,12 +741,12 @@       d <- newDimVar loc (Rigid rsrc) "n"       modify $ \s -> s {stateDimTable = M.insert e d $ stateDimTable s}       pure-        ( NamedDim $ qualName d,+        ( NamedSize $ qualName d,           Just d         )     Just d ->       pure-        ( NamedDim $ qualName d,+        ( NamedSize $ qualName d,           Just d         ) @@ -739,9 +771,9 @@   v <- newTypeName desc   constrain v $ NoConstraint Unlifted $ mkUsage' loc   dims <- replicateM r $ newDimVar loc Nonrigid "dim"-  let rowt = TypeVar () Nonunique (typeName v) []+  let rowt = TypeVar () Nonunique (qualName v) []   pure-    ( Array () Nonunique (ShapeDecl $ map (NamedDim . qualName) dims) rowt,+    ( Array () Nonunique (Shape $ map (NamedSize . qualName) dims) rowt,       Scalar rowt     ) @@ -750,15 +782,15 @@   SrcLoc ->   Rigidity ->   Name ->-  TypeBase (DimDecl VName) als ->-  TermTypeM (TypeBase (DimDecl VName) als, M.Map VName (DimDecl VName))+  TypeBase Size als ->+  TermTypeM (TypeBase Size als, M.Map VName Size) allDimsFreshInType loc r desc t =   runStateT (bitraverse onDim pure t) mempty   where     onDim d = do       v <- lift $ newDimVar loc r desc       modify $ M.insert v d-      pure $ NamedDim $ qualName v+      pure $ NamedSize $ qualName v  -- | Replace all type variables with their concrete types. updateTypes :: ASTMappable e => e -> TermTypeM e@@ -768,7 +800,6 @@       ASTMapper         { mapOnExp = astMap tv,           mapOnName = pure,-          mapOnQualName = pure,           mapOnStructType = normTypeFully,           mapOnPatType = normTypeFully,           mapOnStructRetType = normTypeFully,@@ -801,12 +832,11 @@    -- Observe the sizes so we do not get any warnings about them not   -- being used.-  mapM_ observeDim $ nestedDims st+  mapM_ observeDim $ freeInType st   pure (te', svars, RetType dims st)   where-    observeDim (NamedDim v) =-      observe $ Ident (qualLeaf v) (Info $ Scalar $ Prim $ Signed Int64) mempty-    observeDim _ = pure ()+    observeDim v =+      observe $ Ident v (Info $ Scalar $ Prim $ Signed Int64) mempty  checkTypeExpNonrigid :: TypeExp Name -> TermTypeM (TypeExp VName, StructType, [VName]) checkTypeExpNonrigid te = do@@ -833,13 +863,13 @@ isInt64 (Negate x _) = negate <$> isInt64 x isInt64 _ = Nothing -maybeDimFromExp :: Exp -> Maybe (DimDecl VName)-maybeDimFromExp (Var v _ _) = Just $ NamedDim v+maybeDimFromExp :: Exp -> Maybe Size+maybeDimFromExp (Var v _ _) = Just $ NamedSize v maybeDimFromExp (Parens e _) = maybeDimFromExp e maybeDimFromExp (QualParens _ e _) = maybeDimFromExp e-maybeDimFromExp e = ConstDim . fromIntegral <$> isInt64 e+maybeDimFromExp e = ConstSize . fromIntegral <$> isInt64 e -dimFromExp :: (Exp -> SizeSource) -> Exp -> TermTypeM (DimDecl VName, Maybe VName)+dimFromExp :: (Exp -> SizeSource) -> Exp -> TermTypeM (Size, Maybe VName) dimFromExp rf (Attr _ e _) = dimFromExp rf e dimFromExp rf (Assert _ e _ _) = dimFromExp rf e dimFromExp rf (Parens e _) = dimFromExp rf e@@ -850,8 +880,8 @@   | otherwise =       extSize (srclocOf e) $ rf e -dimFromArg :: Maybe (QualName VName) -> Exp -> TermTypeM (DimDecl VName, Maybe VName)-dimFromArg fname = dimFromExp $ SourceArg (FName fname) . bareExp+sizeFromArg :: Maybe (QualName VName) -> Exp -> TermTypeM (Size, Maybe VName)+sizeFromArg fname = dimFromExp $ SourceArg (FName fname) . bareExp  -- | Any argument sizes created with 'extSize' inside the given action -- will be removed once the action finishes.  This is to ensure that@@ -1003,7 +1033,9 @@       Just         ( name,           BoundV Global tvs $-            fromStruct $ Scalar $ Arrow mempty Unnamed pts' rt+            fromStruct $+              Scalar $+                Arrow mempty Unnamed pts' rt         )       where         pts' = case pts of
src/Language/Futhark/TypeChecker/Terms/Pat.hs view
@@ -38,7 +38,7 @@ nonrigidFor [] t = pure t -- Minor optimisation. nonrigidFor sizes t = evalStateT (bitraverse onDim pure t) mempty   where-    onDim (NamedDim (QualName _ v))+    onDim (NamedSize (QualName _ v))       | Just size <- find ((== v) . sizeName) sizes = do           prev <- gets $ lookup v           case prev of@@ -46,9 +46,9 @@               v' <- lift $ newID $ baseName v               lift $ constrain v' $ Size Nothing $ mkUsage' $ srclocOf size               modify ((v, v') :)-              pure $ NamedDim $ qualName v'+              pure $ NamedSize $ qualName v'             Just v' ->-              pure $ NamedDim $ qualName v'+              pure $ NamedSize $ qualName v'     onDim d = pure d  -- | The set of in-scope variables that are being aliased.@@ -61,7 +61,7 @@ checkIfUsed :: Bool -> Occurrences -> Ident -> TermTypeM () checkIfUsed allow_consume occs v   | not allow_consume,-    not $ unique $ unInfo $ identType v,+    not $ consumable $ unInfo $ identType v,     Just occ <- find consumes occs =       typeError (srclocOf occ) mempty $         "Consuming"@@ -76,6 +76,13 @@   where     consumes = maybe False (identName v `S.member`) . consumed +    consumable (Scalar (Record fs)) = all consumable fs+    consumable (Scalar (Sum cs)) = all (all consumable) cs+    consumable (Scalar (TypeVar _ u _ _)) = u == Unique+    consumable (Scalar Arrow {}) = True+    consumable (Scalar Prim {}) = True+    consumable (Array _ u _ _) = u == Unique+ -- | Bind these identifiers locally while running the provided action. -- Checks that the identifiers are used properly within the scope -- (e.g. consumption).@@ -171,7 +178,7 @@     . bindingTypes (concatMap typeParamType tparams)   where     typeParamType (TypeParamType l v loc) =-      [ Left (v, TypeAbbr l [] $ RetType [] $ Scalar (TypeVar () Nonunique (typeName v) [])),+      [ Left (v, TypeAbbr l [] $ RetType [] $ Scalar (TypeVar () Nonunique (qualName v) [])),         Right (v, ParamType l loc)       ]     typeParamType (TypeParamDim v loc) =@@ -240,7 +247,7 @@           Ident v (Info (Scalar $ Prim $ Signed Int64)) loc     mapM_ (observe . ident) sizes -    let used_sizes = typeDimNames $ patternStructType p'+    let used_sizes = freeInType $ patternStructType p'     case filter ((`S.notMember` used_sizes) . sizeName) sizes of       [] -> m p'       size : _ -> unusedSize size@@ -314,7 +321,8 @@   fields' <- traverse (const $ newTypeVar loc "t") $ M.fromList fields    when (sort (M.keys fields') /= sort (map fst fields)) $-    typeError loc mempty $ "Duplicate fields in record pattern" <+> ppr p <> "."+    typeError loc mempty $+      "Duplicate fields in record pattern" <+> ppr p <> "."    unify (mkUsage loc "matching a record pattern") (Scalar (Record fields')) $ toStruct t   t' <- normTypeFully t@@ -337,7 +345,8 @@         <*> pure t'         <*> pure loc     NoneInferred ->-      PatAscription <$> checkPat' sizes p (Ascribed (fromStruct st))+      PatAscription+        <$> checkPat' sizes p (Ascribed (fromStruct st))         <*> pure t'         <*> pure loc checkPat' _ (PatLit l NoInfo loc) (Ascribed t) = do@@ -388,7 +397,8 @@   case filter ((`S.member` explicit) . sizeName) sizes of     size : _ ->       typeError size mempty $-        "Cannot bind" <+> ppr size+        "Cannot bind"+          <+> ppr size           <+> "as it is never used as the size of a concrete (non-function) value."     [] ->       bindNameMap (patNameMap p') $ m p'
src/Language/Futhark/TypeChecker/Types.hs view
@@ -19,6 +19,11 @@     TypeSubs,     Substitutable (..),     substTypesAny,++    -- * Witnesses+    mustBeExplicitInType,+    mustBeExplicitInBinding,+    determineSizeWitnesses,   ) where @@ -36,6 +41,55 @@ import Language.Futhark.Traversals import Language.Futhark.TypeChecker.Monad +mustBeExplicitAux :: StructType -> M.Map VName Bool+mustBeExplicitAux t =+  execState (traverseDims onDim t) mempty+  where+    onDim bound _ (NamedSize d)+      | qualLeaf d `S.member` bound =+          modify $ \s -> M.insertWith (&&) (qualLeaf d) False s+    onDim _ PosImmediate (NamedSize d) =+      modify $ \s -> M.insertWith (&&) (qualLeaf d) False s+    onDim _ _ (NamedSize d) =+      modify $ M.insertWith (&&) (qualLeaf d) True+    onDim _ _ _ =+      pure ()++-- | Determine which of the sizes in a type are used as sizes outside+-- of functions in the type, and which are not.  The former are said+-- to be "witnessed" by this type, while the latter are not.  In+-- practice, the latter means that the actual sizes must come from+-- somewhere else.+determineSizeWitnesses :: StructType -> (S.Set VName, S.Set VName)+determineSizeWitnesses t =+  bimap (S.fromList . M.keys) (S.fromList . M.keys) $+    M.partition not $+      mustBeExplicitAux t++-- | Figure out which of the sizes in a binding type must be passed+-- explicitly, because their first use is as something else than just+-- an array dimension.+mustBeExplicitInBinding :: StructType -> S.Set VName+mustBeExplicitInBinding bind_t =+  let (ts, ret) = unfoldFunType bind_t+      alsoRet =+        M.unionWith (&&) $+          M.fromList $+            zip (S.toList $ freeInType ret) $+              repeat True+   in S.fromList $ M.keys $ M.filter id $ alsoRet $ foldl' onType mempty ts+  where+    onType uses t = uses <> mustBeExplicitAux t -- Left-biased union.++-- | Figure out which of the sizes in a parameter type must be passed+-- explicitly, because their first use is as something else than just+-- an array dimension.+mustBeExplicitInType :: StructType -> S.Set VName+mustBeExplicitInType = snd . determineSizeWitnesses++-- | The two types are assumed to be structurally equal, but not+-- necessarily regarding sizes.  Adds aliases from the latter to the+-- former. addAliasesFromType :: StructType -> PatType -> PatType addAliasesFromType (Array _ u1 et1 shape1) (Array als _ _ _) =   Array als u1 et1 shape1@@ -67,20 +121,21 @@ -- Uniqueness is unified with @uf@.  Assumes sizes already match, and -- always picks the size of the leftmost type. unifyTypesU ::-  (Monoid als, ArrayDim dim) =>+  (Monoid als) =>   (Uniqueness -> Uniqueness -> Maybe Uniqueness) ->   TypeBase dim als ->   TypeBase dim als ->   Maybe (TypeBase dim als) unifyTypesU uf (Array als1 u1 shape1 et1) (Array als2 u2 _shape2 et2) =-  Array (als1 <> als2) <$> uf u1 u2+  Array (als1 <> als2)+    <$> uf u1 u2     <*> pure shape1     <*> unifyScalarTypes uf et1 et2 unifyTypesU uf (Scalar t1) (Scalar t2) = Scalar <$> unifyScalarTypes uf t1 t2 unifyTypesU _ _ _ = Nothing  unifyScalarTypes ::-  (Monoid als, ArrayDim dim) =>+  (Monoid als) =>   (Uniqueness -> Uniqueness -> Maybe Uniqueness) ->   ScalarTypeBase dim als ->   ScalarTypeBase dim als ->@@ -112,7 +167,8 @@   uf   (Arrow as1 mn1 t1 (RetType dims1 t1'))   (Arrow as2 _ t2 (RetType _ t2')) =-    Arrow (as1 <> as2) mn1 <$> unifyTypesU (flip uf) t1 t2+    Arrow (as1 <> as2) mn1+      <$> unifyTypesU (flip uf) t1 t2       <*> (RetType dims1 <$> unifyTypesU uf t1' t2') unifyScalarTypes uf (Sum cs1) (Sum cs2)   | length cs1 == length cs2,@@ -142,7 +198,7 @@ renameRetType (RetType dims st)   | dims /= mempty = do       dims' <- mapM newName dims-      let m = M.fromList $ zip dims $ map (SizeSubst . NamedDim . qualName) dims'+      let m = M.fromList $ zip dims $ map (SizeSubst . NamedSize . qualName) dims'           st' = applySubst (`M.lookup` m) st       pure $ RetType dims' st'   | otherwise =@@ -159,7 +215,8 @@     [] -> pure (TEVar name' loc, [], t', l)     _ ->       typeError loc mempty $-        "Type constructor" <+> pquote (spread (ppr name : map ppr ps))+        "Type constructor"+          <+> pquote (spread (ppr name : map ppr ps))           <+> "used without any arguments." -- evalTypeExp (TETuple ts loc) = do@@ -175,7 +232,8 @@   -- Check for duplicate field names.   let field_names = map fst fs   unless (sort field_names == sort (nubOrd field_names)) $-    typeError loc mempty $ "Duplicate record fields in" <+> ppr t <> "."+    typeError loc mempty $+      "Duplicate record fields in" <+> ppr t <> "."    checked <- traverse evalTypeExp $ M.fromList fs   let fs' = fmap (\(x, _, _, _) -> x) checked@@ -190,9 +248,9 @@     ) -- evalTypeExp (TEArray d t loc) = do-  (d_svars, d', d'') <- checkDimExp d+  (d_svars, d', d'') <- checkSizeExp d   (t', svars, RetType dims st, l) <- evalTypeExp t-  case (l, arrayOf Nonunique (ShapeDecl [d'']) st) of+  case (l, arrayOf Nonunique (Shape [d'']) st) of     (Unlifted, st') ->       pure         ( TEArray d' t' loc,@@ -202,26 +260,29 @@         )     (SizeLifted, _) ->       typeError loc mempty $-        "Cannot create array with elements of size-lifted type" <+> pquote (ppr t)+        "Cannot create array with elements of size-lifted type"+          <+> pquote (ppr t)           <+/> "(might cause irregular array)."     (Lifted, _) ->       typeError loc mempty $-        "Cannot create array with elements of lifted type" <+> pquote (ppr t)+        "Cannot create array with elements of lifted type"+          <+> pquote (ppr t)           <+/> "(might contain function)."   where-    checkDimExp DimExpAny = do+    checkSizeExp SizeExpAny = do       dv <- newTypeName "d"-      pure ([dv], DimExpAny, NamedDim $ qualName dv)-    checkDimExp (DimExpConst k dloc) =-      pure ([], DimExpConst k dloc, ConstDim k)-    checkDimExp (DimExpNamed v dloc) = do-      v' <- checkNamedDim loc v-      pure ([], DimExpNamed v' dloc, NamedDim v')+      pure ([dv], SizeExpAny, NamedSize $ qualName dv)+    checkSizeExp (SizeExpConst k dloc) =+      pure ([], SizeExpConst k dloc, ConstSize k)+    checkSizeExp (SizeExpNamed v dloc) = do+      v' <- checkNamedSize loc v+      pure ([], SizeExpNamed v' dloc, NamedSize v') -- evalTypeExp (TEUnique t loc) = do   (t', svars, RetType dims st, l) <- evalTypeExp t   unless (mayContainArray st) $-    warn loc $ "Declaring" <+> pquote (ppr st) <+> "as unique has no effect."+    warn loc $+      "Declaring" <+> pquote (ppr st) <+> "as unique has no effect."   pure (TEUnique t' loc, svars, RetType dims $ st `setUniqueness` Unique, l)   where     mayContainArray (Scalar Prim {}) = False@@ -263,7 +324,8 @@       case find (`S.notMember` witnessed) dims' of         Just d ->           typeError loc mempty . withIndexLink "unused-existential" $-            "Existential size " <> pquote (pprName d)+            "Existential size "+              <> pquote (pprName d)               <> " not used as array size."         Nothing ->           pure@@ -280,7 +342,8 @@ evalTypeExp t@(TESum cs loc) = do   let constructors = map fst cs   unless (sort constructors == sort (nubOrd constructors)) $-    typeError loc mempty $ "Duplicate constructors in" <+> ppr t+    typeError loc mempty $+      "Duplicate constructors in" <+> ppr t    unless (length constructors < 256) $     typeError loc mempty "Sum types must have less than 256 constructors."@@ -294,7 +357,9 @@     ( TESum (M.toList cs') loc,       cs_svars,       RetType (foldMap (foldMap retDims) ts_s) $-        Scalar $ Sum $ M.map (map retType) ts_s,+        Scalar $+          Sum $+            M.map (map retType) ts_s,       foldl' max Unlifted ls     ) evalTypeExp ote@TEApply {} = do@@ -304,7 +369,10 @@   if length ps /= length targs     then       typeError tloc mempty $-        "Type constructor" <+> pquote (ppr tname) <+> "requires" <+> ppr (length ps)+        "Type constructor"+          <+> pquote (ppr tname)+          <+> "requires"+          <+> ppr (length ps)           <+> "arguments, but provided"           <+> ppr (length targs) <> "."     else do@@ -327,25 +395,25 @@       typeError (srclocOf te') mempty $         "Type" <+> pquote (ppr te') <+> "is not a type constructor." -    checkArgApply (TypeParamDim pv _) (TypeArgExpDim (DimExpNamed v dloc) loc) = do-      v' <- checkNamedDim loc v+    checkArgApply (TypeParamDim pv _) (TypeArgExpDim (SizeExpNamed v dloc) loc) = do+      v' <- checkNamedSize loc v       pure-        ( TypeArgExpDim (DimExpNamed v' dloc) loc,+        ( TypeArgExpDim (SizeExpNamed v' dloc) loc,           [],-          M.singleton pv $ SizeSubst $ NamedDim v'+          M.singleton pv $ SizeSubst $ NamedSize v'         )-    checkArgApply (TypeParamDim pv _) (TypeArgExpDim (DimExpConst x dloc) loc) =+    checkArgApply (TypeParamDim pv _) (TypeArgExpDim (SizeExpConst x dloc) loc) =       pure-        ( TypeArgExpDim (DimExpConst x dloc) loc,+        ( TypeArgExpDim (SizeExpConst x dloc) loc,           [],-          M.singleton pv $ SizeSubst $ ConstDim x+          M.singleton pv $ SizeSubst $ ConstSize x         )-    checkArgApply (TypeParamDim pv _) (TypeArgExpDim DimExpAny loc) = do+    checkArgApply (TypeParamDim pv _) (TypeArgExpDim SizeExpAny loc) = do       d <- newTypeName "d"       pure-        ( TypeArgExpDim DimExpAny loc,+        ( TypeArgExpDim SizeExpAny loc,           [d],-          M.singleton pv $ SizeSubst $ NamedDim $ qualName d+          M.singleton pv $ SizeSubst $ NamedSize $ qualName d         )     checkArgApply (TypeParamType _ pv _) (TypeArgExpType te) = do       (te', svars, RetType dims st, _) <- evalTypeExp te@@ -356,7 +424,8 @@         )     checkArgApply p a =       typeError tloc mempty $-        "Type argument" <+> ppr a+        "Type argument"+          <+> ppr a           <+> "not valid for a type parameter"           <+> ppr p <> "." @@ -400,7 +469,9 @@         Just prev_loc ->           lift $             typeError loc mempty $-              "Name" <+> pquote (ppr v) <+> "also bound at"+              "Name"+                <+> pquote (ppr v)+                <+> "also bound at"                 <+> text (locStr prev_loc) <> "."         Nothing ->           modify $ M.insert (ns, v) loc@@ -418,7 +489,8 @@   where     bad v loc prev_loc =       typeError loc mempty $-        text "Name" <+> pquote (ppr v)+        text "Name"+          <+> pquote (ppr v)           <+> "also bound at"           <+> text (locStr prev_loc) <> "." @@ -470,7 +542,8 @@         Just prev ->           lift $             typeError loc mempty $-              text "Type parameter" <+> pquote (ppr v)+              text "Type parameter"+                <+> pquote (ppr v)                 <+> "previously defined at"                 <+> text (locStr prev) <> "."         Nothing -> do@@ -485,15 +558,15 @@ -- | Construct a type argument corresponding to a type parameter. typeParamToArg :: TypeParam -> StructTypeArg typeParamToArg (TypeParamDim v ploc) =-  TypeArgDim (NamedDim $ qualName v) ploc+  TypeArgDim (NamedSize $ qualName v) ploc typeParamToArg (TypeParamType _ v ploc) =-  TypeArgType (Scalar $ TypeVar () Nonunique (typeName v) []) ploc+  TypeArgType (Scalar $ TypeVar () Nonunique (qualName v) []) ploc  -- | A type substitution may be a substitution or a yet-unknown -- substitution (but which is certainly an overloaded primitive -- type!).  The latter is used to remove aliases from types that are -- yet-unknown but that we know cannot carry aliases (see issue #682).-data Subst t = Subst [TypeParam] t | PrimSubst | SizeSubst (DimDecl VName)+data Subst t = Subst [TypeParam] t | PrimSubst | SizeSubst Size   deriving (Show)  instance Pretty t => Pretty (Subst t) where@@ -519,30 +592,30 @@ class Substitutable a where   applySubst :: TypeSubs -> a -> a -instance Substitutable (RetTypeBase (DimDecl VName) ()) where+instance Substitutable (RetTypeBase Size ()) where   applySubst f (RetType dims t) =     let RetType more_dims t' = substTypesRet f t      in RetType (dims ++ more_dims) t' -instance Substitutable (RetTypeBase (DimDecl VName) Aliasing) where+instance Substitutable (RetTypeBase Size Aliasing) where   applySubst f (RetType dims t) =     let RetType more_dims t' = substTypesRet f' t      in RetType (dims ++ more_dims) t'     where       f' = fmap (fmap (second (const mempty))) . f -instance Substitutable (TypeBase (DimDecl VName) ()) where+instance Substitutable (TypeBase Size ()) where   applySubst = substTypesAny -instance Substitutable (TypeBase (DimDecl VName) Aliasing) where+instance Substitutable (TypeBase Size Aliasing) where   applySubst = substTypesAny . (fmap (fmap (second (const mempty))) .) -instance Substitutable (DimDecl VName) where-  applySubst f (NamedDim (QualName _ v))+instance Substitutable Size where+  applySubst f (NamedSize (QualName _ v))     | Just (SizeSubst d) <- f v = d   applySubst _ d = d -instance Substitutable d => Substitutable (ShapeDecl d) where+instance Substitutable d => Substitutable (Shape d) where   applySubst f = fmap $ applySubst f  instance Substitutable Pat where@@ -552,7 +625,6 @@         ASTMapper           { mapOnExp = pure,             mapOnName = pure,-            mapOnQualName = pure,             mapOnStructType = pure . applySubst f,             mapOnPatType = pure . applySubst f,             mapOnStructRetType = pure . applySubst f,@@ -562,9 +634,9 @@ applyType ::   Monoid als =>   [TypeParam] ->-  TypeBase (DimDecl VName) als ->+  TypeBase Size als ->   [StructTypeArg] ->-  TypeBase (DimDecl VName) als+  TypeBase Size als applyType ps t args = substTypesAny (`M.lookup` substs) t   where     substs = M.fromList $ zipWith mkSubst ps args@@ -578,9 +650,9 @@  substTypesRet ::   Monoid as =>-  (VName -> Maybe (Subst (RetTypeBase (DimDecl VName) as))) ->-  TypeBase (DimDecl VName) as ->-  RetTypeBase (DimDecl VName) as+  (VName -> Maybe (Subst (RetTypeBase Size as))) ->+  TypeBase Size as ->+  RetTypeBase Size as substTypesRet lookupSubst ot =   uncurry (flip RetType) $ runState (onType ot) []   where@@ -601,15 +673,15 @@         else do           let start = maximum $ map baseTag seen_ext               ext' = zipWith VName (map baseName ext) [start + 1 ..]-              extsubsts = M.fromList $ zip ext $ map (SizeSubst . NamedDim . qualName) ext'+              extsubsts = M.fromList $ zip ext $ map (SizeSubst . NamedSize . qualName) ext'               RetType [] t' = substTypesRet (`M.lookup` extsubsts) t           pure $ RetType ext' t'      onType ::       forall as.       Monoid as =>-      TypeBase (DimDecl VName) as ->-      State [VName] (TypeBase (DimDecl VName) as)+      TypeBase Size as ->+      State [VName] (TypeBase Size as)      onType (Array als u shape et) = do       t <- arrayOf u (applySubst lookupSubst' shape) <$> onType (Scalar et)@@ -617,13 +689,14 @@     onType (Scalar (Prim t)) = pure $ Scalar $ Prim t     onType (Scalar (TypeVar als u v targs)) = do       targs' <- mapM subsTypeArg targs-      case lookupSubst $ qualLeaf (qualNameFromTypeName v) of+      case lookupSubst $ qualLeaf v of         Just (Subst ps rt) -> do           RetType ext t <- freshDims rt           modify (ext ++)           pure $             applyType ps (t `setAliases` mempty) targs'-              `setUniqueness` u `addAliases` (<> als)+              `setUniqueness` u+              `addAliases` (<> als)         Just PrimSubst ->           pure $ Scalar $ TypeVar mempty u v targs'         _ ->@@ -659,23 +732,23 @@ -- regardless of what shape and uniqueness information is attached to the type. substTypesAny ::   Monoid as =>-  (VName -> Maybe (Subst (RetTypeBase (DimDecl VName) as))) ->-  TypeBase (DimDecl VName) as ->-  TypeBase (DimDecl VName) as+  (VName -> Maybe (Subst (RetTypeBase Size as))) ->+  TypeBase Size as ->+  TypeBase Size as substTypesAny lookupSubst ot =   case substTypesRet lookupSubst ot of     RetType [] ot' -> ot'     RetType dims ot' ->       -- XXX HACK FIXME: turn any sizes that propagate to the top into-      -- AnyDim.  This should _never_ happen during type-checking, but+      -- AnySize.  This should _never_ happen during type-checking, but       -- may happen as we substitute types during monomorphisation and-      -- defunctorisation later on. See Note [AnyDim]-      let toAny (NamedDim v)-            | qualLeaf v `elem` dims = AnyDim Nothing+      -- defunctorisation later on. See Note [AnySize]+      let toAny (NamedSize v)+            | qualLeaf v `elem` dims = AnySize Nothing           toAny d = d        in first toAny ot' --- Note [AnyDim]+-- Note [AnySize] -- -- Consider a program: --@@ -695,13 +768,13 @@ -- -- let f (x: []bool) (y: []bool) = 0 ----- I.e. we put in empty dimensions (AnyDim), which are much later+-- I.e. we put in empty dimensions (AnySize), which are much later -- turned into distinct sizes in Futhark.Internalise.Exps.  This will -- result in unnecessary dynamic size checks, which will hopefully be -- optimised away. -- -- Important: The type checker will _never_ produce programs with--- AnyDim, but unfortunately some of the compilation steps+-- AnySize, but unfortunately some of the compilation steps -- (defunctorisation, monomorphisation, defunctionalisation) will do -- so.  Similarly, the core language is also perfectly well behaved. --
src/Language/Futhark/TypeChecker/Unify.hs view
@@ -45,7 +45,7 @@ import Data.Maybe import qualified Data.Set as S import Futhark.Util.Pretty hiding (empty)-import Language.Futhark hiding (unifyDims)+import Language.Futhark import Language.Futhark.TypeChecker.Monad hiding (BoundV) import Language.Futhark.TypeChecker.Types @@ -60,7 +60,8 @@  instance Pretty BreadCrumb where   ppr (MatchingTypes t1 t2) =-    "When matching type" </> indent 2 (ppr t1)+    "When matching type"+      </> indent 2 (ppr t1)       </> "with"       </> indent 2 (ppr t2)   ppr (MatchingFields fields) =@@ -132,7 +133,7 @@   | ParamSize SrcLoc   | -- | Is not actually a type, but a term-level size,     -- possibly already set to something specific.-    Size (Maybe (DimDecl VName)) Usage+    Size (Maybe Size) Usage   | -- | A size that does not unify with anything -     -- created from the result of applying a function     -- whose return size is existential, or otherwise@@ -174,7 +175,7 @@     RigidRet (Maybe (QualName VName))   | RigidLoop   | -- | Produced by a complicated slice expression.-    RigidSlice (Maybe (DimDecl VName)) String+    RigidSlice (Maybe Size) String   | -- | Produced by a complicated range expression.     RigidRange   | -- | Produced by a range expression with this bound.@@ -198,19 +199,24 @@   "is unknown size returned by function at"     <+> text (locStrRel ctx loc) <> "." prettySource ctx loc (RigidRet (Just fname)) =-  "is unknown size returned by" <+> pquote (ppr fname)+  "is unknown size returned by"+    <+> pquote (ppr fname)     <+> "at"     <+> text (locStrRel ctx loc) <> "." prettySource ctx loc (RigidArg fname arg) =   "is value of argument"     </> indent 2 (shorten arg)-    </> "passed to" <+> fname' <+> "at" <+> text (locStrRel ctx loc) <> "."+    </> "passed to"+    <+> fname'+    <+> "at"+    <+> text (locStrRel ctx loc) <> "."   where     fname' = maybe "function" (pquote . ppr) fname prettySource ctx loc (RigidSlice d slice) =   "is size produced by slice"     </> indent 2 (shorten slice)-    </> d_desc <> "at" <+> text (locStrRel ctx loc) <> "."+    </> d_desc <> "at"+    <+> text (locStrRel ctx loc) <> "."   where     d_desc = case d of       Just d' -> "of dimension of size " <> pquote (ppr d') <> " "@@ -224,13 +230,14 @@     </> indent 2 (shorten bound)     </> "used in range at " <> text (locStrRel ctx loc) <> "." prettySource ctx loc (RigidOutOfScope boundloc v) =-  "is an unknown size arising from " <> pquote (pprName v)+  "is an unknown size arising from "+    <> pquote (pprName v)     <> " going out of scope at "     <> text (locStrRel ctx loc)     <> "."     </> "Originally bound at "-    <> text (locStrRel ctx boundloc)-    <> "."+      <> text (locStrRel ctx boundloc)+      <> "." prettySource ctx loc RigidCoerce =   "is an unknown size arising from empty dimension in coercion at"     <+> text (locStrRel ctx loc) <> "."@@ -241,42 +248,43 @@     <> text (locStrRel ctx loc)     <> "."     </> "One branch returns array of type: "-    <> align (ppr t1)+      <> align (ppr t1)     </> "The other an array of type:       "-    <> align (ppr t2)+      <> align (ppr t2)  -- | Retrieve notes describing the purpose or origin of the given--- 'DimDecl'.  The location is used as the *current* location, for the+-- t'Size'.  The location is used as the *current* location, for the -- purpose of reporting relative locations.-dimNotes :: (Located a, MonadUnify m) => a -> DimDecl VName -> m Notes-dimNotes ctx (NamedDim d) = do+dimNotes :: (Located a, MonadUnify m) => a -> Size -> m Notes+dimNotes ctx (NamedSize d) = do   c <- M.lookup (qualLeaf d) <$> getConstraints   case c of     Just (_, UnknowableSize loc rsrc) ->-      pure $-        aNote $-          pretty $-            pquote (ppr d) <+> prettySource (srclocOf ctx) loc rsrc+      pure . aNote . pretty $+        pquote (ppr d) <+> prettySource (srclocOf ctx) loc rsrc     _ -> pure mempty dimNotes _ _ = pure mempty  typeNotes :: (Located a, MonadUnify m) => a -> StructType -> m Notes typeNotes ctx =-  fmap mconcat . mapM (dimNotes ctx . NamedDim . qualName)+  fmap mconcat+    . mapM (dimNotes ctx . NamedSize . qualName)     . S.toList-    . typeDimNames+    . freeInType  typeVarNotes :: MonadUnify m => VName -> m Notes typeVarNotes v = maybe mempty (aNote . note . snd) . M.lookup v <$> getConstraints   where     note (HasConstrs cs _) =-      pprName v <+> "="+      pprName v+        <+> "="         <+> mconcat (map ppConstr (M.toList cs))         <+> "..."     note (Overloaded ts _) =       pprName v <+> "must be one of" <+> mconcat (punctuate ", " (map ppr ts))     note (HasFields fs _) =-      pprName v <+> "="+      pprName v+        <+> "="         <+> braces (mconcat (punctuate ", " (map ppField (M.toList fs))))     note _ = mempty @@ -323,7 +331,7 @@  -- | Replace any top-level type variable with its substitution. normType :: MonadUnify m => StructType -> m StructType-normType t@(Scalar (TypeVar _ _ (TypeName [] v) [])) = do+normType t@(Scalar (TypeVar _ _ (QualName [] v) [])) = do   constraints <- getConstraints   case snd <$> M.lookup v constraints of     Just (Constraint (RetType [] t') _) -> normType t'@@ -332,7 +340,7 @@  -- | Replace any top-level type variable with its substitution. normPatType :: MonadUnify m => PatType -> m PatType-normPatType t@(Scalar (TypeVar als u (TypeName [] v) [])) = do+normPatType t@(Scalar (TypeVar als u (QualName [] v) [])) = do   constraints <- getConstraints   case snd <$> M.lookup v constraints of     Just (Constraint (RetType [] t') _) ->@@ -351,15 +359,15 @@   MonadUnify m =>   SrcLoc ->   Rigidity ->-  RetTypeBase (DimDecl VName) als ->-  m (TypeBase (DimDecl VName) als, [VName])+  RetTypeBase Size als ->+  m (TypeBase Size als, [VName]) instantiateEmptyArrayDims tloc r (RetType dims t) = do   dims' <- mapM new dims   pure (first (onDim $ zip dims dims') t, dims')   where     new = newDimVar tloc r . nameFromString . takeWhile isAscii . baseString-    onDim dims' (NamedDim d) =-      NamedDim $ maybe d qualName (lookup (qualLeaf d) dims')+    onDim dims' (NamedSize d) =+      NamedSize $ maybe d qualName (lookup (qualLeaf d) dims')     onDim _ d = d  -- | Is the given type variable the name of an abstract type or type@@ -376,7 +384,7 @@   pure lvl  type UnifyDims m =-  BreadCrumbs -> [VName] -> (VName -> Maybe Int) -> DimDecl VName -> DimDecl VName -> m ()+  BreadCrumbs -> [VName] -> (VName -> Maybe Int) -> Size -> Size -> m ()  flipUnifyDims :: UnifyDims m -> UnifyDims m flipUnifyDims onDims bcs bound nonrigid t1 t2 =@@ -448,15 +456,15 @@                         ++ filter (`notElem` M.keys fs) (M.keys arg_fs)                 unifyError usage mempty bcs $                   "Unshared fields:" <+> commasep (map ppr missing) <> "."-        ( Scalar (TypeVar _ _ (TypeName _ tn) targs),-          Scalar (TypeVar _ _ (TypeName _ arg_tn) arg_targs)+        ( Scalar (TypeVar _ _ (QualName _ tn) targs),+          Scalar (TypeVar _ _ (QualName _ arg_tn) arg_targs)           )             | tn == arg_tn,               length targs == length arg_targs -> do                 let bcs' = breadCrumb (Matching "When matching type arguments.") bcs                 zipWithM_ (unifyTypeArg bcs') targs arg_targs-        ( Scalar (TypeVar _ _ (TypeName [] v1) []),-          Scalar (TypeVar _ _ (TypeName [] v2) [])+        ( Scalar (TypeVar _ _ (QualName [] v1) []),+          Scalar (TypeVar _ _ (QualName [] v2) [])           ) ->             case (nonrigid v1, nonrigid v2) of               (Nothing, Nothing) -> failure@@ -465,10 +473,10 @@               (Just lvl1, Just lvl2)                 | lvl1 <= lvl2 -> link ord v1 lvl1 t2'                 | otherwise -> link (not ord) v2 lvl2 t1'-        (Scalar (TypeVar _ _ (TypeName [] v1) []), _)+        (Scalar (TypeVar _ _ (QualName [] v1) []), _)           | Just lvl <- nonrigid v1 ->               link ord v1 lvl t2'-        (_, Scalar (TypeVar _ _ (TypeName [] v2) []))+        (_, Scalar (TypeVar _ _ (QualName [] v2) []))           | Just lvl <- nonrigid v2 ->               link (not ord) v2 lvl t1'         ( Scalar (Arrow _ p1 a1 (RetType b1_dims b1)),@@ -512,7 +520,7 @@                 case (p1, p2) of                   (Named p1', Named p2') ->                     let f v-                          | v == p2' = Just $ SizeSubst $ NamedDim $ qualName p1'+                          | v == p2' = Just $ SizeSubst $ NamedSize $ qualName p1'                           | otherwise = Nothing                      in (b1, applySubst f b2)                   (_, _) ->@@ -521,8 +529,8 @@               pname (Named x) = Just x               pname Unnamed = Nothing         (Array {}, Array {})-          | ShapeDecl (t1_d : _) <- arrayShape t1',-            ShapeDecl (t2_d : _) <- arrayShape t2',+          | Shape (t1_d : _) <- arrayShape t1',+            Shape (t2_d : _) <- arrayShape t2',             Just t1'' <- peelArray 1 t1',             Just t2'' <- peelArray 1 t2' -> do               onDims' bcs (swap ord t1_d t2_d)@@ -545,16 +553,17 @@ unifyDims :: MonadUnify m => Usage -> UnifyDims m unifyDims _ _ _ _ d1 d2   | d1 == d2 = pure ()-unifyDims usage bcs _ nonrigid (NamedDim (QualName _ d1)) d2+unifyDims usage bcs _ nonrigid (NamedSize (QualName _ d1)) d2   | Just lvl1 <- nonrigid d1 =       linkVarToDim usage bcs d1 lvl1 d2-unifyDims usage bcs _ nonrigid d1 (NamedDim (QualName _ d2))+unifyDims usage bcs _ nonrigid d1 (NamedSize (QualName _ d2))   | Just lvl2 <- nonrigid d2 =       linkVarToDim usage bcs d2 lvl2 d1 unifyDims usage bcs _ _ d1 d2 = do   notes <- (<>) <$> dimNotes usage d1 <*> dimNotes usage d2   unifyError usage notes bcs $-    "Dimensions" <+> pquote (ppr d1)+    "Dimensions"+      <+> pquote (ppr d1)       <+> "and"       <+> pquote (ppr d2)       <+> "do not match."@@ -571,23 +580,24 @@       | d1 == d2 = pure ()     -- We identify existentially bound names by them being nonrigid     -- and yet bound.  It's OK to unify with those.-    onDims bcs bound nonrigid (NamedDim (QualName _ d1)) d2+    onDims bcs bound nonrigid (NamedSize (QualName _ d1)) d2       | Just lvl1 <- nonrigid d1,         not (boundParam bound d2) || (d1 `elem` bound) =           linkVarToDim usage bcs d1 lvl1 d2-    onDims bcs bound nonrigid d1 (NamedDim (QualName _ d2))+    onDims bcs bound nonrigid d1 (NamedSize (QualName _ d2))       | Just lvl2 <- nonrigid d2,         not (boundParam bound d1) || (d2 `elem` bound) =           linkVarToDim usage bcs d2 lvl2 d1     onDims bcs _ _ d1 d2 = do       notes <- (<>) <$> dimNotes usage d1 <*> dimNotes usage d2       unifyError usage notes bcs $-        "Dimensions" <+> pquote (ppr d1)+        "Dimensions"+          <+> pquote (ppr d1)           <+> "and"           <+> pquote (ppr d2)           <+> "do not match." -    boundParam bound (NamedDim (QualName _ d)) = d `elem` bound+    boundParam bound (NamedSize (QualName _ d)) = d `elem` bound     boundParam _ _ = False  occursCheck ::@@ -618,7 +628,7 @@   checkType constraints tp   where     checkType constraints t =-      mapM_ (check constraints) $ typeVars t <> typeDimNames t+      mapM_ (check constraints) $ typeVars t <> freeInType t      check constraints v       | Just (lvl, c) <- M.lookup v constraints,@@ -669,7 +679,8 @@               M.insert vn (lvl, Constraint (RetType ext tp) usage)           problems ->             unifyError usage mempty bcs . withIndexLink "unify-param-existential" $-              "Parameter(s) " <> commasep (map (pquote . pprName) problems)+              "Parameter(s) "+                <> commasep (map (pquote . pprName) problems)                 <> " used as size(s) would go out of scope."    case snd <$> M.lookup vn constraints of@@ -677,7 +688,8 @@       let bcs' =             breadCrumb               ( Matching $-                  "When verifying that" <+> pquote (pprName vn)+                  "When verifying that"+                    <+> pquote (pprName vn)                     <+> textwrap "is not instantiated with a function type, due to"                     <+> ppr unlift_usage               )@@ -686,9 +698,10 @@       link        arrayElemTypeWith usage bcs' tp-      when (any (`elem` bound) (typeDimNames tp)) $+      when (any (`elem` bound) (freeInType tp)) $         unifyError usage mempty bcs $-          "Type variable" <+> pprName vn+          "Type variable"+            <+> pprName vn             <+> "cannot be instantiated with type containing anonymous sizes:"             </> indent 2 (ppr tp)             </> textwrap "This is usually because the size of an array returned by a higher-order function argument cannot be determined statically.  This can also be due to the return size being a value parameter.  Add type annotation to clarify."@@ -699,14 +712,17 @@       | tp `notElem` map (Scalar . Prim) ts -> do           link           case tp of-            Scalar (TypeVar _ _ (TypeName [] v) [])+            Scalar (TypeVar _ _ (QualName [] v) [])               | not $ isRigid v constraints ->                   linkVarToTypes usage v ts             _ ->               unifyError usage mempty bcs $-                "Cannot instantiate" <+> pquote (pprName vn)-                  <+> "with type" </> indent 2 (ppr tp) </> "as"+                "Cannot instantiate"                   <+> pquote (pprName vn)+                  <+> "with type"+                  </> indent 2 (ppr tp)+                  </> "as"+                  <+> pquote (pprName vn)                   <+> "must be one of"                   <+> commasep (map ppr ts)                   <+/> "due to"@@ -730,7 +746,7 @@               mapM_ (uncurry $ unifyWith onDims usage bound bcs') $                 M.elems $                   M.intersectionWith (,) required_fields tp_fields-        Scalar (TypeVar _ _ (TypeName [] v) [])+        Scalar (TypeVar _ _ (QualName [] v) [])           | not $ isRigid v constraints ->               modifyConstraints $                 M.insert@@ -738,22 +754,27 @@                   (lvl, HasFields required_fields old_usage)         _ ->           unifyError usage mempty bcs $-            "Cannot instantiate" <+> pquote (pprName vn) <+> "with type"+            "Cannot instantiate"+              <+> pquote (pprName vn)+              <+> "with type"               </> indent 2 (ppr tp)-              </> "as" <+> pquote (pprName vn) <+> "must be a record with fields"+              </> "as"+              <+> pquote (pprName vn)+              <+> "must be a record with fields"               </> indent 2 (ppr (Record required_fields))-              </> "due to" <+> ppr old_usage <> "."+              </> "due to"+              <+> ppr old_usage <> "."     -- See Note [Linking variables to sum types]     Just (HasConstrs required_cs old_usage) ->       case tp of         Scalar (Sum ts)           | all (`M.member` ts) $ M.keys required_cs -> do               let tp' = Scalar $ Sum $ required_cs <> ts -- Crucially left-biased.-                  ext = filter (`S.member` typeDimNames tp') bound+                  ext = filter (`S.member` freeInType tp') bound               modifyConstraints $                 M.insert vn (lvl, Constraint (RetType ext tp') usage)               unifySharedConstructors onDims usage bound bcs required_cs ts-        Scalar (TypeVar _ _ (TypeName [] v) []) -> do+        Scalar (TypeVar _ _ (QualName [] v) []) -> do           case M.lookup v constraints of             Just (_, HasConstrs v_cs _) -> do               unifySharedConstructors onDims usage bound bcs required_cs v_cs@@ -788,20 +809,21 @@   BreadCrumbs ->   VName ->   Level ->-  DimDecl VName ->+  Size ->   m () linkVarToDim usage bcs vn lvl dim = do   constraints <- getConstraints    case dim of-    NamedDim dim'+    NamedSize dim'       | Just (dim_lvl, c) <- qualLeaf dim' `M.lookup` constraints,         dim_lvl > lvl ->           case c of             ParamSize {} -> do               notes <- dimNotes usage dim               unifyError usage notes bcs $-                "Cannot unify size variable" <+> pquote (ppr dim')+                "Cannot unify size variable"+                  <+> pquote (ppr dim')                   <+> "with"                   <+> pquote (pprName vn)                   <+> "(scope violation)."@@ -822,14 +844,15 @@   let isRigid' v = isRigid v constraints    case t' of-    Scalar (TypeVar _ _ (TypeName [] v) [])+    Scalar (TypeVar _ _ (QualName [] v) [])       | not $ isRigid' v -> linkVarToTypes usage v ts     Scalar (Prim pt) | pt `elem` ts -> pure ()     _ -> failure   where     failure =       unifyError usage mempty noBreadCrumbs $-        text "Cannot unify type" <+> pquote (ppr t)+        text "Cannot unify type"+          <+> pquote (ppr t)           <+> "with any of " <> commasep (map ppr ts) <> "."  linkVarToTypes :: MonadUnify m => Usage -> VName -> [PrimType] -> m ()@@ -849,14 +872,18 @@         ts' -> modifyConstraints $ M.insert vn (lvl, Overloaded ts' usage)     Just (_, HasConstrs _ vn_usage) ->       unifyError usage mempty noBreadCrumbs $-        "Type constrained to one of" <+> commasep (map ppr ts)-          <> ", but also inferred to be sum type due to" <+> ppr vn_usage-          <> "."+        "Type constrained to one of"+          <+> commasep (map ppr ts)+            <> ", but also inferred to be sum type due to"+          <+> ppr vn_usage+            <> "."     Just (_, HasFields _ vn_usage) ->       unifyError usage mempty noBreadCrumbs $-        "Type constrained to one of" <+> commasep (map ppr ts)-          <> ", but also inferred to be record due to" <+> ppr vn_usage-          <> "."+        "Type constrained to one of"+          <+> commasep (map ppr ts)+            <> ", but also inferred to be record due to"+          <+> ppr vn_usage+            <> "."     Just (lvl, _) -> modifyConstraints $ M.insert vn (lvl, Overloaded ts usage)     Nothing ->       unifyError usage mempty noBreadCrumbs $@@ -864,7 +891,7 @@  -- | Assert that this type must support equality. equalityType ::-  (MonadUnify m, Pretty (ShapeDecl dim), Monoid as) =>+  (MonadUnify m, Pretty (Shape dim), Monoid as) =>   Usage ->   TypeBase dim as ->   m ()@@ -877,13 +904,17 @@     mustBeEquality vn = do       constraints <- getConstraints       case M.lookup vn constraints of-        Just (_, Constraint (RetType [] (Scalar (TypeVar _ _ (TypeName [] vn') []))) _) ->+        Just (_, Constraint (RetType [] (Scalar (TypeVar _ _ (QualName [] vn') []))) _) ->           mustBeEquality vn'         Just (_, Constraint (RetType _ vn_t) cusage)           | not $ orderZero vn_t ->               unifyError usage mempty noBreadCrumbs $-                "Type" <+> pquote (ppr t) <+> "does not support equality."-                  </> "Constrained to be higher-order due to" <+> ppr cusage <+> "."+                "Type"+                  <+> pquote (ppr t)+                  <+> "does not support equality."+                  </> "Constrained to be higher-order due to"+                  <+> ppr cusage+                  <+> "."           | otherwise -> pure ()         Just (lvl, NoConstraint _ _) ->           modifyConstraints $ M.insert vn (lvl, Equality usage)@@ -898,7 +929,7 @@             "Type" <+> pprName vn <+> "does not support equality."  zeroOrderTypeWith ::-  (MonadUnify m, Pretty (ShapeDecl dim), Monoid as) =>+  (MonadUnify m, Pretty (Shape dim), Monoid as) =>   Usage ->   BreadCrumbs ->   TypeBase dim as ->@@ -925,7 +956,7 @@  -- | Assert that this type must be zero-order. zeroOrderType ::-  (MonadUnify m, Pretty (ShapeDecl dim), Monoid as) =>+  (MonadUnify m, Pretty (Shape dim), Monoid as) =>   Usage ->   String ->   TypeBase dim as ->@@ -936,7 +967,7 @@     bc = Matching $ "When checking" <+> textwrap desc  arrayElemTypeWith ::-  (MonadUnify m, Pretty (ShapeDecl dim), Monoid as) =>+  (MonadUnify m, Pretty (Shape dim), Monoid as) =>   Usage ->   BreadCrumbs ->   TypeBase dim as ->@@ -964,7 +995,7 @@  -- | Assert that this type must be valid as an array element. arrayElemType ::-  (MonadUnify m, Pretty (ShapeDecl dim), Monoid as) =>+  (MonadUnify m, Pretty (Shape dim), Monoid as) =>   Usage ->   String ->   TypeBase dim as ->@@ -1007,7 +1038,7 @@ mustHaveConstr usage c t fs = do   constraints <- getConstraints   case t of-    Scalar (TypeVar _ _ (TypeName _ tn) [])+    Scalar (TypeVar _ _ (QualName _ tn) [])       | Just (lvl, NoConstraint {}) <- M.lookup tn constraints -> do           mapM_ (scopeCheck usage noBreadCrumbs tn lvl) fs           modifyConstraints $ M.insert tn (lvl, HasConstrs (M.singleton c fs) usage)@@ -1046,7 +1077,7 @@   l_type <- newTypeVar (srclocOf usage) "t"   let l_type' = l_type `setAliases` aliases t   case t of-    Scalar (TypeVar _ _ (TypeName _ tn) [])+    Scalar (TypeVar _ _ (QualName _ tn) [])       | Just (lvl, NoConstraint {}) <- M.lookup tn constraints -> do           scopeCheck usage bcs tn lvl l_type           modifyConstraints $ M.insert tn (lvl, HasFields (M.singleton l l_type) usage)@@ -1066,7 +1097,9 @@           pure t'       | otherwise ->           unifyError usage mempty bcs $-            "Attempt to access field" <+> pquote (ppr l) <+> " of value of type"+            "Attempt to access field"+              <+> pquote (ppr l)+              <+> " of value of type"               <+> ppr (toStructural t) <> "."     _ -> do       unify usage (toStruct t) $ Scalar $ Record $ M.singleton l l_type@@ -1084,9 +1117,9 @@ newDimOnMismatch ::   (Monoid as, MonadUnify m) =>   SrcLoc ->-  TypeBase (DimDecl VName) as ->-  TypeBase (DimDecl VName) as ->-  m (TypeBase (DimDecl VName) as, [VName])+  TypeBase Size as ->+  TypeBase Size as ->+  m (TypeBase Size as, [VName]) newDimOnMismatch loc t1 t2 = do   (t, seen) <- runStateT (matchDims onDims t1 t2) mempty   pure (t, M.elems seen)@@ -1099,11 +1132,11 @@           -- same new size.           maybe_d <- gets $ M.lookup (d1, d2)           case maybe_d of-            Just d -> pure $ NamedDim $ qualName d+            Just d -> pure $ NamedSize $ qualName d             Nothing -> do               d <- lift $ newDimVar loc r "differ"               modify $ M.insert (d1, d2) d-              pure $ NamedDim $ qualName d+              pure $ NamedSize $ qualName d  -- | Like unification, but creates new size variables where mismatches -- occur.  Returns the new dimensions thus created.@@ -1148,7 +1181,7 @@   newTypeVar loc name = do     v <- newVar name     modifyConstraints $ M.insert v (0, NoConstraint Lifted $ Usage Nothing loc)-    pure $ Scalar $ TypeVar mempty Nonunique (typeName v) []+    pure $ Scalar $ TypeVar mempty Nonunique (qualName v) []    newDimVar loc rigidity name = do     dim <- newVar name
unittests/Futhark/AD/DerivativesTests.hs view
@@ -14,7 +14,8 @@     "Futhark.AD.DerivativesTests"     [ testGroup "Primitive functions" $         map primFunTest $-          filter (not . (`elem` missing_primfuns) . fst) $ M.toList primFuns,+          filter (not . (`elem` missing_primfuns) . fst) $+            M.toList primFuns,       testGroup "BinOps" $ map binOpTest allBinOps,       testGroup "UnOps" $ map unOpTest allUnOps     ]
unittests/Futhark/BenchTests.hs view
@@ -21,7 +21,9 @@       <*> oneof         [ Left <$> arbText,           Right-            <$> ( Result <$> arbitrary <*> arbMap+            <$> ( Result+                    <$> arbitrary+                    <*> arbMap                     <*> oneof [pure Nothing, Just <$> arbText]                 )         ]
unittests/Futhark/IR/Mem/IxFun/Alg.hs view
@@ -57,7 +57,8 @@   ppr (Index fun is) = ppr fun <> ppr is   ppr (FlatIndex fun is) = ppr fun <> ppr is   ppr (Reshape fun oldshape) =-    ppr fun <> text "->reshape"+    ppr fun+      <> text "->reshape"       <> parens (commasep (map ppr oldshape))   ppr (OffsetIndex fun i) =     ppr fun <> text "->offset_index" <> parens (ppr i)
unittests/Futhark/IR/Mem/IxFunTests.hs view
@@ -51,7 +51,9 @@       resLMAD = map (IxFunLMAD.index ixfunLMAD) points       resAlg = map (IxFunAlg.index ixfunAlg) points       errorMessage =-        "lmad ixfun:  " ++ PR.pretty ixfunLMAD ++ "\n"+        "lmad ixfun:  "+          ++ PR.pretty ixfunLMAD+          ++ "\n"           ++ "alg ixfun:   "           ++ PR.pretty ixfunAlg           ++ "\n"
− unittests/Futhark/IR/PrimitiveTests.hs
@@ -1,77 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Futhark.IR.PrimitiveTests-  ( tests,-    arbitraryPrimValOfType,-  )-where--import Control.Applicative-import Futhark.IR.Primitive-import Futhark.Util (convFloat)-import Test.QuickCheck-import Test.Tasty-import Test.Tasty.HUnit-import Prelude--tests :: TestTree-tests = testGroup "PrimitiveTests" [propPrimValuesHaveRightType]--propPrimValuesHaveRightType :: TestTree-propPrimValuesHaveRightType =-  testGroup-    "propPrimValuesHaveRightTypes"-    [ testCase (show t ++ " has blank of right type") $-        primValueType (blankPrimValue t) @?= t-      | t <- [minBound .. maxBound]-    ]--instance Arbitrary IntType where-  arbitrary = elements [minBound .. maxBound]--instance Arbitrary FloatType where-  arbitrary = elements [minBound .. maxBound]--instance Arbitrary PrimType where-  arbitrary = elements [minBound .. maxBound]--instance Arbitrary IntValue where-  arbitrary =-    oneof-      [ Int8Value <$> arbitrary,-        Int16Value <$> arbitrary,-        Int32Value <$> arbitrary,-        Int64Value <$> arbitrary-      ]--instance Arbitrary Half where-  arbitrary = (convFloat :: Float -> Half) <$> arbitrary--instance Arbitrary FloatValue where-  arbitrary =-    oneof-      [ Float16Value <$> arbitrary,-        Float32Value <$> arbitrary,-        Float64Value <$> arbitrary-      ]--instance Arbitrary PrimValue where-  arbitrary =-    oneof-      [ IntValue <$> arbitrary,-        FloatValue <$> arbitrary,-        BoolValue <$> arbitrary,-        pure UnitValue-      ]--arbitraryPrimValOfType :: PrimType -> Gen PrimValue-arbitraryPrimValOfType (IntType Int8) = IntValue . Int8Value <$> arbitrary-arbitraryPrimValOfType (IntType Int16) = IntValue . Int16Value <$> arbitrary-arbitraryPrimValOfType (IntType Int32) = IntValue . Int32Value <$> arbitrary-arbitraryPrimValOfType (IntType Int64) = IntValue . Int64Value <$> arbitrary-arbitraryPrimValOfType (FloatType Float16) = FloatValue . Float16Value <$> arbitrary-arbitraryPrimValOfType (FloatType Float32) = FloatValue . Float32Value <$> arbitrary-arbitraryPrimValOfType (FloatType Float64) = FloatValue . Float32Value <$> arbitrary-arbitraryPrimValOfType Bool = BoolValue <$> arbitrary-arbitraryPrimValOfType Unit = pure UnitValue
unittests/Futhark/IR/Syntax/CoreTests.hs view
@@ -5,9 +5,9 @@  import Control.Applicative import Futhark.IR.Pretty (pretty)-import Futhark.IR.PrimitiveTests () import Futhark.IR.Syntax.Core import Language.Futhark.CoreTests ()+import Language.Futhark.PrimitiveTests () import Test.QuickCheck import Test.Tasty import Test.Tasty.HUnit@@ -40,7 +40,9 @@     subShapeTest :: ExtShape -> ExtShape -> Bool -> TestTree     subShapeTest shape1 shape2 expected =       testCase-        ( "subshapeOf " ++ pretty shape1 ++ " "+        ( "subshapeOf "+            ++ pretty shape1+            ++ " "             ++ pretty shape2             ++ " == "             ++ show expected
unittests/Futhark/Optimise/MemoryBlockMerging/GreedyColoringTests.hs view
@@ -19,33 +19,35 @@  psumTest :: TestTree psumTest =-  testCase "psumTest" $-    assertEqual+  testCase "psumTest"+    $ assertEqual       "Color simple 1-2-3 using two colors"       ([(0, "local"), (1, "local")], [(1 :: Int, 0), (2, 1), (3, 0)])-      $ (M.toList *** M.toList) $-        GreedyColoring.colorGraph-          (M.fromList [(1, "local"), (2, "local"), (3, "local")])-          $ S.fromList [(1, 2), (2, 3)]+    $ (M.toList *** M.toList)+    $ GreedyColoring.colorGraph+      (M.fromList [(1, "local"), (2, "local"), (3, "local")])+    $ S.fromList [(1, 2), (2, 3)]  allIntersect :: TestTree allIntersect =-  testCase "allIntersect" $-    assertEqual+  testCase "allIntersect"+    $ assertEqual       "Color a graph where all values intersect"       ([(0, "local"), (1, "local"), (2, "local")], [(1 :: Int, 2), (2, 1), (3, 0)])-      $ (M.toList *** M.toList) $-        GreedyColoring.colorGraph-          (M.fromList [(1, "local"), (2, "local"), (3, "local")])-          $ S.fromList [(1, 2), (2, 3), (1, 3)]+    $ (M.toList *** M.toList)+    $ GreedyColoring.colorGraph+      (M.fromList [(1, "local"), (2, "local"), (3, "local")])+    $ S.fromList [(1, 2), (2, 3), (1, 3)]  emptyGraph :: TestTree emptyGraph =-  testCase "emptyGraph" $-    assertEqual+  testCase "emptyGraph"+    $ assertEqual       "Color an empty graph"       ([] :: [(Int, Char)], [] :: [(Int, Int)])-      $ (M.toList *** M.toList) $ GreedyColoring.colorGraph M.empty $ S.fromList []+    $ (M.toList *** M.toList)+    $ GreedyColoring.colorGraph M.empty+    $ S.fromList []  noIntersections :: TestTree noIntersections =
unittests/Language/Futhark/CoreTests.hs view
@@ -3,8 +3,8 @@  module Language.Futhark.CoreTests () where -import Futhark.IR.PrimitiveTests () import Language.Futhark.Core+import Language.Futhark.PrimitiveTests () import Test.QuickCheck  instance Arbitrary Name where
+ unittests/Language/Futhark/PrimitiveTests.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Language.Futhark.PrimitiveTests+  ( tests,+    arbitraryPrimValOfType,+  )+where++import Control.Applicative+import Futhark.Util (convFloat)+import Language.Futhark.Primitive+import Test.QuickCheck+import Test.Tasty+import Test.Tasty.HUnit+import Prelude++tests :: TestTree+tests = testGroup "PrimitiveTests" [propPrimValuesHaveRightType]++propPrimValuesHaveRightType :: TestTree+propPrimValuesHaveRightType =+  testGroup+    "propPrimValuesHaveRightTypes"+    [ testCase (show t ++ " has blank of right type") $+        primValueType (blankPrimValue t) @?= t+      | t <- [minBound .. maxBound]+    ]++instance Arbitrary IntType where+  arbitrary = elements [minBound .. maxBound]++instance Arbitrary FloatType where+  arbitrary = elements [minBound .. maxBound]++instance Arbitrary PrimType where+  arbitrary = elements [minBound .. maxBound]++instance Arbitrary IntValue where+  arbitrary =+    oneof+      [ Int8Value <$> arbitrary,+        Int16Value <$> arbitrary,+        Int32Value <$> arbitrary,+        Int64Value <$> arbitrary+      ]++instance Arbitrary Half where+  arbitrary = (convFloat :: Float -> Half) <$> arbitrary++instance Arbitrary FloatValue where+  arbitrary =+    oneof+      [ Float16Value <$> arbitrary,+        Float32Value <$> arbitrary,+        Float64Value <$> arbitrary+      ]++instance Arbitrary PrimValue where+  arbitrary =+    oneof+      [ IntValue <$> arbitrary,+        FloatValue <$> arbitrary,+        BoolValue <$> arbitrary,+        pure UnitValue+      ]++arbitraryPrimValOfType :: PrimType -> Gen PrimValue+arbitraryPrimValOfType (IntType Int8) = IntValue . Int8Value <$> arbitrary+arbitraryPrimValOfType (IntType Int16) = IntValue . Int16Value <$> arbitrary+arbitraryPrimValOfType (IntType Int32) = IntValue . Int32Value <$> arbitrary+arbitraryPrimValOfType (IntType Int64) = IntValue . Int64Value <$> arbitrary+arbitraryPrimValOfType (FloatType Float16) = FloatValue . Float16Value <$> arbitrary+arbitraryPrimValOfType (FloatType Float32) = FloatValue . Float32Value <$> arbitrary+arbitraryPrimValOfType (FloatType Float64) = FloatValue . Float32Value <$> arbitrary+arbitraryPrimValOfType Bool = BoolValue <$> arbitrary+arbitraryPrimValOfType Unit = pure UnitValue
unittests/Language/Futhark/SyntaxTests.hs view
@@ -12,10 +12,10 @@ import Data.String import qualified Data.Text as T import Data.Void-import Futhark.IR.Primitive.Parse (constituent, keyword, lexeme)-import Futhark.IR.PrimitiveTests () import Language.Futhark import Language.Futhark.Parser+import Language.Futhark.Primitive.Parse (constituent, keyword, lexeme)+import Language.Futhark.PrimitiveTests () import Test.QuickCheck import Test.Tasty import Text.Megaparsec@@ -78,7 +78,8 @@ pVName :: Parser VName pVName = lexeme $ do   (s, tag) <--    satisfy constituent `manyTill_` try pTag+    satisfy constituent+      `manyTill_` try pTag       <?> "variable name"   pure $ VName (nameFromString s) tag   where@@ -88,9 +89,6 @@ pQualName :: Parser (QualName VName) pQualName = QualName [] <$> pVName -pTypeName :: Parser TypeName-pTypeName = TypeName [] <$> pVName- pPrimType :: Parser PrimType pPrimType =   choice $@@ -114,15 +112,15 @@ pUniqueness :: Parser Uniqueness pUniqueness = choice [lexeme "*" $> Unique, pure Nonunique] -pDimDecl :: Parser (DimDecl VName)-pDimDecl =+pSize :: Parser Size+pSize =   brackets $     choice-      [ ConstDim <$> lexeme L.decimal,-        NamedDim <$> pQualName+      [ ConstSize <$> lexeme L.decimal,+        NamedSize <$> pQualName       ] -pScalarNonFun :: Parser (ScalarTypeBase (DimDecl VName) ())+pScalarNonFun :: Parser (ScalarTypeBase Size ()) pScalarNonFun =   choice     [ Prim <$> pPrimType,@@ -132,10 +130,10 @@     ]   where     pField = (,) <$> pName <* lexeme ":" <*> pStructType-    pTypeVar = TypeVar () <$> pUniqueness <*> pTypeName <*> many pTypeArg+    pTypeVar = TypeVar () <$> pUniqueness <*> pQualName <*> many pTypeArg     pTypeArg =       choice-        [ TypeArgDim <$> pDimDecl <*> pure mempty,+        [ TypeArgDim <$> pSize <*> pure mempty,           TypeArgType <$> pTypeArgType <*> pure mempty         ]     pTypeArgType =@@ -146,13 +144,13 @@  pArrayType :: Parser StructType pArrayType =-  Array () <$> pUniqueness <*> (ShapeDecl <$> some pDimDecl) <*> pScalarNonFun+  Array () <$> pUniqueness <*> (Shape <$> some pSize) <*> pScalarNonFun  pNonFunType :: Parser StructType pNonFunType =   choice [try pArrayType, try $ parens pStructType, Scalar <$> pScalarNonFun] -pScalarType :: Parser (ScalarTypeBase (DimDecl VName) ())+pScalarType :: Parser (ScalarTypeBase Size ()) pScalarType = choice [try pFun, pScalarNonFun]   where     pFun =@@ -180,7 +178,7 @@     onError e =       error $ "not a " <> what <> ": " <> s <> "\n" <> errorBundlePretty e -instance IsString (ScalarTypeBase (DimDecl VName) ()) where+instance IsString (ScalarTypeBase Size ()) where   fromString = fromStringParse pScalarType "ScalarType"  instance IsString StructType where
unittests/futhark_tests.hs view
@@ -3,11 +3,11 @@ import qualified Futhark.AD.DerivativesTests import qualified Futhark.BenchTests import qualified Futhark.IR.Mem.IxFunTests-import qualified Futhark.IR.PrimitiveTests import qualified Futhark.IR.PropTests import qualified Futhark.IR.Syntax.CoreTests import qualified Futhark.Optimise.MemoryBlockMerging.GreedyColoringTests import qualified Futhark.Pkg.SolveTests+import qualified Language.Futhark.PrimitiveTests import qualified Language.Futhark.SyntaxTests import qualified Language.Futhark.TypeCheckerTests import Test.Tasty@@ -23,7 +23,7 @@       Futhark.IR.Syntax.CoreTests.tests,       Futhark.Pkg.SolveTests.tests,       Futhark.IR.Mem.IxFunTests.tests,-      Futhark.IR.PrimitiveTests.tests,+      Language.Futhark.PrimitiveTests.tests,       Futhark.Optimise.MemoryBlockMerging.GreedyColoringTests.tests,       Language.Futhark.TypeCheckerTests.tests     ]