Begin cleaning up floating point and x86-specific functions.

This commit is contained in:
Joe Hendrix 2017-12-05 13:31:12 -08:00
parent 716de707c2
commit 4d5b90e285
No known key found for this signature in database
GPG Key ID: 8DFA5FF784098C4F
17 changed files with 306 additions and 238 deletions

View File

@ -339,6 +339,10 @@ isEmpty _ = False
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Joining abstract values -- Joining abstract values
instance MemWidth w => AbsDomain (AbsValue w tp) where
top = TopV
joinD = joinAbsValue
-- | Join the old and new states and return the updated state iff -- | Join the old and new states and return the updated state iff
-- the result is larger than the old state. -- the result is larger than the old state.
-- This also returns any addresses that are discarded during joining. -- This also returns any addresses that are discarded during joining.

View File

@ -46,6 +46,7 @@ import Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
import Data.Macaw.CFG import Data.Macaw.CFG
import Data.Macaw.CFG.BlockLabel import Data.Macaw.CFG.BlockLabel
import Data.Macaw.CFG.DemandSet
import Data.Macaw.Discovery.State import Data.Macaw.Discovery.State
import Data.Macaw.Fold import Data.Macaw.Fold
import Data.Macaw.Memory import Data.Macaw.Memory
@ -197,6 +198,8 @@ data ArchDemandInfo arch = ArchDemandInfo
, calleeSavedRegs :: !(Set (Some (ArchReg arch))) , calleeSavedRegs :: !(Set (Some (ArchReg arch)))
-- | Compute the effects of a terminal statement on registers. -- | Compute the effects of a terminal statement on registers.
, computeArchTermStmtEffects :: !(forall ids . ComputeArchTermStmtEffects arch ids) , computeArchTermStmtEffects :: !(forall ids . ComputeArchTermStmtEffects arch ids)
-- | Information needed to infer what values are demanded by a AssignRhs and Stmt.
, demandInfoCtx :: !(DemandContext arch)
} }
-- | This is information needed to compute dependencies for a single function. -- | This is information needed to compute dependencies for a single function.
@ -461,17 +464,17 @@ summarizeCall mem lbl proc_state isTailCall = do
recordBlockDemand lbl proc_state (\_ -> DemandAlways) ([Some ip_reg] ++ argRegs) recordBlockDemand lbl proc_state (\_ -> DemandAlways) ([Some ip_reg] ++ argRegs)
-- | Return values that must be evaluated to execute side effects. -- | Return values that must be evaluated to execute side effects.
stmtDemandedValues :: FoldableF (ArchStmt arch) stmtDemandedValues :: DemandContext arch
=> Stmt arch ids -> Stmt arch ids
-> [Some (Value arch ids)] -> [Some (Value arch ids)]
stmtDemandedValues stmt = stmtDemandedValues ctx stmt = demandConstraints ctx $
case stmt of case stmt of
-- Assignment statements are side effect free so we ignore them. AssignStmt a
AssignStmt a -> case (assignRhs a) of | hasSideEffects ctx (assignRhs a) -> do
EvalApp _ -> [] foldMapFC (\v -> [Some v]) (assignRhs a)
SetUndefined _ -> [] | otherwise ->
ReadMem addr _ -> [Some addr] []
EvalArchFn _ _ -> []
WriteMem addr _ v -> [Some addr, Some v] WriteMem addr _ v -> [Some addr, Some v]
-- Place holder statements are unknown. -- Place holder statements are unknown.
PlaceHolderStmt _ _ -> [] PlaceHolderStmt _ _ -> []
@ -496,9 +499,10 @@ summarizeBlock mem interp_state addr stmts = do
-- Add this label to block demand map with empty set. -- Add this label to block demand map with empty set.
blockDemandMap %= Map.insertWith demandMapUnion lbl mempty blockDemandMap %= Map.insertWith demandMapUnion lbl mempty
ctx <- gets $ demandInfoCtx . archDemandInfo
-- Add all values demanded by non-terminal statements in list. -- Add all values demanded by non-terminal statements in list.
mapM_ (\(Some v) -> demandValue lbl v) mapM_ (mapM_ (\(Some v) -> demandValue lbl v) . stmtDemandedValues ctx)
(concatMap stmtDemandedValues (stmtsNonterm stmts)) (stmtsNonterm stmts)
-- Add values demanded by terminal statements -- Add values demanded by terminal statements
case stmtsTerm stmts of case stmtsTerm stmts of
ParsedTranslateError _ -> do ParsedTranslateError _ -> do

View File

