{-# LANGUAGE TypeFamilies #-} module LLVM.Extra.Multi.Class where import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Multi.Vector as MultiVector import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Core as LLVM import qualified Type.Data.Num.Decimal as TypeNum class C value where type Size value :: * switch :: f MultiValue.T -> f (MultiVector.T (Size value)) -> f value instance C MultiValue.T where type Size MultiValue.T = TypeNum.D1 switch x _ = x instance (TypeNum.Positive n) => C (MultiVector.T n) where type Size (MultiVector.T n) = n switch _ x = x newtype Const a value = Const {getConst :: value a} undef :: (C value, Size value ~ n, TypeNum.Positive n, MultiVector.C a) => value a undef = getConst $ switch (Const MultiValue.undef) (Const MultiVector.undef) zero :: (C value, Size value ~ n, TypeNum.Positive n, MultiVector.C a) => value a zero = getConst $ switch (Const MultiValue.zero) (Const MultiVector.zero) newtype Op0 r a value = Op0 {runOp0 :: LLVM.CodeGenFunction r (value a)} newtype Op1 r a b value = Op1 {runOp1 :: value a -> LLVM.CodeGenFunction r (value b)} newtype Op2 r a b c value = Op2 {runOp2 :: value a -> value b -> LLVM.CodeGenFunction r (value c)} add, sub :: (TypeNum.Positive n, MultiVector.Additive a, n ~ Size value, C value) => value a -> value a -> LLVM.CodeGenFunction r (value a) add = runOp2 $ switch (Op2 A.add) (Op2 A.add) sub = runOp2 $ switch (Op2 A.sub) (Op2 A.sub) neg :: (TypeNum.Positive n, MultiVector.Additive a, n ~ Size value, C value) => value a -> LLVM.CodeGenFunction r (value a) neg = runOp1 $ switch (Op1 A.neg) (Op1 A.neg) mul :: (TypeNum.Positive n, MultiVector.PseudoRing a, n ~ Size value, C value) => value a -> value a -> LLVM.CodeGenFunction r (value a) mul = runOp2 $ switch (Op2 A.mul) (Op2 A.mul) fdiv :: (TypeNum.Positive n, MultiVector.Field a, n ~ Size value, C value) => value a -> value a -> LLVM.CodeGenFunction r (value a) fdiv = runOp2 $ switch (Op2 A.fdiv) (Op2 A.fdiv) scale :: (TypeNum.Positive n, MultiVector.PseudoModule v, n ~ Size value, C value) => value (MultiValue.Scalar v) -> value v -> LLVM.CodeGenFunction r (value v) scale = runOp2 $ switch (Op2 A.scale) (Op2 A.scale) min, max :: (TypeNum.Positive n, MultiVector.Real a, n ~ Size value, C value) => value a -> value a -> LLVM.CodeGenFunction r (value a) min = runOp2 $ switch (Op2 A.min) (Op2 A.min) max = runOp2 $ switch (Op2 A.max) (Op2 A.max) abs, signum :: (TypeNum.Positive n, MultiVector.Real a, n ~ Size value, C value) => value a -> LLVM.CodeGenFunction r (value a) abs = runOp1 $ switch (Op1 A.abs) (Op1 A.abs) signum = runOp1 $ switch (Op1 A.signum) (Op1 A.signum) truncate, fraction :: (TypeNum.Positive n, MultiVector.Fraction a, n ~ Size value, C value) => value a -> LLVM.CodeGenFunction r (value a) truncate = runOp1 $ switch (Op1 A.truncate) (Op1 A.truncate) fraction = runOp1 $ switch (Op1 A.fraction) (Op1 A.fraction) sqrt :: (TypeNum.Positive n, MultiVector.Algebraic a, n ~ Size value, C value) => value a -> LLVM.CodeGenFunction r (value a) sqrt = runOp1 $ switch (Op1 A.sqrt) (Op1 A.sqrt) pi :: (TypeNum.Positive n, MultiVector.Transcendental a, n ~ Size value, C value) => LLVM.CodeGenFunction r (value a) pi = runOp0 $ switch (Op0 A.pi) (Op0 A.pi) sin, cos, exp, log :: (TypeNum.Positive n, MultiVector.Transcendental a, n ~ Size value, C value) => value a -> LLVM.CodeGenFunction r (value a) sin = runOp1 $ switch (Op1 A.sin) (Op1 A.sin) cos = runOp1 $ switch (Op1 A.cos) (Op1 A.cos) exp = runOp1 $ switch (Op1 A.exp) (Op1 A.exp) log = runOp1 $ switch (Op1 A.log) (Op1 A.log) pow :: (TypeNum.Positive n, MultiVector.Transcendental a, n ~ Size value, C value) => value a -> value a -> LLVM.CodeGenFunction r (value a) pow = runOp2 $ switch (Op2 A.pow) (Op2 A.pow) cmp :: (TypeNum.Positive n, MultiVector.Comparison a, n ~ Size value, C value) => LLVM.CmpPredicate -> value a -> value a -> LLVM.CodeGenFunction r (value Bool) cmp p = runOp2 $ switch (Op2 $ A.cmp p) (Op2 $ A.cmp p) fcmp :: (TypeNum.Positive n, MultiVector.FloatingComparison a, n ~ Size value, C value) => LLVM.FPPredicate -> value a -> value a -> LLVM.CodeGenFunction r (value Bool) fcmp p = runOp2 $ switch (Op2 $ A.fcmp p) (Op2 $ A.fcmp p) and, or, xor :: (TypeNum.Positive n, MultiVector.Logic a, n ~ Size value, C value) => value a -> value a -> LLVM.CodeGenFunction r (value a) and = runOp2 $ switch (Op2 A.and) (Op2 A.and) or = runOp2 $ switch (Op2 A.or) (Op2 A.or) xor = runOp2 $ switch (Op2 A.xor) (Op2 A.xor) inv :: (TypeNum.Positive n, MultiVector.Logic a, n ~ Size value, C value) => value a -> LLVM.CodeGenFunction r (value a) inv = runOp1 $ switch (Op1 A.inv) (Op1 A.inv)