{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TypeFamilies #-} module LLVM.Util.Arithmetic( TValue, (%==), (%/=), (%<), (%<=), (%>), (%>=), (%&&), (%||), (?), (??), retrn, set, {- ArithFunction, arithFunction, UnwrapArgs, toArithFunction, recursiveFunction, -} CallIntrinsic, ) where import qualified Types.Data.Num as TypeNum import qualified LLVM.Core as LLVM import LLVM.Core hiding (cmp, ) import LLVM.Util.Loop(mapVector, mapVector2) -- |Synonym for @CodeGenFunction r (Value a)@. type TValue r a = CodeGenFunction r (Value a) infix 4 %==, %/=, %<, %<=, %>=, %> -- |Comparison functions. (%==), (%/=), (%<), (%<=), (%>), (%>=) :: (CmpRet a) => TValue r a -> TValue r a -> TValue r (CmpResult a) (%==) = binop $ LLVM.cmp CmpEQ (%/=) = binop $ LLVM.cmp CmpNE (%>) = binop $ LLVM.cmp CmpGT (%>=) = binop $ LLVM.cmp CmpGE (%<) = binop $ LLVM.cmp CmpLT (%<=) = binop $ LLVM.cmp CmpLE infixr 3 %&& infixr 2 %|| -- |Lazy and. (%&&) :: TValue r Bool -> TValue r Bool -> TValue r Bool a %&& b = a ? (b, return (valueOf False)) -- |Lazy or. (%||) :: TValue r Bool -> TValue r Bool -> TValue r Bool a %|| b = a ? (return (valueOf True), b) infix 0 ? -- |Conditional, returns first element of the pair when condition is true, otherwise second. (?) :: (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')] infix 0 ?? (??) :: (IsFirstClass a, CmpRet a) => TValue r (CmpResult a) -> (TValue r a, TValue r a) -> TValue r a c ?? (t, f) = do c' <- c t' <- t f' <- f select c' t' f' -- | Return a value from an 'arithFunction'. retrn :: (Ret (Value a) r) => TValue r a -> CodeGenFunction r () retrn x = x >>= ret -- | Use @x <- set $ ...@ to make a binding. set :: TValue r a -> (CodeGenFunction r (TValue r a)) set x = do x' <- x; return (return x') instance (Show (TValue r a)) instance (Eq (TValue r a)) instance (Ord (TValue r a)) instance (IsArithmetic a, CmpRet a, Num 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 (IsArithmetic a, CmpRet a, Num a, IsConst a) => Enum (TValue r a) where succ x = x + 1 pred x = x - 1 fromEnum _ = error "CodeGenFunction Value: fromEnum" toEnum = fromIntegral instance (IsArithmetic a, CmpRet a, Num a, IsConst a) => Real (TValue r a) where toRational _ = error "CodeGenFunction Value: toRational" instance (CmpRet a, Num a, IsConst a, IsInteger a) => Integral (TValue r a) where quot = binop idiv rem = binop irem quotRem x y = (quot x y, rem x y) toInteger _ = error "CodeGenFunction Value: toInteger" instance (CmpRet a, Fractional a, IsConst a, IsFloating a) => Fractional (TValue r a) where (/) = binop fdiv fromRational = return . valueOf . fromRational instance (CmpRet a, Fractional a, IsConst a, IsFloating a) => RealFrac (TValue r a) where properFraction _ = error "CodeGenFunction Value: properFraction" instance (CmpRet a, CallIntrinsic 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: 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 instance (CmpRet a, CallIntrinsic 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' {- If we add the ReadNone attribute, then LLVM-2.8 complains: llvm/examples$ Arith_dyn.exe Attribute readnone only applies to the function! %2 = call readnone double @llvm.sin.f64(double %0) Attribute readnone only applies to the function! %3 = call readnone double @llvm.exp.f64(double %2) Broken module found, compilation aborted! Stack dump: 0. Running pass 'Function Pass Manager' on module '_module'. 1. Running pass 'Module Verifier' on function '@_fun1' Aborted -} addReadNone :: Value a -> CodeGenFunction r (Value a) addReadNone x = do -- addAttributes x 0 [ReadNoneAttribute] return x callIntrinsicP1 :: forall a b r . (IsFirstClass a, IsFirstClass b, IsPrimitive a) => String -> Value a -> TValue r b callIntrinsicP1 fn x = do op <- externFunction ("llvm." ++ fn ++ "." ++ intrinsicTypeName (undefined :: a)) {- You can add these attributes, but the verifier pass in the optimizer checks whether they match the attributes that are declared for that intrinsic. If we omit adding attributes then the right attributes are added automatically. addFunctionAttributes op [NoUnwindAttribute, ReadOnlyAttribute] -} runCall (callFromFunction op `applyCall` x) >>= addReadNone callIntrinsicP2 :: forall a b c r . (IsFirstClass a, IsFirstClass b, IsFirstClass c, IsPrimitive a) => String -> Value a -> Value b -> TValue r c callIntrinsicP2 fn x y = do op <- externFunction ("llvm." ++ fn ++ "." ++ intrinsicTypeName (undefined :: a)) runCall (callFromFunction op `applyCall` x `applyCall` y) >>= addReadNone {- ------------------------------------------- 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 -- |Unlift a function with @TValue@ to have @Value@ arguments. arithFunction :: ArithFunction a b => a -> b arithFunction = arithFunction' ------------------------------------------- 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) = liftM2 (,) a (liftTuple 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 b1 -> a2 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 -> uncurryN f =<< liftTuple x -- |Lift a function from having @Value@ arguments to having @TValue@ arguments. toArithFunction :: (CallArgs f g r, UnwrapArgs a a1 b1 b g r) => Function f -> a toArithFunction f = unwrapArgs (call f) ------------------------------------------- -- |Define a recursive 'arithFunction', gets passed itself as the first argument. recursiveFunction :: (CallArgs a g r0, UnwrapArgs a11 a1 b1 b g r0, FunctionArgs a, a2 ~ FunctionCodeGen a, r1 ~ FunctionResult a, 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 -} ------------------------------------------- class CallIntrinsic a where callIntrinsic1' :: String -> Value a -> TValue r a callIntrinsic2' :: String -> Value a -> Value a -> TValue r a instance CallIntrinsic Float where callIntrinsic1' = callIntrinsicP1 callIntrinsic2' = callIntrinsicP2 instance CallIntrinsic Double where callIntrinsic1' = callIntrinsicP1 callIntrinsic2' = callIntrinsicP2 {- I think such a special case for certain systems would be better handled as in LLVM.Extra.Extension. (lemming) -} macOS :: Bool #if defined(__MACOS__) macOS = True #else macOS = False #endif instance (PositiveT n, IsPrimitive a, CallIntrinsic a) => CallIntrinsic (Vector n a) where callIntrinsic1' s x = if macOS && TypeNum.fromIntegerT (undefined :: n) == (4::Int) && elem s ["sqrt", "log", "exp", "sin", "cos", "tan"] then do op <- externFunction ("v" ++ s ++ "f") call op x >>= addReadNone else mapVector (callIntrinsic1' s) x callIntrinsic2' s = mapVector2 (callIntrinsic2' s) callIntrinsic1 :: (CallIntrinsic a) => String -> TValue r a -> TValue r a callIntrinsic1 s x = do x' <- x; callIntrinsic1' s x' callIntrinsic2 :: (CallIntrinsic a) => String -> TValue r a -> TValue r a -> TValue r a callIntrinsic2 s = binop (callIntrinsic2' s)