@ -124,7 +124,7 @@ data ArchitectureInfo arch
, rewriteArchTermStmt :: (forall s src tgt . ArchTermStmt arch src , rewriteArchTermStmt :: (forall s src tgt . ArchTermStmt arch src
-> Rewriter arch s src tgt (ArchTermStmt arch tgt)) -> Rewriter arch s src tgt (ArchTermStmt arch tgt))
-- ^ This rewrites an architecture specific statement -- ^ This rewrites an architecture specific statement
, archDemandContext :: !(forall ids . DemandContext arch ids) , archDemandContext :: !(DemandContext arch)
-- ^ Provides architecture-specific information for computing which arguments must be -- ^ Provides architecture-specific information for computing which arguments must be
-- evaluated when evaluating a statement. -- evaluated when evaluating a statement.
, postArchTermStmtAbsState :: !(forall ids , postArchTermStmtAbsState :: !(forall ids

View File

@ -190,16 +190,6 @@ data App (f :: Type -> *) (tp :: Type) where
---------------------------------------------------------------------- ----------------------------------------------------------------------
-- Floating point operations -- Floating point operations
-- | Return true if floating point value is a "quiet" NaN.
FPIsQNaN :: !(FloatInfoRepr flt)
-> !(f (FloatType flt))
-> App f BoolType
-- | Return true if floating point value is a "signaling" NaN.
FPIsSNaN :: !(FloatInfoRepr flt)
-> !(f (FloatType flt))
-> App f BoolType
FPAdd :: !(FloatInfoRepr flt) FPAdd :: !(FloatInfoRepr flt)
-> !(f (FloatType flt)) -> !(f (FloatType flt))
-> !(f (FloatType flt)) -> !(f (FloatType flt))
@ -408,8 +398,6 @@ ppAppA pp a0 =
Bsr _ x -> sexprA "bsr" [ pp x ] Bsr _ x -> sexprA "bsr" [ pp x ]
-- Floating point -- Floating point
FPIsQNaN rep x -> sexprA "fpIsQNaN" [ prettyPure rep, pp x ]
FPIsSNaN rep x -> sexprA "fpIsSNaN" [ prettyPure rep, pp x ]
FPAdd rep x y -> sexprA "fpAdd" [ prettyPure rep, pp x, pp y ] FPAdd rep x y -> sexprA "fpAdd" [ prettyPure rep, pp x, pp y ]
FPAddRoundedUp rep x y -> sexprA "fpAddRoundedUp" [ prettyPure rep, pp x, pp y ] FPAddRoundedUp rep x y -> sexprA "fpAddRoundedUp" [ prettyPure rep, pp x, pp y ]
FPSub rep x y -> sexprA "fpSub" [ prettyPure rep, pp x, pp y ] FPSub rep x y -> sexprA "fpSub" [ prettyPure rep, pp x, pp y ]
@ -478,8 +466,6 @@ instance HasRepr (App f) TypeRepr where
Bsr w _ -> BVTypeRepr w Bsr w _ -> BVTypeRepr w
-- Floating point -- Floating point
FPIsQNaN _ _ -> knownType
FPIsSNaN _ _ -> knownType
FPAdd rep _ _ -> floatTypeRepr rep FPAdd rep _ _ -> floatTypeRepr rep
FPAddRoundedUp{} -> knownType FPAddRoundedUp{} -> knownType
FPSub rep _ _ -> floatTypeRepr rep FPSub rep _ _ -> floatTypeRepr rep

View File

@ -91,6 +91,7 @@ import Control.Monad.State.Strict
import Data.Bits import Data.Bits
import Data.Int (Int64) import Data.Int (Int64)
import Data.Maybe (isNothing, catMaybes) import Data.Maybe (isNothing, catMaybes)
import Data.Monoid
import Data.Parameterized.Classes import Data.Parameterized.Classes
import Data.Parameterized.Map (MapF) import Data.Parameterized.Map (MapF)
import qualified Data.Parameterized.Map as MapF import qualified Data.Parameterized.Map as MapF
@ -106,7 +107,8 @@ import Data.Text (Text)
import qualified Data.Text as Text import qualified Data.Text as Text
import GHC.TypeLits import GHC.TypeLits
import Numeric (showHex) import Numeric (showHex)
import Text.PrettyPrint.ANSI.Leijen as PP hiding ((<$>)) import Text.PrettyPrint.ANSI.Leijen hiding ((<$>), (<>))
import qualified Text.PrettyPrint.ANSI.Leijen as PP
import Data.Macaw.CFG.App import Data.Macaw.CFG.App
import Data.Macaw.Memory ( MemWord, MemWidth, MemAddr, MemSegmentOff, Endianness(..) import Data.Macaw.Memory ( MemWord, MemWidth, MemAddr, MemSegmentOff, Endianness(..)
@ -228,38 +230,7 @@ type ArchMemAddr arch = MemAddr (ArchAddrWidth arch)
type ArchSegmentOff arch = MemSegmentOff (ArchAddrWidth arch) type ArchSegmentOff arch = MemSegmentOff (ArchAddrWidth arch)
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Value, Assignment, AssignRhs declarations. -- MemRepr
-- | A value at runtime.
data Value arch ids tp
= forall n
. (tp ~ BVType n, 1 <= n)
=> BVValue !(NatRepr n) !Integer
-- ^ A constant bitvector
| (tp ~ BoolType)
=> BoolValue !Bool
-- ^ A constant Boolean
| ( tp ~ BVType (ArchAddrWidth arch)
, 1 <= ArchAddrWidth arch
)
=> RelocatableValue !(NatRepr (ArchAddrWidth arch)) !(ArchMemAddr arch)
-- ^ A legal memory address
| AssignedValue !(Assignment arch ids tp)
-- ^ Value from an assignment statement.
| Initial !(ArchReg arch tp)
-- ^ Represents the value assigned to the register when the block started.
type BVValue arch ids w = Value arch ids (BVType w)
-- | A address value for a specific architecture
type ArchAddrValue arch ids = BVValue arch ids (ArchAddrWidth arch)
-- | An assignment consists of a unique location identifier and a right-
-- hand side that returns a value.
data Assignment arch ids tp =
Assignment { assignId :: !(AssignId ids tp)
, assignRhs :: !(AssignRhs arch ids tp)
}
-- | The type stored in memory. -- | The type stored in memory.
-- --
@ -301,38 +272,94 @@ instance HasRepr MemRepr TypeRepr where
in case leqMulPos (Proxy :: Proxy 8) w of in case leqMulPos (Proxy :: Proxy 8) w of
LeqProof -> BVTypeRepr r LeqProof -> BVTypeRepr r
------------------------------------------------------------------------
-- AssignRhs
-- | The right hand side of an assignment is an expression that -- | The right hand side of an assignment is an expression that
-- returns a value. -- returns a value.
data AssignRhs (arch :: *) ids tp where data AssignRhs (arch :: *) (f :: Type -> *) tp where
-- An expression that is computed from evaluating subexpressions. -- An expression that is computed from evaluating subexpressions.
EvalApp :: !(App (Value arch ids) tp) EvalApp :: !(App f tp)
-> AssignRhs arch ids tp -> AssignRhs arch f tp
-- An expression with an undefined value. -- An expression with an undefined value.
SetUndefined :: !(TypeRepr tp) SetUndefined :: !(TypeRepr tp)
-> AssignRhs arch ids tp -> AssignRhs arch f tp
-- Read memory at given location. -- Read memory at given location.
ReadMem :: !(ArchAddrValue arch ids) ReadMem :: !(f (BVType (ArchAddrWidth arch)))
-> !(MemRepr tp) -> !(MemRepr tp)
-> AssignRhs arch ids tp -> AssignRhs arch f tp
CondReadMem :: !(MemRepr tp)
-> !(f BoolType)
-> !(f (BVType (ArchAddrWidth arch)))
-> !(f tp)
-> AssignRhs arch f tp
-- ^ @CondReadMem tp cond addr v@ reads from memory at the given address if the
-- condition is true and returns the value if it false.
-- Call an architecture specific function that returns some result. -- Call an architecture specific function that returns some result.
EvalArchFn :: !(ArchFn arch (Value arch ids) tp) EvalArchFn :: !(ArchFn arch f tp)
-> !(TypeRepr tp) -> !(TypeRepr tp)
-> AssignRhs arch ids tp -> AssignRhs arch f tp
------------------------------------------------------------------------ instance HasRepr (AssignRhs arch f) TypeRepr where
-- Type operations on assignment AssignRhs, and Value
instance HasRepr (AssignRhs arch ids) TypeRepr where
typeRepr rhs = typeRepr rhs =
case rhs of case rhs of
EvalApp a -> typeRepr a EvalApp a -> typeRepr a
SetUndefined tp -> tp SetUndefined tp -> tp
ReadMem _ tp -> typeRepr tp ReadMem _ tp -> typeRepr tp
CondReadMem tp _ _ _ -> typeRepr tp
EvalArchFn _ rtp -> rtp EvalArchFn _ rtp -> rtp
instance FoldableFC (ArchFn arch) => FoldableFC (AssignRhs arch) where
foldMapFC go v =
case v of
EvalApp a -> foldMapFC go a
SetUndefined _w -> mempty
ReadMem addr _ -> go addr
CondReadMem _ c a d -> go c <> go a <> go d
EvalArchFn f _ -> foldMapFC go f
------------------------------------------------------------------------
-- Value and Assignment, AssignRhs declarations.
-- | A value at runtime.
data Value arch ids tp
= forall n
. (tp ~ BVType n, 1 <= n)
=> BVValue !(NatRepr n) !Integer
-- ^ A constant bitvector
| (tp ~ BoolType)
=> BoolValue !Bool
-- ^ A constant Boolean
| ( tp ~ BVType (ArchAddrWidth arch)
, 1 <= ArchAddrWidth arch
)
=> RelocatableValue !(NatRepr (ArchAddrWidth arch)) !(ArchMemAddr arch)
-- ^ A legal memory address
| AssignedValue !(Assignment arch ids tp)
-- ^ Value from an assignment statement.
| Initial !(ArchReg arch tp)
-- ^ Represents the value assigned to the register when the block started.
-- | An assignment consists of a unique location identifier and a right-
-- hand side that returns a value.
data Assignment arch ids tp =
Assignment { assignId :: !(AssignId ids tp)
, assignRhs :: !(AssignRhs arch (Value arch ids) tp)
}
-- | A value with a bitvector type.
type BVValue arch ids w = Value arch ids (BVType w)
-- | A address value for a specific architecture
type ArchAddrValue arch ids = BVValue arch ids (ArchAddrWidth arch)
------------------------------------------------------------------------
-- Type operations on assignment AssignRhs, and Value
instance ( HasRepr (ArchReg arch) TypeRepr instance ( HasRepr (ArchReg arch) TypeRepr
) )
=> HasRepr (Value arch ids) TypeRepr where => HasRepr (Value arch ids) TypeRepr where
@ -605,17 +632,19 @@ type ArchConstraints arch
-- | Pretty print an assignment right-hand side using operations parameterized -- | Pretty print an assignment right-hand side using operations parameterized
-- over an application to allow side effects. -- over an application to allow side effects.
ppAssignRhs :: (Applicative m, ArchConstraints arch) ppAssignRhs :: (Applicative m, ArchConstraints arch)
=> (forall u . Value arch ids u -> m Doc) => (forall u . f u -> m Doc)
-- ^ Function for pretty printing value. -- ^ Function for pretty printing value.
-> AssignRhs arch ids tp -> AssignRhs arch f tp
-> m Doc -> m Doc
ppAssignRhs pp (EvalApp a) = ppAppA pp a ppAssignRhs pp (EvalApp a) = ppAppA pp a
ppAssignRhs _ (SetUndefined tp) = pure $ text "undef ::" <+> brackets (text (show tp)) ppAssignRhs _ (SetUndefined tp) = pure $ text "undef ::" <+> brackets (text (show tp))
ppAssignRhs pp (ReadMem a repr) = ppAssignRhs pp (ReadMem a repr) =
(\d -> text "read_mem" <+> d <+> PP.parens (pretty repr)) <$> pp a (\d -> text "read_mem" <+> d <+> PP.parens (pretty repr)) <$> pp a
ppAssignRhs pp (CondReadMem repr c a d) = f <$> pp c <*> pp a <*> pp d
where f cd ad dd = text "read_mem" <+> PP.parens (pretty repr) <+> cd <+> ad <+> dd
ppAssignRhs pp (EvalArchFn f _) = ppArchFn pp f ppAssignRhs pp (EvalArchFn f _) = ppArchFn pp f
instance ArchConstraints arch => Pretty (AssignRhs arch ids tp) where instance ArchConstraints arch => Pretty (AssignRhs arch (Value arch ids) tp) where
pretty = runIdentity . ppAssignRhs (Identity . ppValue 10) pretty = runIdentity . ppAssignRhs (Identity . ppValue 10)
instance ArchConstraints arch => Pretty (Assignment arch ids tp) where instance ArchConstraints arch => Pretty (Assignment arch ids tp) where
@ -756,11 +785,14 @@ refsInApp :: App (Value arch ids) tp -> Set (Some (AssignId ids))
refsInApp app = foldMapFC refsInValue app refsInApp app = foldMapFC refsInValue app
refsInAssignRhs :: FoldableFC (ArchFn arch) refsInAssignRhs :: FoldableFC (ArchFn arch)
=> AssignRhs arch ids tp => AssignRhs arch (Value arch ids) tp
-> Set (Some (AssignId ids)) -> Set (Some (AssignId ids))
refsInAssignRhs rhs = refsInAssignRhs rhs =
case rhs of case rhs of
EvalApp v -> refsInApp v EvalApp v -> refsInApp v
SetUndefined _ -> Set.empty SetUndefined _ -> Set.empty
ReadMem v _ -> refsInValue v ReadMem v _ -> refsInValue v
CondReadMem _ c a d ->
Set.union (refsInValue c) $
Set.union (refsInValue a) (refsInValue d)
EvalArchFn f _ -> foldMapFC refsInValue f EvalArchFn f _ -> foldMapFC refsInValue f

View File

@ -3,11 +3,13 @@
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
module Data.Macaw.CFG.DemandSet module Data.Macaw.CFG.DemandSet
( DemandComp ( DemandComp
, DemandContext(..)
, AssignIdSet , AssignIdSet
, runDemandComp , runDemandComp
, addValueDemands , addValueDemands
, addStmtDemands , addStmtDemands
-- * DemandContext
, DemandContext(..)
, hasSideEffects
-- * Filtering after demand set is computed. -- * Filtering after demand set is computed.
, stmtNeeded , stmtNeeded
) where ) where
@ -28,7 +30,7 @@ type AssignIdSet ids = Set (Some (AssignId ids))
-- | This provides the architecture specific functions needed to -- | This provides the architecture specific functions needed to
-- resolve demand sets. -- resolve demand sets.
data DemandContext arch ids data DemandContext arch
= DemandContext { archFnHasSideEffects :: !(forall v tp . ArchFn arch v tp -> Bool) = DemandContext { archFnHasSideEffects :: !(forall v tp . ArchFn arch v tp -> Bool)
-- ^ This returns true if the architecture function has implicit -- ^ This returns true if the architecture function has implicit
-- side effects (and thus can be safely removed). -- side effects (and thus can be safely removed).
@ -37,17 +39,18 @@ data DemandContext arch ids
=> a) -> a) => a) -> a)
} }
-- | Return true if assign rhs has side effects (and thus should alwatys be demanded) -- | Return true if assign rhs has side effects (and thus should always be demanded)
hasSideEffects :: DemandContext arch ids -> AssignRhs arch ids tp -> Bool hasSideEffects :: DemandContext arch -> AssignRhs arch f tp -> Bool
hasSideEffects ctx rhs = hasSideEffects ctx rhs =
case rhs of case rhs of
EvalApp{} -> False EvalApp{} -> False
SetUndefined{} -> False SetUndefined{} -> False
ReadMem{} -> True ReadMem{} -> True
CondReadMem{} -> True
EvalArchFn fn _ -> archFnHasSideEffects ctx fn EvalArchFn fn _ -> archFnHasSideEffects ctx fn
data DemandState arch ids data DemandState arch ids
= DemandState { demandContext :: !(DemandContext arch ids) = DemandState { demandContext :: !(DemandContext arch)
, demandedAssignIds :: !(AssignIdSet ids) , demandedAssignIds :: !(AssignIdSet ids)
} }
@ -57,28 +60,12 @@ newtype DemandComp arch ids a = DemandComp { unDemandComp :: State (DemandState
-- | Run demand computation and return the set of assignments that -- | Run demand computation and return the set of assignments that
-- were determined to be needed. -- were determined to be needed.
runDemandComp :: DemandContext arch ids -> DemandComp arch ids () -> AssignIdSet ids runDemandComp :: DemandContext arch -> DemandComp arch ids () -> AssignIdSet ids
runDemandComp ctx comp = demandedAssignIds $ execState (unDemandComp comp) s runDemandComp ctx comp = demandedAssignIds $ execState (unDemandComp comp) s
where s = DemandState { demandContext = ctx where s = DemandState { demandContext = ctx
, demandedAssignIds = Set.empty , demandedAssignIds = Set.empty
} }
-- | Record assign ids needed to compute this assignment right-hand
-- side.
addAssignRhsDemands :: AssignRhs arch ids tp -> DemandComp arch ids ()
addAssignRhsDemands rhs =
case rhs of
EvalApp app -> do
traverseFC_ addValueDemands app
SetUndefined{} ->
pure ()
ReadMem addr _ -> do
addValueDemands addr
EvalArchFn fn _ -> do
ctx <- DemandComp $ gets $ demandContext
demandConstraints ctx $
addValueListDemands $ foldMapFC (\v -> [Some v]) fn
-- | Add the ID of this assignment to demand set and also that of any -- | Add the ID of this assignment to demand set and also that of any
-- values needed to compute it. -- values needed to compute it.
addAssignmentDemands :: Assignment arch ids tp -> DemandComp arch ids () addAssignmentDemands :: Assignment arch ids tp -> DemandComp arch ids ()
@ -88,7 +75,8 @@ addAssignmentDemands a = do
when (Set.notMember thisId (demandedAssignIds s)) $ do when (Set.notMember thisId (demandedAssignIds s)) $ do
let s' = s { demandedAssignIds = Set.insert thisId (demandedAssignIds s) } let s' = s { demandedAssignIds = Set.insert thisId (demandedAssignIds s) }
seq s' $ DemandComp $ put s' seq s' $ DemandComp $ put s'
addAssignRhsDemands (assignRhs a) demandConstraints (demandContext s) $
traverseFC_ addValueDemands (assignRhs a)
-- | Add any subassignments needed to compute values to demand set. -- | Add any subassignments needed to compute values to demand set.
addValueDemands :: Value arch ids tp -> DemandComp arch ids () addValueDemands :: Value arch ids tp -> DemandComp arch ids ()
@ -100,9 +88,6 @@ addValueDemands v = do
AssignedValue a -> addAssignmentDemands a AssignedValue a -> addAssignmentDemands a
Initial{} -> pure () Initial{} -> pure ()
addValueListDemands :: [Some (Value arch ids)] -> DemandComp arch ids ()
addValueListDemands = mapM_ (viewSome addValueDemands)
-- | Parse statement, and if it has side effects, add assignments -- | Parse statement, and if it has side effects, add assignments
-- needed to compute statement to demand set. -- needed to compute statement to demand set.
addStmtDemands :: Stmt arch ids -> DemandComp arch ids () addStmtDemands :: Stmt arch ids -> DemandComp arch ids ()
@ -124,7 +109,7 @@ addStmtDemands s =
ExecArchStmt astmt -> do ExecArchStmt astmt -> do
ctx <- DemandComp $ gets $ demandContext ctx <- DemandComp $ gets $ demandContext
demandConstraints ctx $ demandConstraints ctx $
addValueListDemands $ foldMapF (\v -> [Some v]) astmt traverseF_ addValueDemands astmt
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Functions for computing demanded values -- Functions for computing demanded values

View File

@ -118,7 +118,7 @@ appendRewrittenArchStmt :: ArchStmt arch (Value arch tgt) -> Rewriter arch s src
appendRewrittenArchStmt = appendRewrittenStmt . ExecArchStmt appendRewrittenArchStmt = appendRewrittenStmt . ExecArchStmt
-- | Add an assignment statement that evaluates the right hand side and return the resulting value. -- | Add an assignment statement that evaluates the right hand side and return the resulting value.
evalRewrittenRhs :: AssignRhs arch tgt tp -> Rewriter arch s src tgt (Value arch tgt tp) evalRewrittenRhs :: AssignRhs arch (Value arch tgt) tp -> Rewriter arch s src tgt (Value arch tgt tp)
evalRewrittenRhs rhs = Rewriter $ do evalRewrittenRhs rhs = Rewriter $ do
gen <- gets $ rwctxNonceGen . rwContext gen <- gets $ rwctxNonceGen . rwContext
aid <- lift $ AssignId <$> freshNonce gen aid <- lift $ AssignId <$> freshNonce gen
@ -379,7 +379,8 @@ rewriteApp app = do
_ -> evalRewrittenRhs (EvalApp app) _ -> evalRewrittenRhs (EvalApp app)
rewriteAssignRhs :: AssignRhs arch src tp -> Rewriter arch s src tgt (Value arch tgt tp) rewriteAssignRhs :: AssignRhs arch (Value arch src) tp
-> Rewriter arch s src tgt (Value arch tgt tp)
rewriteAssignRhs rhs = rewriteAssignRhs rhs =
case rhs of case rhs of
EvalApp app -> do EvalApp app -> do
@ -388,6 +389,12 @@ rewriteAssignRhs rhs =
ReadMem addr repr -> do ReadMem addr repr -> do
tgtAddr <- rewriteValue addr tgtAddr <- rewriteValue addr
evalRewrittenRhs (ReadMem tgtAddr repr) evalRewrittenRhs (ReadMem tgtAddr repr)
CondReadMem repr cond addr def -> do
rhs' <- CondReadMem repr
<$> rewriteValue cond
<*> rewriteValue addr
<*> rewriteValue def
evalRewrittenRhs rhs'
EvalArchFn archFn _repr -> do EvalArchFn archFn _repr -> do
f <- Rewriter $ gets $ rwctxArchFn . rwContext f <- Rewriter $ gets $ rwctxArchFn . rwContext
f archFn f archFn

View File

@ -42,13 +42,19 @@ absEvalReadMem r a tp
-- | Get the abstract domain for the right-hand side of an assignment. -- | Get the abstract domain for the right-hand side of an assignment.
transferRHS :: ArchitectureInfo a transferRHS :: ArchitectureInfo a
-> AbsProcessorState (ArchReg a) ids -> AbsProcessorState (ArchReg a) ids
-> AssignRhs a ids tp -> AssignRhs a (Value a ids) tp
-> ArchAbsValue a tp -> ArchAbsValue a tp
transferRHS info r rhs = transferRHS info r rhs =
case rhs of case rhs of
EvalApp app -> withArchConstraints info $ transferApp r app EvalApp app -> withArchConstraints info $ transferApp r app
SetUndefined _ -> TopV SetUndefined _ -> TopV
ReadMem a tp -> withArchConstraints info $ absEvalReadMem r a tp ReadMem a tp -> withArchConstraints info $ absEvalReadMem r a tp
-- TODO: See if we should build a mux specific version
CondReadMem tp _ a d ->
withArchConstraints info $ do
lub (absEvalReadMem r a tp)
(transferValue r d)
EvalArchFn f _ -> absEvalArchFn info r f EvalArchFn f _ -> absEvalArchFn info r f
-- | Merge in the value of the assignment. -- | Merge in the value of the assignment.

View File

@ -7,9 +7,12 @@ a value without revisiting shared subterms.
-} -}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Macaw.Fold module Data.Macaw.Fold
( Data.Parameterized.TraversableFC.FoldableFC(..) ( Data.Parameterized.TraversableFC.FoldableFC(..)
, foldValueCached , foldValueCached
@ -26,25 +29,18 @@ import Data.Macaw.CFG
-- Helper that is a state monad, and also a monoid when the return value -- Helper that is a state monad, and also a monoid when the return value
-- is a monoid. -- is a monoid.
newtype StateMonadMonoid s m = SMM { getStateMonadMonoid :: State s m } newtype MonadMonoid m a = MM { getMonadMonoid :: m a }
deriving (Functor, Applicative, Monad, MonadState s) deriving (Functor, Applicative, Monad)
instance MonadState s m => MonadState s (MonadMonoid m) where
get = MM get
put s = MM (put s)
instance Monoid m => Monoid (StateMonadMonoid s m) where instance (Applicative m, Monoid a) => Monoid (MonadMonoid m a) where
mempty = return mempty mempty = pure mempty
mappend m m' = mappend <$> m <*> m' mappend m m' = mappend <$> m <*> m'
foldAssignRHSValues :: (Monoid r, FoldableFC (ArchFn arch))
=> (forall vtp . Value arch ids vtp -> r)
-> AssignRhs arch ids tp
-> r
foldAssignRHSValues go v =
case v of
EvalApp a -> foldMapFC go a
SetUndefined _w -> mempty
ReadMem addr _ -> go addr
EvalArchFn f _ -> foldMapFC go f
-- | This folds over elements of a values in a values. -- | This folds over elements of a values in a values.
-- --
-- It memoizes values so that it only evaluates assignments with the same id -- It memoizes values so that it only evaluates assignments with the same id
@ -61,11 +57,11 @@ foldValueCached :: forall m arch ids tp
-- ^ Function for assignments -- ^ Function for assignments
-> Value arch ids tp -> Value arch ids tp
-> State (Map (Some (AssignId ids)) m) m -> State (Map (Some (AssignId ids)) m) m
foldValueCached litf rwf initf assignf = getStateMonadMonoid . go foldValueCached litf rwf initf assignf = getMonadMonoid . go
where where
go :: forall tp' go :: forall tp'
. Value arch ids tp' . Value arch ids tp'
-> StateMonadMonoid (Map (Some (AssignId ids)) m) m -> MonadMonoid (State (Map (Some (AssignId ids)) m)) m
go v = go v =
case v of case v of
BoolValue b -> return (litf (knownNat :: NatRepr 1) (if b then 1 else 0)) BoolValue b -> return (litf (knownNat :: NatRepr 1) (if b then 1 else 0))
@ -78,6 +74,6 @@ foldValueCached litf rwf initf assignf = getStateMonadMonoid . go
Just v' -> Just v' ->
return $ assignf a_id v' return $ assignf a_id v'
Nothing -> do Nothing -> do
rhs_v <- foldAssignRHSValues go rhs rhs_v <- foldMapFC go rhs
modify' $ Map.insert (Some a_id) rhs_v modify' $ Map.insert (Some a_id) rhs_v
return (assignf a_id rhs_v) return (assignf a_id rhs_v)

View File

@ -8,6 +8,9 @@ module Data.Macaw.TypedList
, Index(..) , Index(..)
, indexValue , indexValue
, (!) , (!)
, index0
, index1
, index2
) where ) where
import Data.Parameterized.Classes import Data.Parameterized.Classes
@ -73,3 +76,12 @@ indexValue = go 0
where go :: Integer -> Index l x -> Integer where go :: Integer -> Index l x -> Integer
go i ZeroIndex = i go i ZeroIndex = i
go i (ConsIndex x) = go (i+1) x go i (ConsIndex x) = go (i+1) x
index0 :: Index (x:r) x
index0 = ZeroIndex
index1 :: Index (x0:x1:r) x1
index1 = ConsIndex index0
index2 :: Index (x0:x1:x2:r) x2
index2 = ConsIndex index1

