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 +1/−1
- docs/c-api.rst +56/−7
- docs/conf.py +1/−0
- docs/index.rst +1/−0
- docs/installation.rst +1/−1
- docs/language-reference.rst +2/−2
- docs/man/futhark-ispc.rst +61/−0
- docs/man/futhark-literate.rst +6/−0
- docs/man/futhark.rst +6/−1
- docs/server-protocol.rst +40/−1
- futhark.cabal +67/−31
- prelude/soacs.fut +40/−36
- rts/c/ispc_util.h +457/−0
- rts/c/scalar.h +2923/−1699
- rts/c/scalar_f16.h +198/−6
- rts/c/scheduler.h +15/−5
- rts/c/server.h +190/−32
- rts/c/uniform.h +1708/−0
- rts/c/util.h +5/−0
- rts/python/server.py +11/−1
- src/Futhark/AD/Derivatives.hs +1/−1
- src/Futhark/AD/Fwd.hs +6/−6
- src/Futhark/AD/Rev.hs +10/−9
- src/Futhark/AD/Rev/Loop.hs +34/−33
- src/Futhark/AD/Rev/Map.hs +4/−4
- src/Futhark/AD/Rev/Monad.hs +14/−14
- src/Futhark/AD/Rev/Reduce.hs +7/−4
- src/Futhark/AD/Rev/Scan.hs +3/−1
- src/Futhark/AD/Rev/Scatter.hs +2/−1
- src/Futhark/Actions.hs +84/−2
- src/Futhark/Analysis/Alias.hs +7/−3
- src/Futhark/Analysis/CallGraph.hs +2/−35
- src/Futhark/Analysis/HORep/MapNest.hs +2/−1
- src/Futhark/Analysis/HORep/SOAC.hs +39/−26
- src/Futhark/Analysis/Interference.hs +6/−4
- src/Futhark/Analysis/LastUse.hs +19/−9
- src/Futhark/Analysis/MemAlias.hs +7/−12
- src/Futhark/Analysis/PrimExp.hs +2/−2
- src/Futhark/Analysis/PrimExp/Convert.hs +3/−1
- src/Futhark/Analysis/PrimExp/Parse.hs +1/−1
- src/Futhark/Analysis/Rephrase.hs +4/−4
- src/Futhark/Analysis/SymbolTable.hs +2/−1
- src/Futhark/Analysis/UsageTable.hs +5/−5
- src/Futhark/Bench.hs +3/−1
- src/Futhark/Builder.hs +7/−1
- src/Futhark/CLI/Autotune.hs +20/−13
- src/Futhark/CLI/Bench.hs +4/−2
- src/Futhark/CLI/Check.hs +3/−1
- src/Futhark/CLI/Dataset.hs +2/−2
- src/Futhark/CLI/Dev.hs +16/−5
- src/Futhark/CLI/Doc.hs +2/−1
- src/Futhark/CLI/LSP.hs +0/−5
- src/Futhark/CLI/Literate.hs +53/−27
- src/Futhark/CLI/Main.hs +5/−1
- src/Futhark/CLI/Misc.hs +27/−1
- src/Futhark/CLI/MulticoreISPC.hs +19/−0
- src/Futhark/CLI/Pkg.hs +14/−5
- src/Futhark/CLI/REPL.hs +2/−1
- src/Futhark/CLI/Run.hs +6/−2
- src/Futhark/CLI/Test.hs +32/−14
- src/Futhark/CodeGen/Backends/CCUDA.hs +21/−18
- src/Futhark/CodeGen/Backends/CCUDA/Boilerplate.hs +2/−2
- src/Futhark/CodeGen/Backends/COpenCL.hs +17/−11
- src/Futhark/CodeGen/Backends/GenericC.hs +411/−166
- src/Futhark/CodeGen/Backends/GenericC/CLI.hs +5/−4
- src/Futhark/CodeGen/Backends/GenericC/Options.hs +5/−5
- src/Futhark/CodeGen/Backends/GenericC/Server.hs +73/−29
- src/Futhark/CodeGen/Backends/GenericPython.hs +106/−94
- src/Futhark/CodeGen/Backends/GenericPython/AST.hs +23/−10
- src/Futhark/CodeGen/Backends/GenericPython/Options.hs +3/−1
- src/Futhark/CodeGen/Backends/GenericWASM.hs +20/−18
- src/Futhark/CodeGen/Backends/MulticoreC.hs +47/−7
- src/Futhark/CodeGen/Backends/MulticoreISPC.hs +1114/−0
- src/Futhark/CodeGen/Backends/MulticoreWASM.hs +5/−5
- src/Futhark/CodeGen/Backends/PyOpenCL.hs +7/−5
- src/Futhark/CodeGen/Backends/PyOpenCL/Boilerplate.hs +2/−1
- src/Futhark/CodeGen/Backends/SequentialC.hs +1/−1
- src/Futhark/CodeGen/Backends/SequentialWASM.hs +4/−4
- src/Futhark/CodeGen/Backends/SimpleRep.hs +31/−33
- src/Futhark/CodeGen/ImpCode.hs +120/−93
- src/Futhark/CodeGen/ImpCode/GPU.hs +79/−34
- src/Futhark/CodeGen/ImpCode/Multicore.hs +51/−2
- src/Futhark/CodeGen/ImpGen.hs +136/−84
- src/Futhark/CodeGen/ImpGen/GPU.hs +9/−8
- src/Futhark/CodeGen/ImpGen/GPU/Base.hs +89/−55
- src/Futhark/CodeGen/ImpGen/GPU/SegHist.hs +66/−39
- src/Futhark/CodeGen/ImpGen/GPU/SegMap.hs +3/−3
- src/Futhark/CodeGen/ImpGen/GPU/SegRed.hs +53/−42
- src/Futhark/CodeGen/ImpGen/GPU/SegScan/SinglePass.hs +46/−36
- src/Futhark/CodeGen/ImpGen/GPU/SegScan/TwoPass.hs +18/−12
- src/Futhark/CodeGen/ImpGen/GPU/ToOpenCL.hs +9/−5
- src/Futhark/CodeGen/ImpGen/GPU/Transpose.hs +8/−4
- src/Futhark/CodeGen/ImpGen/Multicore.hs +5/−12
- src/Futhark/CodeGen/ImpGen/Multicore/Base.hs +115/−9
- src/Futhark/CodeGen/ImpGen/Multicore/SegHist.hs +82/−42
- src/Futhark/CodeGen/ImpGen/Multicore/SegMap.hs +5/−4
- src/Futhark/CodeGen/ImpGen/Multicore/SegRed.hs +265/−96
- src/Futhark/CodeGen/ImpGen/Multicore/SegScan.hs +225/−96
- src/Futhark/CodeGen/ImpGen/Transpose.hs +0/−2
- src/Futhark/CodeGen/RTS/C.hs +12/−0
- src/Futhark/CodeGen/SetDefaultSpace.hs +14/−8
- src/Futhark/Compiler.hs +5/−4
- src/Futhark/Compiler/Program.hs +6/−2
- src/Futhark/Construct.hs +9/−4
- src/Futhark/Doc/Generator.hs +52/−42
- src/Futhark/IR/Aliases.hs +3/−1
- src/Futhark/IR/GPU/Op.hs +4/−2
- src/Futhark/IR/GPU/Simplify.hs +33/−3
- src/Futhark/IR/MC/Op.hs +4/−2
- src/Futhark/IR/Mem.hs +34/−16
- src/Futhark/IR/Mem/IxFun.hs +9/−7
- src/Futhark/IR/Mem/Simplify.hs +3/−1
- src/Futhark/IR/Parse.hs +220/−96
- src/Futhark/IR/Pretty.hs +52/−19
- src/Futhark/IR/Primitive.hs +0/−1873
- src/Futhark/IR/Primitive/Parse.hs +0/−112
- src/Futhark/IR/Prop.hs +9/−16
- src/Futhark/IR/Prop/Constants.hs +2/−1
- src/Futhark/IR/Prop/Names.hs +2/−1
- src/Futhark/IR/Prop/Scope.hs +2/−1
- src/Futhark/IR/Prop/Types.hs +7/−7
- src/Futhark/IR/Rep.hs +1/−1
- src/Futhark/IR/RetType.hs +2/−1
- src/Futhark/IR/SOACS/SOAC.hs +114/−49
- src/Futhark/IR/SOACS/Simplify.hs +40/−16
- src/Futhark/IR/SegOp.hs +47/−21
- src/Futhark/IR/Syntax.hs +18/−20
- src/Futhark/IR/Syntax/Core.hs +54/−2
- src/Futhark/IR/Traversals.hs +23/−9
- src/Futhark/IR/TypeCheck.hs +214/−183
- src/Futhark/Internalise.hs +2/−1
- src/Futhark/Internalise/Bindings.hs +7/−5
- src/Futhark/Internalise/Defunctionalise.hs +70/−57
- src/Futhark/Internalise/Defunctorise.hs +20/−8
- src/Futhark/Internalise/Entry.hs +165/−0
- src/Futhark/Internalise/Exps.hs +172/−184
- src/Futhark/Internalise/FreeVars.hs +0/−132
- src/Futhark/Internalise/Lambdas.hs +4/−20
- src/Futhark/Internalise/LiftLambdas.hs +14/−12
- src/Futhark/Internalise/Monad.hs +47/−25
- src/Futhark/Internalise/Monomorphise.hs +62/−45
- src/Futhark/Internalise/TypesValues.hs +49/−41
- src/Futhark/LSP/Compile.hs +12/−11
- src/Futhark/LSP/Diagnostic.hs +3/−2
- src/Futhark/LSP/Handlers.hs +12/−12
- src/Futhark/Optimise/BlkRegTiling.hs +19/−13
- src/Futhark/Optimise/CSE.hs +4/−1
- src/Futhark/Optimise/DoubleBuffer.hs +9/−5
- src/Futhark/Optimise/Fusion.hs +479/−1133
- src/Futhark/Optimise/Fusion/Composing.hs +6/−3
- src/Futhark/Optimise/Fusion/GraphRep.hs +431/−0
- src/Futhark/Optimise/Fusion/LoopKernel.hs +0/−937
- src/Futhark/Optimise/Fusion/TryFusion.hs +856/−0
- src/Futhark/Optimise/GenRedOpt.hs +8/−6
- src/Futhark/Optimise/HistAccs.hs +6/−2
- src/Futhark/Optimise/InPlaceLowering.hs +5/−2
- src/Futhark/Optimise/InPlaceLowering/LowerIntoStm.hs +14/−9
- src/Futhark/Optimise/InPlaceLowering/SubstituteIndices.hs +19/−7
- src/Futhark/Optimise/InliningDeadFun.hs +10/−5
- src/Futhark/Optimise/ReduceDeviceSyncs.hs +37/−44
- src/Futhark/Optimise/ReduceDeviceSyncs/MigrationTable.hs +6/−15
- src/Futhark/Optimise/Simplify.hs +8/−2
- src/Futhark/Optimise/Simplify/Engine.hs +36/−30
- src/Futhark/Optimise/Simplify/Rules.hs +31/−14
- src/Futhark/Optimise/Simplify/Rules/BasicOp.hs +50/−36
- src/Futhark/Optimise/Simplify/Rules/ClosedForm.hs +6/−3
- src/Futhark/Optimise/Simplify/Rules/Index.hs +6/−3
- src/Futhark/Optimise/Simplify/Rules/Loop.hs +9/−6
- src/Futhark/Optimise/Simplify/Rules/Simple.hs +14/−0
- src/Futhark/Optimise/Sink.hs +6/−3
- src/Futhark/Optimise/TileLoops.hs +36/−21
- src/Futhark/Optimise/TileLoops/Shared.hs +14/−4
- src/Futhark/Optimise/Unstream.hs +4/−2
- src/Futhark/Pass.hs +4/−19
- src/Futhark/Pass/ExpandAllocations.hs +27/−15
- src/Futhark/Pass/ExplicitAllocations.hs +17/−6
- src/Futhark/Pass/ExplicitAllocations/GPU.hs +4/−2
- src/Futhark/Pass/ExplicitAllocations/SegOp.hs +5/−2
- src/Futhark/Pass/ExtractKernels.hs +46/−26
- src/Futhark/Pass/ExtractKernels/BlockedKernel.hs +3/−1
- src/Futhark/Pass/ExtractKernels/DistributeNests.hs +44/−20
- src/Futhark/Pass/ExtractKernels/Distribution.hs +5/−3
- src/Futhark/Pass/ExtractKernels/ISRWIM.hs +21/−10
- src/Futhark/Pass/ExtractKernels/Interchange.hs +9/−5
- src/Futhark/Pass/ExtractKernels/Intragroup.hs +7/−3
- src/Futhark/Pass/ExtractKernels/StreamKernel.hs +5/−2
- src/Futhark/Pass/ExtractMulticore.hs +17/−8
- src/Futhark/Pass/KernelBabysitting.hs +13/−7
- src/Futhark/Passes.hs +0/−6
- src/Futhark/Pkg/Info.hs +18/−6
- src/Futhark/Pkg/Solve.hs +4/−1
- src/Futhark/Pkg/Types.hs +9/−4
- src/Futhark/Script.hs +82/−34
- src/Futhark/Test.hs +13/−8
- src/Futhark/Test/Spec.hs +5/−2
- src/Futhark/Tools.hs +2/−1
- src/Futhark/Transform/FirstOrderTransform.hs +23/−11
- src/Futhark/Util.hs +4/−11
- src/Language/Futhark.hs +3/−1
- src/Language/Futhark/Core.hs +2/−9
- src/Language/Futhark/FreeVars.hs +164/−0
- src/Language/Futhark/Interpreter.hs +69/−49
- src/Language/Futhark/Parser/Monad.hs +6/−3
- src/Language/Futhark/Parser/Parser.y +13/−13
- src/Language/Futhark/Pretty.hs +64/−43
- src/Language/Futhark/Primitive.hs +1873/−0
- src/Language/Futhark/Primitive/Parse.hs +111/−0
- src/Language/Futhark/Prop.hs +127/−199
- src/Language/Futhark/Query.hs +3/−2
- src/Language/Futhark/Semantic.hs +10/−4
- src/Language/Futhark/Syntax.hs +77/−102
- src/Language/Futhark/Traversals.hs +61/−38
- src/Language/Futhark/Tuple.hs +43/−0
- src/Language/Futhark/TypeChecker.hs +13/−9
- src/Language/Futhark/TypeChecker/Modules.hs +28/−21
- src/Language/Futhark/TypeChecker/Monad.hs +20/−17
- src/Language/Futhark/TypeChecker/Terms.hs +153/−137
- src/Language/Futhark/TypeChecker/Terms/DoLoop.hs +19/−17
- src/Language/Futhark/TypeChecker/Terms/Monad.hs +84/−52
- src/Language/Futhark/TypeChecker/Terms/Pat.hs +19/−9
- src/Language/Futhark/TypeChecker/Types.hs +141/−68
- src/Language/Futhark/TypeChecker/Unify.hs +121/−88
- unittests/Futhark/AD/DerivativesTests.hs +2/−1
- unittests/Futhark/BenchTests.hs +3/−1
- unittests/Futhark/IR/Mem/IxFun/Alg.hs +2/−1
- unittests/Futhark/IR/Mem/IxFunTests.hs +3/−1
- unittests/Futhark/IR/PrimitiveTests.hs +0/−77
- unittests/Futhark/IR/Syntax/CoreTests.hs +4/−2
- unittests/Futhark/Optimise/MemoryBlockMerging/GreedyColoringTests.hs +17/−15
- unittests/Language/Futhark/CoreTests.hs +1/−1
- unittests/Language/Futhark/PrimitiveTests.hs +77/−0
- unittests/Language/Futhark/SyntaxTests.hs +14/−16
- unittests/futhark_tests.hs +2/−2
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 }
@@ -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 ]