packages feed

llvm-dsl-0.1.2: src/LLVM/DSL/Example/Median.hs

module LLVM.DSL.Example.Median where

import qualified LLVM.DSL.Expression as Expr
import LLVM.DSL.Expression (Exp, (==*), (<=*), (&&*), (||*))

import qualified LLVM.Extra.Multi.Vector as MVec
import qualified LLVM.Extra.Multi.Value as MV

import qualified LLVM.Core as LLVM

import Data.Tuple.HT (uncurry3)
import Data.Word (Word8)



median3IfThen :: (MV.Comparison a) => Exp a -> Exp a -> Exp a -> Exp a
median3IfThen a b c =
   Expr.ifThenElse (a<=*b)
      (Expr.ifThenElse (b<=*c)
         b
         (Expr.ifThenElse (a<=*c) c a))
      (Expr.ifThenElse (a<=*c)
         a
         (Expr.ifThenElse (b<=*c) c b))

median3Select ::
   (MV.Comparison a, MV.Select a) => Exp a -> Exp a -> Exp a -> Exp a
median3Select a b c =
   Expr.select (a<=*b)
      (Expr.select (b<=*c)
         b
         (Expr.select (a<=*c) c a))
      (Expr.select (a<=*c)
         a
         (Expr.select (b<=*c) c b))

median3SelectShared ::
   (MV.Comparison a, MV.Select a) => Exp a -> Exp a -> Exp a -> Exp a
median3SelectShared a b c =
   Expr.with (a<=*b) $ \a_le_b ->
   Expr.with (b<=*c) $ \b_le_c ->
   Expr.with (a<=*c) $ \a_le_c ->
   Expr.select a_le_b
      (Expr.select b_le_c b (Expr.select a_le_c c a))
      (Expr.select a_le_c a (Expr.select b_le_c c b))

median3MinMax ::
   (MV.Comparison a, MV.Select a) => Exp a -> Exp a -> Exp a -> Exp a
median3MinMax a b c =
   let minab = Expr.min a b in
   let maxab = Expr.max a b in
   Expr.select (maxab <=* c) maxab $ Expr.select (minab <=* c) c minab

median3MinMaxVector ::
   (LLVM.Positive n, MVec.C a) =>
   (MV.Comparison a, MV.Select a) =>
   MVec.T n a -> MVec.T n a -> MVec.T n a ->
   LLVM.CodeGenFunction r (MVec.T n a)
median3MinMaxVector a b c =
   MVec.map (uncurry3 (Expr.unliftM3 median3MinMax) . MV.unzip3) $
   MVec.zip3 a b c


type MV = MV.T

median3Case ::
   (MV.Comparison a, MV.Select a) =>
   MV a -> MV a -> MV a -> LLVM.CodeGenFunction r (MV a)
median3Case a b c = do
   a_le_b <- MV.cmp LLVM.CmpLE a b
   a_le_c <- MV.cmp LLVM.CmpLE a c
   b_le_c <- MV.cmp LLVM.CmpLE b c
   let mask = MV.fromInteger'
   a_le_b_mask <- MV.select a_le_b (mask 1) (mask 0)
   a_le_c_mask <- MV.select a_le_c (mask 2) (mask 0)
   b_le_c_mask <- MV.select b_le_c (mask 4) (mask 0)
   maskMV <- MV.or a_le_b_mask =<< MV.or a_le_c_mask b_le_c_mask
   let maskE = Expr.lift0 (maskMV :: MV Word8)
   selectB <- Expr.unExp (maskE ==* 0 ||* maskE ==* 7)
   selectA <- Expr.unExp (maskE ==* 1 ||* maskE ==* 6)
   MV.select selectA a =<< MV.select selectB b c

median3CaseVec ::
   (MV.Comparison a, MV.Select a) =>
   MV a -> MV a -> MV a -> LLVM.CodeGenFunction r (MV a)
median3CaseVec a b c = do
   a_le_b <- MV.cmp LLVM.CmpLE a b
   a_le_c <- MV.cmp LLVM.CmpLE a c
   b_le_c <- MV.cmp LLVM.CmpLE b c
   let check ab ac bc =
         Expr.select (Expr.lift0 a_le_b) 1 0 ==* (ab :: Exp Word8)
         &&*
         Expr.select (Expr.lift0 a_le_c) 1 0 ==* (ac :: Exp Word8)
         &&*
         Expr.select (Expr.lift0 b_le_c) 1 0 ==* (bc :: Exp Word8)
   selectB <- Expr.unExp (check 0 0 0 ||* check 1 1 1)
   selectA <- Expr.unExp (check 1 0 0 ||* check 0 1 1)
   MV.select selectA a =<< MV.select selectB b c