Properties of dead-definition elimination #
deadDefElimH, one backward pass with one hash set, returns deadDefElim's list
(deadDefElimH_eq): the hash set holds exactly the identifiers that deadDefElim
recomputes.
Erasure keeps every property of all nested statements that does not look into branches or
bodies (deadDefElim_allSubstmts), the order conditions Block.nondetIteLast and
Block.onlyChecksAfterAssert (deadDefElim_nondetIteLast,
deadDefElim_onlyChecksAfterAssert) and the reads of defined names Block.readsDefined
(deadDefElim_readsDefined).
For Core statement lists, the facts the trace over-approximation (DeadDefElimCoreCorrect) is
built from: the correspondence of final environments (DDOut); a Core run of a call-free
configuration is a run over EvalE and back (star_evalE, star_core); and erasure keeps the
initial-environment gate BlockInitEnvWF of a list without loops and calls
(blockInitEnvWF_dd), through its defined variables (dd_definedVars), its init types
(dd_initTypes) and def-use well-formedness (dd_defUse).
Key theorems: deadDefElimH_eq, deadDefElim_allSubstmts, deadDefElim_nondetIteLast,
deadDefElim_onlyChecksAfterAssert, deadDefElim_readsDefined, star_evalE, star_core,
blockInitEnvWF_dd.
Key definitions: Core.DeadDefElim.DDOut, Core.DeadDefElim.CallFree.
Erasure keeps the order conditions and the reads of defined names #
Erasure keeps every property of all nested statements whose value on an ite or a
block does not depend on its branches or body: if f holds of every statement of ss,
nested ones included (Block.allSubstmts f), it holds of every statement of
deadDefElim live ss.
Erasure keeps every nondeterministic ite last in its list
(Block.nondetIteLast).
Erasure keeps only checks after every assert
(Block.onlyChecksAfterAssert).
Erasure keeps the reads of defined names: if ss reads only names defined before each
statement, starting from the defined names D (Block.readsDefined), so does
deadDefElim live ss.
Final environments of the output #
The environment ρ' at the end of a run of the output of deadDefElim corresponds to the
environment ρ at the end of the source run: same factory, and the store of ρ' is the
store of ρ with some bindings removed.
Equations
- Core.DeadDefElim.DDOut ρ ρ' = (ρ'.factory = ρ.factory ∧ Imperative.StoreAgreement ρ'.store ρ.store)
Instances For
Call-free Core runs are runs over EvalE #
Every statement still to run in the configuration makes no procedure call.
Equations
- Core.DeadDefElim.CallFree (Imperative.Config.stmt s a) = (Core.Statements.noCalls [s] = true)
- Core.DeadDefElim.CallFree (Imperative.Config.stmts ss a) = (Core.Statements.noCalls ss = true)
- Core.DeadDefElim.CallFree (Imperative.Config.terminal a) = True
- Core.DeadDefElim.CallFree (Imperative.Config.exiting a a_1) = True
- Core.DeadDefElim.CallFree (Imperative.Config.block a a_1 c) = Core.DeadDefElim.CallFree c
- Core.DeadDefElim.CallFree (c.seq ss) = (Core.DeadDefElim.CallFree c ∧ Core.Statements.noCalls ss = true)
Instances For
A Core run of a call-free configuration is a run over EvalE.
A run over EvalE is a Core run.
Initial-environment well-formedness of the output #
The output of deadDefElim is well formed from every environment the input is: the
gate BlockInitEnvWF of the input gives that of the output.