Vocabulary of the WP and SSA phases (language-generic) #
The WP phase (WP/WP.lean) turns a loop-free program (structured, without loops or calls, with
deterministic guards) into a guarded program, and the SSA phase (SSA/SSA.lean) turns a guarded
program into an obligation program (init/assume/assert/cover commands combined by
nondeterministic ites, as consumed by obligation extraction), generic over the expression
language P (see WPOps, WPLang). This file holds what both phases, their composition and their
correctness statements share:
- renamings (
Ren) and source-variable types (Tys); - reachability conditions (
RE):top, a Boolean name, the negation of a guard name, or the conjunction of a Boolean name with the negation of a guard name; - the flat output (
Item: straight-line statements, side branches of obligations under one reachability, real branches) and its nesting into a statement list (nest, computed in one pass bynestFast); - the choice record of the SSA phase (
LogEntry,substObl): the substitution under which each loop-free obligation is emitted; - fresh names
b@n(freshName) outside a two-level hash set of avoided names (AvoidSet,freshIn);baseOfstrips the counter of a fresh name; the initial state of both phases (FreshSt: counter, avoided names, free-variable types) and the names a phase avoids for its input (inputAvoid).
Key definitions: RE, Item, nest, LogEntry, substObl, freshName, AvoidSet,
freshIn, FreshSt, inputAvoid.
Names, renamings, expressions #
A renaming: source variable → current SSA name (first binding wins; unbound variables are their own current name).
Instances For
Source-variable types.
Instances For
A branch is local when it consists only of assert/cover commands: skipping
it on the continuation's path skips no evaluation, no assumption and no
assignment, so it can become a side branch of its own.
Equations
Instances For
Reachability conditions and the flat output #
A reachability condition: top (reached whenever the enclosing path is), a Boolean
name, the negation ¬g of a guard name, or q ∧ ¬g for a Boolean name q and a guard
name g. Literals and negations are kept inline.
- top {P : PureExpr} : RE P
- name {P : PureExpr} (r : P.Ident) : RE P
- neg {P : PureExpr} (g : P.Ident) : RE P
- andNeg {P : PureExpr} (q g : P.Ident) : RE P
Instances For
Equations
Equations
- Imperative.WP.instDecidableEqRE Imperative.WP.RE.top Imperative.WP.RE.top = isTrue ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.name r) (Imperative.WP.RE.name r') = if h : r = r' then isTrue ⋯ else isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.neg g) (Imperative.WP.RE.neg g') = if h : g = g' then isTrue ⋯ else isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.andNeg q g) (Imperative.WP.RE.andNeg q' g') = if h : q = q' ∧ g = g' then isTrue ⋯ else isFalse ⋯
- Imperative.WP.instDecidableEqRE Imperative.WP.RE.top (Imperative.WP.RE.name r) = isFalse ⋯
- Imperative.WP.instDecidableEqRE Imperative.WP.RE.top (Imperative.WP.RE.neg g) = isFalse ⋯
- Imperative.WP.instDecidableEqRE Imperative.WP.RE.top (Imperative.WP.RE.andNeg q g) = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.name r) Imperative.WP.RE.top = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.name r) (Imperative.WP.RE.neg g) = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.name r) (Imperative.WP.RE.andNeg q g) = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.neg g) Imperative.WP.RE.top = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.neg g) (Imperative.WP.RE.name r) = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.neg g) (Imperative.WP.RE.andNeg q g_1) = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.andNeg q g) Imperative.WP.RE.top = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.andNeg q g) (Imperative.WP.RE.name r) = isFalse ⋯
- Imperative.WP.instDecidableEqRE (Imperative.WP.RE.andNeg q g) (Imperative.WP.RE.neg g_1) = isFalse ⋯
The Boolean expression of a reachability condition.
Equations
- Imperative.WP.RE.top.expr = Imperative.WP.tt
- (Imperative.WP.RE.name r).expr = Imperative.HasFvar.mkBoolVar r
- (Imperative.WP.RE.neg g).expr = Imperative.WP.notE (Imperative.HasFvar.mkBoolVar g)
- (Imperative.WP.RE.andNeg q g).expr = Imperative.WP.andE (Imperative.HasFvar.mkBoolVar q) (Imperative.WP.notE (Imperative.HasFvar.mkBoolVar g))
Instances For
ite(r, t, e) with the condition folded: t for top, ite(g, e, t) for ¬g,
ite(q, ite(g, e, t), e) for q ∧ ¬g.
Equations
- Imperative.WP.RE.top.ite t e = t
- (Imperative.WP.RE.name r_1).ite t e = Imperative.WP.WPOps.ite (Imperative.HasFvar.mkBoolVar r_1) t e
- (Imperative.WP.RE.neg g).ite t e = Imperative.WP.WPOps.ite (Imperative.HasFvar.mkBoolVar g) e t
- (Imperative.WP.RE.andNeg q g).ite t e = Imperative.WP.WPOps.ite (Imperative.HasFvar.mkBoolVar q) (Imperative.WP.WPOps.ite (Imperative.HasFvar.mkBoolVar g) e t) e
Instances For
The label of generated reachability assumptions.
Equations
- Imperative.WP.reachLabel = "wp$reach"
Instances For
The reachability assumption opening a side branch: none when always reached.
Equations
Instances For
One element of the flat translation.
- plain
{P : PureExpr}
(s : BigStep.PStmt P)
: Item P
A straight-line statement of the obligation program.
- obls
{P : PureExpr}
(reach : Option (RE P))
(cs : BigStep.PStmts P)
: Item P
A side branch: the consecutive obligations
csunder the reachabilityreach. - branch
{P : PureExpr}
(t e : List (Item P))
: Item P
A real branch: the flat translations
tandeof the two arms of aniteafter which no obligation follows. It ends the main path.
Instances For
Equations
Does the item leave the main path (a side branch or a real branch)?
Equations
Instances For
Turn the flat translation into the obligation program.
Equations
- Imperative.WP.nest [] = []
- Imperative.WP.nest (it :: rest) = Imperative.WP.nestCons it rest (Imperative.WP.nest rest)
Instances For
nest (it :: rest), given nr = nest rest: a straight-line statement is kept when a
branching item follows; a side branch becomes the then branch of a nondeterministic ite
whose else branch is nr, and is inline when no branching item follows; a real branch
becomes a nondeterministic ite of its nested arms, or the one nested arm that is not
empty, and ends the list.
Equations
- One or more equations did not get rendered due to their size.
- Imperative.WP.nestCons (Imperative.WP.Item.plain s) x✝¹ x✝ = if x✝¹.any Imperative.WP.Item.isBranching = true then s :: x✝ else []
Instances For
nest of an item list, with whether one of its items leaves the main path
(Item.isBranching), in one pass over the list.
Equations
- Imperative.WP.nestB [] = ([], false)
- Imperative.WP.nestB (it :: rest) = match Imperative.WP.nestB rest with | (nr, b) => (Imperative.WP.nestConsB it b nr, it.isBranching || b)
Instances For
nestCons it rest nr, given b, whether an item of rest leaves the main path.
Equations
Instances For
The choice record #
An entry of the record of the obligations the SSA phase emits.
- obl
{P : PureExpr}
(label : String)
(sub : List (P.Ident × P.Ident × Option P.Ty))
: LogEntry P
An obligation with label
label, emitted on the SSA names:submaps each renamed free variablexof its loop-free condition to its current nameyand the type annotationtyof the emitted variable, so the emitted condition is the loop-free one with each suchxreplaced byy : ty(substObl), and the loop-free condition is the emitted one withsubinverted.
Instances For
Equations
The condition an obligation of the obligation program has, for the loop-free condition e
and the substitution sub of its choice-record entry: each x with (x, y, ty) in sub
replaced by the variable y annotated ty.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Fresh names #
The name the pass introduces with base b and counter n: b@n.
Equations
- Imperative.WP.freshName b n = Imperative.HasIdent.ident (b ++ "@" ++ toString n)
Instances For
The statement init x : ty := e.
Equations
Instances For
The statement assume l : e.
Equations
Instances For
The names declared by the inits of a list, at any depth.
Equations
- Imperative.WP.stmtsInits [] = []
- Imperative.WP.stmtsInits (Imperative.Stmt.cmd (Imperative.CmdExt.cmd (Imperative.Cmd.init x_1 ty e md)) :: rest) = x_1 :: Imperative.WP.stmtsInits rest
- Imperative.WP.stmtsInits (Imperative.Stmt.ite cond t e md :: rest) = Imperative.WP.stmtsInits t ++ Imperative.WP.stmtsInits e ++ Imperative.WP.stmtsInits rest
- Imperative.WP.stmtsInits (Imperative.Stmt.block label b md :: rest) = Imperative.WP.stmtsInits b ++ Imperative.WP.stmtsInits rest
- Imperative.WP.stmtsInits (Imperative.Stmt.loop guard measure invariants b md :: rest) = Imperative.WP.stmtsInits b ++ Imperative.WP.stmtsInits rest
- Imperative.WP.stmtsInits (head :: rest) = Imperative.WP.stmtsInits rest
Instances For
A hash set of identifiers.
Equations
Instances For
The names fresh names avoid, in two levels: the global names glob (built once per program
and shared by its procedures) and the identifiers loc of one procedure.
Instances For
Is x avoided?
Equations
- a.contains x = (Std.HashSet.contains a.glob x || Std.HashSet.contains a.loc x)
Instances For
The first counter from n (within fuel tries) whose name with base b is not avoided.
Equations
- Imperative.WP.freeCounterIn avoid b 0 x✝ = x✝
- Imperative.WP.freeCounterIn avoid b fuel.succ x✝ = if avoid.contains (Imperative.WP.freshName b x✝) = true then Imperative.WP.freeCounterIn avoid b fuel (x✝ + 1) else x✝
Instances For
A fresh name with base b from counter n: freshName b k for the least k ≥ n whose
name is not avoided, and the counter advanced past it.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The initial state of the WP and SSA phases: fresh-name counter, avoided names, types of the free variables.
Instances For
The names a phase avoids for its input ss with free-variable types tys: the names of G
(the names of the enclosing program), the identifiers of ss and the free variables.
Equations
- Imperative.WP.inputAvoid G tys ss = { glob := G, loc := Imperative.WP.IdSet.ofList (Imperative.Block.idents ss ++ List.map (fun (x : P.Ident × P.Ty) => x.fst) tys) }