Theory Arithmetic_Diagnostics
theory Arithmetic_Diagnostics
imports "Voblint_Framework.Contextual_Check_Report"
begin
section ‹Division and remainder occurrences›
text ‹Diagnostics inspect all expression operands, matching VIMP's total,
pure expression model. They neither change execution nor assume short-circuit
evaluation for logical operators. Lists retain repeated syntactically equal occurrences.›
datatype arithmetic_obligation = Arithmetic_Obligation
(arithmetic_operation: exp)
(arithmetic_divisor: exp)
fun arithmetic_obligations :: "exp ⇒ arithmetic_obligation list" where
"arithmetic_obligations (N n) = []"
| "arithmetic_obligations (V x) = []"
| "arithmetic_obligations (Not a) = arithmetic_obligations a"
| "arithmetic_obligations (And a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (Or a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (Div a b) =
arithmetic_obligations a @ arithmetic_obligations b @
[Arithmetic_Obligation (Div a b) b]"
| "arithmetic_obligations (Mod a b) =
arithmetic_obligations a @ arithmetic_obligations b @
[Arithmetic_Obligation (Mod a b) b]"
| "arithmetic_obligations (Plus a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (Minus a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (Times a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (Less a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (LessEq a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (Greater a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (GreaterEq a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (Eq a b) =
arithmetic_obligations a @ arithmetic_obligations b"
| "arithmetic_obligations (NotEq a b) =
arithmetic_obligations a @ arithmetic_obligations b"
text ‹The set specification ignores occurrence numbering and names every denominator
appearing anywhere in an expression. The extraction theorem connects it to the
occurrence-preserving list consumed by the report.›
fun expression_divisors :: "exp ⇒ exp set" where
"expression_divisors (N n) = {}"
| "expression_divisors (V x) = {}"
| "expression_divisors (Not a) = expression_divisors a"
| "expression_divisors (And a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (Or a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (Div a b) =
insert b (expression_divisors a ∪ expression_divisors b)"
| "expression_divisors (Mod a b) =
insert b (expression_divisors a ∪ expression_divisors b)"
| "expression_divisors (Plus a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (Minus a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (Times a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (Less a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (LessEq a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (Greater a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (GreaterEq a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (Eq a b) =
expression_divisors a ∪ expression_divisors b"
| "expression_divisors (NotEq a b) =
expression_divisors a ∪ expression_divisors b"
lemma arithmetic_obligations_divisors:
"arithmetic_divisor ` set (arithmetic_obligations e) = expression_divisors e"
by (induction e) auto
definition arithmetic_condition :: "arithmetic_obligation ⇒ exp" where
"arithmetic_condition obligation = NotEq (arithmetic_divisor obligation) (N 0)"
lemma arithmetic_condition_safe:
"truthy (⟦arithmetic_condition obligation⟧⇩e s) ⟷
⟦arithmetic_divisor obligation⟧⇩e s ≠ 0"
by (auto simp: arithmetic_condition_def split: if_splits)
section ‹Sites and their solved classifications›
text ‹
‹arithmetic_expression_sites› collects the expressions each CFG edge and call
evaluates; ‹arithmetic_sites› turns them into the divisor obligations the
solved table then classifies.
›
text ‹Only suppress a negative guard edge when the same point has a matching
positive guard edge. All other expression-bearing edges remain in the report.›
definition arithmetic_expression_sites :: "cfg ⇒ (pp × exp list) list" where
"arithmetic_expression_sites g =
(let edges = cfg_intra_list g
in map (λ(u, a, v). (u, edge_expressions a))
(filter (λ(u, a, v). case a of EA_AssumeNot e ⇒
¬ list_ex (λ(u', a', v'). u = u' ∧ a' = EA_Assume e) edges
| _ ⇒ True) edges)) @
map (λ(u, ca, ce, k). (u, ce_args ca)) (cfg_calls_list g)"
definition arithmetic_sites :: "cfg ⇒ (pp × arithmetic_obligation list) list" where
"arithmetic_sites g =
map (λ(v, es). (v, concat (map arithmetic_obligations es)))
(arithmetic_expression_sites g)"