packages feed

llvm-extra-0.12.1: src/LLVM/Extra/FastMath.hs

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module LLVM.Extra.FastMath ( 
   NoNaNs(NoNaNs),
   NoInfs(NoInfs),
   NoSignedZeros(NoSignedZeros),
   AllowReciprocal(AllowReciprocal),
   Fast(Fast),
   Flags(setFlags),

   Number(Number, deconsNumber),
   getNumber,
   nvNumber,
   nvDenumber,
   mvNumber,
   mvDenumber,

   NiceValue(setMultiValueFlags, setNiceValueFlags),
   attachNiceValueFlags,
   attachMultiValueFlags,
   liftNumberM,
   liftNumberM2,
   nvecNumber,
   nvecDenumber,
   mvecNumber,
   mvecDenumber,

   NiceVector(setMultiVectorFlags, setNiceVectorFlags),
   attachNiceVectorFlags,
   liftNiceVectorM,
   liftNiceVectorM2,
   attachMultiVectorFlags,
   liftMultiVectorM,
   liftMultiVectorM2,

   Tuple(setTupleFlags),
   Context(Context),
   attachTupleFlags,
   liftContext,
   liftContext2,
   ) where

import qualified LLVM.Extra.Nice.Vector as NiceVector
import qualified LLVM.Extra.Nice.Value.Private as Nice
import qualified LLVM.Extra.Arithmetic as A
import qualified LLVM.Extra.Tuple as Tuple
import qualified LLVM.Core as LLVM
import LLVM.Util.Proxy (Proxy(Proxy))

import Foreign.Storable (Storable)

import qualified Control.Monad.HT as Monad
import Control.Applicative ((<$>))


data NoNaNs          = NoNaNs          deriving (Show, Eq)
data NoInfs          = NoInfs          deriving (Show, Eq)
data NoSignedZeros   = NoSignedZeros   deriving (Show, Eq)
data AllowReciprocal = AllowReciprocal deriving (Show, Eq)
data Fast            = Fast            deriving (Show, Eq)


class Flags flags where
   setFlags ::
      (LLVM.IsFloating a) =>
      Proxy flags -> Bool -> LLVM.Value a -> LLVM.CodeGenFunction r ()

instance Flags NoNaNs          where setFlags Proxy = LLVM.setHasNoNaNs
instance Flags NoInfs          where setFlags Proxy = LLVM.setHasNoInfs
instance Flags NoSignedZeros   where setFlags Proxy = LLVM.setHasNoSignedZeros
instance Flags AllowReciprocal where setFlags Proxy = LLVM.setHasAllowReciprocal
instance Flags Fast            where setFlags Proxy = LLVM.setFastMath

instance (Flags f0, Flags f1) => Flags (f0,f1) where
   setFlags p b v = setFlags (fst<$>p) b v >> setFlags (snd<$>p) b v

instance (Flags f0, Flags f1, Flags f2) => Flags (f0,f1,f2) where
   setFlags = setSplitFlags $ \(f0,f1,f2) -> (f0,(f1,f2))

instance (Flags f0, Flags f1, Flags f2, Flags f3) => Flags (f0,f1,f2,f3) where
   setFlags = setSplitFlags $ \(f0,f1,f2,f3) -> (f0,(f1,f2,f3))

instance
   (Flags f0, Flags f1, Flags f2, Flags f3, Flags f4) =>
      Flags (f0,f1,f2,f3,f4) where
   setFlags = setSplitFlags $ \(f0,f1,f2,f3,f4) -> (f0,(f1,f2,f3,f4))

setSplitFlags ::
   (Flags split, LLVM.IsFloating a) =>
   (flags -> split) ->
   Proxy flags -> Bool -> LLVM.Value a -> LLVM.CodeGenFunction r ()
setSplitFlags split p = setFlags (fmap split p)


newtype Number flags a = Number {deconsNumber :: a}
   deriving (Eq, Ord, Show, Num, Fractional, Floating, Storable)

getNumber :: flags -> Number flags a -> a
getNumber _ (Number a) = a

instance NiceValue a => Nice.C (Number flags a) where
   type Repr (Number flags a) = Nice.Repr a
   cons = nvNumber . Nice.cons . deconsNumber
   undef = nvNumber Nice.undef
   zero = nvNumber Nice.zero
   phi bb = fmap nvNumber . Nice.phi bb . nvDenumber
   addPhi bb a b = Nice.addPhi bb (nvDenumber a) (nvDenumber b)

