(* *********************************************************************)
(*                                                                     *)
(*              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.     *)
(*                                                                     *)
(* *********************************************************************)
(** Recognition of tail calls: correctness proof *)
(** * Syntactic properties of the code transformation *)
(** ** Measuring the number of instructions eliminated *)
(** The [return_measure c pc] function counts the number of instructions eliminated by the code transformation, where [pc] is the successor of a call turned into a tailcall.  This is the length of the move/nop/return sequence recognized by the [is_return] boolean function. *)
Fixpoint return_measure_rec (n: nat) (c: code) (pc: node)
{struct n}: nat :=
match n with
| O => O
| S n' =>
match c!pc with
| Some(Inop s) => S(return_measure_rec n' c s)
| Some(Iop op args dst s) => S(return_measure_rec n' c s)
| _ => O
end
end.
Definition return_measure (c: code) (pc: node) :=
return_measure_rec niter c pc.
Remark return_measure_rec_incr:
forall f n1 n2 pc,
(n1 <= n2)%nat ->
(return_measure_rec n1 f pc <= return_measure_rec n2 f pc)%nat.
(** ** Relational characterization of the code transformation *)
(** The [is_return_spec] characterizes the instruction sequences recognized by the [is_return] boolean function.  *)
Inductive is_return_spec (f:function): node -> reg -> Prop :=
| is_return_none: forall pc r,
f.(fn_code)!pc = Some(Ireturn None) ->
is_return_spec f pc r
| is_return_some: forall pc r,
f.(fn_code)!pc = Some(Ireturn (Some r)) ->
is_return_spec f pc r
| is_return_nop: forall pc r s,
f.(fn_code)!pc = Some(Inop s) ->
is_return_spec f s r ->
(return_measure f.(fn_code) s < return_measure f.(fn_code) pc)%nat ->
is_return_spec f pc r
| is_return_move: forall pc r r' s,
f.(fn_code)!pc = Some(Iop Omove (r::nil) r' s) ->
is_return_spec f s r' ->
(return_measure f.(fn_code) s < return_measure f.(fn_code) pc)%nat ->
is_return_spec f pc r.
(** The [transf_instr_spec] predicate relates one instruction in the initial code with its possible transformations in the optimized code. *)
Inductive transf_instr_spec (f: function): instruction -> instruction -> Prop :=
| transf_instr_tailcall: forall sig ros args res s,
f.(fn_stacksize) = 0 ->
is_return_spec f s res ->
transf_instr_spec f (Icall sig ros args res s) (Itailcall sig ros args)
| transf_instr_default: forall i,
transf_instr_spec f i i.
(** * Semantic properties of the code transformation *)
(** ** The ``less defined than'' relation between register states *)
(** A call followed by a return without an argument can be turned into a tail call.  In this case, the original function returns [Vundef], while the transformed function can return any value. We account for this situation by using the ``less defined than'' relation between values and between memory states.  We need to extend it pointwise to register states. *)
(** * Proof of semantic preservation *)
Definition match_prog (p tp: RTL.program) :=
match_program (fun cu f tf => tf = transf_fundef f) eq p tp.

Lemma transf_program_match:
forall p, match_prog p (transf_program p).