115 lines
4.6 KiB
Lean4
115 lines
4.6 KiB
Lean4
|
|
import Spa.Language.Properties
|
|||
|
|
import Spa.Language.Equivalence
|
|||
|
|
|
|||
|
|
namespace Spa
|
|||
|
|
open GGraph
|
|||
|
|
|
|||
|
|
/-- Recorded nodes contain instructions; empty CFG nodes are omitted from the history. -/
|
|||
|
|
lemma Path.steps_nonempty {g : Graph} {a b : Configuration g} (p : Path g a b)
|
|||
|
|
{d : g.Index} (hm : d ∈ p.steps) : g.nodes d ≠ none := by
|
|||
|
|
induction p with
|
|||
|
|
| nil => simp [Path.steps] at hm
|
|||
|
|
| cons st p ih =>
|
|||
|
|
rcases List.mem_append.mp hm with hs | hp
|
|||
|
|
· cases st with
|
|||
|
|
| edge => simp [Step.steps] at hs
|
|||
|
|
| @execute i ρ σ h =>
|
|||
|
|
cases hc : g.nodes i <;> aesop (add simp [Step.steps, hc])
|
|||
|
|
· exact ih hp
|
|||
|
|
|
|||
|
|
private lemma optional_preserves_unwritten {ρ σ : Env} {obs : Option BasicStmt}
|
|||
|
|
(h : EvalBasicStmtOpt ρ obs σ) (x : String)
|
|||
|
|
(hn : ∀ rhs, obs ≠ some (.assign x rhs)) :
|
|||
|
|
∀ v, Env.Mem (x, v) ρ ↔ Env.Mem (x, v) σ := by
|
|||
|
|
cases h with
|
|||
|
|
| none => exact fun _ => Iff.rfl
|
|||
|
|
| some h =>
|
|||
|
|
cases h with
|
|||
|
|
| noop => exact fun _ => Iff.rfl
|
|||
|
|
| assign y rhs w hv =>
|
|||
|
|
have hxy : x ≠ y := by
|
|||
|
|
rintro rfl
|
|||
|
|
exact hn rhs rfl
|
|||
|
|
intro v; simp [Env.mem_cons, hxy]
|
|||
|
|
|
|||
|
|
/-- A path whose executed nodes do not assign `x` preserves its binding. -/
|
|||
|
|
lemma Path.preserves_unwritten {g : Graph} {a b : Configuration g} (p : Path g a b)
|
|||
|
|
{x : String} (hn : ∀ d ∈ p.steps, ∀ rhs, g.nodes d ≠ some (.assign x rhs)) :
|
|||
|
|
∀ v, Env.Mem (x, v) a.2 ↔ Env.Mem (x, v) b.2 := by
|
|||
|
|
induction p with
|
|||
|
|
| nil => exact fun _ => Iff.rfl
|
|||
|
|
| cons st p ih =>
|
|||
|
|
have ht := ih (fun d hm => hn d (List.mem_append_right _ hm))
|
|||
|
|
suffices hs : ∀ v, Env.Mem (x, v) _ ↔ Env.Mem (x, v) _ from
|
|||
|
|
fun v => (hs v).trans (ht v)
|
|||
|
|
cases st with
|
|||
|
|
| edge => exact fun _ => Iff.rfl
|
|||
|
|
| execute h =>
|
|||
|
|
apply optional_preserves_unwritten h x
|
|||
|
|
intro rhs hc
|
|||
|
|
exact hn _ (List.mem_append_left _ (by simp [Step.steps, hc])) rhs hc
|
|||
|
|
|
|||
|
|
lemma Step.steps_embed {g h : Graph} (e : Embed g h) {a b : Configuration g}
|
|||
|
|
(s : Step g a b) :
|
|||
|
|
(s.embed e).steps = s.steps.map e.f := by
|
|||
|
|
cases s with
|
|||
|
|
| edge => rfl
|
|||
|
|
| @execute i ρ σ h =>
|
|||
|
|
simp only [Step.embed, Step.steps, e.nodes_eq]
|
|||
|
|
cases g.nodes i <;> rfl
|
|||
|
|
|
|||
|
|
lemma Path.steps_embed {g h : Graph} (e : Embed g h) {a b : Configuration g}
|
|||
|
|
(p : Path g a b) :
|
|||
|
|
(p.embed e).steps = p.steps.map e.f := by
|
|||
|
|
induction p <;> aesop (add simp [Path.embed, Path.steps, Step.steps_embed])
|
|||
|
|
|
|||
|
|
/-- Every nonempty node in a loop belongs to its body. -/
|
|||
|
|
lemma GGraph.loop_node_in_body {g : Graph} {i : (Graph.loop g).Index} {bs : BasicStmt}
|
|||
|
|
(hc : (Graph.loop g).nodes i = some bs) : ∃ j, (Embed.loop g).f j = i := by
|
|||
|
|
refine Fin.addCases ?_ ?_ i hc
|
|||
|
|
· intro j hj
|
|||
|
|
simp [Graph.loop, Fin.append_left] at hj
|
|||
|
|
· intro j _; exact ⟨j, rfl⟩
|
|||
|
|
|
|||
|
|
/-- Variables at any CFG statement occur in its source statement. -/
|
|||
|
|
lemma Stmt.cfg_node_vars {s : Stmt} {i : s.cfg.Index} {bs : BasicStmt}
|
|||
|
|
(hc : s.cfg.nodes i = some bs) : bs.vars ⊆ s.vars := by
|
|||
|
|
induction s with
|
|||
|
|
| basic b =>
|
|||
|
|
have : b = bs := Option.some.inj hc
|
|||
|
|
subst bs; exact Finset.Subset.refl _
|
|||
|
|
| andThen a b iha ihb =>
|
|||
|
|
refine Fin.addCases ?_ ?_ i hc
|
|||
|
|
· intro j hj; have hv := iha (by simpa [Stmt.cfg, Graph.sequence] using hj)
|
|||
|
|
exact fun x hx => Finset.mem_union_left _ (hv hx)
|
|||
|
|
· intro j hj; have hv := ihb (by simpa [Stmt.cfg, Graph.sequence] using hj)
|
|||
|
|
exact fun x hx => Finset.mem_union_right _ (hv hx)
|
|||
|
|
| ifElse cond a b iha ihb =>
|
|||
|
|
refine Fin.addCases ?_ ?_ i hc
|
|||
|
|
· intro j hj; have hv := iha (by simpa [Stmt.cfg, Graph.overlay] using hj)
|
|||
|
|
exact fun x hx => Finset.mem_union_left _ (Finset.mem_union_right _ (hv hx))
|
|||
|
|
· intro j hj; have hv := ihb (by simpa [Stmt.cfg, Graph.overlay] using hj)
|
|||
|
|
exact fun x hx => Finset.mem_union_right _ (hv hx)
|
|||
|
|
| whileLoop cond body ih =>
|
|||
|
|
obtain ⟨j, rfl⟩ := GGraph.loop_node_in_body hc
|
|||
|
|
have hv := ih (((Embed.loop body.cfg).nodes_eq j).symm.trans hc)
|
|||
|
|
exact fun x hx => Finset.mem_union_right _ (hv hx)
|
|||
|
|
|
|||
|
|
lemma Program.code_vars {prog : Program} {i : prog.State} {bs : BasicStmt}
|
|||
|
|
(hc : prog.code i = some bs) : ∀ x ∈ bs.vars, x ∈ prog.vars := by
|
|||
|
|
have hroot : ∃ j, prog.rootStmt.cfg.nodes j = some bs := by
|
|||
|
|
unfold Program.code Program.cfg Graph.wrap at hc
|
|||
|
|
revert hc
|
|||
|
|
refine Fin.addCases ?_ ?_ i
|
|||
|
|
· intro j hj; simp [Graph.sequence, Graph.singleton] at hj
|
|||
|
|
· intro j
|
|||
|
|
refine Fin.addCases ?_ ?_ j
|
|||
|
|
· intro k hk
|
|||
|
|
exact ⟨k, by simpa [Graph.sequence] using hk⟩
|
|||
|
|
· intro k hk; simp [Graph.sequence, Graph.singleton] at hk
|
|||
|
|
obtain ⟨j, hj⟩ := hroot
|
|||
|
|
intro x hx
|
|||
|
|
simpa [Program.vars] using Stmt.cfg_node_vars hj hx
|
|||
|
|
|
|||
|
|
end Spa
|