2026-06-23 15:12:37 -05:00
|
|
|
|
import Spa.Analysis.Forward
|
|
|
|
|
|
import Spa.Lattice.Bool
|
2026-06-27 16:29:16 -05:00
|
|
|
|
import Spa.Lattice.Tuple
|
|
|
|
|
|
import Spa.Language.Tagged.Graphs
|
2026-06-23 15:12:37 -05:00
|
|
|
|
import Spa.Showable
|
|
|
|
|
|
|
|
|
|
|
|
namespace Spa
|
|
|
|
|
|
|
|
|
|
|
|
open Forward
|
|
|
|
|
|
|
|
|
|
|
|
instance : Showable Bool := ⟨fun b => if b then "true" else "false"⟩
|
|
|
|
|
|
|
2026-06-27 16:29:16 -05:00
|
|
|
|
instance {n : ℕ} {β : Type*} [Showable β] : Showable (Fin n → β) :=
|
|
|
|
|
|
⟨fun f =>
|
|
|
|
|
|
"{" ++ (List.finRange n).foldr
|
|
|
|
|
|
(fun i rest => show' i ++ " ↦ " ++ show' (f i) ++ ", " ++ rest) ""
|
|
|
|
|
|
++ "}"⟩
|
|
|
|
|
|
|
|
|
|
|
|
abbrev DefSet (prog : Program) : Type := prog.NodeId → Bool
|
2026-06-23 15:12:37 -05:00
|
|
|
|
|
|
|
|
|
|
namespace ReachingAnalysis
|
|
|
|
|
|
|
|
|
|
|
|
variable (prog : Program)
|
|
|
|
|
|
|
2026-06-27 16:29:16 -05:00
|
|
|
|
def genSet (s : prog.State) {bs : BasicStmt} (h : prog.code s = some bs) :
|
|
|
|
|
|
DefSet prog :=
|
|
|
|
|
|
Function.update (⊥ : DefSet prog) (prog.nodeIdOfNonempty s h) true
|
2026-06-23 15:12:37 -05:00
|
|
|
|
|
|
|
|
|
|
def eval (s : prog.State) :
|
2026-06-27 16:29:16 -05:00
|
|
|
|
(bs : BasicStmt) → prog.code s = some bs →
|
|
|
|
|
|
VariableValues (DefSet prog) prog → VariableValues (DefSet prog) prog
|
|
|
|
|
|
| .assign k _, h, vs =>
|
|
|
|
|
|
FiniteMap.generalizedUpdate id (fun _ _ => genSet prog s h) [k] vs
|
|
|
|
|
|
| .noop, _, vs => vs
|
2026-06-23 15:12:37 -05:00
|
|
|
|
|
2026-06-27 16:29:16 -05:00
|
|
|
|
lemma eval_mono (s : prog.State) (bs : BasicStmt) (h : prog.code s = some bs) :
|
|
|
|
|
|
Monotone (eval prog s bs h) := by
|
2026-06-23 15:12:37 -05:00
|
|
|
|
cases bs with
|
|
|
|
|
|
| assign k e =>
|
|
|
|
|
|
exact FiniteMap.generalizedUpdate_monotone monotone_id (fun _ => monotone_const)
|
|
|
|
|
|
| noop => exact monotone_id
|
|
|
|
|
|
|
|
|
|
|
|
instance stmtEvaluator : StmtEvaluator (DefSet prog) prog :=
|
|
|
|
|
|
⟨eval prog, eval_mono prog⟩
|
|
|
|
|
|
|
|
|
|
|
|
def output : String :=
|
|
|
|
|
|
show' (result (DefSet prog) prog)
|
|
|
|
|
|
|
2026-06-27 16:29:16 -05:00
|
|
|
|
inductive Run (prog : Program) where
|
|
|
|
|
|
| nil : Run prog
|
|
|
|
|
|
| cons (s : prog.State) (bs : BasicStmt) (hc : prog.code s = some bs)
|
|
|
|
|
|
(rest : Run prog) : Run prog
|
|
|
|
|
|
|
2026-06-27 19:30:01 -05:00
|
|
|
|
@[aesop unsafe cases]
|
2026-06-27 16:29:16 -05:00
|
|
|
|
inductive LastAssign (prog : Program) (x : String) : Run prog → prog.NodeId → Prop
|
|
|
|
|
|
| here (s : prog.State) (e : Expr) (hc : prog.code s = some (.assign x e))
|
|
|
|
|
|
(rest : Run prog) :
|
|
|
|
|
|
LastAssign prog x (Run.cons s (.assign x e) hc rest) (prog.nodeIdOfNonempty s hc)
|
|
|
|
|
|
| there (s : prog.State) (bs : BasicStmt) (hc : prog.code s = some bs)
|
|
|
|
|
|
(rest : Run prog) {n : prog.NodeId} :
|
|
|
|
|
|
(∀ e, bs ≠ .assign x e) → LastAssign prog x rest n →
|
|
|
|
|
|
LastAssign prog x (Run.cons s bs hc rest) n
|
|
|
|
|
|
|
|
|
|
|
|
instance stateInterp : StateInterp (DefSet prog) prog where
|
|
|
|
|
|
St := fun _ => Run prog
|
|
|
|
|
|
init := Run.nil
|
|
|
|
|
|
interp vs _ run := ∀ (x : String) (assigners : DefSet prog), (x, assigners) ∈ vs →
|
|
|
|
|
|
∀ (n : prog.NodeId), LastAssign prog x run n → assigners n = true
|
|
|
|
|
|
interp_sup := by
|
|
|
|
|
|
intro vs₁ vs₂ ρ run h x assigners hmem n hla
|
|
|
|
|
|
obtain ⟨a₁, a₂, rfl, h₁, h₂⟩ := FiniteMap.mem_sup hmem
|
2026-06-27 19:30:01 -05:00
|
|
|
|
aesop
|
2026-06-27 16:29:16 -05:00
|
|
|
|
interp_inf := by
|
|
|
|
|
|
intro vs₁ vs₂ ρ run h x assigners hmem n hla
|
|
|
|
|
|
obtain ⟨a₁, a₂, rfl, h₁, h₂⟩ := FiniteMap.mem_inf hmem
|
|
|
|
|
|
aesop
|
|
|
|
|
|
|
|
|
|
|
|
instance validStateEvaluator : ValidStateEvaluator (DefSet prog) prog where
|
|
|
|
|
|
step := by intro s _ _ bs hcode _ rest; exact Run.cons s bs hcode rest
|
|
|
|
|
|
valid := by
|
|
|
|
|
|
intro s ρ₁ ρ₂ bs vs st hcode hbs hvs
|
|
|
|
|
|
cases hbs with
|
2026-06-27 19:30:01 -05:00
|
|
|
|
| noop => intro x assigners hmem n hla; aesop
|
2026-06-27 16:29:16 -05:00
|
|
|
|
| assign x e v hev =>
|
|
|
|
|
|
intro k assigners hmem n hla
|
|
|
|
|
|
have hmem2 : (k, assigners) ∈
|
|
|
|
|
|
FiniteMap.generalizedUpdate id (fun _ _ => genSet prog s hcode) [x] vs := hmem
|
|
|
|
|
|
by_cases hx : k = x
|
|
|
|
|
|
· subst hx
|
|
|
|
|
|
have hd := FiniteMap.generalizedUpdate_mem_eq (List.mem_singleton.mpr rfl) hmem2
|
2026-06-27 19:30:01 -05:00
|
|
|
|
aesop (add simp genSet)
|
|
|
|
|
|
· have hmem' := FiniteMap.generalizedUpdate_not_mem_backward
|
2026-06-27 16:29:16 -05:00
|
|
|
|
(fun hc => hx (List.mem_singleton.mp hc)) hmem2
|
2026-06-27 19:30:01 -05:00
|
|
|
|
aesop
|
2026-06-27 16:29:16 -05:00
|
|
|
|
botV_init := by intro x assigners _ n hla; cases hla
|
|
|
|
|
|
|
|
|
|
|
|
theorem analyze_correct {ρ : Env} (hrun : EvalStmt [] prog.rootStmt ρ) :
|
|
|
|
|
|
⟦ variablesAt prog.finalState (result (DefSet prog) prog) ⟧ ρ
|
|
|
|
|
|
(stepTraceState (prog.trace hrun) (stateInterp prog).init) :=
|
|
|
|
|
|
Forward.analyze_correct_state (DefSet prog) prog hrun
|
|
|
|
|
|
|
2026-06-23 15:12:37 -05:00
|
|
|
|
end ReachingAnalysis
|
|
|
|
|
|
|
|
|
|
|
|
end Spa
|