-- |
-- Module      : Language.Halide
-- Copyright   : (c) Tom Westerhout, 2023
--
-- 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](https://github.com/twesterhout/halide-haskell/tree/master/tutorials).
module Language.Halide
  ( -- * Scalar expressions

    -- | The basic building block of Halide pipelines is 'Expr'. @Expr a@ represents a scalar expression of
    -- type @a@, where @a@ must be an instance of 'IsHalideType'.
    Expr (..)
  , Var
  , RVar
  , VarOrRVar
  , IsHalideType

    -- ** Creating
  , mkExpr
  , mkVar
  , mkRVar
  , undef
  , cast
  , bool

    -- ** Inspecting
  , toIntImm
  , printed
  , evaluate

    -- ** Comparisons

    -- | We can't use 'Eq' and 'Ord' instances here, because we want the comparison to happen
    -- when the pipeline is run rather than when it's built. Hence, we define lifted version of
    -- various comparison operators. Note, that infix versions of the these functions have the
    -- same precedence as the normal comparison operators.
  , eq
  , neq
  , lt
  , lte
  , gt
  , gte

    -- * Functions
  , Func (..)
  , FuncTy (..)
  , Stage (..)

    -- ** Creating
  , define
  , update
  , (!)

    -- ** Inspecting
  , getArgs
  , hasUpdateDefinitions
  , getUpdateStage

    -- * Buffers

    -- | In the C interface of Halide, buffers are described by the C struct
    -- [@halide_buffer_t@](https://halide-lang.org/docs/structhalide__buffer__t.html). On the Haskell side,
    -- we have 'HalideBuffer'.
  , HalideBuffer (..)
    -- | To easily test out your pipeline, there are helper functions to create 'HalideBuffer's without
    -- worrying about the low-level representation.
  , allocaCpuBuffer
    -- | Buffers can also be converted to lists to easily print them for debugging.
  , IsListPeek (..)
    -- | For production usage however, you don't want to work with lists. Instead, you probably want Halide
    -- to work with your existing array data types. For this, we define 'IsHalideBuffer' typeclass that
    -- teaches Halide how to convert your data into a 'HalideBuffer'. Depending on how you implement the
    -- instance, this can be very efficient, because it need not involve any memory copying.
  , IsHalideBuffer (..)
  , withHalideBuffer
    -- | There are also helper functions to simplify writing instances of 'IsHalideBuffer'.
  , bufferFromPtrShapeStrides
  , bufferFromPtrShape

    -- * Running the pipelines

    -- | There are a few ways how one can run a Halide pipeline.
    --
    -- The simplest way to build a t'Func' and then call 'realize' to evaluate it over a rectangular domain.
  , realize
  , asBufferParam
    -- | The drawback of calling 'realize' all the time is that it's impossible to pass parameters to pipelines.
    -- We can define pipelines that operate on buffers using 'asBufferParam', but we have to recompile the
    -- pipeline for every new buffer.
    --
    -- A better way to handle pipeline parameters is to define a /Haskell/ function that accepts t'Expr's
    -- and t'Func's as arguments and returns a 'Func'. We can then pass this function to 'compile'
    -- (or 'compileForTarget'), and it compile it into a /Haskell/ function that can now be invoked with
    -- normal scalars instead of t'Expr's and @Ptr 'HalideBuffer'@s instead of 'Func's.
  , compile

    -- ** Parameters

    -- | Similar to how we can specify the name of a variable in 'mkVar' (or 'mkRVar') or function in 'define',
    -- one can also specify the name of a pipeline parameter. This is achieved by using the @ViewPatterns@
    -- extension together with the 'scalar' and 'buffer' helper functions.
  , buffer
  , scalar
    -- | Another common thing to do with the parameters is to explicitly specify their shapes. For this, we expose the 'Dimension' type:
  , Dimension (..)
  , dim
  , setMin
  , setExtent
  , setStride
  , setEstimate

    -- ** Targets
  , Target (..)
  , hostTarget
  , gpuTarget
  , compileForTarget
  , DeviceAPI (..)
  , TargetFeature (..)
  , setFeature
  , hasGpuFeature
  , hostSupportsTargetDevice

    -- * Scheduling
  , Schedulable (..)
  , TailStrategy (..)
  , LoopLevel (..)
  , LoopLevelTy (..)
  , LoopAlignStrategy (..)
  , computeRoot
  , getStage
  , getLoopLevel
  , getLoopLevelAtStage
  , asUsed
  , asUsedBy
  , copyToDevice
  , copyToHost
  , storeAt
  , computeAt
  , estimate
  , bound

    -- * Debugging / Tracing

    -- | For debugging, it's often useful to observe the value of an expression when it's evaluated. If you
    -- have a complex expression that does not depend on any buffers or indices, you can 'evaluate' it.
    -- | However, often an expression is only used within a definition of a pipeline, and it's impossible to
    -- call 'evaluate' on it. In such cases, it can be wrapped with 'printed' to indicate to Halide that the
    -- value of the expression should be dumped to screen when it's computed.
  , prettyLoopNest
  , compileToLoweredStmt
  , StmtOutputFormat (..)
  , TraceEvent (..)
  , TraceEventCode (..)
  , TraceLoadStoreContents (..)
  , setCustomTrace
  , traceStores
  , traceLoads
  , collectIterationOrder

    -- * Type helpers
  , IsTuple (..)
  , ToTuple
  , FromTuple
  , IndexTuple
  , Length
  , All

    -- * Internal
  , compileToCallable
  , testCUDA
  , testOpenCL
  , SomeLoopLevel (..)
  , RawHalideBuffer (..)
  , HalideDimension (..)
  , HalideDeviceInterface
  , rowMajorStrides
  , colMajorStrides
  , isDeviceDirty
  , isHostDirty
  , bufferCopyToHost
  , module Language.Halide.Schedule
  , IsFuncBuilder
  , ReturnsFunc
  , FunctionArguments
  , FunctionReturn
  , Curry (..)
  , UnCurry (..)
  , Lowered

    -- ** inline-c helpers
  , importHalide
  , CxxExpr
  , CxxVar
  , CxxRVar
  , CxxParameter
  , CxxFunc
  , CxxImageParam
  , CxxStage
  , CxxDimension
  , CxxTarget
  , CxxLoopLevel

    -- * Convenience re-exports
  , Int32
  , Ptr
  , KnownNat
  )
where

import Foreign.Ptr (Ptr)
import GHC.TypeLits (KnownNat)
import Language.Halide.Buffer
import Language.Halide.Context
import Language.Halide.Dimension
import Language.Halide.Expr
import Language.Halide.Func
import Language.Halide.Kernel
import Language.Halide.LoopLevel
import Language.Halide.Schedule
import Language.Halide.Target
import Language.Halide.Trace
import Language.Halide.Type