module LLVM.Util.Arithmetic(
TValue,
Cmp,
(%==), (%/=), (%<), (%<=), (%>), (%>=),
(%&&), (%||),
(?),
retrn,
ArithFunction(..), UnwrapArgs, toArithFunction, recursiveFunction
) where
import Data.Word
import Data.Int
import LLVM.Core
type TValue r a = CodeGenFunction r (Value a)
class Cmp a where
cmp :: IntPredicate -> Value a -> Value a -> TValue r Bool
instance Cmp Bool where cmp = icmp
instance Cmp Word8 where cmp = icmp
instance Cmp Word16 where cmp = icmp
instance Cmp Word32 where cmp = icmp
instance Cmp Word64 where cmp = icmp
instance Cmp Int8 where cmp = icmp . adjSigned
instance Cmp Int16 where cmp = icmp . adjSigned
instance Cmp Int32 where cmp = icmp . adjSigned
instance Cmp Int64 where cmp = icmp . adjSigned
instance Cmp Float where cmp = fcmp . adjFloat
instance Cmp Double where cmp = fcmp . adjFloat
instance Cmp FP128 where cmp = fcmp . adjFloat
adjSigned :: IntPredicate -> IntPredicate
adjSigned IntUGT = IntSGT
adjSigned IntUGE = IntSGE
adjSigned IntULT = IntSLT
adjSigned IntULE = IntSLE
adjSigned p = p
adjFloat :: IntPredicate -> RealPredicate
adjFloat IntEQ = RealOEQ
adjFloat IntNE = RealONE
adjFloat IntUGT = RealOGT
adjFloat IntUGE = RealOGE
adjFloat IntULT = RealOLT
adjFloat IntULE = RealOLE
adjFloat _ = error "adjFloat"
infix 4 %==, %/=, %<, %<=, %>=, %>
(%==), (%/=), (%<), (%<=), (%>), (%>=) :: (Cmp a) => TValue r a -> TValue r a -> TValue r Bool
(%==) = binop $ cmp IntEQ
(%/=) = binop $ cmp IntNE
(%>) = binop $ cmp IntUGT
(%>=) = binop $ cmp IntUGE
(%<) = binop $ cmp IntULT
(%<=) = binop $ cmp IntULE
infixr 3 %&&
infixr 2 %||
(%&&) :: TValue r Bool -> TValue r Bool -> TValue r Bool
a %&& b = a ? (b, return (valueOf False))
(%||) :: TValue r Bool -> TValue r Bool -> TValue r Bool
a %|| b = a ? (return (valueOf True), b)
infix 0 ?
(?) :: (IsFirstClass a) => TValue r Bool -> (TValue r a, TValue r a) -> TValue r a
c ? (t, f) = do
lt <- newBasicBlock
lf <- newBasicBlock
lj <- newBasicBlock
c' <- c
condBr c' lt lf
defineBasicBlock lt
rt <- t
lt' <- getCurrentBasicBlock
br lj
defineBasicBlock lf
rf <- f
lf' <- getCurrentBasicBlock
br lj
defineBasicBlock lj
phi [(rt, lt'), (rf, lf')]
retrn :: (Ret (Value a) r) => TValue r a -> CodeGenFunction r ()
retrn x = x >>= ret
instance (Show (TValue r a))
instance (Eq (TValue r a))
instance (Ord (TValue r a))
instance (Cmp a, Num a, IsArithmetic a, IsConst a) => Num (TValue r a) where
(+) = binop add
() = binop sub
(*) = binop mul
negate = (>>= neg)
abs x = x %< 0 ? (x, x)
signum x = x %< 0 ? (1, x %> 0 ? (1, 0))
fromInteger = return . valueOf . fromInteger
instance (Cmp a, Num a, IsConst a, IsArithmetic a) => Enum (TValue r a) where
succ x = x + 1
pred x = x 1
fromEnum _ = error "CodeGenFunction Value: fromEnum"
toEnum = fromIntegral
instance (Cmp a, Num a, IsConst a, IsArithmetic a) => Real (TValue r a) where
toRational _ = error "CodeGenFunction Value: toRational"
instance (Cmp a, Num a, IsConst a, IsInteger a) => Integral (TValue r a) where
quot = binop (if (isSigned (undefined :: a)) then sdiv else udiv)
rem = binop (if (isSigned (undefined :: a)) then srem else urem)
quotRem x y = (quot x y, rem x y)
toInteger _ = error "CodeGenFunction Value: toInteger"
instance (Cmp a, Fractional a, IsConst a, IsFloating a) => Fractional (TValue r a) where
(/) = binop fdiv
fromRational = return . valueOf . fromRational
instance (Cmp a, Fractional a, IsConst a, IsFloating a) => RealFrac (TValue r a) where
properFraction _ = error "CodeGenFunction Value: properFraction"
instance (Cmp a, Floating a, IsConst a, IsFloating a) => Floating (TValue r a) where
pi = return $ valueOf pi
sqrt = callIntrinsic1 "sqrt"
sin = callIntrinsic1 "sin"
cos = callIntrinsic1 "cos"
(**) = callIntrinsic2 "pow"
exp = callIntrinsic1 "exp"
log = callIntrinsic1 "log"
asin _ = error "LLVM missing intrinsic: asin"
acos _ = error "LLVM missing intrinsic: acos"
atan _ = error "LLVM missing intrinsic: atab"
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
instance (Cmp a, RealFloat a, IsConst a, IsFloating a) => RealFloat (TValue r a) where
floatRadix _ = floatRadix (undefined :: a)
floatDigits _ = floatDigits (undefined :: a)
floatRange _ = floatRange (undefined :: a)
decodeFloat _ = error "CodeGenFunction Value: decodeFloat"
encodeFloat _ _ = error "CodeGenFunction Value: encodeFloat"
exponent _ = 0
scaleFloat 0 x = x
scaleFloat _ _ = error "CodeGenFunction Value: scaleFloat"
isNaN _ = error "CodeGenFunction Value: isNaN"
isInfinite _ = error "CodeGenFunction Value: isInfinite"
isDenormalized _ = error "CodeGenFunction Value: isDenormalized"
isNegativeZero _ = error "CodeGenFunction Value: isNegativeZero"
isIEEE _ = isIEEE (undefined :: a)
binop :: (Value a -> Value b -> TValue r c) ->
TValue r a -> TValue r b -> TValue r c
binop op x y = do
x' <- x
y' <- y
op x' y'
callIntrinsic1 :: forall a b r . (IsArithmetic a, IsFirstClass b) =>
String -> TValue r a -> TValue r b
callIntrinsic1 fn x = do
x' <- x
op <- externFunction ("llvm." ++ fn ++ "." ++ typeName (undefined :: a))
let _ = op :: Function (a -> IO b)
call op x'
callIntrinsic2 :: forall a b c r . (IsArithmetic a, IsFirstClass b, IsFirstClass c) =>
String -> TValue r a -> TValue r b -> TValue r c
callIntrinsic2 fn x y = do
x' <- x
y' <- y
op <- externFunction ("llvm." ++ fn ++ "." ++ typeName (undefined :: a))
let _ = op :: Function (a -> b -> IO c)
call op x' y'
class ArithFunction a b | a -> b, b -> a where
arithFunction :: a -> b
instance (Ret a r) => ArithFunction (CodeGenFunction r a) (CodeGenFunction r ()) where
arithFunction x = x >>= ret
instance (ArithFunction b b') => ArithFunction (CodeGenFunction r a -> b) (a -> b') where
arithFunction f = arithFunction . f . return
class UncurryN a b | a -> b, b -> a where
uncurryN :: a -> b
curryN :: b -> a
instance UncurryN (CodeGenFunction r a) (() -> CodeGenFunction r a) where
uncurryN i = \ () -> i
curryN f = f ()
instance (UncurryN t (b -> c)) => UncurryN (a -> t) ((a, b) -> c) where
uncurryN f = \ (a, b) -> uncurryN (f a) b
curryN f = \ a -> curryN (\ b -> f (a, b))
class LiftTuple r a b | a -> b, b -> a where
liftTuple :: a -> CodeGenFunction r b
instance LiftTuple r () () where
liftTuple = return
instance (LiftTuple r b b') => LiftTuple r (CodeGenFunction r a, b) (a, b') where
liftTuple (a, b) = do a' <- a; b' <- liftTuple b; return (a', b')
class (UncurryN a (a1 -> CodeGenFunction r b1), LiftTuple r a1 b, UncurryN a2 (b -> CodeGenFunction r b1)) =>
UnwrapArgs a a1 b1 b a2 r | a -> a1 b1, a1 b1 -> a, a1 -> b, b -> a1, a2 -> b b1, b b -> a where
unwrapArgs :: a2 -> a
instance (UncurryN a (a1 -> CodeGenFunction r b1), LiftTuple r a1 b, UncurryN a2 (b -> CodeGenFunction r b1)) =>
UnwrapArgs a a1 b1 b a2 r where
unwrapArgs f = curryN $ \ x -> do x' <- liftTuple x; uncurryN f x'
toArithFunction :: (CallArgs f g, UnwrapArgs a a1 b1 b g r) =>
Function f -> a
toArithFunction f = unwrapArgs (call f)
recursiveFunction ::
(CallArgs a g,
UnwrapArgs a11 a1 b1 b g r,
FunctionArgs a a2 (CodeGenFunction r1 ()),
ArithFunction a3 a2,
IsFunction a) =>
(a11 -> a3) -> CodeGenModule (Function a)
recursiveFunction af = do
f <- newFunction ExternalLinkage
let f' = toArithFunction f
defineFunction f $ arithFunction (af f')
return f