View File

@ -147,12 +147,25 @@ instance Show (TypeRepr tp) where
class KnownType tp where class KnownType tp where
knownType :: TypeRepr tp knownType :: TypeRepr tp
class KnownTypeList l where
knownTypeList :: TList TypeRepr l
instance KnownTypeList '[] where
knownTypeList = TList.Empty
instance (KnownType h, KnownTypeList r) => KnownTypeList (h : r) where
knownTypeList = knownType TList.:| knownTypeList
instance KnownType BoolType where instance KnownType BoolType where
knownType = BoolTypeRepr knownType = BoolTypeRepr
instance (KnownNat n, 1 <= n) => KnownType (BVType n) where instance (KnownNat n, 1 <= n) => KnownType (BVType n) where
knownType = BVTypeRepr knownNat knownType = BVTypeRepr knownNat
instance (KnownTypeList l) => KnownType (TupleType l) where
knownType = TupleTypeRepr knownTypeList
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Floating point sizes -- Floating point sizes

View File

@ -37,7 +37,7 @@ module Data.Macaw.X86
, Data.Macaw.X86.X86Reg.x86FloatResultRegs , Data.Macaw.X86.X86Reg.x86FloatResultRegs
, Data.Macaw.X86.X86Reg.x86CalleeSavedRegs , Data.Macaw.X86.X86Reg.x86CalleeSavedRegs
, pattern Data.Macaw.X86.X86Reg.RAX , pattern Data.Macaw.X86.X86Reg.RAX
, x86DemandContext
) where ) where
import Control.Exception (assert) import Control.Exception (assert)
@ -321,6 +321,7 @@ transferAbsValue r f =
X86IRem{} -> TopV X86IRem{} -> TopV
X86Div{} -> TopV X86Div{} -> TopV
X86Rem{} -> TopV X86Rem{} -> TopV
UCOMIS{} -> TopV
-- | Disassemble block, returning either an error, or a list of blocks -- | Disassemble block, returning either an error, or a list of blocks
-- and ending PC. -- and ending PC.
@ -454,7 +455,7 @@ freeBSD_syscallPersonality =
, spResultRegisters = [ Some RAX ] , spResultRegisters = [ Some RAX ]
} }
x86DemandContext :: DemandContext X86_64 ids x86DemandContext :: DemandContext X86_64
x86DemandContext = x86DemandContext =
DemandContext { demandConstraints = \a -> a DemandContext { demandConstraints = \a -> a
, archFnHasSideEffects = x86PrimFnHasSideEffects , archFnHasSideEffects = x86PrimFnHasSideEffects

View File

@ -14,6 +14,7 @@ This defines the X86_64 architecture type and the supporting definitions.
module Data.Macaw.X86.ArchTypes module Data.Macaw.X86.ArchTypes
( -- * Architecture ( -- * Architecture
X86_64 X86_64
, UCOMType(..)
, X86PrimFn(..) , X86PrimFn(..)
, rewriteX86PrimFn , rewriteX86PrimFn
, x86PrimFnHasSideEffects , x86PrimFnHasSideEffects
@ -173,11 +174,10 @@ data X86PrimFn f tp where
-> !(f (BVType 64)) -> !(f (BVType 64))
-> !(f (BVType 64)) -> !(f (BVType 64))
-> X86PrimFn f (BVType 64) -> X86PrimFn f (BVType 64)
-- ^ `RepnzScas sz val base cnt` searchs through a buffer starting at -- ^ `RepnzScas sz val base cnt` searchs through a buffer starting at
-- `base` to find an element `i` such that base[i] = val. -- `base` to find an element `i` such that base[i] = val.
-- Each step it increments `i` by 1 and decrements `cnt` by `1`. It returns -- Each step it increments `i` by 1 and decrements `cnt` by `1`.
-- the final value of `cnt`. -- It returns the final value of `cnt`, the
MMXExtend :: !(f (BVType 64)) -> X86PrimFn f (BVType 80) MMXExtend :: !(f (BVType 64)) -> X86PrimFn f (BVType 80)
-- ^ This returns a 80-bit value where the high 16-bits are all -- ^ This returns a 80-bit value where the high 16-bits are all
-- 1s, and the low 64-bits are the given register. -- 1s, and the low 64-bits are the given register.
@ -208,6 +208,35 @@ data X86PrimFn f tp where
-- ^ This performs an unsigned remainder for div. -- ^ This performs an unsigned remainder for div.
-- It raises a #DE exception if the divisor is 0 or the quotient overflows. -- It raises a #DE exception if the divisor is 0 or the quotient overflows.
UCOMIS :: !(UCOMType tp)
-> !(f tp)
-> !(f tp)
-> X86PrimFn f (TupleType [BoolType, BoolType, BoolType])
-- ^ This performs a comparison of two floating point values and returns three flags:
--
-- * ZF is for the zero-flag and true if the arguments are equal or either argument is a NaN.
--
-- * PF records the unordered flag and is true if either value is a NaN.
--
-- * CF is the carry flag, and true if the first floating point argument is less than
-- second or either value is a NaN.
--
-- The order of the flags was chosen to be consistent with the Intel documentation for
-- UCOMISD and UCOMISS.
--
-- The documentation is a bit unclear, but it appears this function implicitly depends
-- on the MXCSR register and may signal if the invalid operation exception #I is
-- not masked or the denomal exception #D if it is not masked.
-- | A single or double value for floating-point restricted to this types.
data UCOMType tp where
UCOMSingle :: UCOMType (FloatType SingleFloat)
UCOMDouble :: UCOMType (FloatType DoubleFloat)
instance HasRepr UCOMType TypeRepr where
typeRepr UCOMSingle = knownType
typeRepr UCOMDouble = knownType
instance HasRepr (X86PrimFn f) TypeRepr where instance HasRepr (X86PrimFn f) TypeRepr where
typeRepr f = typeRepr f =
case f of case f of
@ -226,6 +255,7 @@ instance HasRepr (X86PrimFn f) TypeRepr where
X86IRem w _ _ -> typeRepr (repValSizeMemRepr w) X86IRem w _ _ -> typeRepr (repValSizeMemRepr w)
X86Div w _ _ -> typeRepr (repValSizeMemRepr w) X86Div w _ _ -> typeRepr (repValSizeMemRepr w)
X86Rem w _ _ -> typeRepr (repValSizeMemRepr w) X86Rem w _ _ -> typeRepr (repValSizeMemRepr w)
UCOMIS _ _ _ -> knownType
instance FunctorFC X86PrimFn where instance FunctorFC X86PrimFn where
fmapFC = fmapFCDefault fmapFC = fmapFCDefault
@ -253,6 +283,7 @@ instance TraversableFC X86PrimFn where
X86IRem w n d -> X86IRem w <$> go n <*> go d X86IRem w n d -> X86IRem w <$> go n <*> go d
X86Div w n d -> X86Div w <$> go n <*> go d X86Div w n d -> X86Div w <$> go n <*> go d
X86Rem w n d -> X86Rem w <$> go n <*> go d X86Rem w n d -> X86Rem w <$> go n <*> go d
UCOMIS tp x y -> UCOMIS tp <$> go x <*> go y
instance IsArchFn X86PrimFn where instance IsArchFn X86PrimFn where
ppArchFn pp f = ppArchFn pp f =
@ -274,7 +305,7 @@ instance IsArchFn X86PrimFn where
X86IRem w n d -> sexprA "irem" [ pure (text $ show $ typeWidth $ repValSizeMemRepr w), pp n, pp d ] X86IRem w n d -> sexprA "irem" [ pure (text $ show $ typeWidth $ repValSizeMemRepr w), pp n, pp d ]
X86Div w n d -> sexprA "div" [ pure (text $ show $ typeWidth $ repValSizeMemRepr w), pp n, pp d ] X86Div w n d -> sexprA "div" [ pure (text $ show $ typeWidth $ repValSizeMemRepr w), pp n, pp d ]
X86Rem w n d -> sexprA "rem" [ pure (text $ show $ typeWidth $ repValSizeMemRepr w), pp n, pp d ] X86Rem w n d -> sexprA "rem" [ pure (text $ show $ typeWidth $ repValSizeMemRepr w), pp n, pp d ]
UCOMIS _ x y -> sexprA "ucomis" [ pp x, pp y ]
-- | This returns true if evaluating the primitive function implicitly -- | This returns true if evaluating the primitive function implicitly
-- changes the processor state in some way. -- changes the processor state in some way.
@ -296,6 +327,7 @@ x86PrimFnHasSideEffects f =
X86IRem{} -> True -- /\ .. X86IRem{} -> True -- /\ ..
X86Div{} -> True -- /\ .. X86Div{} -> True -- /\ ..
X86Rem{} -> True -- /\ .. X86Rem{} -> True -- /\ ..
UCOMIS{} -> True
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- X86Stmt -- X86Stmt

View File

@ -347,7 +347,7 @@ newAssignID = do
gs <- getState gs <- getState
liftM AssignId $ X86G $ lift $ lift $ lift $ freshNonce $ assignIdGen gs liftM AssignId $ X86G $ lift $ lift $ lift $ freshNonce $ assignIdGen gs
addAssignment :: AssignRhs X86_64 ids tp addAssignment :: AssignRhs X86_64 (Value X86_64 ids) tp
-> X86Generator st_s ids (Assignment X86_64 ids tp) -> X86Generator st_s ids (Assignment X86_64 ids tp)
addAssignment rhs = do addAssignment rhs = do
l <- newAssignID l <- newAssignID
@ -355,7 +355,7 @@ addAssignment rhs = do
addStmt $ AssignStmt a addStmt $ AssignStmt a
pure $! a pure $! a
evalAssignRhs :: AssignRhs X86_64 ids tp evalAssignRhs :: AssignRhs X86_64 (Value X86_64 ids) tp
-> X86Generator st_s ids (Expr ids tp) -> X86Generator st_s ids (Expr ids tp)
evalAssignRhs rhs = evalAssignRhs rhs =
ValueExpr . AssignedValue <$> addAssignment rhs ValueExpr . AssignedValue <$> addAssignment rhs

View File

@ -29,6 +29,8 @@ module Data.Macaw.X86.Getters
, getAddrRegOrSegment , getAddrRegOrSegment
, getAddrRegSegmentOrImm , getAddrRegSegmentOrImm
, readXMMValue , readXMMValue
, readXMMOrMem32
, readXMMOrMem64
-- * Utilities -- * Utilities
, reg16Loc , reg16Loc
, reg32Loc , reg32Loc
@ -385,6 +387,18 @@ getAddrRegSegmentOrImm v =
-- | Get a XMM value -- | Get a XMM value
readXMMValue :: F.Value -> X86Generator st ids (Expr ids (BVType 128)) readXMMValue :: F.Value -> X86Generator st ids (Expr ids (BVType 128))
readXMMValue (F.XMMReg r) = get $ fullRegister $ X86_XMMReg r readXMMValue (F.XMMReg r) = getReg $ X86_XMMReg r
readXMMValue (F.Mem128 a) = readBVAddress a xmmMemRepr readXMMValue (F.Mem128 a) = readBVAddress a xmmMemRepr
readXMMValue _ = fail "XMM Instruction given unexpected value." readXMMValue _ = fail "XMM Instruction given unexpected value."
-- | Get the low 32-bits out of an XMM register or a 64-bit XMM address.
readXMMOrMem32 :: F.Value -> X86Generator st ids (Expr ids (BVType 32))
readXMMOrMem32 (F.XMMReg r) = bvTrunc n32 <$> getReg (X86_XMMReg r)
readXMMOrMem32 (F.Mem128 a) = readBVAddress a dwordMemRepr
readXMMOrMem32 _ = fail "XMM Instruction given unexpected value."
-- | Get the low 64-bits out of an XMM register or a 64-bit XMM address.
readXMMOrMem64 :: F.Value -> X86Generator st ids (Expr ids (BVType 64))
readXMMOrMem64 (F.XMMReg r) = bvTrunc n64 <$> getReg (X86_XMMReg r)
readXMMOrMem64 (F.Mem128 a) = readBVAddress a qwordMemRepr
readXMMOrMem64 _ = fail "XMM Instruction given unexpected value."

View File

@ -85,9 +85,6 @@ module Data.Macaw.X86.Monad
, (.*) , (.*)
, (.&&.) , (.&&.)
, (.||.) , (.||.)
, isQNaN
, isSNaN
, isAnyNaN
-- * Semantics -- * Semantics
, SIMDWidth(..) , SIMDWidth(..)
, make_undefined , make_undefined
@ -110,7 +107,6 @@ module Data.Macaw.X86.Monad
, memcopy , memcopy
, memcmp , memcmp
, memset , memset
, rep_scas
, even_parity , even_parity
, fnstcw , fnstcw
, getSegmentBase , getSegmentBase
@ -1661,16 +1657,6 @@ instance IsValue (Expr ids) where
fpFromBV tgt x = app $ FPFromBV x tgt fpFromBV tgt x = app $ FPFromBV x tgt
truncFPToSignedBV tgt src x = app $ TruncFPToSignedBV src x tgt truncFPToSignedBV tgt src x = app $ TruncFPToSignedBV src x tgt
isQNaN :: FloatInfoRepr flt -> Expr s (FloatType flt) -> Expr s BoolType
isQNaN rep x = app $ FPIsQNaN rep x
isSNaN :: FloatInfoRepr flt -> Expr s (FloatType flt) -> Expr s BoolType
isSNaN rep x = app $ FPIsSNaN rep x
-- | is NaN (quiet and signalling)
isAnyNaN :: FloatInfoRepr flt -> Expr s (FloatType flt) -> Expr s BoolType
isAnyNaN fir v = boolOr (isQNaN fir v) (isSNaN fir v)
(.&&.) :: IsValue v => v BoolType -> v BoolType -> v BoolType (.&&.) :: IsValue v => v BoolType -> v BoolType -> v BoolType
(.&&.) = boolAnd (.&&.) = boolAnd
@ -1955,42 +1941,6 @@ memset count val dest dfl = do
df_v <- eval dfl df_v <- eval dfl
addArchStmt $ MemSet count_v val_v dest_v df_v addArchStmt $ MemSet count_v val_v dest_v df_v
-- | This will compare a value against the contents of a memory region for equality and/or
-- inequality.
--
-- It accepts the value to compare, a pointer to the start of the region, and
-- the maximum number of elements to compare, which is decremented after each comparison.
-- It returns the value of the count after it has succeeded, or zero if we reached the
-- end without finding a value. A return value of zero is thus ambiguous on whether
-- the value was found in the last iteration, or whether the value was never found.
rep_scas :: Bool
-- ^ Find first matching (True) or not matching (False)
-> Expr ids BoolType
-- ^ Flag indicates direction of search
-- True means we should decrement buffer pointers after each copy.
-- False means we should increment the buffer pointers after each copy.
-> RepValSize w
-- ^ Number of bytes to compare at a time {1, 2, 4, 8}
-> BVExpr ids w
-- ^ Value to compare
-> Addr ids
-- ^ Pointer to first buffer
-> BVExpr ids 64
-- ^ Maximum number of elements to compare
-> X86Generator st ids (BVExpr ids 64)
rep_scas True is_reverse sz val buf count = do
val_v <- eval val
buf_v <- eval buf
count_v <- eval count
is_reverse_v <- eval is_reverse
case is_reverse_v of
BoolValue False ->
evalArchFn (RepnzScas sz val_v buf_v count_v)
_ ->
fail $ "Unsupported rep_scas value " ++ show is_reverse_v
rep_scas False _is_reverse _sz _val _buf _count = do
fail $ "Semantics only currently supports finding elements."
-- | Return true if value contains an even number of true bits. -- | Return true if value contains an even number of true bits.
even_parity :: BVExpr ids 8 -> X86Generator st ids (Expr ids BoolType) even_parity :: BVExpr ids 8 -> X86Generator st ids (Expr ids BoolType)
even_parity v = do even_parity v = do

View File

@ -17,7 +17,6 @@ module Data.Macaw.X86.Semantics
( execInstruction ( execInstruction
) where ) where
import Prelude hiding (isNaN)
import Control.Monad (when) import Control.Monad (when)
import qualified Data.Bits as Bits import qualified Data.Bits as Bits
import Data.Foldable import Data.Foldable
@ -29,11 +28,20 @@ import Data.Parameterized.Some
import Data.Proxy import Data.Proxy
import qualified Flexdis86 as F import qualified Flexdis86 as F
import Data.Macaw.CFG (MemRepr(..), memReprBytes) import Data.Macaw.CFG ( MemRepr(..)
, memReprBytes
, App(..)
, Value(BoolValue)
, AssignRhs(CondReadMem)
, mkLit
)
import Data.Macaw.Memory (Endianness (LittleEndian)) import Data.Macaw.Memory (Endianness (LittleEndian))
import Data.Macaw.Types import Data.Macaw.Types
import qualified Data.Macaw.TypedList as TList
--import qualified Data.Macaw.X86.ArchTypes as X86
import Data.Macaw.X86.ArchTypes
import Data.Macaw.X86.Generator
import Data.Macaw.X86.Getters import Data.Macaw.X86.Getters
import Data.Macaw.X86.InstructionDef import Data.Macaw.X86.InstructionDef
import Data.Macaw.X86.Monad import Data.Macaw.X86.Monad
@ -1147,7 +1155,8 @@ xaxValLoc QWordRepVal = rax
-- The arguments to this are always rax/QWORD PTR es:[rdi], so we only -- The arguments to this are always rax/QWORD PTR es:[rdi], so we only
-- need the args for the size. -- need the args for the size.
exec_scas :: Bool -- Flag indicating if RepZPrefix appeared before instruction exec_scas :: forall st ids n
. Bool -- Flag indicating if RepZPrefix appeared before instruction
-> Bool -- Flag indicating if RepNZPrefix appeared before instruction -> Bool -- Flag indicating if RepNZPrefix appeared before instruction
-> RepValSize n -> RepValSize n
-> X86Generator st ids () -> X86Generator st ids ()
@ -1163,38 +1172,59 @@ exec_scas False False rep = repValHasSupportedWidth rep $ do
(bvLit n64 (memReprBytes memRepr)) (bvLit n64 (memReprBytes memRepr))
rdi .= v_rdi `bvAdd` bytesPerOp rdi .= v_rdi `bvAdd` bytesPerOp
-- repz or repnz prefix set -- repz or repnz prefix set
exec_scas _repz_pfx repnz_pfx rep = repValHasSupportedWidth rep $ do exec_scas _repz_pfx False _rep =
let mrepr = repValSizeMemRepr rep fail $ "Semantics only currently supports finding elements."
let val_loc = xaxValLoc rep exec_scas _repz_pfx True sz = repValHasSupportedWidth sz $ do
let val_loc = xaxValLoc sz
-- Get the direction flag -- it will be used to determine whether to add or subtract at each step. -- Get the direction flag -- it will be used to determine whether to add or subtract at each step.
-- If the flag is zero, then the register is incremented, otherwise it is incremented. -- If the flag is zero, then the register is incremented, otherwise it is incremented.
df <- get df_loc df <- eval =<< get df_loc
case df of
BoolValue False ->
pure ()
_ ->
fail $ "Unsupported scas value " ++ show df
-- Get value that we are using in comparison -- Get value that we are using in comparison
v_rax <- get val_loc v_rax <- eval =<< get val_loc
-- Get the starting address for the comparsions -- Get the starting address for the comparsions
v_rdi <- get rdi v_rdi <- eval =<< get rdi
-- Get maximum number of times to execute instruction -- Get maximum number of times to execute instruction
count <- get rcx v_rcx <- eval =<< get rcx
unless_ (count .=. bvKLit 0) $ do count' <- evalArchFn (RepnzScas sz v_rax v_rdi v_rcx)
-- Get number of bytes each comparison will use
let bytePerOpLit = bvKLit (memReprBytes (repValSizeMemRepr sz))
count' <- rep_scas repnz_pfx df rep v_rax v_rdi count -- Count the number of bytes seen.
let nBytesSeen = (ValueExpr v_rcx `bvSub` count') `bvMul` bytePerOpLit
-- Get number of bytes each comparison will use let lastWordBytes = nBytesSeen `bvSub` bytePerOpLit
let bytesPerOp = memReprBytes mrepr
-- Get multiple of each element (negated for direction flag
let bytePerOpLit = mux df (bvKLit (negate bytesPerOp)) (bvKLit bytesPerOp)
-- Count the number of bytes seen. let y = ValueExpr v_rax
let nBytesSeen = (count `bvSub` count') `bvMul` bytePerOpLit
let lastWordBytes = nBytesSeen `bvSub` bytePerOpLit dst <- eval (ValueExpr v_rdi `bvAdd` lastWordBytes)
cond <- eval (ValueExpr v_rcx .=. bvKLit 0)
let condExpr = ValueExpr cond
dst_val <- evalAssignRhs $ CondReadMem (repValSizeMemRepr sz) cond dst (mkLit knownNat 0)
exec_cmp (MemoryAddr (v_rdi `bvAdd` lastWordBytes) mrepr) v_rax let condSet :: Location (Addr ids) tp -> Expr ids tp -> X86Generator st ids ()
condSet l e = modify l (mux condExpr e)
condSet rcx count'
condSet rdi $ ValueExpr v_rdi `bvAdd` nBytesSeen
condSet of_loc $ ssub_overflows dst_val y
-- Set overflow and arithmetic flags
condSet af_loc $ usub4_overflows dst_val y
condSet cf_loc $ usub_overflows dst_val y
-- Set result value.
let res = dst_val `bvSub` y
condSet sf_loc $ msb res
condSet zf_loc $ is_zero res
byte <- eval (least_byte res)
condSet pf_loc =<< evalArchFn (EvenParity byte)
rdi .= v_rdi `bvAdd` nBytesSeen
rcx .= count'
def_scas :: InstructionDef def_scas :: InstructionDef
def_scas = defBinary "scas" $ \ii loc loc' -> do def_scas = defBinary "scas" $ \ii loc loc' -> do
@ -1836,33 +1866,47 @@ def_mulps = defBinaryXMMV "mulps" $ \l v -> do
-- SQRTSS Compute square root of scalar single-precision floating-point values -- SQRTSS Compute square root of scalar single-precision floating-point values
-- RSQRTPS Compute reciprocals of square roots of packed single-precision floating-point values -- RSQRTPS Compute reciprocals of square roots of packed single-precision floating-point values
-- RSQRTSS Compute reciprocal of square root of scalar single-precision floating-point values -- RSQRTSS Compute reciprocal of square root of scalar single-precision floating-point values
-- MAXPS Return maximum packed single-precision floating-point values -- MAXPS Return maximum packed single-precision floating-poi1nt values
-- MAXSS Return maximum scalar single-precision floating-point values -- MAXSS Return maximum scalar single-precision floating-point values
-- MINPS Return minimum packed single-precision floating-point values -- MINPS Return minimum packed single-precision floating-point values
-- MINSS Return minimum scalar single-precision floating-point values -- MINSS Return minimum scalar single-precision floating-point values
-- *** SSE Comparison Instructions -- *** SSE Comparison Instructions
-- | UCOMISD Perform unordered comparison of scalar double-precision
-- floating-point values and set flags in EFLAGS register.
def_ucomisd :: InstructionDef
-- Invalid (if SNaN operands), Denormal.
def_ucomisd =
defBinary "ucomisd" $ \_ xv yv -> do
x <- eval =<< readXMMOrMem64 xv
y <- eval =<< readXMMOrMem64 yv
res <- evalArchFn (UCOMIS UCOMDouble x y)
zf_loc .= app (TupleField knownTypeList res TList.index0)
pf_loc .= app (TupleField knownTypeList res TList.index1)
cf_loc .= app (TupleField knownTypeList res TList.index2)
of_loc .= false
af_loc .= false
sf_loc .= false
-- CMPPS Compare packed single-precision floating-point values -- CMPPS Compare packed single-precision floating-point values
-- CMPSS Compare scalar single-precision floating-point values -- CMPSS Compare scalar single-precision floating-point values
-- COMISS Perform ordered comparison of scalar single-precision floating-point values and set flags in EFLAGS register -- COMISS Perform ordered comparison of scalar single-precision floating-point values and set flags in EFLAGS register
-- | UCOMISS Perform unordered comparison of scalar single-precision floating-point values and set flags in EFLAGS register -- | UCOMISS Perform unordered comparison of scalar single-precision floating-point values and set flags in EFLAGS register
def_ucomiss :: InstructionDef def_ucomiss :: InstructionDef
-- Invalid (if SNaN operands), Denormal. -- Invalid (if SNaN operands), Denormal.
def_ucomiss = defBinaryXMMV "ucomiss" $ \l v -> do def_ucomiss =
v' <- bvTrunc knownNat <$> get l defBinary "ucomiss" $ \_ xv yv -> do
let fir = SingleFloatRepr x <- eval =<< readXMMOrMem32 xv
let unordered = (isAnyNaN fir v .||. isAnyNaN fir v') y <- eval =<< readXMMOrMem32 yv
lt = fpLt fir v' v res <- evalArchFn (UCOMIS UCOMSingle x y)
eq = fpEq fir v' v zf_loc .= app (TupleField knownTypeList res TList.index0)
pf_loc .= app (TupleField knownTypeList res TList.index1)
zf_loc .= (unordered .||. eq) cf_loc .= app (TupleField knownTypeList res TList.index2)
pf_loc .= unordered of_loc .= false
cf_loc .= (unordered .||. lt) af_loc .= false
sf_loc .= false
of_loc .= false
af_loc .= false
sf_loc .= false
-- *** SSE Logical Instructions -- *** SSE Logical Instructions
@ -2176,24 +2220,6 @@ def_cmpsd =
-- COMISD Perform ordered comparison of scalar double-precision floating-point values and set flags in EFLAGS register -- COMISD Perform ordered comparison of scalar double-precision floating-point values and set flags in EFLAGS register
-- | UCOMISD Perform unordered comparison of scalar double-precision
-- floating-point values and set flags in EFLAGS register.
def_ucomisd :: InstructionDef
-- Invalid (if SNaN operands), Denormal.
def_ucomisd = defBinaryXMMV "ucomisd" $ \l v -> do
let fir = DoubleFloatRepr
v' <- bvTrunc knownNat <$> get l
let unordered = (isAnyNaN fir v .||. isAnyNaN fir v')
lt = fpLt fir v' v
eq = fpEq fir v' v
zf_loc .= (unordered .||. eq)
pf_loc .= unordered
cf_loc .= (unordered .||. lt)
of_loc .= false
af_loc .= false
sf_loc .= false
-- *** SSE2 Shuffle and Unpack Instructions -- *** SSE2 Shuffle and Unpack Instructions