nvNumber :: Nice.T a -> Nice.T (Number flags a)
nvNumber (Nice.Cons a) = Nice.Cons a

nvDenumber :: Nice.T (Number flags a) -> Nice.T a
nvDenumber (Nice.Cons a) = Nice.Cons a

{-# DEPRECATED mvNumber "Use nvNumber instead" #-}
mvNumber :: Nice.T a -> Nice.T (Number flags a)
mvNumber (Nice.Cons a) = Nice.Cons a

{-# DEPRECATED mvDenumber "Use nvDenumber instead" #-}
mvDenumber :: Nice.T (Number flags a) -> Nice.T a
mvDenumber (Nice.Cons a) = Nice.Cons a


{-# DEPRECATED setMultiValueFlags "use setNiceValueFlags instead" #-}
class Nice.C a => NiceValue a where
   {-# MINIMAL setNiceValueFlags | setMultiValueFlags #-}
   setNiceValueFlags, setMultiValueFlags ::
      (Flags flags) =>
      Proxy flags -> Bool -> Nice.T (Number flags a) ->
      LLVM.CodeGenFunction r ()
   setNiceValueFlags = setMultiValueFlags
   setMultiValueFlags = setNiceValueFlags

instance NiceValue Float where
   setNiceValueFlags p b (Nice.Cons a) = setFlags p b a

instance NiceValue Double where
   setNiceValueFlags p b (Nice.Cons a) = setFlags p b a


type Id a = a -> a

{-# DEPRECATED attachMultiValueFlags "Use attachNiceValueFlags instead." #-}
attachMultiValueFlags, attachNiceValueFlags ::
   (Flags flags, NiceValue a) =>
   Id (LLVM.CodeGenFunction r (Nice.T (Number flags a)))
attachMultiValueFlags = attachNiceValueFlags
attachNiceValueFlags act = do
   mv <- act
   setMultiValueFlags Proxy True mv
   return mv

liftNumberM ::
   (m ~ LLVM.CodeGenFunction r, Flags flags, NiceValue b) =>
   (Nice.T a -> m (Nice.T b)) ->
   Nice.T (Number flags a) -> m (Nice.T (Number flags b))
liftNumberM f =
   attachMultiValueFlags . Monad.lift nvNumber . f . nvDenumber

liftNumberM2 ::
   (m ~ LLVM.CodeGenFunction r, Flags flags, NiceValue c) =>
   (Nice.T a -> Nice.T b -> m (Nice.T c)) ->
   Nice.T (Number flags a) -> Nice.T (Number flags b) ->
   m (Nice.T (Number flags c))
liftNumberM2 f a b =
   attachMultiValueFlags $ Monad.lift nvNumber $ f (nvDenumber a) (nvDenumber b)


instance (Flags flags, Nice.Compose a) => Nice.Compose (Number flags a) where
   type Composed (Number flags a) = Number flags (Nice.Composed a)
   compose = nvNumber . Nice.compose . deconsNumber

instance
      (Flags flags, Nice.Decompose pa) => Nice.Decompose (Number flags pa) where
   decompose (Number p) = Number . Nice.decompose p . nvDenumber

type instance
   Nice.Decomposed f (Number flags pa) = Number flags (Nice.Decomposed f pa)
type instance
   Nice.PatternTuple (Number flags pa) = Number flags (Nice.PatternTuple pa)


instance
   (Flags flags, NiceValue a, Nice.IntegerConstant a) =>
      Nice.IntegerConstant (Number flags a) where
   fromInteger' = nvNumber . Nice.fromInteger'

instance
   (Flags flags, NiceValue a, Nice.RationalConstant a) =>
      Nice.RationalConstant (Number flags a) where
   fromRational' = nvNumber . Nice.fromRational'

instance
   (Flags flags, NiceValue a, Nice.Additive a) =>
      Nice.Additive (Number flags a) where
   add = liftNumberM2 Nice.add
   sub = liftNumberM2 Nice.sub
   neg = liftNumberM Nice.neg

instance
   (Flags flags, NiceValue a, Nice.PseudoRing a) =>
      Nice.PseudoRing (Number flags a) where
   mul = liftNumberM2 Nice.mul

instance
   (Flags flags, NiceValue a, Nice.Field a) =>
      Nice.Field (Number flags a) where
   fdiv = liftNumberM2 Nice.fdiv

type instance Nice.Scalar (Number flags a) = Number flags (Nice.Scalar a)

instance
   (Flags flags, NiceValue a, a ~ Nice.Scalar v,
    NiceValue v, Nice.PseudoModule v) =>
      Nice.PseudoModule (Number flags v) where
   scale = liftNumberM2 Nice.scale

instance
   (Flags flags, NiceValue a, Nice.Real a) =>
      Nice.Real (Number flags a) where
   min = liftNumberM2 Nice.min
   max = liftNumberM2 Nice.max
   abs = liftNumberM Nice.abs
   signum = liftNumberM Nice.signum

instance
   (Flags flags, NiceValue a, Nice.Fraction a) =>
      Nice.Fraction (Number flags a) where
   truncate = liftNumberM Nice.truncate
   fraction = liftNumberM Nice.fraction

instance
   (Flags flags, NiceValue a, Nice.Algebraic a) =>
      Nice.Algebraic (Number flags a) where
   sqrt = liftNumberM Nice.sqrt

instance
   (Flags flags, NiceValue a, Nice.Transcendental a) =>
      Nice.Transcendental (Number flags a) where
   pi = fmap nvNumber Nice.pi
   sin = liftNumberM Nice.sin
   cos = liftNumberM Nice.cos
   exp = liftNumberM Nice.exp
   log = liftNumberM Nice.log
   pow = liftNumberM2 Nice.pow

instance
   (Flags flags, NiceValue a, Nice.Select a) =>
      Nice.Select (Number flags a) where
   select = liftNumberM2 . Nice.select

instance
   (Flags flags, NiceValue a, Nice.Comparison a) =>
      Nice.Comparison (Number flags a) where
   cmp p a b = Nice.cmp p (nvDenumber a) (nvDenumber b)

instance
   (Flags flags, NiceValue a, Nice.FloatingComparison a) =>
      Nice.FloatingComparison (Number flags a) where
   fcmp p a b = Nice.fcmp p (nvDenumber a) (nvDenumber b)



nvecNumber :: NiceVector.T n a -> NiceVector.T n (Number flags a)
nvecNumber (NiceVector.Cons v) = NiceVector.Cons v

nvecDenumber :: NiceVector.T n (Number flags a) -> NiceVector.T n a
nvecDenumber (NiceVector.Cons v) = NiceVector.Cons v

{-# DEPRECATED mvecNumber "Use nvecNumber instead" #-}
mvecNumber :: NiceVector.T n a -> NiceVector.T n (Number flags a)
mvecNumber (NiceVector.Cons v) = NiceVector.Cons v

{-# DEPRECATED mvecDenumber "Use nvecDenumber instead" #-}
mvecDenumber :: NiceVector.T n (Number flags a) -> NiceVector.T n a
mvecDenumber (NiceVector.Cons v) = NiceVector.Cons v

{-# DEPRECATED setMultiVectorFlags "use setNiceVectorFlags instead" #-}
class (NiceValue a, NiceVector.C a) => NiceVector a where
   {-# MINIMAL setNiceVectorFlags | setMultiVectorFlags #-}
   setNiceVectorFlags, setMultiVectorFlags ::
      (Flags flags, LLVM.Positive n) =>
      Proxy flags -> Bool ->
      NiceVector.T n (Number flags a) -> LLVM.CodeGenFunction r ()
   setNiceVectorFlags = setMultiVectorFlags
   setMultiVectorFlags = setNiceVectorFlags

instance NiceVector Float where
   setMultiVectorFlags p b =
      setFlags p b . NiceVector.deconsPrim . nvecDenumber

instance NiceVector Double where
   setMultiVectorFlags p b =
      setFlags p b . NiceVector.deconsPrim . nvecDenumber

{-# DEPRECATED attachMultiVectorFlags "Use attachNiceVectorFlags instead." #-}
attachNiceVectorFlags, attachMultiVectorFlags ::
   (LLVM.Positive n, Flags flags, NiceVector a) =>
   Id (LLVM.CodeGenFunction r (NiceVector.T n (Number flags a)))
attachMultiVectorFlags = attachNiceVectorFlags
attachNiceVectorFlags act = do
   mv <- act
   setMultiVectorFlags Proxy True mv
   return mv

{-# DEPRECATED liftMultiVectorM "Use liftNiceVectorM instead." #-}
liftNiceVectorM, liftMultiVectorM ::
   (m ~ LLVM.CodeGenFunction r, LLVM.Positive n, Flags flags, NiceVector b) =>
   (NiceVector.T n a -> m (NiceVector.T n b)) ->
   NiceVector.T n (Number flags a) -> m (NiceVector.T n (Number flags b))
liftMultiVectorM = liftNiceVectorM
liftNiceVectorM f =
   attachMultiVectorFlags . Monad.lift nvecNumber . f . nvecDenumber

{-# DEPRECATED liftMultiVectorM2 "Use liftNiceVectorM2 instead." #-}
liftNiceVectorM2, liftMultiVectorM2 ::
   (m ~ LLVM.CodeGenFunction r, LLVM.Positive n, Flags flags, NiceVector c) =>
   (NiceVector.T n a -> NiceVector.T n b -> m (NiceVector.T n c)) ->
   NiceVector.T n (Number flags a) -> NiceVector.T n (Number flags b) ->
   m (NiceVector.T n (Number flags c))
liftMultiVectorM2 = liftNiceVectorM2
liftNiceVectorM2 f a b =
   attachMultiVectorFlags $
      Monad.lift nvecNumber $ f (nvecDenumber a) (nvecDenumber b)

instance (Flags flags, NiceVector a) => NiceVector.C (Number flags a) where
   type Repr n (Number flags a) = NiceVector.Repr n a
   cons = nvecNumber . NiceVector.cons . fmap deconsNumber
   undef = nvecNumber NiceVector.undef
   zero = nvecNumber NiceVector.zero
   phi bb = fmap nvecNumber . NiceVector.phi bb . nvecDenumber
   addPhi bb a b = NiceVector.addPhi bb (nvecDenumber a) (nvecDenumber b)
   shuffle ks a b =
      fmap nvecNumber $ NiceVector.shuffle ks (nvecDenumber a) (nvecDenumber b)
   extract k = fmap nvNumber . NiceVector.extract k . nvecDenumber
   insert k x =
      fmap nvecNumber . NiceVector.insert k (nvDenumber x) . nvecDenumber

instance
   (Flags flags, NiceVector a, NiceVector.IntegerConstant a) =>
      NiceVector.IntegerConstant (Number flags a) where
   fromInteger' = nvecNumber . NiceVector.fromInteger'

instance
   (Flags flags, NiceVector a, NiceVector.RationalConstant a) =>
      NiceVector.RationalConstant (Number flags a) where
   fromRational' = nvecNumber . NiceVector.fromRational'

instance
   (Flags flags, NiceVector a, NiceVector.Additive a) =>
      NiceVector.Additive (Number flags a) where
   add = liftNiceVectorM2 NiceVector.add
   sub = liftNiceVectorM2 NiceVector.sub
   neg = liftNiceVectorM NiceVector.neg

instance
   (Flags flags, NiceVector a, NiceVector.PseudoRing a) =>
      NiceVector.PseudoRing (Number flags a) where
   mul = liftNiceVectorM2 NiceVector.mul

instance
   (Flags flags, NiceVector a, NiceVector.Field a) =>
      NiceVector.Field (Number flags a) where
   fdiv = liftNiceVectorM2 NiceVector.fdiv


{-
type instance NiceValue.Scalar (Number flags a) =
      Number flags (NiceValue.Scalar a)
instance
   (Flags flags, NiceVector a, NiceVector.PseudoModule a) =>
      NiceVector.PseudoModule (Number flags a) where
   scale = liftNiceVectorM2 NiceVector.mul
-}

instance
   (Flags flags, NiceVector a, NiceVector.Real a) =>
      NiceVector.Real (Number flags a) where
   min = liftNiceVectorM2 NiceVector.min
   max = liftNiceVectorM2 NiceVector.max
   abs = liftNiceVectorM NiceVector.abs
   signum = liftNiceVectorM NiceVector.signum

instance
   (Flags flags, NiceVector a, NiceVector.Fraction a) =>
      NiceVector.Fraction (Number flags a) where
   truncate = liftNiceVectorM NiceVector.truncate
   fraction = liftNiceVectorM NiceVector.fraction

instance
   (Flags flags, NiceVector a, NiceVector.Algebraic a) =>
      NiceVector.Algebraic (Number flags a) where
   sqrt = liftNiceVectorM NiceVector.sqrt

instance
   (Flags flags, NiceVector a, NiceVector.Transcendental a) =>
      NiceVector.Transcendental (Number flags a) where
   pi = fmap nvecNumber NiceVector.pi
   sin = liftNiceVectorM NiceVector.sin
   cos = liftNiceVectorM NiceVector.cos
   exp = liftNiceVectorM NiceVector.exp
   log = liftNiceVectorM NiceVector.log
   pow = liftNiceVectorM2 NiceVector.pow

instance
   (Flags flags, NiceVector a, NiceVector.Select a) =>
      NiceVector.Select (Number flags a) where
   select = liftNiceVectorM2 . NiceVector.select

instance
   (Flags flags, NiceVector a, NiceVector.Comparison a) =>
      NiceVector.Comparison (Number flags a) where
   cmp p a b = NiceVector.cmp p (nvecDenumber a) (nvecDenumber b)

instance
   (Flags flags, NiceVector a, NiceVector.FloatingComparison a) =>
      NiceVector.FloatingComparison (Number flags a) where
   fcmp p a b = NiceVector.fcmp p (nvecDenumber a) (nvecDenumber b)



class Tuple a where
   setTupleFlags ::
      (Flags flags) => Proxy flags -> Bool -> a -> LLVM.CodeGenFunction r ()

instance (LLVM.IsFloating a) => Tuple (LLVM.Value a) where
   setTupleFlags = setFlags


newtype Context flags a = Context a

proxyFromContext :: Context flags a -> Proxy flags
proxyFromContext (Context _) = Proxy

instance
   (Flags flags, Tuple.Zero a, Tuple a) =>
      Tuple.Zero (Context flags a) where
   zero = Context Tuple.zero

instance
   (Flags flags, Tuple a, A.Additive a) =>
      A.Additive (Context flags a) where
   zero = Context A.zero
   add = liftContext2 A.add
   sub = liftContext2 A.sub
   neg = liftContext A.neg

instance
   (Flags flags, A.PseudoRing a, Tuple a) =>
      A.PseudoRing (Context flags a) where
   mul = liftContext2 A.mul

type instance A.Scalar (Context flags a) = Context flags (A.Scalar a)

instance
   (Flags flags, A.PseudoModule v, Tuple v, A.Scalar v ~ a, Tuple a) =>
      A.PseudoModule (Context flags v) where
   scale = liftContext2 A.scale

instance
   (Flags flags, Tuple a, A.IntegerConstant a) =>
      A.IntegerConstant (Context flags a) where
   fromInteger' = Context . A.fromInteger'

instance
   (Flags flags, Tuple v, A.Field v) =>
      A.Field (Context flags v) where
   fdiv = liftContext2 A.fdiv

instance
   (Flags flags, Tuple a, A.RationalConstant a) =>
      A.RationalConstant (Context flags a) where
   fromRational' = Context . A.fromRational'

instance (Flags flags, Tuple a, A.Real a) => A.Real (Context flags a) where
   min = liftContext2 A.min
   max = liftContext2 A.max
   abs = liftContext A.abs
   signum = liftContext A.signum

instance
   (Flags flags, Tuple a, A.Fraction a) =>
      A.Fraction (Context flags a) where
   truncate = liftContext A.truncate
   fraction = liftContext A.fraction

instance
   (Flags flags, Tuple a, A.Comparison a) =>
      A.Comparison (Context flags a) where
   type CmpResult (Context flags a) = A.CmpResult a
   cmp p (Context x) (Context y) = A.cmp p x y

instance
   (Flags flags, Tuple a, A.FloatingComparison a) =>
      A.FloatingComparison (Context flags a) where
   fcmp p (Context x) (Context y) = A.fcmp p x y

instance
   (Flags flags, Tuple a, A.Algebraic a) =>
      A.Algebraic (Context flags a) where
   sqrt = liftContext A.sqrt

instance
   (Flags flags, Tuple a, A.Transcendental a) =>
      A.Transcendental (Context flags a) where
   pi = attachTupleFlags A.pi
   sin = liftContext A.sin
   cos = liftContext A.cos
   exp = liftContext A.exp
   log = liftContext A.log
   pow = liftContext2 A.pow


attachTupleFlags ::
   (Flags flags, Tuple a) =>
   Id (LLVM.CodeGenFunction r (Context flags a))
attachTupleFlags act = do
   c@(Context x) <- act
   setTupleFlags (proxyFromContext c) True x
   return c

liftContext :: (Flags flags, Tuple b) =>
   (a -> LLVM.CodeGenFunction r b) ->
   Context flags a -> LLVM.CodeGenFunction r (Context flags b)
liftContext f (Context x) = attachTupleFlags (Context <$> f x)

liftContext2 :: (Flags flags, Tuple c) =>
   (a -> b -> LLVM.CodeGenFunction r c) ->
   Context flags a -> Context flags b ->
   LLVM.CodeGenFunction r (Context flags c)
liftContext2 f (Context x) = liftContext $ f x