Theory Entry_State_Routed_Context

theory Entry_State_Routed_Context
  imports "Voblint_Framework.Routed_Context" "Voblint_Compile.Compile_Wellformed"
begin

section ‹Routing when the entry operation is a pure list of alternatives›

text ‹
  A call can be answered with several possible entry states rather than one. This
  theory covers the case where computing that list is a ∗‹pure› step: it reads no
  solver unknown and publishes nothing to a global, so the entry run has an empty
  dependency set and a bottom publication.

  ‹alts ci d› is that list --- the alternatives the specification answers for call
  ‹ci› at caller state ‹d› --- and ‹enter_pure› is the assumption that the
  specification's own ‹enter♯› is exactly that list handed to its continuation.
  What the locale restricts is therefore the entry operation, not the route; hence
  the name.

  ‹route› itself stays unconstrained: it may read the call site, the caller's context and
  the entered state, or ignore any of them.  Entry-state routing is its main application
  and the reason the parameter is there --- const‹formals_route_lifted_gen› projects the
  formals out of an abstract state, an executable instance projects them out of its own
  quotient state, and one policy spelled two ways is what a parameter is for --- but
  nothing here forces a route to look at the entered value at all.  Unlike
  ‹Call_String_Routed_Context›'s ‹call_string_routed_context›, no single seed-key datatype
  is shared across instances: each is keyed by its own carrier's value list, so ‹buffer_key› and
  ‹seed› stay genuine locale parameters too.

  Everything the routed locale asks about ‹adm› reduces to two facts about ‹alts›: its
  alternatives cover every concrete call at a covered call site (‹enter_cover›), and the
  solver visited the callee entry at every context a live alternative routes to
  (‹call_fwd›).  A one-alternative specification instantiates ‹alts ci d = [(d, en ci d)]›;
  one that splits a call into several alternatives, possibly overlapping, instantiates it
  with the longer list and nothing else changes.

  Two of the routed obligations are facts about const‹compile_prog› alone and are
  discharged here once: ‹finC› (‹compile_prog_finite›) and ‹calls_unique›
  (‹compile_prog_calls_source_unique›).  ‹seed_ne_buffer_key›, ‹call_fwd› and ‹comb_fwd›
  remain per-instance assumptions: the first is datatype distinctness of the instance's
  seed key, the other two say the solved variable set covers a routed callee entry or return
  continuation, a property of the program together with what the solver explored.
›

locale pure_entry_routed_context =
  dg_context_activation S "λd e. γDG d (e ())" 𝒢 "compile_prog Pi ps" buffer_key
    "λ_. buffer_key" route
    "routed_call_program S (λ_. buffer_key) seed (static_resolve (compile_prog Pi ps)) is_bot"
    "routed_entry_seed_programs seed"
    bot0 d0 g0 sigma vars x0 sg γM
  for S :: "(pp × 'c, 'k, unit, 'D::bounded_semilattice_sup_bot,
              'G::bounded_semilattice_sup_bot) dg_spec"
    and γDG :: "'D ⇒ 'G ⇒ store set"
    and 𝒢 :: "vname ⇒ bool"
    and Pi :: proc_table and ps :: "pname list"
    and buffer_key :: 'k
    and route :: "pp ⇒ 'c ⇒ 'D ⇒ call_action ⇒ 'c"
    and bot0 d0 g0 sigma vars x0 sg
    and seed :: "pp ⇒ 'c ⇒ 'k"
    and is_bot :: "'D ⇒ bool"
    and γM :: "'M ⇒ store set"
    and alts :: "call_info ⇒ 'D ⇒ 'D enter_result list" +
  assumes seed_ne_buffer_key[simp]: "⋀p ctx. seed p ctx ≠ buffer_key"
    and is_bot_bot: "is_bot bot"
    and is_bot_sound: "⋀d gv. is_bot d ⟹ γDG d gv = {}"
    and enter_pure: "⋀ci. enter♯ S ci = local_enter_transfer (alts ci)"
    and enter_cover:
    "⋀u ctx dst pars args p cont s.
       (u, ctx) ∈ vars
       ⟹ (u, CallEdge dst pars args, FunctionEntry p, cont) ∈ calls (compile_prog Pi ps)
       ⟹ s ∈ γDG (dg_local (sigma (Inl (u, ctx)))) (dg_global (sigma (Inr buffer_key)))
       ⟹ entry_pairs_cover (λd. γDG d (dg_global (sigma (Inr buffer_key)))) s
             (call_enter 𝒢 (CallEdge dst pars args) s)
             (alts (call_info_of (CallEdge dst pars args) p) (dg_local (sigma (Inl (u, ctx)))))"
    and call_fwd:
    "⋀u ctx dst pars args p cont cont' entry.
       (u, ctx) ∈ vars
       ⟹ (u, CallEdge dst pars args, FunctionEntry p, cont) ∈ calls (compile_prog Pi ps)
       ⟹ (cont', entry) ∈ set (alts (call_info_of (CallEdge dst pars args) p)
                                  (dg_local (sigma (Inl (u, ctx)))))
       ⟹ ¬ is_bot entry
       ⟹ (FunctionEntry p, route u ctx entry (CallEdge dst pars args)) ∈ vars"
    and comb_fwd:
    "⋀cl c1 dst pars args p cont.
       (cl, c1) ∈ vars
       ⟹ (cl, CallEdge dst pars args, FunctionEntry p, cont) ∈ calls (compile_prog Pi ps)
       ⟹ (cont, c1) ∈ vars"
begin

