module Feldspar.Core.Constructs.Bits
( BITS (..)
) where
import Data.Typeable
import Language.Syntactic
import Language.Syntactic.Constructs.Literal
import Language.Syntactic.Constructs.Binding
import Feldspar.Range
import Feldspar.Core.Types
import Feldspar.Core.Interpretation
import Feldspar.Core.Constructs.Logic
import Feldspar.Core.Constructs.Eq
import Feldspar.Core.Constructs.Ord
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
import Data.Bits
#else
import Data.Bits
type FiniteBits b = Bits b
#endif
data BITS a
where
BAnd :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> a :-> Full a)
BOr :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> a :-> Full a)
BXor :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> a :-> Full a)
Complement :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Full a)
Bit :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (Index :-> Full a)
SetBit :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Index :-> Full a)
ClearBit :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Index :-> Full a)
ComplementBit :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Index :-> Full a)
TestBit :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Index :-> Full Bool)
ShiftLU :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Index :-> Full a)
ShiftRU :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Index :-> Full a)
ShiftL :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> IntN :-> Full a)
ShiftR :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> IntN :-> Full a)
RotateLU :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Index :-> Full a)
RotateRU :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Index :-> Full a)
RotateL :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> IntN :-> Full a)
RotateR :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> IntN :-> Full a)
ReverseBits :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Full a)
BitScan :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Full Index)
BitCount :: (Type a, Bits a, BoundedInt a, Size a ~ Range a) => BITS (a :-> Full Index)
instance Semantic BITS
where
semantics BAnd = Sem "(.&.)" (.&.)
semantics BOr = Sem "(.|.)" (.|.)
semantics BXor = Sem "xor" xor
semantics Complement = Sem "complement" complement
semantics Bit = Sem "bit" (bit . fromIntegral)
semantics SetBit = Sem "setBit" (liftIntWord setBit)
semantics ClearBit = Sem "clearBit" (liftIntWord clearBit)
semantics ComplementBit = Sem "complementBit" (liftIntWord complementBit)
semantics TestBit = Sem "testBit" (liftIntWord testBit)
semantics ShiftLU = Sem "shiftLU" (liftIntWord shiftL)
semantics ShiftRU = Sem "shiftRU" (liftIntWord shiftR)
semantics ShiftL = Sem "shiftL" (liftInt shiftL)
semantics ShiftR = Sem "shiftR" (liftInt shiftR)
semantics RotateLU = Sem "rotateLU" (liftIntWord rotateL)
semantics RotateRU = Sem "rotateRU" (liftIntWord rotateR)
semantics RotateL = Sem "rotateL" (liftInt rotateL)
semantics RotateR = Sem "rotateR" (liftInt rotateR)
semantics ReverseBits = Sem "reverseBits" evalReverseBits
semantics BitScan = Sem "bitScan" evalBitScan
semantics BitCount = Sem "bitCount" evalBitCount
liftIntWord :: (a -> Int -> b) -> (a -> WordN -> b)
liftIntWord f x = f x . fromIntegral
liftInt :: (a -> Int -> b) -> (a -> IntN -> b)
liftInt f x = f x . fromIntegral
evalReverseBits :: (Num b, FiniteBits b) => b -> b
evalReverseBits b = revLoop b 0 (0 `asTypeOf` b)
where
bSz = finiteBitSize b
revLoop x i n | i >= bSz = n
| testBit x i = revLoop x (i+1) (setBit n (bSz i 1))
| otherwise = revLoop x (i+1) n
evalBitScan :: (FiniteBits b) => b -> WordN
evalBitScan b =
if isSigned b
then scanLoop b (testBit b (finiteBitSize b 1)) (finiteBitSize b 2) 0
else scanLoop b False (finiteBitSize b 1) 0
where
scanLoop x t i n | i Prelude.< 0 = n
| testBit x i Prelude./= t = n
| otherwise = scanLoop x t (i1) (n+1)
evalBitCount :: (FiniteBits b) => b -> WordN
evalBitCount b = loop b (finiteBitSize b 1) 0
where
loop x i n | i Prelude.< 0 = n
| testBit x i = loop x (i1) (n+1)
| otherwise = loop x (i1) n
semanticInstances ''BITS
instance EvalBind BITS where evalBindSym = evalBindSymDefault
instance AlphaEq dom dom dom env => AlphaEq BITS BITS dom env
where
alphaEqSym = alphaEqSymDefault
instance Sharable BITS
instance Monotonic BITS where
monotonicInc _ _ = []
monotonicDec ShiftRU (a :* b :* Nil)
| RangeSet r <- infoRange $ getInfo b
, isNatural r
= [a]
monotonicDec _ _ = []
instance SizeProp (BITS :|| Type)
where
sizeProp (C' BAnd) (WrapFull a :* WrapFull b :* Nil) = rangeAnd (infoSize a) (infoSize b)
sizeProp (C' BOr) (WrapFull a :* WrapFull b :* Nil) = rangeOr (infoSize a) (infoSize b)
sizeProp (C' BXor) (WrapFull a :* WrapFull b :* Nil) = rangeXor (infoSize a) (infoSize b)
sizeProp (C' ShiftLU) (WrapFull a :* WrapFull b :* Nil) = rangeShiftLU (infoSize a) (infoSize b)
sizeProp (C' ShiftRU) (WrapFull a :* WrapFull b :* Nil) = rangeShiftRU (infoSize a) (infoSize b)
sizeProp (C' Complement) (WrapFull a :* Nil) = rangeComplement (infoSize a)
sizeProp a@(C' _) args = sizePropDefault a args
instance ( (BITS :|| Type) :<: dom
, (Logic :|| Type) :<: dom
, (EQ :|| Type) :<: dom
, (ORD :|| Type) :<: dom
, Monotonic dom
, OptimizeSuper dom
)
=> Optimize (BITS :|| Type) dom
where
constructFeatOpt _ (C' BAnd) (a :* b :* Nil)
| Just 0 <- viewLiteral a = return a
| Just x <- viewLiteral a, isAllOnes x = return b
| Just 0 <- viewLiteral b = return b
| Just x <- viewLiteral b, isAllOnes x = return a
constructFeatOpt _ (C' BOr) (a :* b :* Nil)
| Just 0 <- viewLiteral a = return b
| Just x <- viewLiteral a, isAllOnes x = return a
| Just 0 <- viewLiteral b = return a
| Just x <- viewLiteral b, isAllOnes x = return b
constructFeatOpt opts (C' BXor) (a :* b :* Nil)
| Just 0 <- viewLiteral a = return b
| Just x <- viewLiteral a, isAllOnes x = constructFeat opts (c' Complement) (b :* Nil)
| Just 0 <- viewLiteral b = return a
| Just x <- viewLiteral b, isAllOnes x = constructFeat opts (c' Complement) (a :* Nil)
constructFeatOpt _ (C' BXor) ((xo :$ v1 :$ v2) :* v3 :* Nil)
| Just (C' BXor) <- prjF xo
, alphaEq v2 v3
= return v1
constructFeatOpt _ (C' Complement) ((cmpl :$ a) :* Nil)
| Just (C' Complement) <- prjF cmpl
= return a
constructFeatOpt opts (C' TestBit) ((xo :$ v1 :$ v2) :* v3 :* Nil)
| Just (C' BXor) <- prjF xo
, Just a <- viewLiteral v2
, Just b <- viewLiteral v3
, a == 2 ^ b
= do tb <- constructFeat opts (c' TestBit) (v1 :* v3 :* Nil)
constructFeat opts (c' Not) (tb :* Nil)
constructFeatOpt opts x@(C' ShiftRU) ((op :$ a :$ b) :* c :* Nil)
| Just (C' ShiftRU) <- prjF op
, Just i <- viewLiteral a
, Just j <- viewLiteral c
= constructFeat opts x (literalDecor (i `shiftR` fromIntegral j) :* b :* Nil)
constructFeatOpt opts x@(C' ShiftLU) args = optZero opts x args
constructFeatOpt opts x@(C' ShiftRU) args = optZero opts x args
constructFeatOpt opts x@(C' ShiftL) args = optZero opts x args
constructFeatOpt opts x@(C' ShiftR) args = optZero opts x args
constructFeatOpt opts x@(C' RotateLU) args = optZero opts x args
constructFeatOpt opts x@(C' RotateRU) args = optZero opts x args
constructFeatOpt opts x@(C' RotateL) args = optZero opts x args
constructFeatOpt opts x@(C' RotateR) args = optZero opts x args
constructFeatOpt opts feat args = constructFeatUnOpt opts feat args
constructFeatUnOpt opts x@(C' _) = constructFeatUnOptDefault opts x
isAllOnes :: (Num a, Bits a) => a -> Bool
isAllOnes x = x Prelude.== complement 0
optZero :: ( Eq b, Num b
, (Literal :|| Type) :<: dom
, Typeable a
, Optimize feature dom
)
=> FeldOpts -> feature (a :-> (b :-> Full a))
-> Args (AST (Decor Info (dom :|| Typeable))) (a :-> (b :-> Full a))
-> Opt (AST (Decor Info (dom :|| Typeable)) (Full a))
optZero opts f (a :* b :* Nil)
| Just 0 <- viewLiteral b = return a
| otherwise = constructFeatUnOpt opts f (a :* b :* Nil)