crux-0.7: src/Crux/Overrides.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
module Crux.Overrides
( mkFresh
, mkFreshFloat
, baseFreshOverride
, baseFreshOverride'
) where
import qualified Data.Parameterized.Context as Ctx
import What4.BaseTypes (BaseTypeRepr)
import qualified What4.Interface as W4
import qualified What4.InterpretedFloatingPoint as W4
import qualified Lang.Crucible.Backend as C
import qualified Lang.Crucible.Simulator.RegValue as C
import qualified Lang.Crucible.Types as C
import qualified Lang.Crucible.Simulator.OverrideSim as C
import Crux.Types (OverM)
import Control.Monad.IO.Class (liftIO)
-- | Create a fresh constant ('W4.freshConstant') with the given base type
mkFresh ::
C.IsSymInterface sym =>
W4.SolverSymbol ->
BaseTypeRepr ty ->
OverM personality sym ext (C.RegValue sym (C.BaseToType ty))
mkFresh name ty =
C.ovrWithBackend $ \bak ->
do let sym = C.backendGetSym bak
elt <- liftIO (W4.freshConstant sym name ty)
loc <- liftIO $ W4.getCurrentProgramLoc sym
let ev = C.CreateVariableEvent loc (show name) ty elt
liftIO $ C.addAssumptions bak (C.singleEvent ev)
return elt
-- | Create a fresh float constant ('W4.freshFloatConstant')
mkFreshFloat ::
C.IsSymInterface sym =>
W4.SolverSymbol ->
C.FloatInfoRepr fi ->
OverM personality sym ext (C.RegValue sym (C.FloatType fi))
mkFreshFloat name fi =
C.ovrWithBackend $ \bak ->
do let sym = C.backendGetSym bak
elt <- liftIO $ W4.freshFloatConstant sym name fi
loc <- liftIO $ W4.getCurrentProgramLoc sym
let ev = C.CreateVariableEvent loc (show name) (W4.iFloatBaseTypeRepr sym fi) elt
liftIO $ C.addAssumptions bak (C.singleEvent ev)
return elt
-- | Build an override that takes a string and returns a fresh constant with
-- that string as its name.
baseFreshOverride ::
C.IsSymInterface sym =>
W4.BaseTypeRepr bty ->
-- | The language's string type (e.g., @LLVMPointerType@ for LLVM)
C.TypeRepr stringTy ->
-- | Get the variable name as a concrete string from the override arguments
(C.RegValue' sym stringTy -> OverM p sym ext W4.SolverSymbol) ->
C.TypedOverride (p sym) sym ext (C.EmptyCtx C.::> stringTy) (C.BaseToType bty)
baseFreshOverride bty sty getStr =
C.TypedOverride
{ C.typedOverrideHandler = \(Ctx.Empty Ctx.:> strVal) -> do
str <- getStr strVal
mkFresh str bty
, C.typedOverrideArgs = Ctx.Empty Ctx.:> sty
, C.typedOverrideRet = C.baseToType bty
}
-- | Build an override that takes no arguments and returns a fresh
-- constant that uses the given name. Generally, frontends should prefer
-- 'baseFreshOverride', to allow users to specify variable names.
baseFreshOverride' ::
C.IsSymInterface sym =>
-- | Variable name
W4.SolverSymbol ->
W4.BaseTypeRepr bty ->
C.TypedOverride (p sym) sym ext C.EmptyCtx (C.BaseToType bty)
baseFreshOverride' nm bty =
C.TypedOverride
{ C.typedOverrideHandler = \Ctx.Empty -> mkFresh nm bty
, C.typedOverrideArgs = Ctx.Empty
, C.typedOverrideRet = C.baseToType bty
}