text ‹The context relation this instance keys its collecting semantics by.›
abbreviation entry_context_rel :: "'c context_policy" where
  "entry_context_rel ≡ routed_entry_context_rel alts (λd e. γDG d (e ())) sigma (λ_. buffer_key) route"

sublocale routed: routed_context S "λd e. γDG d (e ())" 𝒢 "compile_prog Pi ps" buffer_key
  "λ_. buffer_key"
  route bot0 d0 g0 sigma vars x0 sg seed
  "static_resolve (compile_prog Pi ps)" is_bot γM entry_context_rel
proof unfold_locales
  show "finite (calls (compile_prog Pi ps))" by (simp add: compile_prog_finite)
next
  show "calls_source_unique (compile_prog Pi ps)"
    unfolding calls_source_unique_def using compile_prog_calls_source_unique by blast
next
  show "⋀p ctx. seed p ctx ≠ buffer_key" by (rule seed_ne_buffer_key)
next
  show "is_bot bot" by (rule is_bot_bot)
next
  show "⋀d gv. is_bot d ⟹ γDG d gv = {}" by (rule is_bot_sound)
next
  fix u ctx dst pars args p cont s
  assume "(u, ctx) ∈ vars"
    and "(u, CallEdge dst pars args, FunctionEntry p, cont) ∈ calls (compile_prog Pi ps)"
    and "s ∈ gamma_at u ctx"
  then show "p ∈ set (static_resolve (compile_prog Pi ps) cont u
                        (CallEdge dst pars args) (dg_local (sigma (Inl (u, ctx)))))"
    by (simp add: compile_prog_finite)
next
  fix u ctx dst pars args p cont s ctx'
  assume covV: "(u, ctx) ∈ vars"
    and ce: "(u, CallEdge dst pars args, FunctionEntry p, cont) ∈ calls (compile_prog Pi ps)"
    and "s ∈ gamma_at u ctx"
    and Rc: "ctx' ∈ entry_context_rel u ctx (call_info_of (CallEdge dst pars args) p) s
               (call_enter 𝒢 (CallEdge dst pars args) s)"
  let ?ci = "call_info_of (CallEdge dst pars args) p"
  let ?d = "dg_local (sigma (Inl (u, ctx)))"
  from Rc obtain cont' entry
    where mem: "(cont', entry) ∈ set (alts ?ci ?d)"
      and ccov: "s ∈ γDG cont' (dg_global (sigma (Inr buffer_key)))"
      and ecov: "call_enter 𝒢 (CallEdge dst pars args) s
                   ∈ γDG entry (dg_global (sigma (Inr buffer_key)))"
      and req0: "ctx' = route u ctx entry (CallEdge (ci_dst ?ci) (ci_formals ?ci) (ci_args ?ci))"
    using Rc by (auto elim: routed_entry_context_relE)
  have req: "route u ctx entry (CallEdge dst pars args) = ctx'" using req0 by simp
  have not_bot: "¬ is_bot entry"
    using ecov is_bot_sound by fastforce
  have Rr: "enter_runs (enter♯ S ?ci) (mk_dg_man ?d (λ_. buffer_key)) sigma (alts ?ci ?d) bot"
    unfolding enter_pure by (rule enter_runs_local_enter_transfer_mk_dg_man)
  have D: "enter_deps (enter♯ S ?ci) (mk_dg_man ?d (λ_. buffer_key)) sigma (alts ?ci ?d) {}"
    unfolding enter_pure by (rule enter_deps_local_enter_transfer_mk_dg_man)
  show "∃pairs pub deps cont' entry.
             enter_runs (enter♯ S ?ci) (mk_dg_man ?d (λ_. buffer_key)) sigma pairs pub
           ∧ enter_deps (enter♯ S ?ci) (mk_dg_man ?d (λ_. buffer_key)) sigma pairs deps
           ∧ (cont', entry) ∈ set pairs
           ∧ s ∈ γDG cont' (genv (λ_. buffer_key) sigma ())
           ∧ call_enter 𝒢 (CallEdge dst pars args) s
               ∈ γDG entry (genv (λ_. buffer_key) sigma ())
           ∧ route u ctx entry (CallEdge dst pars args) = ctx'
           ∧ (FunctionEntry p, ctx') ∈ vars"
    using Rr D mem ccov ecov req call_fwd[OF covV ce mem not_bot] by auto
next
  fix u ctx dst pars args p cont s
  assume covV: "(u, ctx) ∈ vars"
    and ce: "(u, CallEdge dst pars args, FunctionEntry p, cont) ∈ calls (compile_prog Pi ps)"
    and sin: "s ∈ gamma_at u ctx"
  show "entry_context_rel u ctx (call_info_of (CallEdge dst pars args) p) s
                 (call_enter 𝒢 (CallEdge dst pars args) s) ≠ {}"
  proof (rule routed_entry_context_rel_total)
    show "entry_pairs_cover (λd. γDG d (genv (λ_. buffer_key) sigma ())) s
            (call_enter 𝒢 (CallEdge dst pars args) s)
            (alts (call_info_of (CallEdge dst pars args) p) (dg_local (sigma (Inl (u, ctx)))))"
      using enter_cover[OF covV ce sin[simplified]] by simp
  qed
next
  fix cl c1 dst pars args p cont
  assume "(cl, c1) ∈ vars"
    and "(cl, CallEdge dst pars args, FunctionEntry p, cont) ∈ calls (compile_prog Pi ps)"
  then show "(cont, c1) ∈ vars" by (rule comb_fwd)
next
  show "⋀p ctx v. seed p ctx ≠ buffer_key" by simp
qed

end

end