llvm-dsl-0.2: src/LLVM/DSL/Expression.hs
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module LLVM.DSL.Expression where
import qualified LLVM.Extra.ScalarOrVector as SoV
import qualified LLVM.Extra.Nice.Value as NiceValue
import qualified LLVM.Extra.FastMath as FastMath
import qualified LLVM.Extra.Scalar as Scalar
import qualified LLVM.Extra.Arithmetic as A
import qualified LLVM.Extra.Control as C
import qualified LLVM.Core as LLVM
import LLVM.Extra.Nice.Value (PatternTuple, Decomposed, Atom)
import qualified Control.Monad.HT as Monad
import Control.Monad.IO.Class (liftIO)
import qualified Data.Enum.Storable as Enum
import qualified Data.Tuple.HT as TupleHT
import qualified Data.Tuple as Tuple
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Complex (Complex((:+)))
import Data.Bool8 (Bool8)
import qualified Foreign.Storable.Record.Tuple as StTuple
import qualified Algebra.Transcendental as Trans
import qualified Algebra.Algebraic as Algebraic
import qualified Algebra.Absolute as Absolute
import qualified Algebra.Module as Module
import qualified Algebra.Field as Field
import qualified Algebra.Ring as Ring
import qualified Algebra.Additive as Additive
import qualified Number.Complex as Complex
import System.IO.Unsafe (unsafePerformIO)
import qualified Prelude as P
import Prelude hiding
(fst, snd, min, max, zip, unzip, zip3, unzip3,
curry, uncurry, recip, pi, sqrt, maybe, toEnum, fromEnum, pred, succ)
newtype Exp a = Exp {unExp :: forall r. LLVM.CodeGenFunction r (NiceValue.T a)}
{-
Using IORef should be thread-safe here,
because you cannot fork within CodeGenFunction.
-}
unique :: (forall r. LLVM.CodeGenFunction r (NiceValue.T a)) -> Exp a
unique = Exp
_unique :: (forall r. LLVM.CodeGenFunction r (NiceValue.T a)) -> Exp a
_unique code = unsafePerformIO $ fmap (withKey code) $ newIORef Nothing
withKey ::
(forall r. LLVM.CodeGenFunction r (NiceValue.T a)) ->
IORef (Maybe (NiceValue.T a)) -> Exp a
withKey code ref =
Exp (do
ma <- liftIO $ readIORef ref
case ma of
Just a -> return a
Nothing -> do
a <- code
liftIO $ writeIORef ref $ Just a
return a)
with :: Exp a -> (Exp a -> Exp b) -> Exp b
with (Exp code) f =
Exp (do
a <- code
unExp (f (Exp (return a))))
class Value val where
lift0 :: NiceValue.T a -> val a
lift1 ::
(NiceValue.T a -> NiceValue.T b) ->
val a -> val b
lift2 ::
(NiceValue.T a -> NiceValue.T b -> NiceValue.T c) ->
val a -> val b -> val c
instance Value NiceValue.T where
lift0 = id
lift1 = id
lift2 = id
instance Value Exp where
lift0 a = unique (return a)
lift1 f (Exp a) = unique (Monad.lift f a)
lift2 f (Exp a) (Exp b) = unique (Monad.lift2 f a b)
lift3 ::
(Value val) =>
(NiceValue.T a -> NiceValue.T b -> NiceValue.T c -> NiceValue.T d) ->
val a -> val b -> val c -> val d
lift3 f a b = lift2 (NiceValue.uncurry f) (zip a b)
lift4 ::
(Value val) =>
(NiceValue.T a -> NiceValue.T b -> NiceValue.T c -> NiceValue.T d ->
NiceValue.T e) ->
val a -> val b -> val c -> val d -> val e
lift4 f a b = lift3 (NiceValue.uncurry f) (zip a b)
liftM ::
(Aggregate ae am) =>
(forall r.
am -> LLVM.CodeGenFunction r (NiceValue.T b)) ->
(ae -> Exp b)
liftM f a = unique (f =<< bundle a)
liftM2 ::
(Aggregate ae am) =>
(Aggregate be bm) =>
(forall r.
am -> bm -> LLVM.CodeGenFunction r (NiceValue.T c)) ->
(ae -> be -> Exp c)
liftM2 f a b = unique (Monad.liftJoin2 f (bundle a) (bundle b))
liftM3 ::
(Aggregate ae am) =>
(Aggregate be bm) =>
(Aggregate ce cm) =>
(forall r.
am -> bm -> cm -> LLVM.CodeGenFunction r (NiceValue.T d)) ->
(ae -> be -> ce -> Exp d)
liftM3 f a b c = unique (Monad.liftJoin3 f (bundle a) (bundle b) (bundle c))
unliftM1 ::
(Aggregate ae am) =>
(Aggregate be bm) =>
(ae -> be) ->
am -> LLVM.CodeGenFunction r bm
unliftM1 f ix = bundle (f (dissect ix))
unliftM2 ::
(Aggregate ae am) =>
(Aggregate be bm) =>
(Aggregate ce cm) =>
(ae -> be -> ce) ->
am -> bm -> LLVM.CodeGenFunction r cm
unliftM2 f ix jx = bundle (f (dissect ix) (dissect jx))
unliftM3 ::
(Aggregate ae am) =>
(Aggregate be bm) =>
(Aggregate ce cm) =>
(Aggregate de dm) =>
(ae -> be -> ce -> de) ->
am -> bm -> cm -> LLVM.CodeGenFunction r dm
unliftM3 f ix jx kx = bundle (f (dissect ix) (dissect jx) (dissect kx))
unliftM4 ::
(Aggregate ae am) =>
(Aggregate be bm) =>
(Aggregate ce cm) =>
(Aggregate de dm) =>
(Aggregate ee em) =>
(ae -> be -> ce -> de -> ee) ->
am -> bm -> cm -> dm -> LLVM.CodeGenFunction r em
unliftM4 f ix jx kx lx =
bundle (f (dissect ix) (dissect jx) (dissect kx) (dissect lx))
liftReprM ::
(forall r.
NiceValue.Repr a ->
LLVM.CodeGenFunction r (NiceValue.Repr b)) ->
(Exp a -> Exp b)
liftReprM f = liftM (NiceValue.liftM f)
liftReprM2 ::
(forall r.
NiceValue.Repr a -> NiceValue.Repr b ->
LLVM.CodeGenFunction r (NiceValue.Repr c)) ->
(Exp a -> Exp b -> Exp c)
liftReprM2 f = liftM2 (NiceValue.liftM2 f)
liftReprM3 ::
(forall r.
NiceValue.Repr a -> NiceValue.Repr b -> NiceValue.Repr c ->
LLVM.CodeGenFunction r (NiceValue.Repr d)) ->
(Exp a -> Exp b -> Exp c -> Exp d)
liftReprM3 f = liftM3 (NiceValue.liftM3 f)
zip :: (Value val) => val a -> val b -> val (a, b)
zip = lift2 NiceValue.zip
zip3 :: (Value val) => val a -> val b -> val c -> val (a, b, c)
zip3 = lift3 NiceValue.zip3
zip4 :: (Value val) => val a -> val b -> val c -> val d -> val (a, b, c, d)
zip4 = lift4 NiceValue.zip4
unzip :: (Value val) => val (a, b) -> (val a, val b)
unzip ab = (fst ab, snd ab)
unzip3 :: (Value val) => val (a, b, c) -> (val a, val b, val c)
unzip3 abc = (fst3 abc, snd3 abc, thd3 abc)
unzip4 :: (Value val) => val (a, b, c, d) -> (val a, val b, val c, val d)
unzip4 abcd =
(lift1 (\(NiceValue.Cons (a,_,_,_)) -> NiceValue.Cons a) abcd,
lift1 (\(NiceValue.Cons (_,b,_,_)) -> NiceValue.Cons b) abcd,
lift1 (\(NiceValue.Cons (_,_,c,_)) -> NiceValue.Cons c) abcd,
lift1 (\(NiceValue.Cons (_,_,_,d)) -> NiceValue.Cons d) abcd)
fst :: (Value val) => val (a, b) -> val a
fst = lift1 NiceValue.fst
snd :: (Value val) => val (a, b) -> val b
snd = lift1 NiceValue.snd
mapFst :: (Exp a -> Exp b) -> Exp (a, c) -> Exp (b, c)
mapFst f = liftM (NiceValue.mapFstF (unliftM1 f))
mapSnd :: (Exp b -> Exp c) -> Exp (a, b) -> Exp (a, c)
mapSnd f = liftM (NiceValue.mapSndF (unliftM1 f))
mapPair :: (Exp a0 -> Exp a1, Exp b0 -> Exp b1) -> Exp (a0, b0) -> Exp (a1, b1)
mapPair (f,g) = mapFst f . mapSnd g
swap :: (Value val) => val (a, b) -> val (b, a)
swap = lift1 NiceValue.swap
curry :: (Exp (a,b) -> c) -> (Exp a -> Exp b -> c)
curry f = Tuple.curry (f . Tuple.uncurry zip)
uncurry :: (Exp a -> Exp b -> c) -> (Exp (a,b) -> c)
uncurry f = Tuple.uncurry f . unzip
fst3 :: (Value val) => val (a,b,c) -> val a
fst3 = lift1 NiceValue.fst3
snd3 :: (Value val) => val (a,b,c) -> val b
snd3 = lift1 NiceValue.snd3
thd3 :: (Value val) => val (a,b,c) -> val c
thd3 = lift1 NiceValue.thd3
mapFst3 :: (Exp a0 -> Exp a1) -> Exp (a0,b,c) -> Exp (a1,b,c)
mapFst3 f = liftM (NiceValue.mapFst3F (unliftM1 f))
mapSnd3 :: (Exp b0 -> Exp b1) -> Exp (a,b0,c) -> Exp (a,b1,c)
mapSnd3 f = liftM (NiceValue.mapSnd3F (unliftM1 f))
mapThd3 :: (Exp c0 -> Exp c1) -> Exp (a,b,c0) -> Exp (a,b,c1)
mapThd3 f = liftM (NiceValue.mapThd3F (unliftM1 f))
mapTriple ::
(Exp a0 -> Exp a1, Exp b0 -> Exp b1, Exp c0 -> Exp c1) ->
Exp (a0,b0,c0) -> Exp (a1,b1,c1)
mapTriple (f,g,h) = mapFst3 f . mapSnd3 g . mapThd3 h
tuple :: Exp tuple -> Exp (StTuple.Tuple tuple)
tuple = lift1 NiceValue.tuple
untuple :: Exp (StTuple.Tuple tuple) -> Exp tuple
untuple = lift1 NiceValue.untuple
modifyNiceValue ::
(Value val,
NiceValue.Compose a,
NiceValue.Decompose pattern,
NiceValue.PatternTuple pattern ~ tuple) =>
pattern ->
(Decomposed NiceValue.T pattern -> a) ->
val tuple -> val (NiceValue.Composed a)
modifyNiceValue p f = lift1 $ NiceValue.modify p f
modifyNiceValue2 ::
(Value val,
NiceValue.Compose a,
NiceValue.Decompose patternA,
NiceValue.Decompose patternB,
NiceValue.PatternTuple patternA ~ tupleA,
NiceValue.PatternTuple patternB ~ tupleB) =>
patternA ->
patternB ->
(Decomposed NiceValue.T patternA ->
Decomposed NiceValue.T patternB -> a) ->
val tupleA -> val tupleB -> val (NiceValue.Composed a)
modifyNiceValue2 pa pb f = lift2 $ NiceValue.modify2 pa pb f
modifyNiceValueM ::
(NiceValue.Compose a,
NiceValue.Decompose pattern,
NiceValue.PatternTuple pattern ~ tuple) =>
pattern ->
(forall r.
Decomposed NiceValue.T pattern ->
LLVM.CodeGenFunction r a) ->
Exp tuple -> Exp (NiceValue.Composed a)
modifyNiceValueM p f = liftM (NiceValue.modifyF p f)
modifyNiceValueM2 ::
(NiceValue.Compose a,
NiceValue.Decompose patternA,
NiceValue.Decompose patternB,
NiceValue.PatternTuple patternA ~ tupleA,
NiceValue.PatternTuple patternB ~ tupleB) =>
patternA ->
patternB ->
(forall r.
Decomposed NiceValue.T patternA ->
Decomposed NiceValue.T patternB ->
LLVM.CodeGenFunction r a) ->
Exp tupleA -> Exp tupleB -> Exp (NiceValue.Composed a)
modifyNiceValueM2 pa pb f = liftM2 (NiceValue.modifyF2 pa pb f)
class Compose nicetuple where
type Composed nicetuple
{- |
A nested 'zip'.
-}
compose :: nicetuple -> Exp (Composed nicetuple)
class
(Composed (Decomposed Exp pattern) ~ PatternTuple pattern) =>
Decompose pattern where
{- |
Analogous to 'NiceValue.decompose'.
-}
decompose :: pattern -> Exp (PatternTuple pattern) -> Decomposed Exp pattern
{- |
Analogus to 'NiceValue.modify'.
-}
modify ::
(Compose a, Decompose pattern) =>
pattern ->
(Decomposed Exp pattern -> a) ->
Exp (PatternTuple pattern) -> Exp (Composed a)
modify p f = compose . f . decompose p
modify2 ::
(Compose a, Decompose patternA, Decompose patternB) =>
patternA ->
patternB ->
(Decomposed Exp patternA -> Decomposed Exp patternB -> a) ->
Exp (PatternTuple patternA) ->
Exp (PatternTuple patternB) -> Exp (Composed a)
modify2 pa pb f a b = compose $ f (decompose pa a) (decompose pb b)
instance Compose (Exp a) where
type Composed (Exp a) = a
compose = id
instance Decompose (Atom a) where
decompose _ = id
instance Compose () where
type Composed () = ()
compose = cons
instance Decompose () where
decompose _ _ = ()
instance (Compose a, Compose b) => Compose (a,b) where
type Composed (a,b) = (Composed a, Composed b)
compose = Tuple.uncurry zip . TupleHT.mapPair (compose, compose)
instance (Decompose pa, Decompose pb) => Decompose (pa,pb) where
decompose (pa,pb) =
TupleHT.mapPair (decompose pa, decompose pb) . unzip
instance (Compose a, Compose b, Compose c) => Compose (a,b,c) where
type Composed (a,b,c) = (Composed a, Composed b, Composed c)
compose =
TupleHT.uncurry3 zip3 . TupleHT.mapTriple (compose, compose, compose)
instance
(Decompose pa, Decompose pb, Decompose pc) =>
Decompose (pa,pb,pc) where
decompose (pa,pb,pc) =
TupleHT.mapTriple (decompose pa, decompose pb, decompose pc) . unzip3
instance (Compose a, Compose b, Compose c, Compose d) => Compose (a,b,c,d) where
type Composed (a,b,c,d) = (Composed a, Composed b, Composed c, Composed d)
compose (a,b,c,d) = zip4 (compose a) (compose b) (compose c) (compose d)
instance
(Decompose pa, Decompose pb, Decompose pc, Decompose pd) =>
Decompose (pa,pb,pc,pd) where
decompose (pa,pb,pc,pd) x =
case unzip4 x of
(a,b,c,d) ->
(decompose pa a, decompose pb b, decompose pc c, decompose pd d)
instance (Compose tuple) => Compose (StTuple.Tuple tuple) where
type Composed (StTuple.Tuple tuple) = StTuple.Tuple (Composed tuple)
compose (StTuple.Tuple tup) = tuple $ compose tup
instance (Decompose p) => Decompose (StTuple.Tuple p) where
decompose (StTuple.Tuple p) = StTuple.Tuple . decompose p . untuple
instance (Compose a) => Compose (Complex a) where
type Composed (Complex a) = Complex (Composed a)
compose (r:+i) = consComplex (compose r) (compose i)
instance (Decompose p) => Decompose (Complex p) where
decompose (pr:+pi) =
Tuple.uncurry (:+) .
TupleHT.mapPair (decompose pr, decompose pi) . deconsComplex
{- |
You can construct complex numbers this way,
but they will not make you happy,
because the numeric operations require a RealFloat instance
that we could only provide with lots of undefined methods
(also in its superclasses).
You may either define your own arithmetic
or use the NumericPrelude type classes.
-}
consComplex :: Exp a -> Exp a -> Exp (Complex a)
consComplex = lift2 NiceValue.consComplex
deconsComplex :: Exp (Complex a) -> (Exp a, Exp a)
deconsComplex c = (lift1 NiceValue.realPart c, lift1 NiceValue.imagPart c)
class (NiceValuesOf exp ~ nv, ExpressionsOf nv ~ exp) => Aggregate exp nv where
type NiceValuesOf exp
type ExpressionsOf nv
bundle :: exp -> LLVM.CodeGenFunction r nv
dissect :: nv -> exp
instance Aggregate (Exp a) (NiceValue.T a) where
type NiceValuesOf (Exp a) = NiceValue.T a
type ExpressionsOf (NiceValue.T a) = Exp a
bundle (Exp x) = x
dissect x = Exp (return x)
instance (Aggregate ae al, Aggregate be bl) => Aggregate (ae,be) (al,bl) where
type NiceValuesOf (ae,be) = (NiceValuesOf ae, NiceValuesOf be)
type ExpressionsOf (al,bl) = (ExpressionsOf al, ExpressionsOf bl)
bundle (a,b) = Monad.lift2 (,) (bundle a) (bundle b)
dissect (a,b) = (dissect a, dissect b)
instance
(Aggregate ae al, Aggregate be bl, Aggregate ce cl) =>
Aggregate (ae,be,ce) (al,bl,cl) where
type NiceValuesOf (ae,be,ce) =
(NiceValuesOf ae, NiceValuesOf be, NiceValuesOf ce)
type ExpressionsOf (al,bl,cl) =
(ExpressionsOf al, ExpressionsOf bl, ExpressionsOf cl)
bundle (a,b,c) = Monad.lift3 (,,) (bundle a) (bundle b) (bundle c)
dissect (a,b,c) = (dissect a, dissect b, dissect c)
instance
(Aggregate ae al, Aggregate be bl, Aggregate ce cl, Aggregate de dl) =>
Aggregate (ae,be,ce,de) (al,bl,cl,dl) where
type NiceValuesOf (ae,be,ce,de) =
(NiceValuesOf ae, NiceValuesOf be,
NiceValuesOf ce, NiceValuesOf de)
type ExpressionsOf (al,bl,cl,dl) =
(ExpressionsOf al, ExpressionsOf bl,
ExpressionsOf cl, ExpressionsOf dl)
bundle (a,b,c,d) =
Monad.lift4 (,,,) (bundle a) (bundle b) (bundle c) (bundle d)
dissect (a,b,c,d) = (dissect a, dissect b, dissect c, dissect d)
instance (Aggregate ae al) => Aggregate (Complex.T ae) (Complex.T al) where
type NiceValuesOf (Complex.T ae) = Complex.T (NiceValuesOf ae)
type ExpressionsOf (Complex.T al) = Complex.T (ExpressionsOf al)
dissect = fmap dissect
bundle c =
Monad.lift2 (Complex.+:)
(bundle $ Complex.real c) (bundle $ Complex.imag c)
-- ToDo: move to numericprelude?
newtype Scalar a = Scalar a
instance (Aggregate exp nv) => Aggregate (Scalar exp) (Scalar.T nv) where
type NiceValuesOf (Scalar exp) = Scalar.T (NiceValuesOf exp)
type ExpressionsOf (Scalar.T nv) = Scalar (ExpressionsOf nv)
bundle (Scalar x) = Scalar.Cons <$> bundle x
dissect (Scalar.Cons x) = Scalar $ dissect x
instance (Additive.C a) => Additive.C (Scalar a) where
zero = Scalar Additive.zero
Scalar a + Scalar b = Scalar (a Additive.+ b)
Scalar a - Scalar b = Scalar (a Additive.- b)
negate (Scalar a) = Scalar $ Additive.negate a
instance (Ring.C a) => Ring.C (Scalar a) where
Scalar a * Scalar b = Scalar (a Ring.* b)
fromInteger = Scalar . Ring.fromInteger
instance (Ring.C a, a~b) => Module.C (Scalar a) (Scalar b) where
Scalar a *> Scalar b = Scalar (a Ring.* b)
cons :: (NiceValue.C a) => a -> Exp a
cons = lift0 . NiceValue.cons
unit :: Exp ()
unit = cons ()
zero :: (NiceValue.C a) => Exp a
zero = lift0 NiceValue.zero
add :: (NiceValue.Additive a) => Exp a -> Exp a -> Exp a
add = liftM2 NiceValue.add
sub :: (NiceValue.Additive a) => Exp a -> Exp a -> Exp a
sub = liftM2 NiceValue.sub
neg :: (NiceValue.Additive a) => Exp a -> Exp a
neg = liftM NiceValue.neg
one :: (NiceValue.IntegerConstant a) => Exp a
one = fromInteger' 1
mul :: (NiceValue.PseudoRing a) => Exp a -> Exp a -> Exp a
mul = liftM2 NiceValue.mul
sqr :: (NiceValue.PseudoRing a) => Exp a -> Exp a
sqr = liftM $ \x -> NiceValue.mul x x
recip :: (NiceValue.Field a, NiceValue.IntegerConstant a) => Exp a -> Exp a
recip = fdiv one
fdiv :: (NiceValue.Field a) => Exp a -> Exp a -> Exp a
fdiv = liftM2 NiceValue.fdiv
sqrt :: (NiceValue.Algebraic a) => Exp a -> Exp a
sqrt = liftM NiceValue.sqrt
pow :: (NiceValue.Transcendental a) => Exp a -> Exp a -> Exp a
pow = liftM2 NiceValue.pow
idiv :: (NiceValue.Integral a) => Exp a -> Exp a -> Exp a
idiv = liftM2 NiceValue.idiv
irem :: (NiceValue.Integral a) => Exp a -> Exp a -> Exp a
irem = liftM2 NiceValue.irem
shl :: (NiceValue.BitShift a) => Exp a -> Exp a -> Exp a
shl = liftM2 NiceValue.shl
shr :: (NiceValue.BitShift a) => Exp a -> Exp a -> Exp a
shr = liftM2 NiceValue.shr
fromInteger' :: (NiceValue.IntegerConstant a) => Integer -> Exp a
fromInteger' = lift0 . NiceValue.fromInteger'
fromRational' :: (NiceValue.RationalConstant a) => Rational -> Exp a
fromRational' = lift0 . NiceValue.fromRational'
boolPFrom8 :: Exp Bool8 -> Exp Bool
boolPFrom8 = lift1 NiceValue.boolPFrom8
bool8FromP :: Exp Bool -> Exp Bool8
bool8FromP = lift1 NiceValue.bool8FromP
intFromBool8 :: (NiceValue.NativeInteger i ir) => Exp Bool8 -> Exp i
intFromBool8 = liftM NiceValue.intFromBool8
floatFromBool8 :: (NiceValue.NativeFloating a ar) => Exp Bool8 -> Exp a
floatFromBool8 = liftM NiceValue.floatFromBool8
toEnum ::
(NiceValue.Repr w ~ LLVM.Value w) =>
Exp w -> Exp (Enum.T w e)
toEnum = lift1 NiceValue.toEnum
fromEnum ::
(NiceValue.Repr w ~ LLVM.Value w) =>
Exp (Enum.T w e) -> Exp w
fromEnum = lift1 NiceValue.fromEnum
succ, pred ::
(LLVM.IsArithmetic w, SoV.IntegerConstant w) =>
Exp (Enum.T w e) -> Exp (Enum.T w e)
succ = liftM NiceValue.succ
pred = liftM NiceValue.pred
fromFastMath :: Exp (FastMath.Number flags a) -> Exp a
fromFastMath = lift1 FastMath.nvDenumber
toFastMath :: Exp a -> Exp (FastMath.Number flags a)
toFastMath = lift1 FastMath.nvNumber
minBound, maxBound :: (NiceValue.Bounded a) => Exp a
minBound = lift0 NiceValue.minBound
maxBound = lift0 NiceValue.maxBound
cmp ::
(NiceValue.Comparison a) =>
LLVM.CmpPredicate -> Exp a -> Exp a -> Exp Bool
cmp ord = liftM2 (NiceValue.cmp ord)
infix 4 ==*, /=*, <*, <=*, >*, >=*
(==*), (/=*), (<*), (>=*), (>*), (<=*) ::
(NiceValue.Comparison a) => Exp a -> Exp a -> Exp Bool
(==*) = cmp LLVM.CmpEQ
(/=*) = cmp LLVM.CmpNE
(<*) = cmp LLVM.CmpLT
(>=*) = cmp LLVM.CmpGE
(>*) = cmp LLVM.CmpGT
(<=*) = cmp LLVM.CmpLE
min, max :: (NiceValue.Real a) => Exp a -> Exp a -> Exp a
min = liftM2 A.min
max = liftM2 A.max
limit :: (NiceValue.Real a) => (Exp a, Exp a) -> Exp a -> Exp a
limit (l,u) = max l . min u
fraction :: (NiceValue.Fraction a) => Exp a -> Exp a
fraction = liftM NiceValue.fraction
true, false :: Exp Bool
true = cons True
false = cons False
infixr 3 &&*
(&&*) :: Exp Bool -> Exp Bool -> Exp Bool
(&&*) = liftM2 NiceValue.and
infixr 2 ||*
(||*) :: Exp Bool -> Exp Bool -> Exp Bool
(||*) = liftM2 NiceValue.or
not :: Exp Bool -> Exp Bool
not = liftM NiceValue.inv
{- |
Like 'ifThenElse' but computes both alternative expressions
and then uses LLVM's efficient @select@ instruction.
-}
select :: (NiceValue.Select a) => Exp Bool -> Exp a -> Exp a -> Exp a
select = liftM3 NiceValue.select
ifThenElse :: (NiceValue.C a) => Exp Bool -> Exp a -> Exp a -> Exp a
ifThenElse ec ex ey =
unique (do
NiceValue.Cons c <- unExp ec
C.ifThenElse c (unExp ex) (unExp ey))
complement :: (NiceValue.Logic a) => Exp a -> Exp a
complement = liftM NiceValue.inv
infixl 7 .&.*
(.&.*) :: (NiceValue.Logic a) => Exp a -> Exp a -> Exp a
(.&.*) = liftM2 NiceValue.and
infixl 5 .|.*
(.|.*) :: (NiceValue.Logic a) => Exp a -> Exp a -> Exp a
(.|.*) = liftM2 NiceValue.or
infixl 6 `xor`
xor :: (NiceValue.Logic a) => Exp a -> Exp a -> Exp a
xor = liftM2 NiceValue.xor
toMaybe :: Exp Bool -> Exp a -> Exp (Maybe a)
toMaybe = lift2 NiceValue.toMaybe
maybe :: (NiceValue.C b) => Exp b -> (Exp a -> Exp b) -> Exp (Maybe a) -> Exp b
maybe n j = liftM $ \m -> do
let (NiceValue.Cons b, a) = NiceValue.splitMaybe m
C.ifThenElse b (unliftM1 j a) (unExp n)
instance
(NiceValue.PseudoRing a, NiceValue.Real a, NiceValue.IntegerConstant a) =>
Num (Exp a) where
fromInteger = fromInteger'
(+) = add
(-) = sub
negate = neg
(*) = mul
abs = liftM NiceValue.abs
signum = liftM NiceValue.signum
instance
(NiceValue.Field a, NiceValue.Real a, NiceValue.RationalConstant a) =>
Fractional (Exp a) where
fromRational = fromRational'
(/) = fdiv
instance
(NiceValue.Transcendental a, NiceValue.Real a,
NiceValue.RationalConstant a) =>
Floating (Exp a) where
pi = unique NiceValue.pi
sin = liftM NiceValue.sin
cos = liftM NiceValue.cos
sqrt = sqrt
(**) = pow
exp = liftM NiceValue.exp
log = liftM NiceValue.log
asin _ = error "LLVM missing intrinsic: asin"
acos _ = error "LLVM missing intrinsic: acos"
atan _ = error "LLVM missing intrinsic: atan"
sinh x = (exp x - exp (-x)) / 2
cosh x = (exp x + exp (-x)) / 2
asinh x = log (x + sqrt (x*x + 1))
acosh x = log (x + sqrt (x*x - 1))
atanh x = (log (1 + x) - log (1 - x)) / 2
{- |
We do not require a numeric prelude superclass,
thus also LLVM only types like vectors are instances.
-}
instance (NiceValue.Additive a) => Additive.C (Exp a) where
zero = zero
(+) = add
(-) = sub
negate = neg
instance
(NiceValue.PseudoRing a, NiceValue.IntegerConstant a) =>
Ring.C (Exp a) where
one = one
(*) = mul
fromInteger = fromInteger'
{-
This instance is enough for Module here.
The difference to Module instances on Haskell tuples is,
that LLVM vectors cannot be nested.
-}
instance
(a ~ NiceValue.Scalar v,
NiceValue.PseudoModule v, NiceValue.IntegerConstant a) =>
Module.C (Exp a) (Exp v) where
(*>) = liftM2 NiceValue.scale
instance
(NiceValue.Field a, NiceValue.RationalConstant a) =>
Field.C (Exp a) where
(/) = fdiv
fromRational' = fromRational' . Field.fromRational'
instance
(NiceValue.Transcendental a, NiceValue.RationalConstant a) =>
Algebraic.C (Exp a) where
sqrt = sqrt
root n x = pow x (recip $ fromInteger' n)
x^/r = pow x (Field.fromRational' r)
tau :: (NiceValue.Transcendental a, NiceValue.RationalConstant a) => Exp a
tau = mul (fromInteger' 2) Trans.pi
instance
(NiceValue.Transcendental a, NiceValue.RationalConstant a) =>
Trans.C (Exp a) where
pi = unique NiceValue.pi
sin = liftM NiceValue.sin
cos = liftM NiceValue.cos
(**) = pow
exp = liftM NiceValue.exp
log = liftM NiceValue.log
asin _ = error "LLVM missing intrinsic: asin"
acos _ = error "LLVM missing intrinsic: acos"
atan _ = error "LLVM missing intrinsic: atan"
instance
(NiceValue.Real a, NiceValue.PseudoRing a, NiceValue.IntegerConstant a) =>
Absolute.C (Exp a) where
abs = liftM NiceValue.abs
signum = liftM NiceValue.signum
fromIntegral ::
(NiceValue.NativeInteger i ir, NiceValue.NativeFloating a ar) =>
Exp i -> Exp a
fromIntegral = liftM NiceValue.fromIntegral
truncateToInt ::
(NiceValue.NativeInteger i ir, NiceValue.NativeFloating a ar) =>
Exp a -> Exp i
truncateToInt = liftM NiceValue.truncateToInt
floorToInt ::
(NiceValue.NativeInteger i ir, NiceValue.NativeFloating a ar) =>
Exp a -> Exp i
floorToInt = liftM NiceValue.floorToInt
ceilingToInt ::
(NiceValue.NativeInteger i ir, NiceValue.NativeFloating a ar) =>
Exp a -> Exp i
ceilingToInt = liftM NiceValue.ceilingToInt
roundToIntFast ::
(NiceValue.NativeInteger i ir, NiceValue.NativeFloating a ar) =>
Exp a -> Exp i
roundToIntFast = liftM NiceValue.roundToIntFast
splitFractionToInt ::
(NiceValue.NativeInteger i ir, NiceValue.NativeFloating a ar) =>
Exp a -> (Exp i, Exp a)
splitFractionToInt = unzip . liftM NiceValue.splitFractionToInt