Theory VIMP_Expr

theory VIMP_Expr
  imports VIMP_Syntax
begin

section ‹Expression evaluation›

text ‹
  ‹aval› evaluates an expression in a store.  Every VIMP expression is integer-valued, so
  there is no separate Boolean type. Conditions use C-style truthiness (non-zero),
  while comparisons and logical operators yield ‹1› or ‹0›.  Evaluation is total and has no
  effects, which is why a guard can be re-evaluated freely by the transfer functions.
›

text ‹Division and remainder truncate toward zero for non-zero divisors.
  VIMP keeps expressions total by defining division by zero as zero and
  remainder by zero as the dividend. These zero-divisor cases are VIMP
  conventions; they do not model C's undefined behavior.›

definition c_div :: "int ⇒ int ⇒ int" where
  "c_div a b =
    (if b = 0 then 0 else sgn a * sgn b * (abs a div abs b))"

definition c_mod :: "int ⇒ int ⇒ int" where
  "c_mod a b = (if b = 0 then a else a - c_div a b * b)"

lemma c_div_zero [simp]: "c_div a 0 = 0" "c_div 0 b = 0"
  by (simp_all add: c_div_def)

lemma c_mod_zero [simp]: "c_mod a 0 = a" "c_mod 0 b = 0"
  by (simp_all add: c_mod_def)

lemma c_div_one [simp]: "c_div a 1 = a" "c_div a (-1) = -a"
  by (simp_all add: c_div_def sgn_mult_abs)

lemma c_mod_one [simp]: "c_mod a 1 = 0" "c_mod a (-1) = 0"
  by (simp_all add: c_mod_def)

lemma c_div_mod_reconstruct:
  "c_div a b * b + c_mod a b = a"
  by (simp add: c_mod_def)

lemma c_mod_abs:
  "c_mod a b = sgn a * (abs a mod abs b)"
proof (cases "b = 0")
  case True
  then show ?thesis by (simp add: sgn_mult_abs)
next
  case False
  have product: "c_div a b * b = sgn a * (abs a div abs b * abs b)"
    using False unfolding c_div_def
    by (simp add: abs_sgn mult_ac)
  have "sgn a * (abs a div abs b * abs b) + sgn a * (abs a mod abs b) = a"
    by (simp only: distrib_left[symmetric] div_mult_mod_eq sgn_mult_abs)
  with False product show ?thesis unfolding c_mod_def by (simp only: False if_False; linarith)
qed

lemma c_div_exact:
  assumes "b dvd a"
  shows "c_div a b = a div b"
proof (cases "b = 0")
  case True
  with assms show ?thesis by simp
next
  case False
  have rem: "c_mod a b = 0"
    using assms by (simp add: c_mod_abs)
  have product: "c_div a b * b = a"
    using c_div_mod_reconstruct[of a b] rem by simp
  have "c_div a b = (c_div a b * b) div b"
    using False by simp
  also have "... = a div b" using product by simp
  finally show ?thesis .
qed

lemma c_div_nonneg:
  "0 ≤ a ⟹ 0 ≤ b ⟹ 0 ≤ c_div a b"
  "a ≤ 0 ⟹ b ≤ 0 ⟹ 0 ≤ c_div a b"
  by (auto simp: c_div_def sgn_if pos_imp_zdiv_nonneg_iff neg_imp_zdiv_nonneg_iff)

lemma c_div_nonpos:
  "a ≤ 0 ⟹ 0 ≤ b ⟹ c_div a b ≤ 0"
  "0 ≤ a ⟹ b ≤ 0 ⟹ c_div a b ≤ 0"
  by (auto simp: c_div_def sgn_if pos_imp_zdiv_nonneg_iff neg_imp_zdiv_nonneg_iff)

lemma c_mod_nonneg:
  "0 ≤ a ⟹ 0 ≤ c_mod a b"
  by (cases "b = 0") (auto simp: c_mod_abs sgn_if intro: pos_mod_sign)

lemma c_mod_nonpos:
  "a ≤ 0 ⟹ c_mod a b ≤ 0"
  by (cases "b = 0") (auto simp: c_mod_abs sgn_if intro: pos_mod_sign)

lemma c_div_neg_divisor:
  "c_div a (-b) = - c_div a b"
  by (simp add: c_div_def)

lemma c_div_neg_dividend:
  "c_div (-a) b = - c_div a b"
  by (simp add: c_div_def)

definition truthy :: "int ⇒ bool" where
  [simp]: "truthy n ⟷ n ≠ 0"

