module Data.AIG.Operations
(
BV
, empty
, length
, at
, (!)
, (++)
, concat
, take
, drop
, slice
, sliceRev
, mapM
, zipWith
, zipWithM
, msb
, lsb
, bvSame
, bvShow
, generateM_msb0
, generate_msb0
, generateM_lsb0
, generate_lsb0
, replicate
, replicateM
, bvFromInteger
, bvFromList
, muxInteger
, singleton
, lAnd
, lAnd'
, lOr
, lOr'
, lXor
, lXor'
, lEq
, lEq'
, lNot
, lNot'
, ite
, iteM
, asUnsigned
, asSigned
, bvToList
, neg
, add
, addC
, sub
, subC
, addConst
, subConst
, mul
, mulFull
, smulFull
, squot
, srem
, uquot
, urem
, shl
, sshr
, ushr
, rol
, ror
, bvEq
, isZero
, nonZero
, sle
, slt
, ule
, ult
, sabs
, sext
, zext
, trunc
, zeroIntCoerce
, signIntCoerce
, pmul
, pmod
) where
import Control.Applicative hiding (empty)
import Control.Exception
import qualified Control.Monad
import Control.Monad.State hiding (zipWithM, replicateM, mapM)
import Data.Bits ((.|.), setBit, shiftL, testBit)
import qualified Data.Vector as V
import qualified Data.Vector.Generic.Mutable as MV
import Prelude hiding (and, concat, length, not, or, replicate, splitAt, tail, (++), take, drop, zipWith, mapM)
import qualified Prelude
import Data.AIG.Interface
newtype BV l = BV { unBV :: V.Vector l }
deriving (Eq, Ord, Show)
instance Functor BV where
fmap f (BV v) = BV (f <$> v)
empty :: BV l
empty = BV V.empty
length :: BV l -> Int
length (BV v) = V.length v
tail :: BV l -> BV l
tail (BV v) = BV (V.tail v)
generate_lsb0
:: Int
-> (Int -> l)
-> BV l
generate_lsb0 c f = BV (V.reverse (V.generate c f))
generateM_lsb0
:: MonadIO m
=> Int
-> (Int -> m l)
-> m (BV l)
generateM_lsb0 c f = do
mv <- liftIO (MV.new c)
let buildVec i | i >= c = liftIO (V.unsafeFreeze mv) >>= return . BV
| otherwise = (f i >>= liftIO . MV.unsafeWrite mv (ci1)) >> (buildVec $! (i+1))
buildVec 0
generateM_scan_lsb0
:: MonadIO m
=> Int
-> (Int -> a -> m (l,a))
-> a
-> m (BV l, a)
generateM_scan_lsb0 c f a0 = do
mv <- liftIO (MV.new c)
let buildVec i a | i >= c = liftIO (V.unsafeFreeze mv) >>= \v -> return (BV v, a)
| otherwise = do (x,a') <- f i a
liftIO (MV.unsafeWrite mv (ci1) x)
(buildVec $! (i+1)) a'
buildVec 0 a0
generate_msb0
:: Int
-> (Int -> l)
-> BV l
generate_msb0 c f = BV (V.generate c f)
generateM_msb0
:: Monad m
=> Int
-> (Int -> m l)
-> m (BV l)
generateM_msb0 c f = return . BV =<< V.generateM c f
replicate
:: Int
-> l
-> BV l
replicate c e = BV (V.replicate c e)
replicateM
:: Monad m
=> Int
-> m l
-> m (BV l)
replicateM c e = return . BV =<< V.replicateM c e
singleton :: l -> BV l
singleton = BV . V.singleton
at :: BV l -> Int -> l
at (BV v) i = v V.! i
(++) :: BV l -> BV l -> BV l
BV x ++ BV y = BV (x V.++ y)
concat :: [BV l] -> BV l
concat v = BV (V.concat (unBV <$> v))
take :: Int -> BV l -> BV l
take i (BV v) = BV (V.take i v)
drop :: Int -> BV l -> BV l
drop i (BV v) = BV (V.drop i v)
slice :: BV l
-> Int
-> Int
-> BV l
slice (BV v) i n = BV (V.slice i n v)
sliceRev
:: BV l
-> Int
-> Int
-> BV l
sliceRev (BV v) i n = BV (V.slice i' n v)
where i' = V.length v i n
mapM :: Monad m => (a -> m b) -> BV a -> m (BV b)
mapM f (BV x) = V.mapM f x >>= return . BV
zipWith :: (l -> l -> l) -> BV l -> BV l -> BV l
zipWith f (BV x) (BV y) = assert (V.length x == V.length y) $ BV $ V.zipWith f x y
zipWithM :: Monad m => (l -> l -> m l) -> BV l -> BV l -> m (BV l)
zipWithM f (BV x) (BV y) = assert (V.length x == V.length y) $ V.zipWithM f x y >>= return . BV
bvToList :: BV l -> [l]
bvToList (BV v) = V.toList v
bvFromList :: [l] -> BV l
bvFromList xs = BV (V.fromList xs)
(!) :: BV l -> Int -> l
(!) v i = v `at` (length v 1 i)
bvShow :: IsAIG l g => g s -> BV (l s) -> String
bvShow g v = map f $ bvToList v
where f x | x === trueLit g = '1'
| x === falseLit g = '0'
| otherwise = 'x'
bvFromInteger
:: IsAIG l g
=> g s
-> Int
-> Integer
-> BV (l s)
bvFromInteger g n v = generate_msb0 n $ \i -> constant g (v `testBit` (ni1))
asUnsigned :: IsAIG l g => g s -> BV (l s) -> Maybe Integer
asUnsigned g v = go 0 0
where n = length v
go x i | i >= n = return x
go x i = do
b <- asConstant g (v `at` i)
let y = if b then 1 else 0
let z = (x `shiftL` 1) .|. y
seq z $ go z (i+1)
asSigned :: IsAIG l g => g s -> BV (l s) -> Maybe Integer
asSigned g v = assert (n > 0) $ (signfix =<< asUnsigned g (drop 1 v))
where n = length v
signfix x
| msb v === trueLit g = Just (x 2^(n1))
| msb v === falseLit g = Just x
| otherwise = Nothing
msb :: BV l -> l
msb v = v `at` 0
lsb :: BV l -> l
lsb v = v ! 0
ite
:: IsAIG l g
=> g s
-> l s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s))
ite g c x y = zipWithM (mux g c) x y
iteM
:: IsAIG l g
=> g s
-> l s
-> IO (BV (l s))
-> IO (BV (l s))
-> IO (BV (l s))
iteM g c x y
| c === trueLit g = x
| c === falseLit g = y
| otherwise = join $ zipWithM (mux g c) <$> x <*> y
lNot :: IsAIG l g => g s -> IO (l s) -> IO (l s)
lNot g = fmap (lNot' g)
lNot' :: IsAIG l g => g s -> l s -> l s
lNot' g x | x === trueLit g = falseLit g
| x === falseLit g = trueLit g
| otherwise = not x
lOr :: IsAIG l g => g s -> IO (l s) -> IO (l s) -> IO (l s)
lOr g x y = lNot g (lAnd g (lNot g x) (lNot g y))
lOr' :: IsAIG l g => g s -> l s -> l s -> IO (l s)
lOr' g x y = lNot g (lAnd' g (lNot' g x) (lNot' g y))
lEq :: IsAIG l g => g s -> IO (l s) -> IO (l s) -> IO (l s)
lEq g x y = lNot g (lXor g x y)
lEq' :: IsAIG l g => g s -> l s -> l s -> IO (l s)
lEq' g x y = lNot g (lXor' g x y)
lAnd :: IsAIG l g => g s -> IO (l s) -> IO (l s) -> IO (l s)
lAnd g x y = do
x' <- x
if x' === trueLit g then y
else if x' === falseLit g then return (falseLit g)
else do
y' <- y
if y' === trueLit g then return x'
else if y' === falseLit g then return (falseLit g)
else and g x' y'
lAnd'' :: IsAIG l g => g s -> l s -> IO (l s) -> IO (l s)
lAnd'' g x y =
if x === trueLit g then y
else if x === falseLit g then return (falseLit g)
else do
y' <- y
if y' === trueLit g then return x
else if y' === falseLit g then return (falseLit g)
else and g x y'
lAnd' :: IsAIG l g => g s -> l s -> l s -> IO (l s)
lAnd' g x y =
if x === trueLit g then return y
else if x === falseLit g then return (falseLit g)
else if y === trueLit g then return x
else if y === falseLit g then return (falseLit g)
else and g x y
lXor' :: IsAIG l g => g s -> l s -> l s -> IO (l s)
lXor' g x y =
if x === trueLit g then return (not y)
else if x === falseLit g then return y
else if y === trueLit g then return (not x)
else if y === falseLit g then return x
else xor g x y
lXor :: IsAIG l g => g s -> IO (l s) -> IO (l s) -> IO (l s)
lXor g x y = do
x' <- x
y' <- y
if x' === trueLit g then return (not y')
else if x' === falseLit g then return y'
else if y' === trueLit g then return (not x')
else if y' === falseLit g then return x'
else xor g x' y'
halfAdder :: IsAIG l g => g s -> l s -> l s -> IO (l s, l s)
halfAdder g b c = do
c_out <- lAnd' g b c
s <- lAnd'' g (not c_out) (lOr' g b c)
return (s, c_out)
fullAdder :: IsAIG l g => g s -> l s -> l s -> l s -> IO (l s, l s)
fullAdder g a b c_in = do
s <- lXor' g c_in =<< lXor' g a b
c_out <- lOr g (lAnd' g a b) (lAnd'' g c_in (lXor' g a b))
return (s, c_out)
ripple_add :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s), l s)
ripple_add g x _ | length x == 0 = return (x, falseLit g)
ripple_add g x y = do
let unfold i = fullAdder g (x!i) (y!i)
generateM_scan_lsb0 (length x) unfold (falseLit g)
fullSub :: IsAIG l g => g s -> l s -> l s -> l s -> IO (l s, l s)
fullSub g x y b_in = do
s <- lEq' g x =<< (lEq' g y b_in)
b_out <- lOr g (lAnd' g y b_in) (lAnd'' g (not x) (lOr' g y b_in))
return (s, b_out)
ripple_sub :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s), l s)
ripple_sub g x _ | length x == 0 = return (x,falseLit g)
ripple_sub g x y = do
let unfold i = fullSub g (x ! i) (y ! i)
generateM_scan_lsb0 (length x) unfold (falseLit g)
ripple_sub_borrow :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (l s)
ripple_sub_borrow g x y = go 0 (falseLit g)
where n = length x
go i b | i >= n = return b
| otherwise = (go $! (i+1)) =<<
(lOr g (lAnd' g b (y!i))
(lAnd'' g (lNot' g (x!i)) (lOr' g (y!i) b))
)
neg :: IsAIG l g => g s -> BV (l s) -> IO (BV (l s))
neg g x = evalStateT (generateM_lsb0 (length x) unfold) (trueLit g)
where unfold i = StateT $ halfAdder g (lNot' g (x ! i))
add :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
add g x y = fst <$> addC g x y
addC :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s), l s)
addC g x y = assert (length x == length y) $ ripple_add g x y
sub :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
sub g x y = fst <$> subC g x y
subC :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s), l s)
subC g x y = assert (length x == length y) $ ripple_sub g x y
addConst :: IsAIG l g => g s -> BV (l s) -> Integer -> IO (BV (l s))
addConst g x y = do
let n = length x
m <- MV.new n
let adderStepM c i
| i == n = return ()
| otherwise = do
let a = x ! i
let b = y `testBit` i
ac <- lAnd' g a c
negAnegC <- lAnd' g (lNot' g a) (lNot' g c)
aEqC <- lOr' g ac negAnegC
if b
then do
MV.write m (ni1) aEqC
adderStepM (lNot' g negAnegC) (i+1)
else do
MV.write m (ni1) (lNot' g aEqC)
adderStepM ac (i+1)
adderStepM (falseLit g) 0
fmap BV $ V.freeze m
subConst :: IsAIG l g => g s -> BV (l s) -> Integer -> IO (BV (l s))
subConst g x c = addConst g x (c)
mul :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
mul g x y = assert (length x == length y) $ do
let n = length y
let updateBits i z | i == n = return z
updateBits i z = do
z' <- iteM g (y ! i) (add g z (shlC g x i)) (return z)
updateBits (i+1) z'
updateBits 0 $ replicate (length x) (falseLit g)
mulFull :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
mulFull g x y =
let len = length x + length y
x' = zext g x len
y' = zext g y len
in mul g x' y'
smulFull :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
smulFull g x y = do
let len = length x + length y
x' = sext g x len
y' = sext g y len
in mul g x' y'
squot :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
squot g x y = fst <$> squotRem g x y
srem :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
srem g x y = snd <$> squotRem g x y
shiftL1 :: BV l -> l -> BV l
shiftL1 (BV v) e = assert (V.length v > 0) $ BV (V.tail v `V.snoc` e)
splitAt :: Int -> BV l -> (BV l, BV l)
splitAt n (BV v) = (BV x, BV y)
where (x,y) = V.splitAt n v
sabs :: IsAIG l g => g s -> BV (l s) -> IO (BV (l s))
sabs g x = assert (length x > 0) $ negWhen g x (msb x)
negWhen :: IsAIG l g => g s -> BV (l s) -> l s -> IO (BV (l s))
negWhen g x c = iteM g c (neg g x) (return x)
uquotRem :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s), BV (l s))
uquotRem g dividend divisor = do
let n = length dividend
assert (n == length divisor) $ do
let initial = zext g dividend (2*n)
let divStep i p rr | i == n = return (q `shiftL1` p, r)
where (r,q) = splitAt n rr
divStep i p rr = do
let rs = rr `shiftL1` p
let (r,q) = splitAt n rs
(s,b) <- ripple_sub g r divisor
divStep (i+1) (lNot' g b) =<< ite g b rs (s ++ q)
divStep 0 (falseLit g) initial
squotRem :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s), BV (l s))
squotRem g dividend divisor =
assert (length dividend > 0 && length dividend == length divisor) $ do
let sign1 = msb dividend
let sign2 = msb divisor
signXor <- xor g sign1 sign2
dividend' <- negWhen g dividend sign1
divisor' <- negWhen g divisor sign2
(q,r) <- uquotRem g dividend' divisor'
q' <- negWhen g q signXor
r' <- negWhen g r sign1
return (q',r')
uquot :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
uquot g x y = fst <$> uquotRem g x y
urem :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
urem g x y = snd <$> uquotRem g x y
bvSame :: IsLit l => BV (l s) -> BV (l s) -> Bool
bvSame (BV x) (BV y) = assert (V.length x == V.length y) $ V.foldr (&&) True $ V.zipWith (===) x y
bvEq :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (l s)
bvEq g x y = assert (n == length y) $ go 0 (trueLit g)
where n = length x
go i r | i == n = return r
go i r = go (i+1) =<< and g r =<< eq g (x `at` i) (y `at` i)
isZero :: IsAIG l g => g s -> BV (l s) -> IO (l s)
isZero g (BV v) = V.foldM (\x y -> and g (lNot' g x) y) (trueLit g) v
nonZero :: IsAIG l g => g s -> BV (l s) -> IO (l s)
nonZero g bv = lNot g $ isZero g bv
ult :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (l s)
ult g x y = assert (length x == length y) $ ripple_sub_borrow g x y
ule :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (l s)
ule g x y = lNot g $ ult g y x
slt :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (l s)
slt g x y = assert (length x == length y) $ do
let xs = x `at` 0
let ys = y `at` 0
c0 <- and g xs (lNot' g ys)
c1 <- and g (lNot' g xs) ys
c2 <- and g (lNot' g c1) =<< ult g (tail x) (tail y)
or g c0 c2
sle :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (l s)
sle g x y = lNot g $ slt g y x
sext :: IsAIG l g => g s -> BV (l s) -> Int -> BV (l s)
sext _g v r = assert (r >= n && n > 0) $ replicate (r n) (msb v) ++ v
where n = length v
zext :: IsAIG l g => g s -> BV (l s) -> Int -> BV (l s)
zext g v r = assert (r >= n) $ replicate (r n) (falseLit g) ++ v
where n = length v
trunc :: Int -> BV (l s) -> BV (l s)
trunc w vx = assert (length vx >= w) $ drop (length vx w) vx
zeroIntCoerce :: IsAIG l g => g s -> Int -> BV (l s) -> BV (l s)
zeroIntCoerce g r t
| r > l = zext g t r
| r < l = trunc r t
| otherwise = t
where l = length t
signIntCoerce :: IsAIG l g => g s -> Int -> BV (l s) -> BV (l s)
signIntCoerce g r t
| r > l = sext g t r
| r < l = trunc r t
| otherwise = t
where l = length t
muxInteger :: (Integral i, Monad m)
=> (l -> m a -> m a -> m a)
-> i
-> BV l
-> (i -> m a)
-> m a
muxInteger mergeFn maxValue vx valueFn = impl (length vx) 0
where impl _ y | y >= toInteger maxValue = valueFn maxValue
impl 0 y = valueFn (fromInteger y)
impl i y = mergeFn (vx ! j) (impl j (y `setBit` j)) (impl j y)
where j = i 1
shl :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s))
shl g x y = muxInteger (iteM g) (length x) y (return . shlC g x)
shlC :: IsAIG l g => g s -> BV (l s) -> Int -> BV (l s)
shlC g x s0 = slice x j (nj) ++ replicate j (falseLit g)
where n = length x
j = min n s0
shrC :: l s -> BV (l s) -> Int -> BV (l s)
shrC c x s0 = replicate j c ++ slice x 0 (nj)
where n = length x
j = min n s0
sshr :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s))
sshr g x y = muxInteger (iteM g) (length x) y (return . shrC (msb x) x)
ushr :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s))
ushr g x y = muxInteger (iteM g) (length x) y (return . shrC (falseLit g) x)
rolC :: BV l -> Int -> BV l
rolC (BV x) i
| V.null x = BV x
| otherwise = BV (V.drop j x V.++ V.take j x)
where j = i `mod` V.length x
rorC :: BV l -> Int -> BV l
rorC x i = rolC x ( i)
rol :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s))
rol g x y = do
r <- urem g y (bvFromInteger g (length y) (toInteger (length x)))
muxInteger (iteM g) (length x 1) r (return . rolC x)
ror :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s))
ror g x y = do
r <- urem g y (bvFromInteger g (length y) (toInteger (length x)))
muxInteger (iteM g) (length x 1) r (return . rorC x)
pmul :: IsAIG l g
=> g s
-> BV (l s)
-> BV (l s)
-> IO (BV (l s))
pmul g x y = generateM_msb0 (max 0 (m + n 1)) coeff
where
m = length x
n = length y
coeff k = foldM (xor g) (falseLit g) =<<
sequence [ and g (at x i) (at y j) | i <- [0 .. k], let j = k i, i < m, j < n ]
pmod :: forall l g s. IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
pmod g x y = findmsb (bvToList y)
where
findmsb :: [l s] -> IO (BV (l s))
findmsb [] = return (replicate (length y 1) (falseLit g))
findmsb (c : cs)
| c === trueLit g = usemask cs
| c === falseLit g = findmsb cs
| otherwise = do
t <- usemask cs
f <- findmsb cs
zipWithM (mux g c) t f
usemask :: [l s] -> IO (BV (l s))
usemask m = do
rs <- go 0 p0 z0
return (zext g (bvFromList rs) (length y 1))
where
msize = Prelude.length m
p0 = Prelude.replicate (msize 1) (falseLit g) Prelude.++ [trueLit g]
z0 = Prelude.replicate msize (falseLit g)
next :: [l s] -> IO [l s]
next [] = return []
next (b : bs) = do
m' <- Prelude.mapM (and g b) m
let bs' = bs Prelude.++ [falseLit g]
Control.Monad.zipWithM (xor g) m' bs'
go :: Int -> [l s] -> [l s] -> IO [l s]
go i p acc
| i >= length x = return acc
| otherwise = do
px <- Prelude.mapM (and g (x ! i)) p
acc' <- Control.Monad.zipWithM (xor g) px acc
p' <- next p
go (i+1) p' acc'