(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)
(** Correctness proof for the branch tunneling optimization. *)
Definition match_prog (p tp: program) :=
match_program (fun ctx f tf => tf = tunnel_fundef f) eq p tp.
(** * Properties of the branch map computed using union-find. *)
(** A variant of [record_goto] that also incrementally computes a measure [f: node -> nat] counting the number of [Lnop] instructions starting at a given [pc] that were eliminated. *)
Definition measure_edge (u: U.t) (pc s: node) (f: node -> nat) : node -> nat :=
fun x => if peq (U.repr u s) pc then f x
else if peq (U.repr u x) pc then (f x + f s + 1)%nat
else f x.
Definition record_goto' (uf: U.t * (node -> nat)) (pc: node) (b: bblock) : U.t * (node -> nat) :=
match b with
| Lbranch s :: b' => let (u, f) := uf in (U.union u pc s, measure_edge u pc s f)
| _ => uf
end.
Definition branch_map_correct (c: code) (uf: U.t * (node -> nat)): Prop :=
forall pc,
match c!pc with
| Some(Lbranch s :: b) =>
U.repr (fst uf) pc = pc \/ (U.repr (fst uf) pc = U.repr (fst uf) s /\ snd uf s < snd uf pc)%nat
| _ =>
U.repr (fst uf) pc = pc
end.
Definition record_gotos' (f: function) :=
PTree.fold record_goto' f.(fn_code) (U.empty, fun (x: node) => O).
Definition branch_target (f: function) (pc: node) : node :=
U.repr (record_gotos f) pc.
Definition count_gotos (f: function) (pc: node) : nat :=
snd (record_gotos' f) pc.

Theorem record_gotos_correct:
forall f pc,
match f.(fn_code)!pc with
| Some(Lbranch s :: b) =>
branch_target f pc = pc \/
(branch_target f pc = branch_target f s /\ count_gotos f s < count_gotos f pc)%nat
| _ => branch_target f pc = pc
end.