{-# Language FlexibleContexts #-}
{-# Language TypeFamilies #-}
module Cryptol.Eval.Backend
( Backend(..)
, sDelay
, invalidIndex
, cryUserError
, cryNoPrimError
, FPArith2
, SRational(..)
, intToRational
, ratio
, rationalAdd
, rationalSub
, rationalNegate
, rationalMul
, rationalRecip
, rationalDivide
, rationalFloor
, rationalCeiling
, rationalTrunc
, rationalRoundAway
, rationalRoundToEven
, rationalEq
, rationalLessThan
, rationalGreaterThan
, iteRational
, ppRational
) where
import Control.Monad.IO.Class
import Data.Kind (Type)
import Data.Ratio ( (%), numerator, denominator )
import Cryptol.Eval.Monad
import Cryptol.TypeCheck.AST(Name)
import Cryptol.Utils.PP
invalidIndex :: Backend sym => sym -> Integer -> SEval sym a
invalidIndex sym = raiseError sym . InvalidIndex . Just
cryUserError :: Backend sym => sym -> String -> SEval sym a
cryUserError sym = raiseError sym . UserError
cryNoPrimError :: Backend sym => sym -> Name -> SEval sym a
cryNoPrimError sym = raiseError sym . NoPrim
{-# INLINE sDelay #-}
sDelay :: Backend sym => sym -> Maybe String -> SEval sym a -> SEval sym (SEval sym a)
sDelay sym msg m =
let msg' = maybe "" ("while evaluating "++) msg
retry = raiseError sym (LoopError msg')
in sDelayFill sym m retry
data SRational sym =
SRational
{ sNum :: SInteger sym
, sDenom :: SInteger sym
}
intToRational :: Backend sym => sym -> SInteger sym -> SEval sym (SRational sym)
intToRational sym x = SRational x <$> (integerLit sym 1)
ratio :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SRational sym)
ratio sym n d =
do pz <- bitComplement sym =<< intEq sym d =<< integerLit sym 0
assertSideCondition sym pz DivideByZero
pure (SRational n d)
rationalRecip :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)
rationalRecip sym (SRational a b) = ratio sym b a
rationalDivide :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
rationalDivide sym x y = rationalMul sym x =<< rationalRecip sym y
rationalFloor :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
rationalFloor sym (SRational n d) = intDiv sym n d
rationalCeiling :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
rationalCeiling sym r = intNegate sym =<< rationalFloor sym =<< rationalNegate sym r
rationalTrunc :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
rationalTrunc sym r =
do p <- rationalLessThan sym r =<< intToRational sym =<< integerLit sym 0
cr <- rationalCeiling sym r
fr <- rationalFloor sym r
iteInteger sym p cr fr
rationalRoundAway :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
rationalRoundAway sym r =
do p <- rationalLessThan sym r =<< intToRational sym =<< integerLit sym 0
half <- SRational <$> integerLit sym 1 <*> integerLit sym 2
cr <- rationalCeiling sym =<< rationalSub sym r half
fr <- rationalFloor sym =<< rationalAdd sym r half
iteInteger sym p cr fr
rationalRoundToEven :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
rationalRoundToEven sym r =
do lo <- rationalFloor sym r
hi <- intPlus sym lo =<< integerLit sym 1
diff <- rationalSub sym r =<< intToRational sym lo
half <- SRational <$> integerLit sym 1 <*> integerLit sym 2
ite (rationalLessThan sym diff half) (pure lo) $
ite (rationalGreaterThan sym diff half) (pure hi) $
ite (isEven lo) (pure lo) (pure hi)
where
isEven x =
do parity <- intMod sym x =<< integerLit sym 2
intEq sym parity =<< integerLit sym 0
ite x t e =
do x' <- x
case bitAsLit sym x' of
Just True -> t
Just False -> e
Nothing ->
do t' <- t
e' <- e
iteInteger sym x' t' e'
rationalAdd :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
rationalAdd sym (SRational a b) (SRational c d) =
do ad <- intMult sym a d
bc <- intMult sym b c
bd <- intMult sym b d
ad_bc <- intPlus sym ad bc
pure (SRational ad_bc bd)
rationalSub :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
rationalSub sym (SRational a b) (SRational c d) =
do ad <- intMult sym a d
bc <- intMult sym b c
bd <- intMult sym b d
ad_bc <- intMinus sym ad bc
pure (SRational ad_bc bd)
rationalNegate :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)
rationalNegate sym (SRational a b) =
do aneg <- intNegate sym a
pure (SRational aneg b)
rationalMul :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
rationalMul sym (SRational a b) (SRational c d) =
do ac <- intMult sym a c
bd <- intMult sym b d
pure (SRational ac bd)
rationalEq :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
rationalEq sym (SRational a b) (SRational c d) =
do ad <- intMult sym a d
bc <- intMult sym b c
intEq sym ad bc
normalizeSign :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)
normalizeSign sym (SRational a b) =
do p <- intLessThan sym b =<< integerLit sym 0
case bitAsLit sym p of
Just False -> pure (SRational a b)
Just True ->
do aneg <- intNegate sym a
bneg <- intNegate sym b
pure (SRational aneg bneg)
Nothing ->
do aneg <- intNegate sym a
bneg <- intNegate sym b
a' <- iteInteger sym p aneg a
b' <- iteInteger sym p bneg b
pure (SRational a' b')
rationalLessThan:: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
rationalLessThan sym x y =
do SRational a b <- normalizeSign sym x
SRational c d <- normalizeSign sym y
ad <- intMult sym a d
bc <- intMult sym b c
intLessThan sym ad bc
rationalGreaterThan:: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
rationalGreaterThan sym = flip (rationalLessThan sym)
iteRational :: Backend sym => sym -> SBit sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
iteRational sym p (SRational a b) (SRational c d) =
SRational <$> iteInteger sym p a c <*> iteInteger sym p b d
ppRational :: Backend sym => sym -> PPOpts -> SRational sym -> Doc
ppRational sym opts (SRational n d)
| Just ni <- integerAsLit sym n
, Just di <- integerAsLit sym d
= let q = ni % di in
text "(ratio" <+> integer (numerator q) <+> (integer (denominator q) <> text ")")
| otherwise
= text "(ratio" <+> ppInteger sym opts n <+> (ppInteger sym opts d <> text ")")
class MonadIO (SEval sym) => Backend sym where
type SBit sym :: Type
type SWord sym :: Type
type SInteger sym :: Type
type SFloat sym :: Type
type SEval sym :: Type -> Type
isReady :: sym -> SEval sym a -> Bool
sDeclareHole :: sym -> String -> SEval sym (SEval sym a, SEval sym a -> SEval sym ())
sDelayFill :: sym -> SEval sym a -> SEval sym a -> SEval sym (SEval sym a)
sSpark :: sym -> SEval sym a -> SEval sym (SEval sym a)
mergeEval ::
sym ->
(SBit sym -> a -> a -> SEval sym a) ->
SBit sym ->
SEval sym a ->
SEval sym a ->
SEval sym a
assertSideCondition :: sym -> SBit sym -> EvalError -> SEval sym ()
raiseError :: sym -> EvalError -> SEval sym a
ppBit :: sym -> SBit sym -> Doc
ppWord :: sym -> PPOpts -> SWord sym -> Doc
ppInteger :: sym -> PPOpts -> SInteger sym -> Doc
ppFloat :: sym -> PPOpts -> SFloat sym -> Doc
bitAsLit :: sym -> SBit sym -> Maybe Bool
wordLen :: sym -> SWord sym -> Integer
wordAsLit :: sym -> SWord sym -> Maybe (Integer, Integer)
wordAsChar :: sym -> SWord sym -> Maybe Char
integerAsLit :: sym -> SInteger sym -> Maybe Integer
bitLit :: sym -> Bool -> SBit sym
wordLit ::
sym ->
Integer ->
Integer ->
SEval sym (SWord sym)
integerLit ::
sym ->
Integer ->
SEval sym (SInteger sym)
fpLit ::
sym ->
Integer ->
Integer ->
Rational ->
SEval sym (SFloat sym)
iteBit :: sym -> SBit sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
iteWord :: sym -> SBit sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
iteInteger :: sym -> SBit sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
bitEq :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
bitOr :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
bitAnd :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
bitXor :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
bitComplement :: sym -> SBit sym -> SEval sym (SBit sym)
wordBit ::
sym ->
SWord sym ->
Integer ->
SEval sym (SBit sym)
wordUpdate ::
sym ->
SWord sym ->
Integer ->
SBit sym ->
SEval sym (SWord sym)
packWord ::
sym ->
[SBit sym] ->
SEval sym (SWord sym)
unpackWord ::
sym ->
SWord sym ->
SEval sym [SBit sym]
wordFromInt ::
sym ->
Integer ->
SInteger sym ->
SEval sym (SWord sym)
joinWord ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
splitWord ::
sym ->
Integer ->
Integer ->
SWord sym ->
SEval sym (SWord sym, SWord sym)
extractWord ::
sym ->
Integer ->
Integer ->
SWord sym ->
SEval sym (SWord sym)
wordOr ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordAnd ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordXor ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordComplement ::
sym ->
SWord sym ->
SEval sym (SWord sym)
wordPlus ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordMinus ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordMult ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordDiv ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordMod ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordSignedDiv ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordSignedMod ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SWord sym)
wordNegate ::
sym ->
SWord sym ->
SEval sym (SWord sym)
wordLg2 ::
sym ->
SWord sym ->
SEval sym (SWord sym)
wordEq ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SBit sym)
wordSignedLessThan ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SBit sym)
wordLessThan ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SBit sym)
wordGreaterThan ::
sym ->
SWord sym ->
SWord sym ->
SEval sym (SBit sym)
wordToInt ::
sym ->
SWord sym ->
SEval sym (SInteger sym)
intPlus ::
sym ->
SInteger sym ->
SInteger sym ->
SEval sym (SInteger sym)
intNegate ::
sym ->
SInteger sym ->
SEval sym (SInteger sym)
intMinus ::
sym ->
SInteger sym ->
SInteger sym ->
SEval sym (SInteger sym)
intMult ::
sym ->
SInteger sym ->
SInteger sym ->
SEval sym (SInteger sym)
intDiv ::
sym ->
SInteger sym ->
SInteger sym ->
SEval sym (SInteger sym)
intMod ::
sym ->
SInteger sym ->
SInteger sym ->
SEval sym (SInteger sym)
intEq ::
sym ->
SInteger sym ->
SInteger sym ->
SEval sym (SBit sym)
intLessThan ::
sym ->
SInteger sym ->
SInteger sym ->
SEval sym (SBit sym)
intGreaterThan ::
sym ->
SInteger sym ->
SInteger sym ->
SEval sym (SBit sym)
intToZn ::
sym ->
Integer ->
SInteger sym ->
SEval sym (SInteger sym)
znToInt ::
sym ->
Integer ->
SInteger sym ->
SEval sym (SInteger sym)
znPlus ::
sym ->
Integer ->
SInteger sym ->
SInteger sym ->
SEval sym (SInteger sym)
znNegate ::
sym ->
Integer ->
SInteger sym ->
SEval sym (SInteger sym)
znMinus ::
sym ->
Integer ->
SInteger sym ->
SInteger sym ->
SEval sym (SInteger sym)
znMult ::
sym ->
Integer ->
SInteger sym ->
SInteger sym ->
SEval sym (SInteger sym)
znEq ::
sym ->
Integer ->
SInteger sym ->
SInteger sym ->
SEval sym (SBit sym)
fpEq :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
fpLessThan :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
fpGreaterThan :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
fpPlus, fpMinus, fpMult, fpDiv :: FPArith2 sym
fpNeg :: sym -> SFloat sym -> SEval sym (SFloat sym)
fpToInteger ::
sym ->
String ->
SWord sym ->
SFloat sym -> SEval sym (SInteger sym)
fpFromInteger ::
sym ->
Integer ->
Integer ->
SWord sym ->
SInteger sym ->
SEval sym (SFloat sym)
type FPArith2 sym =
sym ->
SWord sym ->
SFloat sym ->
SFloat sym ->
SEval sym (SFloat sym)