{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances, TypeSynonymInstances, ScopedTypeVariables, OverlappingInstances, FlexibleContexts #-} module LLVM.Core.Instructions( -- * Terminator instructions ret, condBr, br, switch, invoke, unwind, unreachable, -- * Arithmetic binary operations -- | Arithmetic operations with the normal semantics. -- The u instractions are unsigned, the s instructions are signed. add, sub, mul, neg, udiv, sdiv, fdiv, urem, srem, frem, -- * Logical binary operations -- |Logical instructions with the normal semantics. shl, lshr, ashr, and, or, xor, inv, -- * Vector operations extractelement, insertelement, shufflevector, -- * Memory access malloc, arrayMalloc, alloca, arrayAlloca, free, load, store, getElementPtr, -- * Conversions trunc, zext, sext, fptrunc, fpext, fptoui, fptosi, uitofp, sitofp, ptrtoint, inttoptr, bitcast, -- * Comparison IntPredicate(..), RealPredicate(..), icmp, fcmp, select, -- * Other phi, addPhiInputs, call, -- * Classes and types Terminate, Ret, CallArgs, ABinOp, CmpOp, FunctionArgs, IsConst, AllocArg, GetElementPtr, IsIndexArg ) where import Prelude hiding (and, or) import Control.Monad(liftM) import Data.Int import Data.Word import Foreign.C(CInt) --import Data.TypeNumbers import qualified LLVM.FFI.Core as FFI import LLVM.Core.Data import LLVM.Core.Type import LLVM.Core.CodeGenMonad import LLVM.Core.CodeGen import qualified LLVM.Core.Util as U -- TODO: -- Add vector version of arithmetic -- Add rest of instructions -- Use Terminate to ensure bb termination (how?) -- more intrinsics are needed to, e.g., create an empty vector type Terminate = () terminate :: Terminate terminate = () -------------------------------------- -- |Acceptable arguments to the 'ret' instruction. class Ret a r where ret' :: a -> CodeGenFunction r Terminate -- | Return from the current function with the given value. Use () as the return value for what would be a void function is C. ret :: (Ret a r) => a -> CodeGenFunction r Terminate ret = ret' instance (IsFirstClass a, IsConst a) => Ret a a where ret' = ret . valueOf instance Ret (Value a) a where ret' (Value a) = do withCurrentBuilder $ \ bldPtr -> FFI.buildRet bldPtr a return terminate instance Ret () () where ret' _ = do withCurrentBuilder $ FFI.buildRetVoid return terminate -------------------------------------- -- | Branch to the first basic block if the boolean is true, otherwise to the second basic block. condBr :: Value Bool -- ^ Boolean to branch upon. -> BasicBlock -- ^ Target for true. -> BasicBlock -- ^ Target for false. -> CodeGenFunction r Terminate condBr (Value b) (BasicBlock t1) (BasicBlock t2) = do withCurrentBuilder $ \ bldPtr -> FFI.buildCondBr bldPtr b t1 t2 return terminate -------------------------------------- -- | Unconditionally branch to the given basic block. br :: BasicBlock -- ^ Branch target. -> CodeGenFunction r Terminate br (BasicBlock t) = do withCurrentBuilder $ \ bldPtr -> FFI.buildBr bldPtr t return terminate -------------------------------------- -- | Branch table instruction. switch :: (IsInteger a) => Value a -- ^ Value to branch upon. -> BasicBlock -- ^ Default branch target. -> [(ConstValue a, BasicBlock)] -- ^ Labels and corresponding branch targets. -> CodeGenFunction r Terminate switch (Value val) (BasicBlock dflt) arms = do withCurrentBuilder $ \ bldPtr -> do inst <- FFI.buildSwitch bldPtr val dflt (fromIntegral $ length arms) sequence_ [ FFI.addCase inst c b | (ConstValue c, BasicBlock b) <- arms ] return terminate -------------------------------------- -- |Unwind the call stack until a function call performed with 'invoke' is reached. -- I.e., throw a non-local exception. unwind :: CodeGenFunction r Terminate unwind = do withCurrentBuilder FFI.buildUnwind return terminate -- |Inform the code generator that this code can never be reached. unreachable :: CodeGenFunction r Terminate unreachable = do withCurrentBuilder FFI.buildUnreachable return terminate -------------------------------------- -- XXX Vector ops not implemented type FFIBinOp = FFI.BuilderRef -> FFI.ValueRef -> FFI.ValueRef -> U.CString -> IO FFI.ValueRef type FFIConstBinOp = FFI.ValueRef -> FFI.ValueRef -> FFI.ValueRef -- |Acceptable arguments to arithmetic binary instructions. class ABinOp a b c | a b -> c where abinop :: FFIConstBinOp -> FFIBinOp -> a -> b -> CodeGenFunction r c add :: (IsArithmetic c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) add = abinop FFI.constAdd FFI.buildAdd sub :: (IsArithmetic c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) sub = abinop FFI.constSub FFI.buildSub mul :: (IsArithmetic c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) mul = abinop FFI.constMul FFI.buildMul udiv :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) udiv = abinop FFI.constUDiv FFI.buildUDiv sdiv :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) sdiv = abinop FFI.constSDiv FFI.buildSDiv urem :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) urem = abinop FFI.constURem FFI.buildURem srem :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) srem = abinop FFI.constSRem FFI.buildSRem -- | Floating point division. fdiv :: (IsFloating c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) fdiv = abinop FFI.constFDiv FFI.buildFDiv -- | Floating point remainder. frem :: (IsFloating c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) frem = abinop FFI.constFRem FFI.buildFRem shl :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) shl = abinop FFI.constShl FFI.buildShl lshr :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) lshr = abinop FFI.constLShr FFI.buildLShr ashr :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) ashr = abinop FFI.constAShr FFI.buildAShr and :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) and = abinop FFI.constAnd FFI.buildAnd or :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) or = abinop FFI.constOr FFI.buildOr xor :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c) xor = abinop FFI.constXor FFI.buildXor instance ABinOp (Value a) (Value a) (Value a) where abinop _ op (Value a1) (Value a2) = buildBinOp op a1 a2 instance ABinOp (ConstValue a) (Value a) (Value a) where abinop _ op (ConstValue a1) (Value a2) = buildBinOp op a1 a2 instance ABinOp (Value a) (ConstValue a) (Value a) where abinop _ op (Value a1) (ConstValue a2) = buildBinOp op a1 a2 instance ABinOp (ConstValue a) (ConstValue a) (ConstValue a) where abinop cop _ (ConstValue a1) (ConstValue a2) = return $ ConstValue $ cop a1 a2 instance (IsConst a) => ABinOp (Value a) a (Value a) where abinop cop op a1 a2 = abinop cop op a1 (constOf a2) instance (IsConst a) => ABinOp a (Value a) (Value a) where abinop cop op a1 a2 = abinop cop op (constOf a1) a2 --instance (IsConst a) => ABinOp a a (ConstValue a) where -- abinop cop op a1 a2 = abinop cop op (constOf a1) (constOf a2) buildBinOp :: FFIBinOp -> FFI.ValueRef -> FFI.ValueRef -> CodeGenFunction r (Value a) buildBinOp op a1 a2 = liftM Value $ withCurrentBuilder $ \ bld -> U.withEmptyCString $ op bld a1 a2 type FFIUnOp = FFI.BuilderRef -> FFI.ValueRef -> U.CString -> IO FFI.ValueRef buildUnOp :: FFIUnOp -> FFI.ValueRef -> CodeGenFunction r (Value a) buildUnOp op a = liftM Value $ withCurrentBuilder $ \ bld -> U.withEmptyCString $ op bld a neg :: (IsArithmetic a) => Value a -> CodeGenFunction r (Value a) neg (Value x) = buildUnOp FFI.buildNeg x inv :: (IsInteger a) => Value a -> CodeGenFunction r (Value a) inv (Value x) = buildUnOp FFI.buildNot x -------------------------------------- -- | Get a value from a vector. extractelement :: Value (Vector n a) -- ^ Vector -> Value Word32 -- ^ Index into the vector -> CodeGenFunction r (Value a) extractelement (Value vec) (Value i) = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildExtractElement bldPtr vec i -- | Insert a value into a vector, nondescructive. insertelement :: Value (Vector n a) -- ^ Vector -> Value a -- ^ Value to insert -> Value Word32 -- ^ Index into the vector -> CodeGenFunction r (Value (Vector n a)) insertelement (Value vec) (Value e) (Value i) = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildInsertElement bldPtr vec e i -- XXX The documentation say the mask and result can different length from -- the two first operand, but the C++ code doesn't do that. -- | Permute vector. shufflevector :: Value (Vector n a) -> Value (Vector n a) -> ConstValue (Vector n Word32) -> CodeGenFunction r (Value (Vector n a)) shufflevector (Value a) (Value b) (ConstValue mask) = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildShuffleVector bldPtr a b mask -------------------------------------- -- XXX should allows constants -- XXX size a > size b not enforced -- | Truncate a value to a shorter bit width. trunc :: (IsInteger a, IsInteger b) => Value a -> CodeGenFunction r (Value b) trunc = convert FFI.buildTrunc -- XXX size a < size b not enforced -- | Zero extend a value to a wider width. zext :: (IsInteger a, IsInteger b) => Value a -> CodeGenFunction r (Value b) zext = convert FFI.buildZExt -- XXX size a < size b not enforced -- | Sign extend a value to wider width. sext :: (IsInteger a, IsInteger b) => Value a -> CodeGenFunction r (Value b) sext = convert FFI.buildSExt -- XXX size a > size b not enforced -- | Truncate a floating point value. fptrunc :: (IsFloating a, IsFloating b) => Value a -> CodeGenFunction r (Value b) fptrunc = convert FFI.buildFPTrunc -- XXX size a < size b not enforced -- | Extend a floating point value. fpext :: (IsFloating a, IsFloating b) => Value a -> CodeGenFunction r (Value b) fpext = convert FFI.buildFPExt -- | Convert a floating point value to an unsigned integer. fptoui :: (IsFloating a, IsInteger b) => Value a -> CodeGenFunction r (Value b) fptoui = convert FFI.buildFPToUI -- | Convert a floating point value to a signed integer. fptosi :: (IsFloating a, IsInteger b) => Value a -> CodeGenFunction r (Value b) fptosi = convert FFI.buildFPToSI -- | Convert an unsigned integer to a floating point value. uitofp :: (IsInteger a, IsFloating b) => Value a -> CodeGenFunction r (Value b) uitofp = convert FFI.buildUIToFP -- | Convert a signed integer to a floating point value. sitofp :: (IsInteger a, IsFloating b) => Value a -> CodeGenFunction r (Value b) sitofp = convert FFI.buildSIToFP -- | Convert a pointer to an integer. ptrtoint :: (IsInteger b) => Value (Ptr a) -> CodeGenFunction r (Value b) ptrtoint = convert FFI.buildPtrToInt -- | Convert an integer to a pointer. inttoptr :: (IsInteger a, IsType b) => Value (Ptr a) -> CodeGenFunction r (Value (Ptr b)) inttoptr = convert FFI.buildIntToPtr -- XXX a and b must use the same space, and there are also pointer restrictions -- | Convert between to values of the same size by just copying the bit pattern. bitcast :: (IsFirstClass a, IsFirstClass b) => Value a -> CodeGenFunction r (Value b) bitcast = convert FFI.buildBitCast type FFIConvert = FFI.BuilderRef -> FFI.ValueRef -> FFI.TypeRef -> U.CString -> IO FFI.ValueRef convert :: forall a b r . (IsType b) => FFIConvert -> Value a -> CodeGenFunction r (Value b) convert conv (Value a) = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ conv bldPtr a (typeRef (undefined :: b)) -------------------------------------- data IntPredicate = IntEQ -- ^ equal | IntNE -- ^ not equal | IntUGT -- ^ unsigned greater than | IntUGE -- ^ unsigned greater or equal | IntULT -- ^ unsigned less than | IntULE -- ^ unsigned less or equal | IntSGT -- ^ signed greater than | IntSGE -- ^ signed greater or equal | IntSLT -- ^ signed less than | IntSLE -- ^ signed less or equal deriving (Eq, Ord, Enum, Show) fromIntPredicate :: IntPredicate -> CInt fromIntPredicate p = fromIntegral (fromEnum p + 32) data RealPredicate = RealFalse -- ^ Always false (always folded) | RealOEQ -- ^ True if ordered and equal | RealOGT -- ^ True if ordered and greater than | RealOGE -- ^ True if ordered and greater than or equal | RealOLT -- ^ True if ordered and less than | RealOLE -- ^ True if ordered and less than or equal | RealONE -- ^ True if ordered and operands are unequal | RealORD -- ^ True if ordered (no nans) | RealUNO -- ^ True if unordered: isnan(X) | isnan(Y) | RealUEQ -- ^ True if unordered or equal | RealUGT -- ^ True if unordered or greater than | RealUGE -- ^ True if unordered, greater than, or equal | RealULT -- ^ True if unordered or less than | RealULE -- ^ True if unordered, less than, or equal | RealUNE -- ^ True if unordered or not equal | RealT -- ^ Always true (always folded) deriving (Eq, Ord, Enum, Show) fromRealPredicate :: RealPredicate -> CInt fromRealPredicate p = fromIntegral (fromEnum p) -- |Acceptable operands to comparison instructions. class CmpOp a b c | a b -> c where cmpop :: FFIBinOp -> a -> b -> CodeGenFunction r (Value Bool) instance CmpOp (Value a) (Value a) a where cmpop op (Value a1) (Value a2) = buildBinOp op a1 a2 instance (IsConst a) => CmpOp a (Value a) a where cmpop op a1 a2 = cmpop op (valueOf a1) a2 instance (IsConst a) => CmpOp (Value a) a a where cmpop op a1 a2 = cmpop op a1 (valueOf a2) -- | Compare integers. icmp :: (IsInteger c, CmpOp a b c) => IntPredicate -> a -> b -> CodeGenFunction r (Value Bool) icmp p = cmpop (flip FFI.buildICmp (fromIntPredicate p)) -- | Compare floating point values. fcmp :: (IsFloating c, CmpOp a b c) => RealPredicate -> a -> b -> CodeGenFunction r (Value Bool) fcmp p = cmpop (flip FFI.buildFCmp (fromRealPredicate p)) -------------------------------------- -- XXX could do const song and dance -- | Select between two values depending on a boolean. select :: (IsFirstClass a) => Value Bool -> Value a -> Value a -> CodeGenFunction r (Value a) select (Value cnd) (Value thn) (Value els) = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildSelect bldPtr cnd thn els -------------------------------------- type Caller = FFI.BuilderRef -> [FFI.ValueRef] -> IO FFI.ValueRef -- |Acceptable arguments to 'call'. class CallArgs f g | f -> g, g -> f where doCall :: Caller -> [FFI.ValueRef] -> f -> g instance (CallArgs b b') => CallArgs (a -> b) (Value a -> b') where doCall mkCall args f (Value arg) = doCall mkCall (arg : args) (f (undefined :: a)) --instance (CallArgs b b') => CallArgs (a -> b) (ConstValue a -> b') where -- doCall mkCall args f (ConstValue arg) = doCall mkCall (arg : args) (f (undefined :: a)) instance CallArgs (IO a) (CodeGenFunction r (Value a)) where doCall = doCallDef doCallDef :: Caller -> [FFI.ValueRef] -> b -> CodeGenFunction r (Value a) doCallDef mkCall args _ = withCurrentBuilder $ \ bld -> liftM Value $ mkCall bld (reverse args) -- | Call a function with the given arguments. The 'call' instruction is variadic, i.e., the number of arguments -- it takes depends on the type of /f/. call :: (CallArgs f g) => Function f -> g call (Value f) = doCall (U.makeCall f) [] (undefined :: f) -- | Call a function with exception handling. invoke :: (CallArgs f g) => BasicBlock -- ^Normal return point. -> BasicBlock -- ^Exception return point. -> Function f -- ^Function to call. -> g invoke (BasicBlock norm) (BasicBlock expt) (Value f) = doCall (U.makeInvoke norm expt f) [] (undefined :: f) -------------------------------------- -- XXX could do const song and dance -- |Join several variables (virtual registers) from different basic blocks into one. -- All of the variables in the list are joined. See also 'addPhiInputs'. phi :: forall a r . (IsFirstClass a) => [(Value a, BasicBlock)] -> CodeGenFunction r (Value a) phi incoming = liftM Value $ withCurrentBuilder $ \ bldPtr -> do inst <- U.buildEmptyPhi bldPtr (typeRef (undefined :: a)) U.addPhiIns inst [ (v, b) | (Value v, BasicBlock b) <- incoming ] return inst -- |Add additional inputs to an existing phi node. -- The reason for this instruction is that sometimes the structure of the code -- makes it impossible to have all variables in scope at the point where you need the phi node. addPhiInputs :: forall a r . (IsFirstClass a) => Value a -- ^Must be a variable from a call to 'phi'. -> [(Value a, BasicBlock)] -- ^Variables to add. -> CodeGenFunction r () addPhiInputs (Value inst) incoming = liftIO $ U.addPhiIns inst [ (v, b) | (Value v, BasicBlock b) <- incoming ] -------------------------------------- -- | Acceptable argument to array memory allocation. class AllocArg a where getAllocArg :: a -> FFI.ValueRef instance AllocArg (Value Word32) where getAllocArg (Value v) = v instance AllocArg (ConstValue Word32) where getAllocArg = unConst instance AllocArg Word32 where getAllocArg = unConst . constOf -- XXX What's the type returned by malloc -- | Allocate heap memory. malloc :: forall a r . (IsSized a) => CodeGenFunction r (Value (Ptr a)) malloc = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildMalloc bldPtr (typeRef (undefined :: a)) -- XXX What's the type returned by arrayMalloc? -- | Allocate heap (array) memory. arrayMalloc :: forall a r s . (IsSized a, AllocArg s) => s -> CodeGenFunction r (Value (Ptr a)) -- XXX arrayMalloc s = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildArrayMalloc bldPtr (typeRef (undefined :: a)) (getAllocArg s) -- XXX What's the type returned by malloc -- | Allocate stack memory. alloca :: forall a r . (IsSized a) => CodeGenFunction r (Value (Ptr a)) alloca = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildAlloca bldPtr (typeRef (undefined :: a)) -- XXX What's the type returned by arrayAlloca? -- | Allocate stack (array) memory. arrayAlloca :: forall a r s . (IsSized a, AllocArg s) => s -> CodeGenFunction r (Value (Ptr a)) arrayAlloca s = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildArrayAlloca bldPtr (typeRef (undefined :: a)) (getAllocArg s) -- XXX What's the type of free? -- | Free heap memory. free :: Value (Ptr a) -> CodeGenFunction r (Value ()) free (Value a) = liftM Value $ withCurrentBuilder $ \ bldPtr -> FFI.buildFree bldPtr a -- | Load a value from memory. load :: Value (Ptr a) -- ^ Address to load from. -> CodeGenFunction r (Value a) load (Value p) = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withEmptyCString $ FFI.buildLoad bldPtr p -- | Store a value in memory store :: Value a -- ^ Value to store. -> Value (Ptr a) -- ^ Address to store to. -> CodeGenFunction r (Value ()) store (Value v) (Value p) = liftM Value $ withCurrentBuilder $ \ bldPtr -> FFI.buildStore bldPtr v p {- -- XXX type is wrong -- | Address arithmetic. See LLVM description. -- (The type isn't as accurate as it should be.) getElementPtr :: (IsInteger i) => Value (Ptr a) -> [Value i] -> CodeGenFunction r (Value (Ptr b)) getElementPtr (Value ptr) ixs = liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withArrayLen [ v | Value v <- ixs ] $ \ idxLen idxPtr -> U.withEmptyCString $ FFI.buildGEP bldPtr ptr idxPtr (fromIntegral idxLen) -} -- |Acceptable arguments to 'getElementPointer'. class GetElementPtr optr ixs nptr | optr ixs -> nptr {-, ixs nptr -> optr, nptr optr -> ixs-} where getIxList :: optr -> ixs -> [FFI.ValueRef] -- |Acceptable single index to 'getElementPointer'. class IsIndexArg a where getArg :: a -> FFI.ValueRef instance IsIndexArg (Value Word32) where getArg (Value v) = v instance IsIndexArg (Value Word64) where getArg (Value v) = v instance IsIndexArg (Value Int32) where getArg (Value v) = v instance IsIndexArg (Value Int64) where getArg (Value v) = v instance IsIndexArg (ConstValue Word32) where getArg = unConst instance IsIndexArg (ConstValue Word64) where getArg = unConst instance IsIndexArg (ConstValue Int32) where getArg = unConst instance IsIndexArg (ConstValue Int64) where getArg = unConst instance IsIndexArg Word32 where getArg = unConst . constOf instance IsIndexArg Word64 where getArg = unConst . constOf instance IsIndexArg Int32 where getArg = unConst . constOf instance IsIndexArg Int64 where getArg = unConst . constOf unConst :: ConstValue a -> FFI.ValueRef unConst (ConstValue v) = v -- End of indexing instance GetElementPtr a () a where getIxList _ () = [] -- Index in Array instance (GetElementPtr o i n, IsIndexArg a) => GetElementPtr (Array k o) (a, i) n where getIxList _ (v, i) = getArg v : getIxList (undefined :: o) i -- Index in Vector instance (GetElementPtr o i n, IsIndexArg a) => GetElementPtr (Vector k o) (a, i) n where getIxList _ (v, i) = getArg v : getIxList (undefined :: o) i -- | Address arithmetic. See LLVM description. -- The index is a nested tuple of the form @(i1,(i2,( ... ())))@. -- (This is without a doubt the most confusing LLVM instruction, but the types help.) getElementPtr :: forall a o i n r . (GetElementPtr o i n, IsIndexArg a) => Value (Ptr o) -> (a, i) -> CodeGenFunction r (Value (Ptr n)) getElementPtr (Value ptr) (a, ixs) = let ixl = getArg a : getIxList (undefined :: o) ixs in liftM Value $ withCurrentBuilder $ \ bldPtr -> U.withArrayLen ixl $ \ idxLen idxPtr -> U.withEmptyCString $ FFI.buildGEP bldPtr ptr idxPtr (fromIntegral idxLen) -------------------------------------- {- instance (IsConst a) => Show (ConstValue a) -- XXX instance (IsConst a) => Eq (ConstValue a) {- instance (IsConst a) => Eq (ConstValue a) where ConstValue x == ConstValue y = if isFloating x then ConstValue (FFI.constFCmp (fromRealPredicate RealOEQ) x y) else ConstValue (FFI.constICmp (fromIntPredicate IntEQ) x y) ConstValue x /= ConstValue y = if isFloating x then ConstValue (FFI.constFCmp (fromRealPredicate RealONE) x y) else ConstValue (FFI.constICmp (fromIntPredicate IntNE) x y) instance (IsConst a) => Ord (ConstValue a) where ConstValue x < ConstValue y = if isFloating x then ConstValue (FFI.constFCmp (fromRealPredicate RealOLT) x y) else ConstValue (FFI.constICmp (fromIntPredicate IntLT) x y) ConstValue x <= ConstValue y = if isFloating x then ConstValue (FFI.constFCmp (fromRealPredicate RealOLE) x y) else ConstValue (FFI.constICmp (fromIntPredicate IntLE) x y) ConstValue x > ConstValue y = if isFloating x then ConstValue (FFI.constFCmp (fromRealPredicate RealOGT) x y) else ConstValue (FFI.constICmp (fromIntPredicate IntGT) x y) ConstValue x >= ConstValue y = if isFloating x then ConstValue (FFI.constFCmp (fromRealPredicate RealOGE) x y) else ConstValue (FFI.constICmp (fromIntPredicate IntGE) x y) -} instance (Num a, IsConst a) => Num (ConstValue a) where ConstValue x + ConstValue y = ConstValue (FFI.constAdd x y) ConstValue x - ConstValue y = ConstValue (FFI.constSub x y) ConstValue x * ConstValue y = ConstValue (FFI.constMul x y) negate (ConstValue x) = ConstValue (FFI.constNeg x) fromInteger x = constOf (fromInteger x :: a) -}