fun aval :: "exp ⇒ store ⇒ int" ("⟦_⟧e") where
    "⟦N n⟧e     s  = n"
  | "⟦V x⟧e     s  = s x"
  | "⟦Plus  a b⟧e s  = ⟦a⟧e s + ⟦b⟧e s"
  | "⟦Minus a b⟧e s  = ⟦a⟧e s - ⟦b⟧e s"
  | "⟦Times a b⟧e s  = ⟦a⟧e s * ⟦b⟧e s"
  | "⟦Div a b⟧e s = c_div (⟦a⟧e s) (⟦b⟧e s)"
  | "⟦Mod a b⟧e s = c_mod (⟦a⟧e s) (⟦b⟧e s)"
  | "⟦Less a b⟧e  s  = (if ⟦a⟧e s < ⟦b⟧e s then 1 else 0)"
  | "⟦LessEq a b⟧e s = (if ⟦a⟧e s ≤ ⟦b⟧e s then 1 else 0)"
  | "⟦Greater a b⟧e s = (if ⟦a⟧e s > ⟦b⟧e s then 1 else 0)"
  | "⟦GreaterEq a b⟧e s = (if ⟦a⟧e s ≥ ⟦b⟧e s then 1 else 0)"
  | "⟦NotEq a b⟧e s = (if ⟦a⟧e s ≠ ⟦b⟧e s then 1 else 0)"
  | "⟦Eq   a b⟧e  s  = (if ⟦a⟧e s = ⟦b⟧e s then 1 else 0)"
  | "⟦Not b⟧e     s  = (if truthy (⟦b⟧e s) then 0 else 1)"
  | "⟦And b1 b2⟧e s  = (if truthy (⟦b1⟧e s) ∧ truthy (⟦b2⟧e s) then 1 else 0)"
  | "⟦Or  b1 b2⟧e s  = (if truthy (⟦b1⟧e s) ∨ truthy (⟦b2⟧e s) then 1 else 0)"

text ‹
  ‹truthy› of a compiled comparison or Boolean expression restated in plain
  Boolean form, so a caller never has to re-derive it from ‹aval.simps› and
  ‹truthy›'s own ‹≠ 0› encoding through an explicit ‹if›-split.
›

lemma truthy_aval_Less [simp]:
  "truthy (⟦Less a b⟧e s) ⟷ ⟦a⟧e s < ⟦b⟧e s"
  by simp

lemma truthy_aval_LessEq [simp]:
  "truthy (⟦LessEq a b⟧e s) ⟷ ⟦a⟧e s ≤ ⟦b⟧e s"
  by simp

lemma truthy_aval_Greater [simp]:
  "truthy (⟦Greater a b⟧e s) ⟷ ⟦a⟧e s > ⟦b⟧e s"
  by simp

lemma truthy_aval_GreaterEq [simp]:
  "truthy (⟦GreaterEq a b⟧e s) ⟷ ⟦a⟧e s ≥ ⟦b⟧e s"
  by simp

lemma truthy_aval_NotEq [simp]:
  "truthy (⟦NotEq a b⟧e s) ⟷ ⟦a⟧e s ≠ ⟦b⟧e s"
  by simp

lemma truthy_aval_Eq [simp]:
  "truthy (⟦Eq a b⟧e s) ⟷ ⟦a⟧e s = ⟦b⟧e s"
  by simp

lemma truthy_aval_Not [simp]:
  "truthy (⟦Not b⟧e s) ⟷ ¬ truthy (⟦b⟧e s)"
  by simp

lemma truthy_aval_And [simp]:
  "truthy (⟦And b1 b2⟧e s) ⟷ truthy (⟦b1⟧e s) ∧ truthy (⟦b2⟧e s)"
  by simp

lemma truthy_aval_Or [simp]:
  "truthy (⟦Or b1 b2⟧e s) ⟷ truthy (⟦b1⟧e s) ∨ truthy (⟦b2⟧e s)"
  by simp

subsection ‹Finite expression footprints›

text ‹The variables an expression mentions. A transfer that evaluates the
  expression needs no other variable, which is what lets a keyed analysis read
  only the globals an edge mentions.›

fun exp_vnames :: "exp ⇒ vname set" where
  "exp_vnames (N _) = {}"
| "exp_vnames (V x) = {x}"
| "exp_vnames (Plus a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (Minus a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (Times a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (Div a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (Mod a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (Less a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (LessEq a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (Greater a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (GreaterEq a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (NotEq a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (Eq a b) = exp_vnames a ∪ exp_vnames b"
| "exp_vnames (Not b) = exp_vnames b"
| "exp_vnames (And b1 b2) = exp_vnames b1 ∪ exp_vnames b2"
| "exp_vnames (Or b1 b2) = exp_vnames b1 ∪ exp_vnames b2"

lemma finite_exp_vnames [simp]: "finite (exp_vnames a)"
  by (induction a) auto

end