|
|
@ -52,6 +52,18 @@ import Data.Macaw.CFG.DemandSet
|
|
|
|
import Data.Macaw.Discovery.State
|
|
|
|
import Data.Macaw.Discovery.State
|
|
|
|
import Data.Macaw.Types
|
|
|
|
import Data.Macaw.Types
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- | Map from blocks to their predcessors within a function.
|
|
|
|
|
|
|
|
type PredBlockMap arch = Map (ArchSegmentOff arch) [ArchSegmentOff arch]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- | Generate map from block within a function to their predecessors
|
|
|
|
|
|
|
|
predBlockMap :: DiscoveryFunInfo arch ids -> PredBlockMap arch
|
|
|
|
|
|
|
|
predBlockMap finfo =
|
|
|
|
|
|
|
|
Map.fromListWith (++)
|
|
|
|
|
|
|
|
[ (dest, [pblockAddr b])
|
|
|
|
|
|
|
|
| b <- Map.elems (finfo^.parsedBlocks)
|
|
|
|
|
|
|
|
, dest <- parsedTermSucc (pblockTermStmt b)
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
-- The algorithm computes the set of direct deps (i.e., from writes)
|
|
|
|
-- The algorithm computes the set of direct deps (i.e., from writes)
|
|
|
@ -93,6 +105,11 @@ data DemandSet (r :: Type -> Kind.Type) =
|
|
|
|
, functionResultDemands :: !(Map (MemSegmentOff (RegAddrWidth r)) (RegisterSet r))
|
|
|
|
, functionResultDemands :: !(Map (MemSegmentOff (RegAddrWidth r)) (RegisterSet r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- | Return True if the demand set indicates no registers are needed.
|
|
|
|
|
|
|
|
isEmptyDemandSet :: DemandSet r -> Bool
|
|
|
|
|
|
|
|
isEmptyDemandSet ds =
|
|
|
|
|
|
|
|
Set.null (registerDemands ds) && Map.null (functionResultDemands ds)
|
|
|
|
|
|
|
|
|
|
|
|
-- | Create a demand set for specific registers.
|
|
|
|
-- | Create a demand set for specific registers.
|
|
|
|
registerDemandSet :: RegisterSet r -> DemandSet r
|
|
|
|
registerDemandSet :: RegisterSet r -> DemandSet r
|
|
|
|
registerDemandSet s = DemandSet { registerDemands = s
|
|
|
|
registerDemandSet s = DemandSet { registerDemands = s
|
|
|
@ -145,7 +162,8 @@ data DemandType r
|
|
|
|
-- | This denotes a value needed if the function at the given
|
|
|
|
-- | This denotes a value needed if the function at the given
|
|
|
|
-- address needs the specific register as an argument.
|
|
|
|
-- address needs the specific register as an argument.
|
|
|
|
| forall tp. DemandFunctionArg (RegSegmentOff r) (r tp)
|
|
|
|
| forall tp. DemandFunctionArg (RegSegmentOff r) (r tp)
|
|
|
|
-- | This denotes demands if we need the return value of this
|
|
|
|
-- | This key is used to denote the demands associating with
|
|
|
|
|
|
|
|
-- needing to compute the the return value of the
|
|
|
|
-- function stored in the given register.
|
|
|
|
-- function stored in the given register.
|
|
|
|
| forall tp. DemandFunctionResult (r tp)
|
|
|
|
| forall tp. DemandFunctionResult (r tp)
|
|
|
|
|
|
|
|
|
|
|
@ -211,12 +229,26 @@ instance OrdF r => Semigroup (BlockDemands r) where
|
|
|
|
instance OrdF r => Monoid (BlockDemands r) where
|
|
|
|
instance OrdF r => Monoid (BlockDemands r) where
|
|
|
|
mempty = BD Map.empty
|
|
|
|
mempty = BD Map.empty
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- | A cache from assignment identifiers to registers.
|
|
|
|
type AssignmentCache r ids = Map (Some (AssignId ids)) (RegisterSet r)
|
|
|
|
type AssignmentCache r ids = Map (Some (AssignId ids)) (RegisterSet r)
|
|
|
|
|
|
|
|
|
|
|
|
-- | Maps each register to the what information is needed to compute
|
|
|
|
-- | Maps each register to the what information is needed to compute
|
|
|
|
-- the value stored in that register.
|
|
|
|
-- the value stored in that register.
|
|
|
|
newtype FinalRegisterDemands r = FRD (Map (Some r) (DemandSet r))
|
|
|
|
newtype FinalRegisterDemands r = FRD (Map (Some r) (DemandSet r))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- | Add demands for a register to collection.
|
|
|
|
|
|
|
|
insertRegDemand :: OrdF r
|
|
|
|
|
|
|
|
=> r tp
|
|
|
|
|
|
|
|
-> DemandSet r
|
|
|
|
|
|
|
|
-> FinalRegisterDemands r
|
|
|
|
|
|
|
|
-> FinalRegisterDemands r
|
|
|
|
|
|
|
|
insertRegDemand r s (FRD m)
|
|
|
|
|
|
|
|
| isEmptyDemandSet s = FRD m
|
|
|
|
|
|
|
|
| otherwise = FRD (Map.insertWith mappend (Some r) s m)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
postRegisterDemands :: OrdF r => FinalRegisterDemands r -> r tp -> DemandSet r
|
|
|
|
|
|
|
|
postRegisterDemands (FRD m) r = m^.ix (Some r)
|
|
|
|
|
|
|
|
|
|
|
|
instance OrdF r => Semigroup (FinalRegisterDemands r) where
|
|
|
|
instance OrdF r => Semigroup (FinalRegisterDemands r) where
|
|
|
|
FRD x <> FRD y = FRD (Map.unionWith mappend x y)
|
|
|
|
FRD x <> FRD y = FRD (Map.unionWith mappend x y)
|
|
|
|
|
|
|
|
|
|
|
@ -289,16 +321,11 @@ data FunArgContext arch = FAC
|
|
|
|
data FunctionArgsState arch ids = FAS
|
|
|
|
data FunctionArgsState arch ids = FAS
|
|
|
|
{ -- | Map from block address to the result demands map for the block.
|
|
|
|
{ -- | Map from block address to the result demands map for the block.
|
|
|
|
_blockTransfer :: !(Map (ArchSegmentOff arch) (FinalRegisterDemands (ArchReg arch)))
|
|
|
|
_blockTransfer :: !(Map (ArchSegmentOff arch) (FinalRegisterDemands (ArchReg arch)))
|
|
|
|
|
|
|
|
-- | If a demand d is demanded of block address then the block
|
|
|
|
-- | If a demand d is demanded of block address then the block demands S, s.t.
|
|
|
|
-- demands S, s.t. `blockDemandMap ^. at addr ^. at d = Just S1
|
|
|
|
-- `blockDemandMap ^. at addr ^. at d = Just S1
|
|
|
|
|
|
|
|
, _blockDemandMap :: !(Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch)))
|
|
|
|
, _blockDemandMap :: !(Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch)))
|
|
|
|
|
|
|
|
-- | A cache of the assignments and their deps. The key is not
|
|
|
|
-- | Maps each global block label to the set of blocks that have intra-procedural
|
|
|
|
-- included in the set of deps (but probably should be).
|
|
|
|
-- jumps to that block. Since the function does not change, we omit the global label
|
|
|
|
|
|
|
|
, _blockPreds :: !(Map (ArchSegmentOff arch) [ArchSegmentOff arch])
|
|
|
|
|
|
|
|
-- | A cache of the assignments and their deps. The key is not included
|
|
|
|
|
|
|
|
-- in the set of deps (but probably should be).
|
|
|
|
|
|
|
|
, _assignmentCache :: !(AssignmentCache (ArchReg arch) ids)
|
|
|
|
, _assignmentCache :: !(AssignmentCache (ArchReg arch) ids)
|
|
|
|
-- | Warnings from summarization in reverse order.
|
|
|
|
-- | Warnings from summarization in reverse order.
|
|
|
|
, reversedWarnings :: [String]
|
|
|
|
, reversedWarnings :: [String]
|
|
|
@ -312,9 +339,6 @@ blockDemandMap :: Simple Lens (FunctionArgsState arch ids)
|
|
|
|
(Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch)))
|
|
|
|
(Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch)))
|
|
|
|
blockDemandMap = lens _blockDemandMap (\s v -> s { _blockDemandMap = v })
|
|
|
|
blockDemandMap = lens _blockDemandMap (\s v -> s { _blockDemandMap = v })
|
|
|
|
|
|
|
|
|
|
|
|
blockPreds :: Simple Lens (FunctionArgsState arch ids) (Map (ArchSegmentOff arch) [ArchSegmentOff arch])
|
|
|
|
|
|
|
|
blockPreds = lens _blockPreds (\s v -> s { _blockPreds = v })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assignmentCache :: Simple Lens (FunctionArgsState arch ids) (AssignmentCache (ArchReg arch) ids)
|
|
|
|
assignmentCache :: Simple Lens (FunctionArgsState arch ids) (AssignmentCache (ArchReg arch) ids)
|
|
|
|
assignmentCache = lens _assignmentCache (\s v -> s { _assignmentCache = v })
|
|
|
|
assignmentCache = lens _assignmentCache (\s v -> s { _assignmentCache = v })
|
|
|
|
|
|
|
|
|
|
|
@ -322,7 +346,6 @@ initFunctionArgsState :: [String] -> FunctionArgsState arch ids
|
|
|
|
initFunctionArgsState prevWarn =
|
|
|
|
initFunctionArgsState prevWarn =
|
|
|
|
FAS { _blockTransfer = Map.empty
|
|
|
|
FAS { _blockTransfer = Map.empty
|
|
|
|
, _blockDemandMap = Map.empty
|
|
|
|
, _blockDemandMap = Map.empty
|
|
|
|
, _blockPreds = Map.empty
|
|
|
|
|
|
|
|
, _assignmentCache = Map.empty
|
|
|
|
, _assignmentCache = Map.empty
|
|
|
|
, reversedWarnings = prevWarn
|
|
|
|
, reversedWarnings = prevWarn
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -344,14 +367,6 @@ addWarning msg =
|
|
|
|
-- ----------------------------------------------------------------------------------------
|
|
|
|
-- ----------------------------------------------------------------------------------------
|
|
|
|
-- Phase one functions
|
|
|
|
-- Phase one functions
|
|
|
|
|
|
|
|
|
|
|
|
-- | This registers a block in the first phase (block discovery).
|
|
|
|
|
|
|
|
addIntraproceduralJumpTarget :: {-ArchConstraints arch
|
|
|
|
|
|
|
|
=> -} ArchSegmentOff arch
|
|
|
|
|
|
|
|
-> ArchSegmentOff arch
|
|
|
|
|
|
|
|
-> FunctionArgsM arch ids ()
|
|
|
|
|
|
|
|
addIntraproceduralJumpTarget src dest = -- record the edge
|
|
|
|
|
|
|
|
blockPreds %= Map.insertWith (++) dest [src]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
withAssignmentCache :: State (AssignmentCache (ArchReg arch) ids) a -> FunctionArgsM arch ids a
|
|
|
|
withAssignmentCache :: State (AssignmentCache (ArchReg arch) ids) a -> FunctionArgsM arch ids a
|
|
|
|
withAssignmentCache m = do
|
|
|
|
withAssignmentCache m = do
|
|
|
|
c <- use assignmentCache
|
|
|
|
c <- use assignmentCache
|
|
|
@ -410,14 +425,14 @@ recordBlockTransfer :: forall arch ids t
|
|
|
|
-- ^ List of registers that subsequent blocks may depend on.
|
|
|
|
-- ^ List of registers that subsequent blocks may depend on.
|
|
|
|
-> FunctionArgsM arch ids ()
|
|
|
|
-> FunctionArgsM arch ids ()
|
|
|
|
recordBlockTransfer addr regs regSet = do
|
|
|
|
recordBlockTransfer addr regs regSet = do
|
|
|
|
curDemands <- fromMaybe (FRD Map.empty) . Map.lookup addr <$> use blockTransfer
|
|
|
|
curDemands <- use $ blockTransfer . ix addr
|
|
|
|
let doReg :: FinalRegisterDemands (ArchReg arch)
|
|
|
|
let doReg :: FinalRegisterDemands (ArchReg arch)
|
|
|
|
-> Some (ArchReg arch)
|
|
|
|
-> Some (ArchReg arch)
|
|
|
|
-> State (AssignmentCache (ArchReg arch) ids)
|
|
|
|
-> State (AssignmentCache (ArchReg arch) ids)
|
|
|
|
(FinalRegisterDemands (ArchReg arch))
|
|
|
|
(FinalRegisterDemands (ArchReg arch))
|
|
|
|
doReg (FRD m) (Some r) = do
|
|
|
|
doReg m (Some r) = do
|
|
|
|
rs' <- valueUses (regs ^. boundValue r)
|
|
|
|
rs' <- valueUses (regs^.boundValue r)
|
|
|
|
return $! FRD (Map.insertWith mappend (Some r) (registerDemandSet rs') m)
|
|
|
|
pure $! insertRegDemand r (registerDemandSet rs') m
|
|
|
|
vs <- withAssignmentCache $ foldlM doReg curDemands regSet
|
|
|
|
vs <- withAssignmentCache $ foldlM doReg curDemands regSet
|
|
|
|
blockTransfer %= Map.insert addr vs
|
|
|
|
blockTransfer %= Map.insert addr vs
|
|
|
|
|
|
|
|
|
|
|
@ -517,7 +532,7 @@ linkKnownCallReturnValues addr faddr regs mReturnAddr = do
|
|
|
|
|
|
|
|
|
|
|
|
-- Update blockTransfer to indicate that for all potential
|
|
|
|
-- Update blockTransfer to indicate that for all potential
|
|
|
|
-- return registers that demanding the register
|
|
|
|
-- return registers that demanding the register
|
|
|
|
let linkRetReg (FRD m) sr = FRD (Map.insertWith mappend sr (demandFunctionReturn faddr sr) m)
|
|
|
|
let linkRetReg m (Some r) = insertRegDemand r (demandFunctionReturn faddr (Some r)) m
|
|
|
|
|
|
|
|
|
|
|
|
let srDemandSet :: FinalRegisterDemands (ArchReg arch)
|
|
|
|
let srDemandSet :: FinalRegisterDemands (ArchReg arch)
|
|
|
|
srDemandSet = foldl linkRetReg mempty retRegs
|
|
|
|
srDemandSet = foldl linkRetReg mempty retRegs
|
|
|
@ -627,17 +642,10 @@ summarizeBlock b = do
|
|
|
|
(pblockStmts b)
|
|
|
|
(pblockStmts b)
|
|
|
|
-- Add values demanded by terminal statements
|
|
|
|
-- Add values demanded by terminal statements
|
|
|
|
case pblockTermStmt b of
|
|
|
|
case pblockTermStmt b of
|
|
|
|
ParsedCall finalRegs mRetAddr -> do
|
|
|
|
ParsedCall regs mRetAddr -> do
|
|
|
|
-- Record the intraprocural jump target for the return address.
|
|
|
|
|
|
|
|
case mRetAddr of
|
|
|
|
|
|
|
|
Nothing -> do
|
|
|
|
|
|
|
|
pure ()
|
|
|
|
|
|
|
|
Just retAddr -> do
|
|
|
|
|
|
|
|
addIntraproceduralJumpTarget addr retAddr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Record the demands based on the call, and add edges between
|
|
|
|
-- Record the demands based on the call, and add edges between
|
|
|
|
-- this note and next nodes.
|
|
|
|
-- this note and next nodes.
|
|
|
|
summarizeCall addr finalRegs mRetAddr
|
|
|
|
summarizeCall addr regs mRetAddr
|
|
|
|
|
|
|
|
|
|
|
|
PLTStub regs _ sym -> do
|
|
|
|
PLTStub regs _ sym -> do
|
|
|
|
-- Get argument registers if known for symbol.
|
|
|
|
-- Get argument registers if known for symbol.
|
|
|
@ -660,45 +668,40 @@ summarizeBlock b = do
|
|
|
|
addBlockDemands addr $ demandAlways $
|
|
|
|
addBlockDemands addr $ demandAlways $
|
|
|
|
registerDemandSet $ demands
|
|
|
|
registerDemandSet $ demands
|
|
|
|
|
|
|
|
|
|
|
|
ParsedJump procState tgtAddr -> do
|
|
|
|
ParsedJump regs _tgtAddr -> do
|
|
|
|
-- record all propagations
|
|
|
|
-- record all propagations
|
|
|
|
recordBlockTransfer addr procState archRegs
|
|
|
|
recordBlockTransfer addr regs archRegs
|
|
|
|
addIntraproceduralJumpTarget addr tgtAddr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ParsedBranch nextRegs cond trueAddr falseAddr -> do
|
|
|
|
ParsedBranch regs cond _trueAddr _falseAddr -> do
|
|
|
|
demandValue addr cond
|
|
|
|
demandValue addr cond
|
|
|
|
-- record all propagations
|
|
|
|
-- record all propagations
|
|
|
|
let notIP (Some r) = isNothing (testEquality r ip_reg)
|
|
|
|
let notIP (Some r) = isNothing (testEquality r ip_reg)
|
|
|
|
recordBlockTransfer addr nextRegs (filter notIP archRegs)
|
|
|
|
recordBlockTransfer addr regs (filter notIP archRegs)
|
|
|
|
addIntraproceduralJumpTarget addr trueAddr
|
|
|
|
|
|
|
|
addIntraproceduralJumpTarget addr falseAddr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ParsedLookupTable finalRegs lookup_idx vec -> do
|
|
|
|
ParsedLookupTable regs lookup_idx _vec -> do
|
|
|
|
demandValue addr lookup_idx
|
|
|
|
demandValue addr lookup_idx
|
|
|
|
-- record all propagations
|
|
|
|
-- record all propagations
|
|
|
|
recordBlockTransfer addr finalRegs archRegs
|
|
|
|
recordBlockTransfer addr regs archRegs
|
|
|
|
traverse_ (addIntraproceduralJumpTarget addr) vec
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ParsedReturn finalRegs -> do
|
|
|
|
ParsedReturn regs -> do
|
|
|
|
let retRegs = functionRetRegs ainfo
|
|
|
|
let retRegs = functionRetRegs ainfo
|
|
|
|
let regDemandSet m (Some r) = do
|
|
|
|
let regDemandSet m (Some r) = do
|
|
|
|
regs <- valueUses (finalRegs^.boundValue r)
|
|
|
|
rUses <- valueUses (regs^.boundValue r)
|
|
|
|
pure $! addDemandFunctionResult r (registerDemandSet regs) m
|
|
|
|
pure $! addDemandFunctionResult r (registerDemandSet rUses) m
|
|
|
|
demands <- withAssignmentCache $ foldlM regDemandSet mempty retRegs
|
|
|
|
demands <- withAssignmentCache $ foldlM regDemandSet mempty retRegs
|
|
|
|
addBlockDemands addr demands
|
|
|
|
addBlockDemands addr demands
|
|
|
|
|
|
|
|
|
|
|
|
ParsedArchTermStmt tstmt finalRegs next_addr -> do
|
|
|
|
ParsedArchTermStmt tstmt regs _nextAddr -> do
|
|
|
|
-- Compute effects of terminal statement.
|
|
|
|
-- Compute effects of terminal statement.
|
|
|
|
let e = computeArchTermStmtEffects ainfo tstmt finalRegs
|
|
|
|
let e = computeArchTermStmtEffects ainfo tstmt regs
|
|
|
|
|
|
|
|
|
|
|
|
-- Demand all registers the terminal statement demands.
|
|
|
|
-- Demand all registers the terminal statement demands.
|
|
|
|
do let regUses s (Some r) = addValueUses s (finalRegs^.boundValue r)
|
|
|
|
do let regUses s (Some r) = addValueUses s (regs^.boundValue r)
|
|
|
|
demands <- withAssignmentCache $
|
|
|
|
demands <- withAssignmentCache $
|
|
|
|
foldlM regUses Set.empty (termRegDemands e)
|
|
|
|
foldlM regUses Set.empty (termRegDemands e)
|
|
|
|
addBlockDemands addr $ demandAlways (registerDemandSet demands)
|
|
|
|
addBlockDemands addr $ demandAlways (registerDemandSet demands)
|
|
|
|
|
|
|
|
|
|
|
|
recordBlockTransfer addr finalRegs (termRegTransfers e)
|
|
|
|
recordBlockTransfer addr regs (termRegTransfers e)
|
|
|
|
traverse_ (addIntraproceduralJumpTarget addr) next_addr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ParsedTranslateError _ -> do
|
|
|
|
ParsedTranslateError _ -> do
|
|
|
|
-- We ignore demands for translate errors.
|
|
|
|
-- We ignore demands for translate errors.
|
|
|
@ -753,58 +756,62 @@ calculateOnePred :: ( MemWidth (ArchAddrWidth arch)
|
|
|
|
, OrdF (ArchReg arch)
|
|
|
|
, OrdF (ArchReg arch)
|
|
|
|
, ShowF (ArchReg arch)
|
|
|
|
, ShowF (ArchReg arch)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
=> ArchSegmentOff arch
|
|
|
|
=> Map (ArchSegmentOff arch) (FinalRegisterDemands (ArchReg arch))
|
|
|
|
|
|
|
|
-- ^ Maps the entry point of each block in the function to the
|
|
|
|
|
|
|
|
-- register demands map for that block.
|
|
|
|
|
|
|
|
-> ArchSegmentOff arch
|
|
|
|
-- ^ Address of the current block
|
|
|
|
-- ^ Address of the current block
|
|
|
|
-> BlockDemands (ArchReg arch)
|
|
|
|
-> BlockDemands (ArchReg arch)
|
|
|
|
|
|
|
|
-- ^ New demands for this block.
|
|
|
|
-> Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch))
|
|
|
|
-> Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch))
|
|
|
|
-- ^ Current demand map for function
|
|
|
|
-- ^ Maps each block to the demands that have not yet
|
|
|
|
--
|
|
|
|
-- been backpropagated to predecessors.
|
|
|
|
-- Maps block addresses to their demand map.
|
|
|
|
|
|
|
|
-> ArchSegmentOff arch
|
|
|
|
-> ArchSegmentOff arch
|
|
|
|
-- ^ Address of the previous block.
|
|
|
|
-- ^ Address of the previous block.
|
|
|
|
-> FunctionArgsM arch ids (Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch)))
|
|
|
|
-> FunctionArgsM arch ids (Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch)))
|
|
|
|
calculateOnePred addr (BD newDemands) pendingMap predAddr = do
|
|
|
|
calculateOnePred xferMap addr (BD newDemands) pendingMap predAddr = do
|
|
|
|
xfer <- use (blockTransfer . ix predAddr)
|
|
|
|
let xfer = xferMap^.ix predAddr
|
|
|
|
|
|
|
|
|
|
|
|
-- update uses, returning value before this iteration
|
|
|
|
-- update uses, returning value before this iteration
|
|
|
|
BD seenDemands <- use (blockDemandMap . ix predAddr)
|
|
|
|
BD seenDemands <- use (blockDemandMap . ix predAddr)
|
|
|
|
|
|
|
|
|
|
|
|
demands' <- traverse (transferDemands predAddr addr xfer) newDemands
|
|
|
|
demands' <- traverse (transferDemands predAddr addr xfer) newDemands
|
|
|
|
|
|
|
|
|
|
|
|
blockDemandMap %= Map.insert predAddr (unionBlockDemands (BD seenDemands) (BD demands'))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let diff :: OrdF r => DemandSet r -> DemandSet r -> Maybe (DemandSet r)
|
|
|
|
let diff :: OrdF r => DemandSet r -> DemandSet r -> Maybe (DemandSet r)
|
|
|
|
diff ds1 ds2 | ds' == mempty = Nothing
|
|
|
|
diff ds1 ds2 | ds' == mempty = Nothing
|
|
|
|
| otherwise = Just ds'
|
|
|
|
| otherwise = Just ds'
|
|
|
|
where ds' = ds1 `demandSetDifference` ds2
|
|
|
|
where ds' = ds1 `demandSetDifference` ds2
|
|
|
|
|
|
|
|
|
|
|
|
let d = Map.differenceWith diff demands' seenDemands
|
|
|
|
let d = Map.differenceWith diff demands' seenDemands
|
|
|
|
|
|
|
|
|
|
|
|
-- If no new entries are seen, then just return pendingMap
|
|
|
|
-- If no new entries are seen, then just return pendingMap
|
|
|
|
if Map.null d then
|
|
|
|
if Map.null d then
|
|
|
|
pure $! pendingMap
|
|
|
|
pure $! pendingMap
|
|
|
|
else
|
|
|
|
else do
|
|
|
|
|
|
|
|
blockDemandMap %= Map.insert predAddr (unionBlockDemands (BD seenDemands) (BD demands'))
|
|
|
|
pure $! Map.insertWith unionBlockDemands predAddr (BD d) pendingMap
|
|
|
|
pure $! Map.insertWith unionBlockDemands predAddr (BD d) pendingMap
|
|
|
|
|
|
|
|
|
|
|
|
-- | This updates the block map
|
|
|
|
-- | This back-propagates demands sets from blocks to their
|
|
|
|
|
|
|
|
-- predecessors until we each a fixpoint.
|
|
|
|
calculateLocalFixpoint :: forall arch ids
|
|
|
|
calculateLocalFixpoint :: forall arch ids
|
|
|
|
. ( MemWidth (ArchAddrWidth arch)
|
|
|
|
. ( MemWidth (ArchAddrWidth arch)
|
|
|
|
, OrdF (ArchReg arch)
|
|
|
|
, OrdF (ArchReg arch)
|
|
|
|
, ShowF (ArchReg arch)
|
|
|
|
, ShowF (ArchReg arch)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
=> Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch))
|
|
|
|
=> PredBlockMap arch
|
|
|
|
-- ^ Maps block addresses to new entries in demand map
|
|
|
|
-- ^ Predecessor block map for function.
|
|
|
|
--
|
|
|
|
-> Map (ArchSegmentOff arch) (BlockDemands (ArchReg arch))
|
|
|
|
-- The function
|
|
|
|
-- ^ Maps each block starting address to demands that
|
|
|
|
|
|
|
|
-- have not yet been back propagated.
|
|
|
|
-> FunctionArgsM arch ids ()
|
|
|
|
-> FunctionArgsM arch ids ()
|
|
|
|
calculateLocalFixpoint new =
|
|
|
|
calculateLocalFixpoint predMap new =
|
|
|
|
case Map.maxViewWithKey new of
|
|
|
|
case Map.maxViewWithKey new of
|
|
|
|
Nothing -> pure ()
|
|
|
|
Nothing -> pure ()
|
|
|
|
Just ((currAddr, newDemands), rest) -> do
|
|
|
|
Just ((currAddr, newDemands), rest) -> do
|
|
|
|
-- propagate new demands bacl to predecessors of this block.
|
|
|
|
-- propagate new demands bacl to predecessors of this block.
|
|
|
|
preds <- use $ blockPreds . ix currAddr
|
|
|
|
xferMap <- use blockTransfer
|
|
|
|
next <- foldlM (calculateOnePred currAddr newDemands) rest preds
|
|
|
|
next <- foldlM (calculateOnePred xferMap currAddr newDemands) rest (predMap^.ix currAddr)
|
|
|
|
calculateLocalFixpoint next
|
|
|
|
calculateLocalFixpoint predMap next
|
|
|
|
|
|
|
|
|
|
|
|
-- | Intermediate information used to infer global demands.
|
|
|
|
-- | Intermediate information used to infer global demands.
|
|
|
|
data FunctionSummaries r = FunctionSummaries {
|
|
|
|
data FunctionSummaries r = FunctionSummaries {
|
|
|
@ -844,10 +851,9 @@ decomposeMap _ addr acc (DemandFunctionArg f r) v =
|
|
|
|
decomposeMap _ addr acc (DemandFunctionResult r) v =
|
|
|
|
decomposeMap _ addr acc (DemandFunctionResult r) v =
|
|
|
|
acc & funResMap %~ Map.insertWith mappend addr (FRD (Map.singleton (Some r) v))
|
|
|
|
acc & funResMap %~ Map.insertWith mappend addr (FRD (Map.singleton (Some r) v))
|
|
|
|
-- Strip out callee saved registers as well.
|
|
|
|
-- Strip out callee saved registers as well.
|
|
|
|
decomposeMap ds addr acc DemandAlways v = do
|
|
|
|
decomposeMap ds addr acc DemandAlways v =
|
|
|
|
|
|
|
|
|
|
|
|
let v' = v { registerDemands = registerDemands v `Set.difference` ds }
|
|
|
|
let v' = v { registerDemands = registerDemands v `Set.difference` ds }
|
|
|
|
acc & alwaysDemandMap %~ Map.insertWith mappend addr v'
|
|
|
|
in acc & alwaysDemandMap %~ Map.insertWith mappend addr v'
|
|
|
|
|
|
|
|
|
|
|
|
-- | This records the registers a function demands in the global state after
|
|
|
|
-- | This records the registers a function demands in the global state after
|
|
|
|
-- being inferred from definition.
|
|
|
|
-- being inferred from definition.
|
|
|
@ -889,7 +895,7 @@ doOneFunction ctx acc (Some finfo) = do
|
|
|
|
|
|
|
|
|
|
|
|
-- Propagate block demands until we are done.
|
|
|
|
-- Propagate block demands until we are done.
|
|
|
|
new <- use blockDemandMap
|
|
|
|
new <- use blockDemandMap
|
|
|
|
calculateLocalFixpoint new
|
|
|
|
calculateLocalFixpoint (predBlockMap finfo) new
|
|
|
|
|
|
|
|
|
|
|
|
-- Get registers demanded by initial block map.
|
|
|
|
-- Get registers demanded by initial block map.
|
|
|
|
entryDemands <- use $ blockDemandMap . ix addr
|
|
|
|
entryDemands <- use $ blockDemandMap . ix addr
|
|
|
@ -917,7 +923,7 @@ calculateGlobalFixpoint s = (go (s^.alwaysDemandMap) (s^.alwaysDemandMap), rever
|
|
|
|
go acc new
|
|
|
|
go acc new
|
|
|
|
| Just ((fun, newDemands), rest) <- Map.maxViewWithKey new =
|
|
|
|
| Just ((fun, newDemands), rest) <- Map.maxViewWithKey new =
|
|
|
|
let (nexts, acc') = backPropagate acc fun newDemands
|
|
|
|
let (nexts, acc') = backPropagate acc fun newDemands
|
|
|
|
in go acc' (Map.unionWith mappend rest nexts)
|
|
|
|
in go acc' (Map.unionWith mappend rest nexts)
|
|
|
|
| otherwise = acc
|
|
|
|
| otherwise = acc
|
|
|
|
|
|
|
|
|
|
|
|
backPropagate :: AddrDemandMap r
|
|
|
|
backPropagate :: AddrDemandMap r
|
|
|
@ -929,11 +935,7 @@ calculateGlobalFixpoint s = (go (s^.alwaysDemandMap) (s^.alwaysDemandMap), rever
|
|
|
|
-- notify all functions which call fun regs.
|
|
|
|
-- notify all functions which call fun regs.
|
|
|
|
let goRet :: RegSegmentOff r -> Set (Some r) -> DemandSet r
|
|
|
|
let goRet :: RegSegmentOff r -> Set (Some r) -> DemandSet r
|
|
|
|
goRet addr retRegs =
|
|
|
|
goRet addr retRegs =
|
|
|
|
foldl (\prev r ->
|
|
|
|
foldMap (\(Some r) -> postRegisterDemands (resultDemandsMap^.ix addr) r) retRegs
|
|
|
|
let FRD m = resultDemandsMap^.ix addr
|
|
|
|
|
|
|
|
in mappend prev (m^.ix r))
|
|
|
|
|
|
|
|
mempty
|
|
|
|
|
|
|
|
retRegs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retDemands :: AddrDemandMap r
|
|
|
|
retDemands :: AddrDemandMap r
|
|
|
|
retDemands = Map.mapWithKey goRet rets
|
|
|
|
retDemands = Map.mapWithKey goRet rets
|
|
|
@ -963,13 +965,14 @@ functionDemands :: forall arch
|
|
|
|
-- registers.
|
|
|
|
-- registers.
|
|
|
|
-> Map BS.ByteString (ComputedRegs (ArchReg arch))
|
|
|
|
-> Map BS.ByteString (ComputedRegs (ArchReg arch))
|
|
|
|
-- ^ Known symbol registers.
|
|
|
|
-- ^ Known symbol registers.
|
|
|
|
-> DiscoveryState arch
|
|
|
|
-> Memory (ArchAddrWidth arch)
|
|
|
|
|
|
|
|
-- ^ State of memory for resolving segment offsets.
|
|
|
|
|
|
|
|
-> [Some (DiscoveryFunInfo arch)]
|
|
|
|
|
|
|
|
-- ^ List of function to compute demands for.
|
|
|
|
-> (AddrDemandMap (ArchReg arch), [String])
|
|
|
|
-> (AddrDemandMap (ArchReg arch), [String])
|
|
|
|
functionDemands archFns addrMap symMap ds =
|
|
|
|
functionDemands archFns addrMap symMap mem entries =
|
|
|
|
calculateGlobalFixpoint (foldl' (doOneFunction ctx) m0 entries)
|
|
|
|
calculateGlobalFixpoint (foldl' (doOneFunction ctx) m0 entries)
|
|
|
|
where
|
|
|
|
where
|
|
|
|
notKnown (Some f) = not (Map.member (discoveredFunAddr f) addrMap)
|
|
|
|
|
|
|
|
entries = filter notKnown $ exploredFunctions ds
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m0 :: FunctionSummaries (ArchReg arch)
|
|
|
|
m0 :: FunctionSummaries (ArchReg arch)
|
|
|
|
m0 = FunctionSummaries
|
|
|
|
m0 = FunctionSummaries
|
|
|
@ -980,7 +983,7 @@ functionDemands archFns addrMap symMap ds =
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ctx = FAC { archDemandInfo = archFns
|
|
|
|
ctx = FAC { archDemandInfo = archFns
|
|
|
|
, ctxMemory = memory ds
|
|
|
|
, ctxMemory = mem
|
|
|
|
, computedAddrSet = Set.fromList $ viewSome discoveredFunAddr <$> entries
|
|
|
|
, computedAddrSet = Set.fromList $ viewSome discoveredFunAddr <$> entries
|
|
|
|
, resolvedAddrs = addrMap
|
|
|
|
, resolvedAddrs = addrMap
|
|
|
|
, knownSymbolDecls = symMap
|
|
|
|
, knownSymbolDecls = symMap
|
|
|
|