{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} module LLVM.Extra.Multi.Value.Private where import qualified LLVM.Extra.ScalarOrVector as SoV import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Control as C import qualified LLVM.Extra.Class as Class import qualified LLVM.Core as LLVM import qualified LLVM.Util.Loop as Loop import LLVM.Util.Loop (Phi, ) import LLVM.Core (WordN, IntN, ) import qualified Type.Data.Num.Decimal.Number as Dec import Type.Data.Num.Decimal (D1) import Foreign.StablePtr (StablePtr, ) import Foreign.Ptr (Ptr, FunPtr, ) import qualified Control.Monad.HT as Monad import qualified Control.Functor.HT as FuncHT import Control.Monad (Monad, return, fmap, (>>), ) import Data.Functor (Functor, ) import qualified Data.Tuple.HT as TupleHT import qualified Data.Tuple as Tuple import qualified Data.EnumBitSet as EnumBitSet import qualified Data.Enum.Storable as Enum import qualified Data.Bool8 as Bool8 import Data.Complex (Complex((:+))) import Data.Tagged (Tagged(Tagged, unTagged)) import Data.Function (id, (.), ($), ) import Data.Tuple.HT (uncurry3, ) import Data.Maybe (Maybe(Nothing,Just), ) import Data.Bool (Bool(False,True), ) import Data.Word (Word8, Word16, Word32, Word64, ) import Data.Int (Int8, Int16, Int32, Int64, ) import Data.Bool8 (Bool8) import qualified Prelude as P import Prelude (Float, Double, Integer, Rational, ) newtype T a = Cons (Repr LLVM.Value a) class C a where type Repr (f :: * -> *) a :: * cons :: a -> T a undef :: T a zero :: T a phis :: LLVM.BasicBlock -> T a -> LLVM.CodeGenFunction r (T a) addPhis :: LLVM.BasicBlock -> T a -> T a -> LLVM.CodeGenFunction r () instance C Bool where type Repr f Bool = f Bool cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Float where type Repr f Float = f Float cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Double where type Repr f Double = f Double cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Word8 where type Repr f Word8 = f Word8 cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Word16 where type Repr f Word16 = f Word16 cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Word32 where type Repr f Word32 = f Word32 cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Word64 where type Repr f Word64 = f Word64 cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance (Dec.Positive n) => C (LLVM.WordN n) where type Repr f (LLVM.WordN n) = f (LLVM.WordN n) cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Int8 where type Repr f Int8 = f Int8 cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Int16 where type Repr f Int16 = f Int16 cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Int32 where type Repr f Int32 = f Int32 cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C Int64 where type Repr f Int64 = f Int64 cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance (Dec.Positive n) => C (LLVM.IntN n) where type Repr f (LLVM.IntN n) = f (LLVM.IntN n) cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance (LLVM.IsType a) => C (Ptr a) where -- Do we also have to convert the pointer target type? type Repr f (Ptr a) = f (Ptr a) cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance (LLVM.IsFunction a) => C (FunPtr a) where type Repr f (FunPtr a) = f (FunPtr a) cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance C (StablePtr a) where type Repr f (StablePtr a) = f (StablePtr a) cons = consPrimitive undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive consPrimitive :: (LLVM.IsConst al, LLVM.Value al ~ Repr LLVM.Value a) => al -> T a consPrimitive = Cons . LLVM.valueOf undefPrimitive, zeroPrimitive :: (LLVM.IsType al, LLVM.Value al ~ Repr LLVM.Value a) => T a undefPrimitive = Cons $ LLVM.value LLVM.undef zeroPrimitive = Cons $ LLVM.value LLVM.zero phisPrimitive :: (LLVM.IsFirstClass al, LLVM.Value al ~ Repr LLVM.Value a) => LLVM.BasicBlock -> T a -> LLVM.CodeGenFunction r (T a) phisPrimitive bb (Cons a) = fmap Cons $ Loop.phis bb a addPhisPrimitive :: (LLVM.IsFirstClass al, LLVM.Value al ~ Repr LLVM.Value a) => LLVM.BasicBlock -> T a -> T a -> LLVM.CodeGenFunction r () addPhisPrimitive bb (Cons a) (Cons b) = Loop.addPhis bb a b instance C () where type Repr f () = () cons = consUnit undef = undefUnit zero = zeroUnit phis = phisUnit addPhis = addPhisUnit consUnit :: (Repr LLVM.Value a ~ ()) => a -> T a consUnit _ = Cons () undefUnit :: (Repr LLVM.Value a ~ ()) => T a undefUnit = Cons () zeroUnit :: (Repr LLVM.Value a ~ ()) => T a zeroUnit = Cons () phisUnit :: (Repr LLVM.Value a ~ ()) => LLVM.BasicBlock -> T a -> LLVM.CodeGenFunction r (T a) phisUnit _bb (Cons ()) = return $ Cons () addPhisUnit :: (Repr LLVM.Value a ~ ()) => LLVM.BasicBlock -> T a -> T a -> LLVM.CodeGenFunction r () addPhisUnit _bb (Cons ()) (Cons ()) = return () instance C Bool8 where type Repr f Bool8 = f Bool cons = consPrimitive . Bool8.toBool undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive boolPFrom8 :: T Bool8 -> T Bool boolPFrom8 (Cons b) = Cons b bool8FromP :: T Bool -> T Bool8 bool8FromP (Cons b) = Cons b intFromBool8 :: (NativeInteger i ir) => T Bool8 -> LLVM.CodeGenFunction r (T i) intFromBool8 = liftM LLVM.zadapt floatFromBool8 :: (NativeFloating a ar) => T Bool8 -> LLVM.CodeGenFunction r (T a) floatFromBool8 = liftM LLVM.uitofp instance (LLVM.IsInteger w, LLVM.IsConst w, P.Num w, P.Enum e) => C (Enum.T w e) where type Repr f (Enum.T w e) = f w cons = consPrimitive . P.fromIntegral . P.fromEnum . Enum.toPlain undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive toEnum :: (Repr LLVM.Value w ~ LLVM.Value w) => T w -> T (Enum.T w e) toEnum (Cons w) = Cons w fromEnum :: (Repr LLVM.Value w ~ LLVM.Value w) => T (Enum.T w e) -> T w fromEnum (Cons w) = Cons w succ, pred :: (LLVM.IsArithmetic w, SoV.IntegerConstant w) => T (Enum.T w e) -> LLVM.CodeGenFunction r (T (Enum.T w e)) succ = liftM $ \w -> A.add w A.one pred = liftM $ \w -> A.sub w A.one -- cannot be an instance of 'Comparison' because there is no 'Real' instance cmpEnum :: (LLVM.CmpRet w, LLVM.CmpResult w ~ Bool) => LLVM.CmpPredicate -> T (Enum.T w a) -> T (Enum.T w a) -> LLVM.CodeGenFunction r (T Bool) cmpEnum = liftM2 . LLVM.cmp class (C a) => Bounded a where minBound, maxBound :: T a instance (LLVM.IsInteger w, LLVM.IsConst w, P.Num w, P.Enum e, P.Bounded e) => Bounded (Enum.T w e) where minBound = cons P.minBound maxBound = cons P.maxBound instance (LLVM.IsInteger w, LLVM.IsConst w) => C (EnumBitSet.T w i) where type Repr f (EnumBitSet.T w i) = f w cons = consPrimitive . EnumBitSet.decons undef = undefPrimitive zero = zeroPrimitive phis = phisPrimitive addPhis = addPhisPrimitive instance (C a) => C (Maybe a) where type Repr f (Maybe a) = (f Bool, Repr f a) cons Nothing = nothing cons (Just a) = just $ cons a undef = toMaybe undef undef zero = toMaybe (cons False) zero phis bb ma = case splitMaybe ma of (b,a) -> Monad.lift2 toMaybe (phis bb b) (phis bb a) addPhis bb x y = case (splitMaybe x, splitMaybe y) of ((xb,xa), (yb,ya)) -> addPhis bb xb yb >> addPhis bb xa ya splitMaybe :: T (Maybe a) -> (T Bool, T a) splitMaybe (Cons (b,a)) = (Cons b, Cons a) toMaybe :: T Bool -> T a -> T (Maybe a) toMaybe (Cons b) (Cons a) = Cons (b,a) nothing :: (C a) => T (Maybe a) nothing = toMaybe (cons False) undef just :: T a -> T (Maybe a) just = toMaybe (cons True) instance (C a, C b) => C (a,b) where type Repr f (a, b) = (Repr f a, Repr f b) cons (a,b) = zip (cons a) (cons b) undef = zip undef undef zero = zip zero zero phis bb a = case unzip a of (a0,a1) -> Monad.lift2 zip (phis bb a0) (phis bb a1) addPhis bb a b = case (unzip a, unzip b) of ((a0,a1), (b0,b1)) -> addPhis bb a0 b0 >> addPhis bb a1 b1 instance (C a, C b, C c) => C (a,b,c) where type Repr f (a, b, c) = (Repr f a, Repr f b, Repr f c) cons (a,b,c) = zip3 (cons a) (cons b) (cons c) undef = zip3 undef undef undef zero = zip3 zero zero zero phis bb a = case unzip3 a of (a0,a1,a2) -> Monad.lift3 zip3 (phis bb a0) (phis bb a1) (phis bb a2) addPhis bb a b = case (unzip3 a, unzip3 b) of ((a0,a1,a2), (b0,b1,b2)) -> addPhis bb a0 b0 >> addPhis bb a1 b1 >> addPhis bb a2 b2 instance (C a, C b, C c, C d) => C (a,b,c,d) where type Repr f (a, b, c, d) = (Repr f a, Repr f b, Repr f c, Repr f d) cons (a,b,c,d) = zip4 (cons a) (cons b) (cons c) (cons d) undef = zip4 undef undef undef undef zero = zip4 zero zero zero zero phis bb a = case unzip4 a of (a0,a1,a2,a3) -> Monad.lift4 zip4 (phis bb a0) (phis bb a1) (phis bb a2) (phis bb a3) addPhis bb a b = case (unzip4 a, unzip4 b) of ((a0,a1,a2,a3), (b0,b1,b2,b3)) -> addPhis bb a0 b0 >> addPhis bb a1 b1 >> addPhis bb a2 b2 >> addPhis bb a3 b3 fst :: T (a,b) -> T a fst (Cons (a,_b)) = Cons a snd :: T (a,b) -> T b snd (Cons (_a,b)) = Cons b curry :: (T (a,b) -> c) -> (T a -> T b -> c) curry f a b = f $ zip a b uncurry :: (T a -> T b -> c) -> (T (a,b) -> c) uncurry f = Tuple.uncurry f . unzip mapFst :: (T a0 -> T a1) -> T (a0,b) -> T (a1,b) mapFst f = Tuple.uncurry zip . TupleHT.mapFst f . unzip mapSnd :: (T b0 -> T b1) -> T (a,b0) -> T (a,b1) mapSnd f = Tuple.uncurry zip . TupleHT.mapSnd f . unzip mapFstF :: (Functor f) => (T a0 -> f (T a1)) -> T (a0,b) -> f (T (a1,b)) mapFstF f = fmap (Tuple.uncurry zip) . FuncHT.mapFst f . unzip mapSndF :: (Functor f) => (T b0 -> f (T b1)) -> T (a,b0) -> f (T (a,b1)) mapSndF f = fmap (Tuple.uncurry zip) . FuncHT.mapSnd f . unzip swap :: T (a,b) -> T (b,a) swap = Tuple.uncurry zip . TupleHT.swap . unzip fst3 :: T (a,b,c) -> T a fst3 (Cons (a,_b,_c)) = Cons a snd3 :: T (a,b,c) -> T b snd3 (Cons (_a,b,_c)) = Cons b thd3 :: T (a,b,c) -> T c thd3 (Cons (_a,_b,c)) = Cons c mapFst3 :: (T a0 -> T a1) -> T (a0,b,c) -> T (a1,b,c) mapFst3 f = uncurry3 zip3 . TupleHT.mapFst3 f . unzip3 mapSnd3 :: (T b0 -> T b1) -> T (a,b0,c) -> T (a,b1,c) mapSnd3 f = uncurry3 zip3 . TupleHT.mapSnd3 f . unzip3 mapThd3 :: (T c0 -> T c1) -> T (a,b,c0) -> T (a,b,c1) mapThd3 f = uncurry3 zip3 . TupleHT.mapThd3 f . unzip3 mapFst3F :: (Functor f) => (T a0 -> f (T a1)) -> T (a0,b,c) -> f (T (a1,b,c)) mapFst3F f = fmap (uncurry3 zip3) . FuncHT.mapFst3 f . unzip3 mapSnd3F :: (Functor f) => (T b0 -> f (T b1)) -> T (a,b0,c) -> f (T (a,b1,c)) mapSnd3F f = fmap (uncurry3 zip3) . FuncHT.mapSnd3 f . unzip3 mapThd3F :: (Functor f) => (T c0 -> f (T c1)) -> T (a,b,c0) -> f (T (a,b,c1)) mapThd3F f = fmap (uncurry3 zip3) . FuncHT.mapThd3 f . unzip3 zip :: T a -> T b -> T (a,b) zip (Cons a) (Cons b) = Cons (a,b) zip3 :: T a -> T b -> T c -> T (a,b,c) zip3 (Cons a) (Cons b) (Cons c) = Cons (a,b,c) zip4 :: T a -> T b -> T c -> T d -> T (a,b,c,d) zip4 (Cons a) (Cons b) (Cons c) (Cons d) = Cons (a,b,c,d) unzip :: T (a,b) -> (T a, T b) unzip (Cons (a,b)) = (Cons a, Cons b) unzip3 :: T (a,b,c) -> (T a, T b, T c) unzip3 (Cons (a,b,c)) = (Cons a, Cons b, Cons c) unzip4 :: T (a,b,c,d) -> (T a, T b, T c, T d) unzip4 (Cons (a,b,c,d)) = (Cons a, Cons b, Cons c, Cons d) instance C a => C (Tagged tag a) where type Repr f (Tagged tag a) = Repr f a cons = tag . cons . unTagged undef = tag undef zero = tag zero phis bb = fmap tag . phis bb . untag addPhis bb a b = addPhis bb (untag a) (untag b) tag :: T a -> T (Tagged tag a) tag (Cons a) = Cons a untag :: T (Tagged tag a) -> T a untag (Cons a) = Cons a liftTaggedM :: (Monad m) => (T a -> m (T b)) -> T (Tagged tag a) -> m (T (Tagged tag b)) liftTaggedM f = Monad.lift tag . f . untag liftTaggedM2 :: (Monad m) => (T a -> T b -> m (T c)) -> T (Tagged tag a) -> T (Tagged tag b) -> m (T (Tagged tag c)) liftTaggedM2 f a b = Monad.lift tag $ f (untag a) (untag b) instance (C a) => C (Complex a) where type Repr f (Complex a) = Complex (Repr f a) cons (a:+b) = consComplex (cons a) (cons b) undef = consComplex undef undef zero = consComplex zero zero phis bb a = case deconsComplex a of (a0,a1) -> Monad.lift2 consComplex (phis bb a0) (phis bb a1) addPhis bb a b = case (deconsComplex a, deconsComplex b) of ((a0,a1), (b0,b1)) -> addPhis bb a0 b0 >> addPhis bb a1 b1 consComplex :: T a -> T a -> T (Complex a) consComplex (Cons a) (Cons b) = Cons (a:+b) deconsComplex :: T (Complex a) -> (T a, T a) deconsComplex (Cons (a:+b)) = (Cons a, Cons b) class Compose multituple where type Composed multituple {- | A nested 'zip'. -} compose :: multituple -> T (Composed multituple) class (Composed (Decomposed T pattern) ~ PatternTuple pattern) => Decompose pattern where {- | A nested 'unzip'. Since it is not obvious how deep to decompose nested tuples, you must provide a pattern of the decomposed tuple. E.g. > f :: MultiValue ((a,b),(c,d)) -> > ((MultiValue a, MultiValue b), MultiValue (c,d)) > f = decompose ((atom,atom),atom) -} decompose :: pattern -> T (PatternTuple pattern) -> Decomposed T pattern type family Decomposed (f :: * -> *) pattern type family PatternTuple pattern {- | A combination of 'compose' and 'decompose' that let you operate on tuple multivalues as Haskell tuples. -} modify :: (Compose a, Decompose pattern) => pattern -> (Decomposed T pattern -> a) -> T (PatternTuple pattern) -> T (Composed a) modify p f = compose . f . decompose p modify2 :: (Compose a, Decompose patternA, Decompose patternB) => patternA -> patternB -> (Decomposed T patternA -> Decomposed T patternB -> a) -> T (PatternTuple patternA) -> T (PatternTuple patternB) -> T (Composed a) modify2 pa pb f a b = compose $ f (decompose pa a) (decompose pb b) modifyF :: (Compose a, Decompose pattern, Functor f) => pattern -> (Decomposed T pattern -> f a) -> T (PatternTuple pattern) -> f (T (Composed a)) modifyF p f = fmap compose . f . decompose p modifyF2 :: (Compose a, Decompose patternA, Decompose patternB, Functor f) => patternA -> patternB -> (Decomposed T patternA -> Decomposed T patternB -> f a) -> T (PatternTuple patternA) -> T (PatternTuple patternB) -> f (T (Composed a)) modifyF2 pa pb f a b = fmap compose $ f (decompose pa a) (decompose pb b) instance Compose (T a) where type Composed (T a) = a compose = id instance Decompose (Atom a) where decompose _ = id type instance Decomposed f (Atom a) = f a type instance PatternTuple (Atom a) = a data Atom a = Atom atom :: Atom a atom = Atom instance Compose () where type Composed () = () compose = cons instance Decompose () where decompose () _ = () type instance Decomposed f () = () type instance PatternTuple () = () 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 type instance Decomposed f (pa,pb) = (Decomposed f pa, Decomposed f pb) type instance PatternTuple (pa,pb) = (PatternTuple pa, PatternTuple pb) instance (Compose a, Compose b, Compose c) => Compose (a,b,c) where type Composed (a,b,c) = (Composed a, Composed b, Composed c) compose = 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 type instance Decomposed f (pa,pb,pc) = (Decomposed f pa, Decomposed f pb, Decomposed f pc) type instance PatternTuple (pa,pb,pc) = (PatternTuple pa, PatternTuple pb, PatternTuple pc) 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) type instance Decomposed f (pa,pb,pc,pd) = (Decomposed f pa, Decomposed f pb, Decomposed f pc, Decomposed f pd) type instance PatternTuple (pa,pb,pc,pd) = (PatternTuple pa, PatternTuple pb, PatternTuple pc, PatternTuple pd) instance (Compose a) => Compose (Tagged tag a) where type Composed (Tagged tag a) = Tagged tag (Composed a) compose = tag . compose . unTagged instance (Decompose pa) => Decompose (Tagged tag pa) where decompose (Tagged p) = Tagged . decompose p . untag type instance Decomposed f (Tagged tag pa) = Tagged tag (Decomposed f pa) type instance PatternTuple (Tagged tag pa) = Tagged tag (PatternTuple pa) instance (Compose a) => Compose (Complex a) where type Composed (Complex a) = Complex (Composed a) compose (a:+b) = consComplex (compose a) (compose b) instance (Decompose pa) => Decompose (Complex pa) where decompose (pa:+pb) = Tuple.uncurry (:+) . TupleHT.mapPair (decompose pa, decompose pb) . deconsComplex type instance Decomposed f (Complex pa) = Complex (Decomposed f pa) type instance PatternTuple (Complex pa) = Complex (PatternTuple pa) realPart, imagPart :: T (Complex a) -> T a realPart (Cons (a:+_)) = Cons a imagPart (Cons (_:+b)) = Cons b lift1 :: (Repr LLVM.Value a -> Repr LLVM.Value b) -> T a -> T b lift1 f (Cons a) = Cons $ f a liftM0 :: (Monad m) => m (Repr LLVM.Value a) -> m (T a) liftM0 f = Monad.lift Cons f liftM :: (Monad m) => (Repr LLVM.Value a -> m (Repr LLVM.Value b)) -> T a -> m (T b) liftM f (Cons a) = Monad.lift Cons $ f a liftM2 :: (Monad m) => (Repr LLVM.Value a -> Repr LLVM.Value b -> m (Repr LLVM.Value c)) -> T a -> T b -> m (T c) liftM2 f (Cons a) (Cons b) = Monad.lift Cons $ f a b liftM3 :: (Monad m) => (Repr LLVM.Value a -> Repr LLVM.Value b -> Repr LLVM.Value c -> m (Repr LLVM.Value d)) -> T a -> T b -> T c -> m (T d) liftM3 f (Cons a) (Cons b) (Cons c) = Monad.lift Cons $ f a b c instance (C a) => Class.Zero (T a) where zeroTuple = zero instance (C a) => Class.Undefined (T a) where undefTuple = undef instance (C a) => Phi (T a) where phis = phis addPhis = addPhis class (C a) => IntegerConstant a where fromInteger' :: Integer -> T a class (IntegerConstant a) => RationalConstant a where fromRational' :: Rational -> T a instance IntegerConstant Float where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Double where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Word8 where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Word16 where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Word32 where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Word64 where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Int8 where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Int16 where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Int32 where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant Int64 where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance (Dec.Positive n) => IntegerConstant (WordN n) where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance (Dec.Positive n) => IntegerConstant (IntN n) where fromInteger' = Cons . LLVM.value . SoV.constFromInteger instance IntegerConstant a => IntegerConstant (Tagged tag a) where fromInteger' = tag . fromInteger' instance RationalConstant Float where fromRational' = Cons . LLVM.value . SoV.constFromRational instance RationalConstant Double where fromRational' = Cons . LLVM.value . SoV.constFromRational instance RationalConstant a => RationalConstant (Tagged tag a) where fromRational' = tag . fromRational' instance (IntegerConstant a) => A.IntegerConstant (T a) where fromInteger' = fromInteger' instance (RationalConstant a) => A.RationalConstant (T a) where fromRational' = fromRational' class (C a) => Additive a where add :: T a -> T a -> LLVM.CodeGenFunction r (T a) sub :: T a -> T a -> LLVM.CodeGenFunction r (T a) neg :: T a -> LLVM.CodeGenFunction r (T a) instance Additive Float where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Double where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Word8 where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Word16 where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Word32 where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Word64 where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Int8 where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Int16 where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Int32 where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive Int64 where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance (Dec.Positive n) => Additive (WordN n) where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance (Dec.Positive n) => Additive (IntN n) where add = liftM2 LLVM.add sub = liftM2 LLVM.sub neg = liftM LLVM.neg instance Additive a => Additive (Tagged tag a) where add = liftTaggedM2 add sub = liftTaggedM2 sub neg = liftTaggedM neg instance (Additive a) => A.Additive (T a) where zero = zero add = add sub = sub neg = neg inc, dec :: (Additive i, IntegerConstant i) => T i -> LLVM.CodeGenFunction r (T i) inc x = add x A.one dec x = sub x A.one class (Additive a) => PseudoRing a where mul :: T a -> T a -> LLVM.CodeGenFunction r (T a) instance PseudoRing Float where mul = liftM2 LLVM.mul instance PseudoRing Double where mul = liftM2 LLVM.mul instance PseudoRing Word8 where mul = liftM2 LLVM.mul instance PseudoRing Word16 where mul = liftM2 LLVM.mul instance PseudoRing Word32 where mul = liftM2 LLVM.mul instance PseudoRing Word64 where mul = liftM2 LLVM.mul instance PseudoRing Int8 where mul = liftM2 LLVM.mul instance PseudoRing Int16 where mul = liftM2 LLVM.mul instance PseudoRing Int32 where mul = liftM2 LLVM.mul instance PseudoRing Int64 where mul = liftM2 LLVM.mul instance (PseudoRing a) => PseudoRing (Tagged tag a) where mul = liftTaggedM2 mul instance (PseudoRing a) => A.PseudoRing (T a) where mul = mul class (PseudoRing a) => Field a where fdiv :: T a -> T a -> LLVM.CodeGenFunction r (T a) instance Field Float where fdiv = liftM2 LLVM.fdiv instance Field Double where fdiv = liftM2 LLVM.fdiv instance (Field a) => Field (Tagged tag a) where fdiv = liftTaggedM2 fdiv instance (Field a) => A.Field (T a) where fdiv = fdiv type family Scalar vector :: * type instance Scalar Float = Float type instance Scalar Double = Double type instance Scalar (Tagged tag a) = Tagged tag (Scalar a) type instance A.Scalar (T a) = T (Scalar a) class (PseudoRing (Scalar v), Additive v) => PseudoModule v where scale :: T (Scalar v) -> T v -> LLVM.CodeGenFunction r (T v) instance PseudoModule Float where scale = liftM2 A.mul instance PseudoModule Double where scale = liftM2 A.mul instance (PseudoModule a) => PseudoModule (Tagged tag a) where scale = liftTaggedM2 scale instance (PseudoModule a) => A.PseudoModule (T a) where scale = scale class (Additive a) => Real a where min :: T a -> T a -> LLVM.CodeGenFunction r (T a) max :: T a -> T a -> LLVM.CodeGenFunction r (T a) abs :: T a -> LLVM.CodeGenFunction r (T a) signum :: T a -> LLVM.CodeGenFunction r (T a) instance Real Float where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Double where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Word8 where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Word16 where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Word32 where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Word64 where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Int8 where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Int16 where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Int32 where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance Real Int64 where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance (Dec.Positive n) => Real (WordN n) where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance (Dec.Positive n) => Real (IntN n) where min = liftM2 A.min max = liftM2 A.max abs = liftM A.abs signum = liftM A.signum instance (Real a) => Real (Tagged tag a) where min = liftTaggedM2 min max = liftTaggedM2 max abs = liftTaggedM abs signum = liftTaggedM signum instance (Real a) => A.Real (T a) where min = min max = max abs = abs signum = signum class (Real a) => Fraction a where truncate :: T a -> LLVM.CodeGenFunction r (T a) fraction :: T a -> LLVM.CodeGenFunction r (T a) instance Fraction Float where truncate = liftM A.truncate fraction = liftM A.fraction instance Fraction Double where truncate = liftM A.truncate fraction = liftM A.fraction instance (Fraction a) => Fraction (Tagged tag a) where truncate = liftTaggedM truncate fraction = liftTaggedM fraction instance (Fraction a) => A.Fraction (T a) where truncate = truncate fraction = fraction class (Repr LLVM.Value i ~ LLVM.Value ir, LLVM.IsInteger ir, SoV.IntegerConstant ir, LLVM.CmpRet ir, LLVM.NumberOfElements ir ~ D1, LLVM.CmpResult ir ~ Bool) => NativeInteger i ir where instance NativeInteger Word8 Word8 where instance NativeInteger Word16 Word16 where instance NativeInteger Word32 Word32 where instance NativeInteger Word64 Word64 where instance NativeInteger Int8 Int8 where instance NativeInteger Int16 Int16 where instance NativeInteger Int32 Int32 where instance NativeInteger Int64 Int64 where class (Repr LLVM.Value a ~ LLVM.Value ar, LLVM.IsFloating ar, SoV.RationalConstant ar, LLVM.CmpRet ar, LLVM.NumberOfElements ar ~ D1, LLVM.CmpResult ar ~ Bool) => NativeFloating a ar where instance NativeFloating Float Float where instance NativeFloating Double Double where truncateToInt, floorToInt, ceilingToInt, roundToIntFast :: (NativeInteger i ir, NativeFloating a ar) => T a -> LLVM.CodeGenFunction r (T i) truncateToInt = liftM SoV.truncateToInt floorToInt = liftM SoV.floorToInt ceilingToInt = liftM SoV.ceilingToInt roundToIntFast = liftM SoV.roundToIntFast splitFractionToInt :: (NativeInteger i ir, NativeFloating a ar) => T a -> LLVM.CodeGenFunction r (T (i,a)) splitFractionToInt = liftM SoV.splitFractionToInt class Field a => Algebraic a where sqrt :: T a -> LLVM.CodeGenFunction r (T a) instance Algebraic Float where sqrt = liftM A.sqrt instance Algebraic Double where sqrt = liftM A.sqrt instance (Algebraic a) => Algebraic (Tagged tag a) where sqrt = liftTaggedM sqrt instance (Algebraic a) => A.Algebraic (T a) where sqrt = sqrt class Algebraic a => Transcendental a where pi :: LLVM.CodeGenFunction r (T a) sin, cos, exp, log :: T a -> LLVM.CodeGenFunction r (T a) pow :: T a -> T a -> LLVM.CodeGenFunction r (T a) instance Transcendental Float where pi = liftM0 A.pi sin = liftM A.sin cos = liftM A.cos exp = liftM A.exp log = liftM A.log pow = liftM2 A.pow instance Transcendental Double where pi = liftM0 A.pi sin = liftM A.sin cos = liftM A.cos exp = liftM A.exp log = liftM A.log pow = liftM2 A.pow instance (Transcendental a) => Transcendental (Tagged tag a) where pi = fmap tag pi sin = liftTaggedM sin cos = liftTaggedM cos exp = liftTaggedM exp log = liftTaggedM log pow = liftTaggedM2 pow instance (Transcendental a) => A.Transcendental (T a) where pi = pi sin = sin cos = cos exp = exp log = log pow = pow class (C a) => Select a where select :: T Bool -> T a -> T a -> LLVM.CodeGenFunction r (T a) instance Select Bool where select = liftM3 LLVM.select instance Select Bool8 where select = liftM3 LLVM.select instance Select Float where select = liftM3 LLVM.select instance Select Double where select = liftM3 LLVM.select instance Select Word8 where select = liftM3 LLVM.select instance Select Word16 where select = liftM3 LLVM.select instance Select Word32 where select = liftM3 LLVM.select instance Select Word64 where select = liftM3 LLVM.select instance Select Int8 where select = liftM3 LLVM.select instance Select Int16 where select = liftM3 LLVM.select instance Select Int32 where select = liftM3 LLVM.select instance Select Int64 where select = liftM3 LLVM.select instance (Select a, Select b) => Select (a,b) where select b = modifyF2 (atom,atom) (atom,atom) $ \(a0,b0) (a1,b1) -> Monad.lift2 (,) (select b a0 a1) (select b b0 b1) instance (Select a, Select b, Select c) => Select (a,b,c) where select b = modifyF2 (atom,atom,atom) (atom,atom,atom) $ \(a0,b0,c0) (a1,b1,c1) -> Monad.lift3 (,,) (select b a0 a1) (select b b0 b1) (select b c0 c1) instance (Select a) => Select (Tagged tag a) where select = liftTaggedM2 . select instance (Select a) => C.Select (T a) where select b = select (Cons b) class (Real a) => Comparison a where {- | It must hold > max x y == do gt <- cmp CmpGT x y; select gt x y -} cmp :: LLVM.CmpPredicate -> T a -> T a -> LLVM.CodeGenFunction r (T Bool) instance Comparison Float where cmp = liftM2 . LLVM.cmp instance Comparison Double where cmp = liftM2 . LLVM.cmp instance Comparison Int8 where cmp = liftM2 . LLVM.cmp instance Comparison Int16 where cmp = liftM2 . LLVM.cmp instance Comparison Int32 where cmp = liftM2 . LLVM.cmp instance Comparison Int64 where cmp = liftM2 . LLVM.cmp instance Comparison Word8 where cmp = liftM2 . LLVM.cmp instance Comparison Word16 where cmp = liftM2 . LLVM.cmp instance Comparison Word32 where cmp = liftM2 . LLVM.cmp instance Comparison Word64 where cmp = liftM2 . LLVM.cmp instance (Dec.Positive n) => Comparison (IntN n) where cmp = liftM2 . LLVM.cmp instance (Dec.Positive n) => Comparison (WordN n) where cmp = liftM2 . LLVM.cmp instance (Comparison a) => Comparison (Tagged tag a) where cmp p a b = cmp p (untag a) (untag b) instance (Comparison a) => A.Comparison (T a) where type CmpResult (T a) = T Bool cmp = cmp class (Comparison a) => FloatingComparison a where fcmp :: LLVM.FPPredicate -> T a -> T a -> LLVM.CodeGenFunction r (T Bool) instance FloatingComparison Float where fcmp = liftM2 . LLVM.fcmp instance (FloatingComparison a) => FloatingComparison (Tagged tag a) where fcmp p a b = fcmp p (untag a) (untag b) instance (FloatingComparison a) => A.FloatingComparison (T a) where fcmp = fcmp class (C a) => Logic a where and :: T a -> T a -> LLVM.CodeGenFunction r (T a) or :: T a -> T a -> LLVM.CodeGenFunction r (T a) xor :: T a -> T a -> LLVM.CodeGenFunction r (T a) inv :: T a -> LLVM.CodeGenFunction r (T a) instance Logic Bool where and = liftM2 LLVM.and; or = liftM2 LLVM.or xor = liftM2 LLVM.xor; inv = liftM LLVM.inv instance Logic Bool8 where and = liftM2 LLVM.and; or = liftM2 LLVM.or xor = liftM2 LLVM.xor; inv = liftM LLVM.inv instance Logic Word8 where and = liftM2 LLVM.and; or = liftM2 LLVM.or xor = liftM2 LLVM.xor; inv = liftM LLVM.inv instance Logic Word16 where and = liftM2 LLVM.and; or = liftM2 LLVM.or xor = liftM2 LLVM.xor; inv = liftM LLVM.inv instance Logic Word32 where and = liftM2 LLVM.and; or = liftM2 LLVM.or xor = liftM2 LLVM.xor; inv = liftM LLVM.inv instance Logic Word64 where and = liftM2 LLVM.and; or = liftM2 LLVM.or xor = liftM2 LLVM.xor; inv = liftM LLVM.inv instance (Dec.Positive n) => Logic (WordN n) where and = liftM2 LLVM.and; or = liftM2 LLVM.or xor = liftM2 LLVM.xor; inv = liftM LLVM.inv instance (LLVM.IsInteger w, LLVM.IsConst w) => Logic (EnumBitSet.T w i) where and = liftM2 LLVM.and; or = liftM2 LLVM.or xor = liftM2 LLVM.xor; inv = liftM LLVM.inv instance Logic a => Logic (Tagged tag a) where and = liftTaggedM2 and; or = liftTaggedM2 or xor = liftTaggedM2 xor; inv = liftTaggedM inv instance Logic a => A.Logic (T a) where and = and or = or xor = xor inv = inv class BitShift a where shl :: T a -> T a -> LLVM.CodeGenFunction r (T a) shr :: T a -> T a -> LLVM.CodeGenFunction r (T a) instance BitShift Word8 where shl = liftM2 LLVM.shl; shr = liftM2 LLVM.lshr instance BitShift Word16 where shl = liftM2 LLVM.shl; shr = liftM2 LLVM.lshr instance BitShift Word32 where shl = liftM2 LLVM.shl; shr = liftM2 LLVM.lshr instance BitShift Word64 where shl = liftM2 LLVM.shl; shr = liftM2 LLVM.lshr instance BitShift Int8 where shl = liftM2 LLVM.shl; shr = liftM2 LLVM.ashr instance BitShift Int16 where shl = liftM2 LLVM.shl; shr = liftM2 LLVM.ashr instance BitShift Int32 where shl = liftM2 LLVM.shl; shr = liftM2 LLVM.ashr instance BitShift Int64 where shl = liftM2 LLVM.shl; shr = liftM2 LLVM.ashr class (PseudoRing a) => Integral a where idiv :: T a -> T a -> LLVM.CodeGenFunction r (T a) irem :: T a -> T a -> LLVM.CodeGenFunction r (T a) instance Integral Word32 where idiv = liftM2 LLVM.idiv irem = liftM2 LLVM.irem instance Integral Word64 where idiv = liftM2 LLVM.idiv irem = liftM2 LLVM.irem instance Integral Int32 where idiv = liftM2 LLVM.idiv irem = liftM2 LLVM.irem instance Integral Int64 where idiv = liftM2 LLVM.idiv irem = liftM2 LLVM.irem instance (Integral a) => Integral (Tagged tag a) where idiv = liftTaggedM2 idiv irem = liftTaggedM2 irem fromIntegral :: (NativeInteger i ir, NativeFloating a ar) => T i -> LLVM.CodeGenFunction r (T a) fromIntegral = liftM LLVM.inttofp