Safe Haskell | None |
---|
- data T a
- type family Result g :: *
- class CallArgs g
- data Subtarget = Subtarget String String (forall r. CodeGenFunction r Bool)
- wrap :: Subtarget -> a -> T a
- intrinsic :: (IsFunction f, CallArgs f g (Result g), CallArgs g) => Subtarget -> String -> T g
- intrinsicAttr :: (IsFunction f, CallArgs f g (Result g), CallArgs g) => [Attribute] -> Subtarget -> String -> T g
- run :: CodeGenFunction r a -> T (CodeGenFunction r a) -> CodeGenFunction r a
- runWhen :: Bool -> CodeGenFunction r a -> T (CodeGenFunction r a) -> CodeGenFunction r a
- runUnsafe :: T a -> a
- with :: Functor f => f a -> (a -> b) -> f b
- with2 :: Applicative f => f a -> f b -> (a -> b -> c) -> f c
- with3 :: Applicative f => f a -> f b -> f c -> (a -> b -> c -> d) -> f d
Documentation
This is an Applicative functor that registers,
what extensions are needed in order to run the contained instructions.
You can escape from the functor by calling run
and providing a generic implementation.
We use an applicative functor since with a monadic interface we had to create the specialised code in every case, in order to see which extensions where used in the course of creating the instructions.
We use only one (unparameterized) type for all extensions, since this is the most simple solution. Alternatively we could use a type parameter where class constraints show what extensions are needed. This would be just like exceptions that are explicit in the type signature as in the control-monad-exception package. However we would still need to lift all basic LLVM instructions to the new monad.
Analogous to FunctionArgs
The type parameter r
and its functional dependency are necessary
since g
must be a function of the form a -> ... -> c -> CodeGenFunction r d
and we must ensure that the explicit r
and the implicit r
in the g
do match.
wrap :: Subtarget -> a -> T aSource
Declare that a certain plain LLVM instruction depends on a particular extension. This can be useful if you rely on the data layout of a certain architecture when doing a bitcast, or if you know that LLVM translates a certain generic operation to something especially optimal for the declared extension.
intrinsic :: (IsFunction f, CallArgs f g (Result g), CallArgs g) => Subtarget -> String -> T gSource
Create an intrinsic and register the needed extension. We cannot immediately check whether the signature matches or whether the right extension is given. However, when resolving intrinsics LLVM will not find the intrinsic if the extension is wrong, and it also checks the signature.
intrinsicAttr :: (IsFunction f, CallArgs f g (Result g), CallArgs g) => [Attribute] -> Subtarget -> String -> T gSource
run :: CodeGenFunction r a -> T (CodeGenFunction r a) -> CodeGenFunction r aSource
run generic specific
generates the specific
code
if the required extensions are available on the host processor
and generic
otherwise.
runWhen :: Bool -> CodeGenFunction r a -> T (CodeGenFunction r a) -> CodeGenFunction r aSource
Convenient variant of run
:
Only run the code with extended instructions
if an additional condition is satisfied.
with2 :: Applicative f => f a -> f b -> (a -> b -> c) -> f cSource
with3 :: Applicative f => f a -> f b -> f c -> (a -> b -> c -> d) -> f dSource