module Synthesizer.LLVM.Random where
import qualified LLVM.Extra.ScalarOrVector as SoV
import qualified LLVM.Extra.Vector as Vector
import qualified LLVM.Extra.Extension.X86 as X86
import qualified LLVM.Extra.Extension as Ext
import qualified LLVM.Extra.Arithmetic as A
import LLVM.Core as LLVM
import qualified Data.TypeLevel.Num as TypeNum
import Data.Function.HT (nest, )
import Data.Word (Word32, Word64, )
factor :: Integral a => a
factor = 40692
modulus :: Integral a => a
modulus = 2147483399
split :: Word32
split = succ $ div modulus factor
splitRem :: Word32
splitRem = split * factor modulus
next :: Word32 -> Word32
next s =
let (sHigh, sLow) = divMod s split
in flip mod modulus $
splitRem*sHigh + factor*sLow
next64 :: Word32 -> Word32
next64 s =
fromIntegral $
flip mod modulus $
factor * (fromIntegral s :: Word64)
nextCG32 :: Value Word32 -> CodeGenFunction r (Value Word32)
nextCG32 s = do
sHigh <- A.mul (valueOf splitRem) =<< udiv s split
sLow <- A.mul (valueOf factor) =<< urem s split
flip A.urem (valueOf modulus) =<< A.add sHigh sLow
nextCG64 :: Value Word32 -> CodeGenFunction r (Value Word32)
nextCG64 s =
trunc =<<
flip A.urem (valueOf (modulus :: Word64)) =<<
A.mul (valueOf factor) =<<
zext s
nextCG :: Value Word32 -> CodeGenFunction r (Value Word32)
nextCG s = do
x <- A.mul (valueOf $ factor :: Value Word64) =<< zext s
let p2e31 = 2^(31::Int)
low <- A.and (valueOf $ p2e311) =<< trunc x
high <- trunc =<< flip lshr (valueOf (31 :: Word64)) x
let fac = p2e31 modulus
prodMod <- A.add low =<< A.mul (valueOf fac) high
prodModS <- A.sub prodMod (valueOf modulus)
b <- A.icmp IntSLT prodModS (value zero)
select b prodMod prodModS
vectorParameter ::
Integral a =>
Int -> a
vectorParameter n =
fromIntegral $ nest n next 1
vectorSeed ::
(IsPowerOf2 n) =>
Word32 -> Vector n Word32
vectorSeed seed =
let n = Vector.size $ valueOf v
v = vector $ take n $ iterate next seed
in v
vector64 :: Value (Vector n Word64) -> Value (Vector n Word64)
vector64 = id
nextVector ::
(IsPowerOf2 n) =>
Value (Vector n Word32) ->
CodeGenFunction r (Value (Vector n Word32))
nextVector s =
Ext.run (nextVectorGeneric s) $
Ext.with nextVector4X86 $ \nextChunk ->
Vector.mapChunks (nextChunk (Vector.size s)) s
nextVector4X86 ::
Ext.T
(Int ->
Value (Vector TypeNum.D4 Word32) ->
CodeGenFunction r (Value (Vector TypeNum.D4 Word32)))
nextVector4X86 =
Ext.with X86.pmuludq $ \muludq n s -> do
let prepConstFactor x =
value $ constVector [constOf x, undef]
fac = 2^(31::Int) modulus
mulAndReduce x = do
(low0, high0) <-
splitVector31to64 =<<
muludq (prepConstFactor (vectorParameter n)) x
splitVector31to64 =<<
A.add low0 =<<
muludq (prepConstFactor fac) =<<
bitcast high0
(lowEven, highEven) <-
mulAndReduce =<<
shufflevector s (value undef)
(constVector [constOf 0, undef, constOf 2, undef])
(lowOdd, highOdd) <-
mulAndReduce =<<
shufflevector s (value undef)
(constVector [constOf 1, undef, constOf 3, undef])
low <- truncAndInterleave2x64to4x32 lowEven lowOdd
high <- truncAndInterleave2x64to4x32 highEven highOdd
prodMod <-
A.add low =<<
Vector.mul (SoV.replicateOf fac) high
prodModS <- A.sub prodMod (SoV.replicateOf modulus)
Vector.min prodModS prodMod
truncAndInterleave2x64to4x32 ::
Value (Vector TypeNum.D2 Word64) ->
Value (Vector TypeNum.D2 Word64) ->
CodeGenFunction r (Value (Vector TypeNum.D4 Word32))
truncAndInterleave2x64to4x32 even2x64 odd2x64 = do
even4x32 <- bitcast even2x64
odd4x32 <- bitcast odd2x64
LLVM.shufflevector even4x32 odd4x32
(constVector [constOf 0, constOf 4, constOf 2, constOf 6])
nextVector2X86 ::
Ext.T
(Int ->
Value (Vector TypeNum.D2 Word32) ->
CodeGenFunction r (Value (Vector TypeNum.D2 Word32)))
nextVector2X86 =
Ext.with X86.pmuludq $ \muludq n s -> do
let prepConstFactor x =
value $ constVector [constOf x, undef]
(low0, high0) <-
splitVector31to64 =<<
muludq (prepConstFactor (vectorParameter n)) =<<
Vector.shuffle s
(constVector [constOf 0, undef, constOf 1, undef])
let fac = 2^(31::Int) modulus
(low1, high1) <-
splitVector31to64 =<<
A.add low0 =<<
muludq (prepConstFactor fac) =<<
bitcast high0
prodMod64 <-
A.add low1 =<<
muludq (prepConstFactor fac) =<<
bitcast high1
prodMod <- bitcast prodMod64
prodModS <- A.sub prodMod (prepConstFactor modulus)
result <- Vector.min prodModS prodMod
Vector.shuffle
(result :: Value (Vector TypeNum.D4 Word32))
(constVector $ map constOf [0,2])
splitVector31to64 ::
(IsPowerOf2 n) =>
Value (Vector n Word64) ->
CodeGenFunction r (Value (Vector n Word64), Value (Vector n Word64))
splitVector31to64 x = do
low <- A.and (SoV.replicateOf (2^(31::Int)1)) x
high <- flip lshr (SoV.replicateOf 31 `asTypeOf` x) x
return (low, high)
nextVectorGeneric ::
(IsPowerOf2 n) =>
Value (Vector n Word32) ->
CodeGenFunction r (Value (Vector n Word32))
nextVectorGeneric s = do
(low0, high0) <-
splitVector31 =<<
Vector.umul32to64 (SoV.replicateOf (vectorParameter (Vector.size s))) s
let fac :: Integral a => a
fac = 2^(31::Int) modulus
(low1, high1) <-
splitVector31 =<<
(\x -> A.add x =<< Vector.map zext low0) =<<
Vector.umul32to64 (SoV.replicateOf fac) high0
prodMod <-
A.add low1 =<<
Vector.mul (SoV.replicateOf fac) high1
prodModS <- A.sub prodMod (SoV.replicateOf modulus)
Vector.min prodModS prodMod
selectNonNegativeGeneric ::
(IsPowerOf2 n) =>
Value (Vector n Word32) ->
Value (Vector n Word32) ->
CodeGenFunction r (Value (Vector n Word32))
selectNonNegativeGeneric x y = do
b <- A.icmp IntSGE x (value zero)
Vector.select b x y
splitVector31 ::
(IsPowerOf2 n) =>
Value (Vector n Word64) ->
CodeGenFunction r (Value (Vector n Word32), Value (Vector n Word32))
splitVector31 x = do
low <- A.and (SoV.replicateOf (2^(31::Int)1)) =<< Vector.map trunc x
high <- Vector.map trunc =<< flip lshr (SoV.replicateOf (31 :: Word64) `asTypeOf` x) x
return (low, high)
nextVector64 ::
(IsPowerOf2 n) =>
Value (Vector n Word32) ->
CodeGenFunction r (Value (Vector n Word32))
nextVector64 s =
Vector.map trunc =<<
flip A.urem (SoV.replicateOf modulus) =<<
Vector.umul32to64 (SoV.replicateOf (vectorParameter (Vector.size s))) s