packages feed

crucible-0.7: test/absint/EvenOdd.hs

-- | A simple domain for tracking even-ness and odd-ness of values
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
module EvenOdd (
  EvenOdd(..), EOExt,
  evenOddDom,
  evenOddInterp
  ) where

import qualified Data.Parameterized.Context as PU

import qualified Lang.Crucible.CFG.Core as C
import qualified Lang.Crucible.CFG.Expr as C
import Lang.Crucible.Analysis.Fixpoint

data EvenOdd (tp :: C.CrucibleType) where
  Even :: EvenOdd tp
  Odd :: EvenOdd tp

deriving instance Eq (EvenOdd tp)
deriving instance Show (EvenOdd tp)

instance C.ShowF EvenOdd

type EvenOdd' = Pointed EvenOdd

evenOddDom :: Domain EvenOdd'
evenOddDom = pointed j (==) WTO
  where
    j Even Odd = Top
    j Odd Even = Top
    j Even Even = Pointed Even
    j Odd Odd = Pointed Odd

type EOExt = ()

evenOddInterp :: Interpretation EOExt EvenOdd'
evenOddInterp = Interpretation { interpExpr = eoIExpr
                               , interpExt = undefined
                               , interpCall = eoICall
                               , interpReadGlobal = eoIRdGlobal
                               , interpWriteGlobal = eoIWrGlobal
                               , interpBr = eoIBr
                               , interpMaybe = eoIMaybe
                               }

eoIExpr :: ScopedReg
        -> C.TypeRepr tp
        -> C.Expr ext ctx tp
        -> PointAbstraction blocks EvenOdd' ctx
        -> (Maybe (PointAbstraction blocks EvenOdd' ctx), EvenOdd' tp)
eoIExpr _sr _tr (C.App e) abstr =
  case e of
    C.IntLit i -> (Nothing, if i `mod` 2 == 0 then Pointed Even else Pointed Odd)
    C.IntAdd r1 r2 ->
      let a1 = lookupAbstractRegValue abstr r1
          a2 = lookupAbstractRegValue abstr r2
      in case (a1, a2) of
        (Pointed Even, Pointed Even) -> (Nothing, Pointed Even)
        (Pointed Odd, Pointed Odd) -> (Nothing, Pointed Even)
        (Pointed Even, Pointed Odd) -> (Nothing, Pointed Odd)
        (Pointed Odd, Pointed Even) -> (Nothing, Pointed Odd)
        _ -> (Nothing, Top)
    _ -> (Nothing, Top)

eoICall :: C.CtxRepr args
        -> C.TypeRepr ret
        -> C.Reg ctx (C.FunctionHandleType args ret)
        -> EvenOdd' (C.FunctionHandleType args ret)
        -> PU.Assignment EvenOdd' args
        -> PointAbstraction blocks dom ctx
        -> (Maybe (PointAbstraction blocks EvenOdd' ctx), EvenOdd' ret)
eoICall _ _ _ _ _ _ = (Nothing, Top)

eoIBr :: C.Reg ctx C.BoolType
      -> EvenOdd' C.BoolType
      -> C.JumpTarget blocks ctx
      -> C.JumpTarget blocks ctx
      -> PointAbstraction blocks EvenOdd' ctx
      -> (Maybe (PointAbstraction blocks EvenOdd' ctx), Maybe (PointAbstraction blocks EvenOdd' ctx))
eoIBr _ _ _ _ _ = (Nothing, Nothing)

eoIMaybe :: C.TypeRepr tp
         -> C.Reg ctx (C.MaybeType tp)
         -> EvenOdd' (C.MaybeType tp)
         -> PointAbstraction blocks EvenOdd' ctx
         -> (Maybe (PointAbstraction blocks EvenOdd' ctx), EvenOdd' tp, Maybe (PointAbstraction blocks EvenOdd' ctx))
eoIMaybe _ _ _ _ = (Nothing, Top, Nothing)

eoIWrGlobal :: C.GlobalVar tp -> C.Reg ctx tp -> PointAbstraction blocks EvenOdd' ctx -> Maybe (PointAbstraction blocks EvenOdd' ctx)
eoIWrGlobal _ _ _ = Nothing

eoIRdGlobal :: C.GlobalVar tp -> PointAbstraction blocks EvenOdd' ctx -> (Maybe (PointAbstraction blocks EvenOdd' ctx), EvenOdd' tp)
eoIRdGlobal _ _ = (Nothing, Top)