-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Haskell bindings to Halide -- -- Halide is a programming language designed to make it easier to write -- high-performance image and array processing code on modern machines. -- Rather than being a standalone programming language, Halide is -- embedded in C++. This means you write C++ code that builds an -- in-memory representation of a Halide pipeline using Halide's C++ API. -- You can then compile this representation to an object file, or -- JIT-compile it and run it in the same process. -- -- This package provides Haskell bindings that allow to write Halide -- embedded in Haskell without C++. -- -- The best way to learn Halide is to have a look at the -- [tutorials](https:/github.comtwesterhouthalide-haskelltreemastertutorials). -- Reference documentation is provided by the haddocks of the -- Language.Halide module. @package halide-haskell @version 0.0.1.0 -- | This package provides Haskell bindings that allow to write Halide -- embedded in Haskell without C++. -- -- This module contains the reference documentation for Halide. If you're -- new, the best way to learn Halide is to have a look at the -- tutorials. module Language.Halide -- | A scalar expression in Halide. -- -- To have a nice experience writing arithmetic expressions in terms of -- Exprs, we want to derive Num, Floating etc. -- instances for Expr. Unfortunately, that means that we encode -- Expr, Var, RVar, and ScalarParam by the -- same type, and passing an Expr to a function that expects a -- Var will produce a runtime error. data Expr a -- | Scalar expression. Expr :: ForeignPtr CxxExpr -> Expr a -- | Index variable. Var :: ForeignPtr CxxVar -> Expr a -- | Reduction variable. RVar :: ForeignPtr CxxRVar -> Expr a -- | Scalar parameter. -- -- The IORef is initialized with Nothing and filled in on -- the first call to asExpr. ScalarParam :: IORef (Maybe (ForeignPtr CxxParameter)) -> Expr a -- | A Var. type Var = Expr Int32 -- | An RVar. type RVar = Expr Int32 -- | Either Var or RVar. type VarOrRVar = Expr Int32 -- | Specifies that a type is supported by Halide. class Storable a => IsHalideType a -- | Create a scalar expression from a Haskell value. mkExpr :: IsHalideType a => a -> Expr a -- | Create a named index variable. mkVar :: Text -> IO (Expr Int32) -- | Create a named reduction variable. -- -- For more information about reduction variables, see -- Halide::RDom. mkRVar :: Text -> Expr Int32 -> Expr Int32 -> IO (Expr Int32) -- | Return an undef value of the given type. -- -- For more information, see Halide::undef. undef :: forall a. IsHalideType a => Expr a -- | Cast a scalar expression to a different type. -- -- Use TypeApplications with this function, e.g. cast @Float x. cast :: forall to from. (IsHalideType to, IsHalideType from) => Expr from -> Expr to -- | Similar to the standard bool function from Prelude except that -- it's lifted to work with Expr types. bool :: IsHalideType a => Expr Bool -> Expr a -> Expr a -> Expr a -- | Convert expression to integer immediate. -- -- Tries to extract the value of an expression if it is a compile-time -- constant. If the expression isn't known at compile-time of the Halide -- pipeline, returns Nothing. toIntImm :: IsHalideType a => Expr a -> Maybe Int -- | Print the expression to stdout when it's evaluated. -- -- This is useful for debugging Halide pipelines. printed :: IsHalideType a => Expr a -> Expr a -- | Evaluate a scalar expression. -- -- It should contain no parameters. If it does contain parameters, an -- exception will be thrown. evaluate :: forall a. IsHalideType a => Expr a -> IO a -- | == but lifted to return an Expr. eq :: IsHalideType a => Expr a -> Expr a -> Expr Bool infix 4 `eq` -- | /= but lifted to return an Expr. neq :: IsHalideType a => Expr a -> Expr a -> Expr Bool infix 4 `neq` -- | < but lifted to return an Expr. lt :: IsHalideType a => Expr a -> Expr a -> Expr Bool infix 4 `lt` -- | <= but lifted to return an Expr. lte :: IsHalideType a => Expr a -> Expr a -> Expr Bool infix 4 `lte` -- | > but lifted to return an Expr. gt :: IsHalideType a => Expr a -> Expr a -> Expr Bool infix 4 `gt` -- | >= but lifted to return an Expr. gte :: IsHalideType a => Expr a -> Expr a -> Expr Bool infix 4 `gte` -- | A function in Halide. Conceptually, it can be thought of as a lazy -- n-dimensional buffer of type a. -- -- This is a wrapper around the Halide::Func C++ type. data Func (t :: FuncTy) (n :: Nat) (a :: Type) [Func] :: {-# UNPACK #-} !ForeignPtr CxxFunc -> Func 'FuncTy n a [Param] :: {-# UNPACK #-} !IORef (Maybe (ForeignPtr CxxImageParam)) -> Func 'ParamTy n a -- | Function type. It can either be FuncTy which means that we have -- defined the function ourselves, or ParamTy which means that -- it's a parameter to our pipeline. data FuncTy FuncTy :: FuncTy ParamTy :: FuncTy -- | A single definition of a Func. newtype Stage (n :: Nat) (a :: Type) Stage :: ForeignPtr CxxStage -> Stage (n :: Nat) (a :: Type) -- | Define a Halide function. -- -- define "f" i e defines a Halide function called "f" such that -- f[i] = e. -- -- Here, i is an n-element tuple of Var, i.e. -- the following are all valid: -- --
--   >>> [x, y, z] <- mapM mkVar ["x", "y", "z"]
--   
--   >>> f1 <- define "f1" x (0 :: Expr Float)
--   
--   >>> f2 <- define "f2" (x, y) (0 :: Expr Float)
--   
--   >>> f3 <- define "f3" (x, y, z) (0 :: Expr Float)
--   
define :: (IsTuple (Arguments ts) i, All ((~) Var) ts, Length ts ~ n, KnownNat n, IsHalideType a) => Text -> i -> Expr a -> IO (Func 'FuncTy n a) -- | Create an update definition for a Halide function. -- -- update f i e creates an update definition for f that -- performs f[i] = e. update :: (IsTuple (Arguments ts) i, All ((~) (Expr Int32)) ts, Length ts ~ n, KnownNat n, IsHalideType a) => Func 'FuncTy n a -> i -> Expr a -> IO () -- | Apply a Halide function. Conceptually, f ! i is equivalent to -- f[i], i.e. indexing into a lazy array. (!) :: (IsTuple (Arguments ts) i, All ((~) (Expr Int32)) ts, Length ts ~ n, KnownNat n, IsHalideType a) => Func t n a -> i -> Expr a infix 9 ! -- | Get the index arguments of the function. -- -- The returned list contains exactly n elements. getArgs :: (KnownNat n, IsHalideType a) => Func t n a -> IO [Var] -- | Return True when the function has update definitions, -- False otherwise. hasUpdateDefinitions :: (KnownNat n, IsHalideType a) => Func t n a -> IO Bool -- | Get a handle to an update step for the purposes of scheduling it. getUpdateStage :: (KnownNat n, IsHalideType a) => Int -> Func 'FuncTy n a -> IO (Stage n a) -- | An n-dimensional buffer of elements of type a. -- -- Most pipelines use Ptr (HalideBuffer n a) for -- input and output array arguments. newtype HalideBuffer (n :: Nat) (a :: Type) HalideBuffer :: RawHalideBuffer -> HalideBuffer (n :: Nat) (a :: Type) [unHalideBuffer] :: HalideBuffer (n :: Nat) (a :: Type) -> RawHalideBuffer -- | Temporary allocate a CPU buffer. -- -- This is useful for testing and debugging when you need to allocate an -- output buffer for your pipeline. E.g. -- --
--   allocaCpuBuffer [3, 3] $ out -> do
--     myKernel out                -- fill the buffer
--     print =<< peekToList out  -- print it for debugging
--   
allocaCpuBuffer :: forall n a b. (HasCallStack, KnownNat n, IsHalideType a) => [Int] -> (Ptr (HalideBuffer n a) -> IO b) -> IO b -- | Specifies that a can be converted to a list. This is very -- similar to IsList except that we read the list from a -- Ptr rather than converting directly. class IsListPeek a where { type ListPeekElem a :: Type; } peekToList :: (IsListPeek a, HasCallStack) => Ptr a -> IO [ListPeekElem a] -- | Specifies that a type t can be used as an -- n-dimensional Halide buffer with elements of type a. class (KnownNat n, IsHalideType a) => IsHalideBuffer t n a withHalideBufferImpl :: IsHalideBuffer t n a => t -> (Ptr (HalideBuffer n a) -> IO b) -> IO b -- | Treat a type t as a HalideBuffer and use it in an -- IO action. -- -- This function is a simple wrapper around withHalideBufferImpl, -- except that the order of type parameters is reversed. If you have -- TypeApplications extension enabled, this allows you to write -- withHalideBuffer 3 Float yourBuffer to specify that -- you want a 3-dimensional buffer of Float. withHalideBuffer :: forall n a t b. IsHalideBuffer t n a => t -> (Ptr (HalideBuffer n a) -> IO b) -> IO b -- | Construct a HalideBuffer from a pointer to the data, a list of -- extents, and a list of strides, and use it in an IO action. -- -- This function throws a runtime error if the number of dimensions does -- not match n. bufferFromPtrShapeStrides :: forall n a b. (HasCallStack, KnownNat n, IsHalideType a) => Ptr a -> [Int] -> [Int] -> (Ptr (HalideBuffer n a) -> IO b) -> IO b -- | Similar to bufferFromPtrShapeStrides, but assumes column-major -- ordering of data. bufferFromPtrShape :: (HasCallStack, KnownNat n, IsHalideType a) => Ptr a -> [Int] -> (Ptr (HalideBuffer n a) -> IO b) -> IO b -- | Evaluate this function over a rectangular domain. realize :: forall n a t b. (KnownNat n, IsHalideType a) => Func t n a -> [Int] -> (Ptr (HalideBuffer n a) -> IO b) -> IO b -- | Wrap a buffer into a Func. -- -- Suppose, we are defining a pipeline that adds together two vectors, -- and we'd like to call realize to evaluate it directly, how do -- we pass the vectors to the Func? asBufferParam allows to -- do exactly this. -- --
--   asBuffer [1, 2, 3] $ \a ->
--     asBuffer [4, 5, 6] $ \b -> do
--       i <- mkVar "i"
--       f <- define "vectorAdd" i $ a ! i + b ! i
--       realize f [3] $ \result ->
--         print =<< peekToList f
--   
asBufferParam :: forall n a t b. IsHalideBuffer t n a => t -> (Func 'ParamTy n a -> IO b) -> IO b -- | Convert a function that builds a Halide Func into a normal -- Haskell function acccepting scalars and HalideBuffers. -- -- For example: -- --
--   builder :: Expr Float -> Func 'ParamTy 1 Float -> IO (Func 'FuncTy 1 Float)
--   builder scale inputVector = do
--     i <- mkVar "i"
--     scaledVector <- define "scaledVector" i $ scale * inputVector ! i
--     pure scaledVector
--   
-- -- The builder function accepts a scalar parameter and a vector -- and scales the vector by the given factor. We can now pass -- builder to compile: -- --
--   scaler <- compile builder
--   withHalideBuffer 1 Float [1, 1, 1] $ inputVector ->
--     allocaCpuBuffer [3] $ outputVector -> do
--       -- invoke the kernel
--       scaler 2.0 inputVector outputVector
--       -- print the result
--       print =<< peekToList outputVector
--   
compile :: forall n a t f kernel. (IsFuncBuilder f t n a, Curry (Lowered (FunctionArguments f)) (Ptr (HalideBuffer n a) -> IO ()) kernel) => f -> IO kernel -- | A view pattern to specify the name of a buffer argument. -- -- Example usage: -- --
--   >>> :{
--   _ <- compile $ \(buffer "src" -> src) -> do
--     i <- mkVar "i"
--     define "dest" i $ (src ! i :: Expr Float)
--   :}
--   
-- -- or if we want to specify the dimension and type, we can use type -- applications: -- --
--   >>> :{
--   _ <- compile $ \(buffer @1 @Float "src" -> src) -> do
--     i <- mkVar "i"
--     define "dest" i $ src ! i
--   :}
--   
buffer :: forall n a. (KnownNat n, IsHalideType a) => Text -> Func 'ParamTy n a -> Func 'ParamTy n a -- | Similar to buffer, but for scalar parameters. -- -- Example usage: -- --
--   >>> :{
--   _ <- compile $ \(scalar @Float "a" -> a) -> do
--     i <- mkVar "i"
--     define "dest" i $ a
--   :}
--   
scalar :: forall a. IsHalideType a => Text -> Expr a -> Expr a -- | Information about a buffer's dimension, such as the min, extent, and -- stride. newtype Dimension Dimension :: ForeignPtr CxxDimension -> Dimension -- | Get a particular dimension of a pipeline parameter. dim :: forall n a. (HasCallStack, KnownNat n, IsHalideType a) => Int -> Func 'ParamTy n a -> IO Dimension -- | Set the min in a given dimension to equal the given expression. -- Setting the mins to zero may simplify some addressing math. -- -- For more info, see Halide::Internal::Dimension::set_min. setMin :: Expr Int32 -> Dimension -> IO Dimension -- | Set the extent in a given dimension to equal the given expression. -- -- Halide will generate runtime errors for Buffers that fail this check. -- -- For more info, see Halide::Internal::Dimension::set_extent. setExtent :: Expr Int32 -> Dimension -> IO Dimension -- | Set the stride in a given dimension to equal the given expression. -- -- This is particularly useful to set when vectorizing. Known strides for -- the vectorized dimensions generate better code. -- -- For more info, see Halide::Internal::Dimension::set_stride. setStride :: Expr Int32 -> Dimension -> IO Dimension -- | Set estimates for autoschedulers. setEstimate :: Expr Int32 -> Expr Int32 -> Dimension -> IO Dimension -- | The compilation target. -- -- This is the Haskell counterpart of Halide::Target. newtype Target Target :: ForeignPtr CxxTarget -> Target -- | Return the target that Halide will use by default. -- -- If the HL_TARGET environment variable is set, it uses that. -- Otherwise, it returns the target corresponding to the host machine. hostTarget :: Target -- | Get the default GPU target. We first check for CUDA and then for -- OpenCL. If neither of the two is usable, Nothing is returned. gpuTarget :: Maybe Target -- | Similar to compile, but the first argument lets you explicitly -- specify the compilation target. compileForTarget :: forall n a t f kernel. (IsFuncBuilder f t n a, Curry (Lowered (FunctionArguments f)) (Ptr (HalideBuffer n a) -> IO ()) kernel) => Target -> f -> IO kernel -- | An enum describing the type of device API. -- -- This is the Haskell counterpart of Halide::DeviceAPI. data DeviceAPI DeviceNone :: DeviceAPI DeviceHost :: DeviceAPI DeviceDefaultGPU :: DeviceAPI DeviceCUDA :: DeviceAPI DeviceOpenCL :: DeviceAPI DeviceOpenGLCompute :: DeviceAPI DeviceMetal :: DeviceAPI DeviceHexagon :: DeviceAPI DeviceHexagonDma :: DeviceAPI DeviceD3D12Compute :: DeviceAPI -- | Note: generated automatically using -- --
--   cat $HALIDE_PATH/include/Halide.h | \
--     grep -E '.* = halide_target_feature_.*' | \
--     sed -E 's/^\s*(.*) = .*$/  | \1/g' | \
--     grep -v FeatureEnd
--   
data TargetFeature FeatureJIT :: TargetFeature FeatureDebug :: TargetFeature FeatureNoAsserts :: TargetFeature FeatureNoBoundsQuery :: TargetFeature FeatureSSE41 :: TargetFeature FeatureAVX :: TargetFeature FeatureAVX2 :: TargetFeature FeatureFMA :: TargetFeature FeatureFMA4 :: TargetFeature FeatureF16C :: TargetFeature FeatureARMv7s :: TargetFeature FeatureNoNEON :: TargetFeature FeatureVSX :: TargetFeature FeaturePOWER_ARCH_2_07 :: TargetFeature FeatureCUDA :: TargetFeature FeatureCUDACapability30 :: TargetFeature FeatureCUDACapability32 :: TargetFeature FeatureCUDACapability35 :: TargetFeature FeatureCUDACapability50 :: TargetFeature FeatureCUDACapability61 :: TargetFeature FeatureCUDACapability70 :: TargetFeature FeatureCUDACapability75 :: TargetFeature FeatureCUDACapability80 :: TargetFeature FeatureCUDACapability86 :: TargetFeature FeatureOpenCL :: TargetFeature FeatureCLDoubles :: TargetFeature FeatureCLHalf :: TargetFeature FeatureCLAtomics64 :: TargetFeature FeatureOpenGLCompute :: TargetFeature FeatureEGL :: TargetFeature FeatureUserContext :: TargetFeature FeatureProfile :: TargetFeature FeatureNoRuntime :: TargetFeature FeatureMetal :: TargetFeature FeatureCPlusPlusMangling :: TargetFeature FeatureLargeBuffers :: TargetFeature FeatureHexagonDma :: TargetFeature FeatureHVX_128 :: TargetFeature FeatureHVX_v62 :: TargetFeature FeatureHVX_v65 :: TargetFeature FeatureHVX_v66 :: TargetFeature FeatureFuzzFloatStores :: TargetFeature FeatureSoftFloatABI :: TargetFeature FeatureMSAN :: TargetFeature FeatureAVX512 :: TargetFeature FeatureAVX512_KNL :: TargetFeature FeatureAVX512_Skylake :: TargetFeature FeatureAVX512_Cannonlake :: TargetFeature FeatureAVX512_SapphireRapids :: TargetFeature FeatureTraceLoads :: TargetFeature FeatureTraceStores :: TargetFeature FeatureTraceRealizations :: TargetFeature FeatureTracePipeline :: TargetFeature FeatureD3D12Compute :: TargetFeature FeatureStrictFloat :: TargetFeature FeatureTSAN :: TargetFeature FeatureASAN :: TargetFeature FeatureCheckUnsafePromises :: TargetFeature FeatureEmbedBitcode :: TargetFeature FeatureEnableLLVMLoopOpt :: TargetFeature FeatureWasmSimd128 :: TargetFeature FeatureWasmSignExt :: TargetFeature FeatureWasmSatFloatToInt :: TargetFeature FeatureWasmThreads :: TargetFeature FeatureWasmBulkMemory :: TargetFeature FeatureSVE :: TargetFeature FeatureSVE2 :: TargetFeature FeatureARMDotProd :: TargetFeature FeatureARMFp16 :: TargetFeature FeatureRVV :: TargetFeature FeatureARMv81a :: TargetFeature FeatureSanitizerCoverage :: TargetFeature FeatureProfileByTimer :: TargetFeature FeatureSPIRV :: TargetFeature FeatureSemihosting :: TargetFeature -- | Add a feature to target. setFeature :: TargetFeature -> Target -> Target -- | Return whether a GPU compute runtime is enabled. -- -- Checks whether gpuBlocks and similar are going to work. -- -- For more info, see Target::has_gpu_feature. hasGpuFeature :: Target -> Bool -- | Attempt to sniff whether a given Target (and its implied -- DeviceAPI) is usable on the current host. -- -- Note that a return value of True does not guarantee -- that future usage of that device will succeed; it is intended mainly -- as a simple diagnostic to allow early-exit when a desired device is -- definitely not usable. -- -- Also note that this call is NOT threadsafe, as it temporarily -- redirects various global error-handling hooks in Halide. hostSupportsTargetDevice :: Target -> Bool -- | Common scheduling functions class (KnownNat n, IsHalideType a) => Schedulable f n a -- | Vectorize the dimension. vectorize :: Schedulable f n a => VarOrRVar -> f n a -> IO (f n a) -- | Unroll the dimension. unroll :: Schedulable f n a => VarOrRVar -> f n a -> IO (f n a) -- | Reorder variables to have the given nesting order, from innermost out. reorder :: Schedulable f n a => [VarOrRVar] -> f n a -> IO (f n a) -- | Split a dimension into inner and outer subdimensions with the given -- names, where the inner dimension iterates from 0 to -- factor-1. -- -- The inner and outer subdimensions can then be dealt with using the -- other scheduling calls. It's okay to reuse the old variable name as -- either the inner or outer variable. The first argument specifies how -- the tail should be handled if the split factor does not provably -- divide the extent. split :: Schedulable f n a => TailStrategy -> VarOrRVar -> (VarOrRVar, VarOrRVar) -> Expr Int32 -> f n a -> IO (f n a) -- | Join two dimensions into a single fused dimenion. -- -- The fused dimension covers the product of the extents of the inner and -- outer dimensions given. fuse :: Schedulable f n a => (VarOrRVar, VarOrRVar) -> VarOrRVar -> f n a -> IO (f n a) -- | Mark the dimension to be traversed serially serial :: Schedulable f n a => VarOrRVar -> f n a -> IO (f n a) -- | Mark the dimension to be traversed in parallel parallel :: Schedulable f n a => VarOrRVar -> f n a -> IO (f n a) specialize :: Schedulable f n a => Expr Bool -> f n a -> IO (Stage n a) specializeFail :: Schedulable f n a => Text -> f n a -> IO () gpuBlocks :: (Schedulable f n a, IndexTuple i ts, 1 <= Length ts, Length ts <= 3) => DeviceAPI -> i -> f n a -> IO (f n a) gpuThreads :: (Schedulable f n a, IndexTuple i ts, 1 <= Length ts, Length ts <= 3) => DeviceAPI -> i -> f n a -> IO (f n a) gpuLanes :: Schedulable f n a => DeviceAPI -> VarOrRVar -> f n a -> IO (f n a) -- | Schedule the iteration over this stage to be fused with another stage -- from outermost loop to a given LoopLevel. -- -- For more info, see Halide::Stage::compute_with. computeWith :: Schedulable f n a => LoopAlignStrategy -> f n a -> LoopLevel t -> IO () -- | Different ways to handle a tail case in a split when the split factor -- does not provably divide the extent. -- -- This is the Haskell counterpart of -- Halide::TailStrategy. data TailStrategy -- | Round up the extent to be a multiple of the split factor. -- -- Not legal for RVars, as it would change the meaning of the algorithm. -- -- TailRoundUp :: TailStrategy -- | Guard the inner loop with an if statement that prevents evaluation -- beyond the original extent. -- -- Always legal. The if statement is treated like a boundary condition, -- and factored out into a loop epilogue if possible. -- -- TailGuardWithIf :: TailStrategy -- | Guard the loads and stores in the loop with an if statement that -- prevents evaluation beyond the original extent. -- -- Always legal. The if statement is treated like a boundary condition, -- and factored out into a loop epilogue if possible. * Pros: no -- redundant re-evaluation; does not constrain input or output sizes. * -- Cons: increases code size due to separate tail-case handling. TailPredicate :: TailStrategy -- | Guard the loads in the loop with an if statement that prevents -- evaluation beyond the original extent. -- -- Only legal for innermost splits. Not legal for RVars, as it would -- change the meaning of the algorithm. The if statement is treated like -- a boundary condition, and factored out into a loop epilogue if -- possible. * Pros: does not constrain input sizes, output size -- constraints are simpler than full predication. * Cons: increases code -- size due to separate tail-case handling, constrains the output size to -- be a multiple of the split factor. TailPredicateLoads :: TailStrategy -- | Guard the stores in the loop with an if statement that prevents -- evaluation beyond the original extent. -- -- Only legal for innermost splits. Not legal for RVars, as it would -- change the meaning of the algorithm. The if statement is treated like -- a boundary condition, and factored out into a loop epilogue if -- possible. * Pros: does not constrain output sizes, input size -- constraints are simpler than full predication. * Cons: increases code -- size due to separate tail-case handling, constraints the input size to -- be a multiple of the split factor. TailPredicateStores :: TailStrategy -- | Prevent evaluation beyond the original extent by shifting the tail -- case inwards, re-evaluating some points near the end. -- -- Only legal for pure variables in pure definitions. If the inner loop -- is very simple, the tail case is treated like a boundary condition and -- factored out into an epilogue. -- -- This is a good trade-off between several factors. Like -- TailRoundUp, it supports vectorization well, because the inner -- loop is always a fixed size with no data-dependent branching. It -- increases code size slightly for inner loops due to the epilogue -- handling, but not for outer loops (e.g. loops over tiles). If used on -- a stage that reads from an input or writes to an output, this stategy -- only requires that the input/output extent be at least the split -- factor, instead of a multiple of the split factor as with -- TailRoundUp. TailShiftInwards :: TailStrategy -- | For pure definitions use TailShiftInwards. -- -- For pure vars in update definitions use TailRoundUp. For RVars -- in update definitions use TailGuardWithIf. TailAuto :: TailStrategy -- | A reference to a site in a Halide statement at the top of the body of -- a particular for loop. data LoopLevel (t :: LoopLevelTy) [InlinedLoopLevel] :: LoopLevel 'InlinedTy [RootLoopLevel] :: LoopLevel 'RootTy [LoopLevel] :: !ForeignPtr CxxLoopLevel -> LoopLevel 'LockedTy data LoopLevelTy InlinedTy :: LoopLevelTy RootTy :: LoopLevelTy LockedTy :: LoopLevelTy -- | Different ways to handle the case when the start/end of the loops of -- stages computed with (fused) are not aligned. data LoopAlignStrategy -- | Shift the start of the fused loops to align. LoopAlignStart :: LoopAlignStrategy -- | Shift the end of the fused loops to align. LoopAlignEnd :: LoopAlignStrategy -- | computeWith will make no attempt to align the start/end of -- the fused loops. LoopNoAlign :: LoopAlignStrategy -- | By default, LoopAlignStrategy is set to LoopNoAlign. LoopAlignAuto :: LoopAlignStrategy -- | Compute all of this function once ahead of time. -- -- See Halide::Func::compute_root for more info. computeRoot :: (KnownNat n, IsHalideType a) => Func t n a -> IO (Func t n a) -- | Get the pure stage of a Func for the purposes of scheduling it. getStage :: (KnownNat n, IsHalideType a) => Func t n a -> IO (Stage n a) -- | Same as getLoopLevelAtStage except that the stage is -- -1. getLoopLevel :: (KnownNat n, IsHalideType a) => Func t n a -> Expr Int32 -> IO (LoopLevel 'LockedTy) -- | Identify the loop nest corresponding to some dimension of some -- function. getLoopLevelAtStage :: (KnownNat n, IsHalideType a) => Func t n a -> Expr Int32 -> Int -> IO (LoopLevel 'LockedTy) -- | Create and return a global identity wrapper, which wraps all calls to -- this Func by any other Func. -- -- If a global wrapper already exists, returns it. The global identity -- wrapper is only used by callers for which no custom wrapper has been -- specified. asUsed :: (KnownNat n, IsHalideType a) => Func t n a -> IO (Func 'FuncTy n a) -- | Creates and returns a new identity Func that wraps this Func. -- -- During compilation, Halide replaces all calls to this Func done by -- f with calls to the wrapper. If this Func is already wrapped -- for use in f, will return the existing wrapper. -- -- For more info, see Halide::Func::in. asUsedBy :: (KnownNat n, KnownNat m, IsHalideType a, IsHalideType b) => Func t1 n a -> Func 'FuncTy m b -> IO (Func 'FuncTy n a) -- | Declare that this function should be implemented by a call to -- halide_buffer_copy with the given target device API. -- -- Asserts that the Func has a pure definition which is a simple -- call to a single input, and no update definitions. The wrapper -- Funcs returned by asUsed are suitable candidates. -- Consumes all pure variables, and rewrites the Func to have an -- extern definition that calls halide_buffer_copy. copyToDevice :: (KnownNat n, IsHalideType a) => DeviceAPI -> Func t n a -> IO (Func t n a) -- | Same as copyToDevice DeviceHost copyToHost :: (KnownNat n, IsHalideType a) => Func t n a -> IO (Func t n a) -- | Allocate storage for this function within a particular loop level. -- -- Scheduling storage is optional, and can be used to separate the loop -- level at which storage is allocated from the loop level at which -- computation occurs to trade off between locality and redundant work. -- -- For more info, see Halide::Func::store_at. storeAt :: (KnownNat n, IsHalideType a) => Func 'FuncTy n a -> LoopLevel t -> IO (Func 'FuncTy n a) -- | Schedule a function to be computed within the iteration over a given -- loop level. -- -- For more info, see Halide::Func::compute_at. computeAt :: (KnownNat n, IsHalideType a) => Func 'FuncTy n a -> LoopLevel t -> IO (Func 'FuncTy n a) -- | Split a dimension by the given factor, then unroll the inner -- dimension. -- -- This is how you unroll a loop of unknown size by some constant factor. -- After this call, var refers to the outer dimension of the -- split. unroll :: (KnownNat n, IsHalideType a) => TailStrategy -> -- Func t n a -> Expr Int32 -- ^ Variable var to vectorize -- -> Expr Int32 -- ^ Split factor -> IO () unroll strategy func -- var factor = withFunc func $ f -> asVarOrRVar var $ x -> asExpr -- factor $ n -> [C.throwBlock| void { $(Halide::Func* -- f)->unroll(*$(Halide::VarOrRVar* x), *$(Halide::Expr* n), -- static_castHalide::TailStrategy($(int tail))); } |] where tail -- = fromIntegral (fromEnum strategy) -- -- Reorder variables to have the given nesting order, from innermost out. -- reorder :: forall t n a i ts . ( IsTuple (Arguments ts) i , All ((~) -- (Expr Int32)) ts , Length ts ~ n , KnownNat n , IsHalideType a ) => -- Func t n a -> i -> IO () reorder func args = asVectorOf @((~) -- (Expr Int32)) asVarOrRVar (fromTuple args) $ v -> do withFunc func -- $ f -> [C.throwBlock| void { $(Halide::Func* -- f)->reorder(*$(std::vectorHalide::VarOrRVar* v)); } |] -- -- Statically declare the range over which the function will be evaluated -- in the general case. -- -- This provides a basis for the auto scheduler to make trade-offs and -- scheduling decisions. The auto generated schedules might break when -- the sizes of the dimensions are very different from the estimates -- specified. These estimates are used only by the auto scheduler if the -- function is a pipeline output. estimate :: (KnownNat n, IsHalideType a) => Expr Int32 -> Expr Int32 -> Expr Int32 -> Func t n a -> IO () -- | Statically declare the range over which a function should be -- evaluated. -- -- This can let Halide perform some optimizations. E.g. if you know there -- are going to be 4 color channels, you can completely vectorize the -- color channel dimension without the overhead of splitting it up. If -- bounds inference decides that it requires more of this function than -- the bounds you have stated, a runtime error will occur when you try to -- run your pipeline. bound :: (KnownNat n, IsHalideType a) => Expr Int32 -> Expr Int32 -> Expr Int32 -> Func t n a -> IO () -- | Write out the loop nests specified by the schedule for this function. -- -- Helpful for understanding what a schedule is doing. -- -- For more info, see Halide::Func::print_loop_nest -- printLoopNest :: (KnownNat n, IsHalideType r) => Func n r -> IO -- () printLoopNest func = withFunc func $ f -> [C.exp| void { -- $(Halide::Func* f)->print_loop_nest() } |] -- -- Get the loop nests specified by the schedule for this function. -- -- Helpful for understanding what a schedule is doing. -- -- For more info, see Halide::Func::print_loop_nest prettyLoopNest :: (KnownNat n, IsHalideType r) => Func t n r -> IO Text -- | Get the internal representation of lowered code. -- -- Useful for analyzing and debugging scheduling. Can emit HTML or plain -- text. compileToLoweredStmt :: forall n a t f. IsFuncBuilder f t n a => StmtOutputFormat -> Target -> f -> IO Text -- | Format in which to return the lowered code. data StmtOutputFormat -- | plain text StmtText :: StmtOutputFormat -- | HTML StmtHTML :: StmtOutputFormat data TraceEvent TraceEvent :: !Text -> !TraceEventCode -> !Maybe TraceLoadStoreContents -> TraceEvent [funcName] :: TraceEvent -> !Text [eventCode] :: TraceEvent -> !TraceEventCode [loadStoreContents] :: TraceEvent -> !Maybe TraceLoadStoreContents -- | Haskell counterpart of halide_trace_event_code_t. data TraceEventCode TraceLoad :: TraceEventCode TraceStore :: TraceEventCode TraceBeginRealization :: TraceEventCode TraceEndRealization :: TraceEventCode TraceProduce :: TraceEventCode TraceEndProduce :: TraceEventCode TraceConsume :: TraceEventCode TraceEndConsume :: TraceEventCode TraceBeginPipeline :: TraceEventCode TraceEndPipeline :: TraceEventCode TraceTag :: TraceEventCode data TraceLoadStoreContents TraceLoadStoreContents :: !Ptr () -> !HalideType -> ![Int] -> TraceLoadStoreContents [valuePtr] :: TraceLoadStoreContents -> !Ptr () [valueType] :: TraceLoadStoreContents -> !HalideType [coordinates] :: TraceLoadStoreContents -> ![Int] setCustomTrace :: (KnownNat n, IsHalideType a) => (TraceEvent -> IO ()) -> Func t n a -> IO b -> IO b traceStores :: (KnownNat n, IsHalideType a) => Func t n a -> IO (Func t n a) traceLoads :: (KnownNat n, IsHalideType a) => Func t n a -> IO (Func t n a) collectIterationOrder :: (KnownNat n, IsHalideType a) => (TraceEventCode -> Bool) -> Func t n a -> IO b -> IO ([[Int]], b) -- | Specifies that there is an isomorphism between a type a and a -- tuple t. -- -- We use this class to convert between Arguments and normal -- tuples. class (ToTuple a ~ t, FromTuple t ~ a) => IsTuple a t | a -> t, t -> a toTuple :: IsTuple a t => a -> t fromTuple :: IsTuple a t => t -> a -- | Type family that maps Arguments ts to the -- corresponding tuple type. type family ToTuple t -- | Type family that maps tuples to the corresponding Arguments -- ts type. This is essentially the inverse of ToTuple. type family FromTuple t -- | Specifies that i is a tuple of Expr Int32. -- -- ts are deduced from i, so you don't have to specify -- them explicitly. type IndexTuple i ts = (IsTuple (Arguments ts) i, All ((~) (Expr Int32)) ts) -- | A type family that returns the length of a type-level list. type family Length (xs :: [k]) :: Nat -- | Apply constraint to all types in a list. type family All (c :: Type -> Constraint) (ts :: [Type]) :: Constraint compileToCallable :: forall n a t f inputs output. (IsFuncBuilder f t n a, Lowered (FunctionArguments f) ~ inputs, Ptr (HalideBuffer n a) ~ output) => Target -> f -> IO (Callable inputs output) -- | A test that tries to compile and run a Halide pipeline using -- FeatureCUDA. -- -- This is implemented fully in C++ to make sure that we test the -- installation rather than our Haskell code. -- -- On non-NixOS systems one should do the following: -- --
--   nixGLNvidia cabal repl --ghc-options='-fobject-code -O0'
--   ghci> testCUDA
--   
testCUDA :: IO () -- | Similar to testCUDA but for FeatureOpenCL. testOpenCL :: IO () data SomeLoopLevel [SomeLoopLevel] :: LoopLevel t -> SomeLoopLevel -- | The low-level untyped Haskell analogue of -- halide_buffer_t. -- -- It's quite difficult to use RawHalideBuffer correctly, and -- misusage can result in crashes and segmentation faults. Hence, prefer -- the higher-level HalideBuffer wrapper for all your code data RawHalideBuffer RawHalideBuffer :: !Word64 -> !Ptr HalideDeviceInterface -> !Ptr Word8 -> !Word64 -> !HalideType -> !Int32 -> !Ptr HalideDimension -> !Ptr () -> RawHalideBuffer [halideBufferDevice] :: RawHalideBuffer -> !Word64 [halideBufferDeviceInterface] :: RawHalideBuffer -> !Ptr HalideDeviceInterface [halideBufferHost] :: RawHalideBuffer -> !Ptr Word8 [halideBufferFlags] :: RawHalideBuffer -> !Word64 [halideBufferType] :: RawHalideBuffer -> !HalideType [halideBufferDimensions] :: RawHalideBuffer -> !Int32 [halideBufferDim] :: RawHalideBuffer -> !Ptr HalideDimension [halideBufferPadding] :: RawHalideBuffer -> !Ptr () -- | Information about a dimension in a buffer. -- -- It is the Haskell analogue of halide_dimension_t. data HalideDimension HalideDimension :: {-# UNPACK #-} !Int32 -> {-# UNPACK #-} !Int32 -> {-# UNPACK #-} !Int32 -> {-# UNPACK #-} !Word32 -> HalideDimension -- | Starting index. [halideDimensionMin] :: HalideDimension -> {-# UNPACK #-} !Int32 -- | Length of the dimension. [halideDimensionExtent] :: HalideDimension -> {-# UNPACK #-} !Int32 -- | Stride along this dimension. [halideDimensionStride] :: HalideDimension -> {-# UNPACK #-} !Int32 -- | Extra flags. [halideDimensionFlags] :: HalideDimension -> {-# UNPACK #-} !Word32 -- | Haskell analogue of halide_device_interface_t. data HalideDeviceInterface -- | Get strides corresponding to row-major ordering rowMajorStrides :: Integral a => [a] -> [a] -- | Get strides corresponding to column-major ordering. colMajorStrides :: Integral a => [a] -> [a] -- | Do we have changes on the device the have not been copied to the host? isDeviceDirty :: Ptr RawHalideBuffer -> IO Bool -- | Do we have changes on the device the have not been copied to the host? isHostDirty :: Ptr RawHalideBuffer -> IO Bool -- | Copy the underlying memory from device to host. bufferCopyToHost :: Ptr RawHalideBuffer -> IO () data Dim Dim :: !Text -> !ForType -> !DeviceAPI -> !DimType -> Dim [$sel:var:Dim] :: Dim -> !Text [$sel:forType:Dim] :: Dim -> !ForType [$sel:deviceApi:Dim] :: Dim -> !DeviceAPI [$sel:dimType:Dim] :: Dim -> !DimType -- | Type of dimension that tells which transformations are legal on it. data DimType DimPureVar :: DimType DimPureRVar :: DimType DimImpureRVar :: DimType -- | Specifies how loop values are traversed. data ForType ForSerial :: ForType ForParallel :: ForType ForVectorized :: ForType ForUnrolled :: ForType ForExtern :: ForType ForGPUBlock :: ForType ForGPUThread :: ForType ForGPULane :: ForType data SplitContents SplitContents :: !Text -> !Text -> !Text -> !Expr Int32 -> !Bool -> !TailStrategy -> SplitContents [$sel:splitOld:SplitContents] :: SplitContents -> !Text [$sel:splitOuter:SplitContents] :: SplitContents -> !Text [$sel:splitInner:SplitContents] :: SplitContents -> !Text [$sel:splitFactor:SplitContents] :: SplitContents -> !Expr Int32 [$sel:splitExact:SplitContents] :: SplitContents -> !Bool [$sel:splitTail:SplitContents] :: SplitContents -> !TailStrategy data FuseContents FuseContents :: !Text -> !Text -> !Text -> FuseContents [$sel:fuseOuter:FuseContents] :: FuseContents -> !Text [$sel:fuseInner:FuseContents] :: FuseContents -> !Text [$sel:fuseNew:FuseContents] :: FuseContents -> !Text data Split SplitVar :: !SplitContents -> Split FuseVars :: !FuseContents -> Split data Bound Bound :: !Text -> !Maybe (Expr Int32) -> !Expr Int32 -> !Maybe (Expr Int32) -> !Maybe (Expr Int32) -> Bound [$sel:boundVar:Bound] :: Bound -> !Text [$sel:boundMin:Bound] :: Bound -> !Maybe (Expr Int32) [$sel:boundExtent:Bound] :: Bound -> !Expr Int32 [$sel:boundModulus:Bound] :: Bound -> !Maybe (Expr Int32) [$sel:boundRemainder:Bound] :: Bound -> !Maybe (Expr Int32) data StorageDim StorageDim :: !Text -> !Maybe (Expr Int32) -> !Maybe (Expr Int32) -> !Maybe (Expr Int32, Bool) -> StorageDim [$sel:storageVar:StorageDim] :: StorageDim -> !Text [$sel:storageAlignment:StorageDim] :: StorageDim -> !Maybe (Expr Int32) [$sel:storageBound:StorageDim] :: StorageDim -> !Maybe (Expr Int32) [$sel:storageFold:StorageDim] :: StorageDim -> !Maybe (Expr Int32, Bool) data FusedPair FusedPair :: !Text -> !(Text, Int) -> !(Text, Int) -> FusedPair data FuseLoopLevel FuseLoopLevel :: !SomeLoopLevel -> FuseLoopLevel data StageSchedule StageSchedule :: ![ReductionVariable] -> ![Split] -> ![Dim] -> ![PrefetchDirective] -> !FuseLoopLevel -> ![FusedPair] -> !Bool -> !Bool -> !Bool -> StageSchedule [$sel:rvars:StageSchedule] :: StageSchedule -> ![ReductionVariable] [$sel:splits:StageSchedule] :: StageSchedule -> ![Split] [$sel:dims:StageSchedule] :: StageSchedule -> ![Dim] [$sel:prefetches:StageSchedule] :: StageSchedule -> ![PrefetchDirective] [$sel:fuseLevel:StageSchedule] :: StageSchedule -> !FuseLoopLevel [$sel:fusedPairs:StageSchedule] :: StageSchedule -> ![FusedPair] [$sel:allowRaceConditions:StageSchedule] :: StageSchedule -> !Bool [$sel:atomic:StageSchedule] :: StageSchedule -> !Bool [$sel:overrideAtomicAssociativityTest:StageSchedule] :: StageSchedule -> !Bool data ReductionVariable ReductionVariable :: !Text -> !Expr Int32 -> !Expr Int32 -> ReductionVariable [$sel:varName:ReductionVariable] :: ReductionVariable -> !Text [$sel:minExpr:ReductionVariable] :: ReductionVariable -> !Expr Int32 [$sel:extentExpr:ReductionVariable] :: ReductionVariable -> !Expr Int32 data PrefetchDirective PrefetchDirective :: !Text -> !Text -> !Text -> !Expr Int32 -> !PrefetchBoundStrategy -> !Maybe (ForeignPtr CxxParameter) -> PrefetchDirective [$sel:prefetchFunc:PrefetchDirective] :: PrefetchDirective -> !Text [$sel:prefetchAt:PrefetchDirective] :: PrefetchDirective -> !Text [$sel:prefetchFrom:PrefetchDirective] :: PrefetchDirective -> !Text [$sel:prefetchOffset:PrefetchDirective] :: PrefetchDirective -> !Expr Int32 [$sel:prefetchStrategy:PrefetchDirective] :: PrefetchDirective -> !PrefetchBoundStrategy [$sel:prefetchParameter:PrefetchDirective] :: PrefetchDirective -> !Maybe (ForeignPtr CxxParameter) getStageSchedule :: (KnownNat n, IsHalideType a) => Stage n a -> IO StageSchedule data AutoScheduler Adams2019 :: AutoScheduler Li2018 :: AutoScheduler Mullapudi2016 :: AutoScheduler loadAutoScheduler :: AutoScheduler -> IO () applyAutoScheduler :: (KnownNat n, IsHalideType a) => AutoScheduler -> Target -> Func t n a -> IO Text getHalideLibraryPath :: IO (Maybe Text) applySplits :: (KnownNat n, IsHalideType a) => [Split] -> Stage n a -> IO () applyDims :: (KnownNat n, IsHalideType a) => [Dim] -> Stage n a -> IO () applySchedule :: (KnownNat n, IsHalideType a) => StageSchedule -> Stage n a -> IO () type IsFuncBuilder f t n a = (All ValidParameter (FunctionArguments f), All ValidArgument (Lowered (FunctionArguments f)), UnCurry f (FunctionArguments f) (FunctionReturn f), PrepareParameters (FunctionArguments f), ReturnsFunc f t n a, KnownNat (Length (FunctionArguments f)), KnownNat (Length (Lowered (FunctionArguments f)))) -- | A constraint that specifies that the function f returns -- IO (Func t n a). class (FunctionReturn f ~ IO (Func t n a), IsHalideType a, KnownNat n) => ReturnsFunc f t n a | f -> t n a -- | Return the list of arguments to of a function type. type family FunctionArguments (f :: Type) :: [Type] -- | Get the return type of a function. type family FunctionReturn (f :: Type) :: Type -- | A helper typeclass to convert a function that takes Arguments -- as input into a normal curried function. This is the inverse of -- UnCurry. -- -- For instance, if we have a function f :: Arguments '[Int, Float] -- -> Double, then it will be converted to f' :: Int -> -- Float -> Double. class Curry (args :: [Type]) (r :: Type) (f :: Type) | args r -> f curryG :: Curry args r f => (Arguments args -> r) -> f -- | A helper typeclass to convert a normal curried function to a function -- that takes Arguments as input. -- -- For instance, if we have a function f :: Int -> Float -> -- Double, then it will be converted to f' :: Arguments '[Int, -- Float] -> Double. class UnCurry (f :: Type) (args :: [Type]) (r :: Type) | args r -> f uncurryG :: UnCurry f args r => f -> Arguments args -> r -- | Specifies how Expr and Func parameters become scalar and -- buffer arguments in compiled kernels. type family Lowered (t :: k) :: k -- | One stop function to include all the neccessary machinery to call -- Halide functions via inline-c. -- -- Put importHalide somewhere at the beginning of the file and -- enjoy using the C++ interface of Halide via inline-c quasiquotes. importHalide :: DecsQ -- | Haskell counterpart of Halide::Expr. data CxxExpr -- | Haskell counterpart of Halide::Var. data CxxVar -- | Haskell counterpart of Halide::RVar. data CxxRVar -- | Haskell counterpart of Halide::Internal::Parameter. data CxxParameter -- | Haskell counterpart of Halide::Func. data CxxFunc -- | Haskell counterpart of Halide::ImageParam. data CxxImageParam -- | Haskell counterpart of Halide::Stage. data CxxStage -- | Haskell counterpart of Halide::Internal::Dimension. data CxxDimension -- | Haskell counterpart of Halide::Target. data CxxTarget -- | Haskell counterpart of Halide::LoopLevel data CxxLoopLevel -- | 32-bit signed integer type data Int32 -- | A value of type Ptr a represents a pointer to an -- object, or an array of objects, which may be marshalled to or from -- Haskell values of type a. -- -- The type a will often be an instance of class Storable -- which provides the marshalling operations. However this is not -- essential, and you can provide your own operations to access the -- pointer. For example you might write small foreign functions to get or -- set the fields of a C struct. data Ptr a -- | This class gives the integer associated with a type-level natural. -- There are instances of the class for every concrete literal: 0, 1, 2, -- etc. class KnownNat (n :: Nat)