(* *********************************************************************)
(*                                                                     *)
(*              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.     *)
(*                                                                     *)
(* *********************************************************************)
(** Function calling conventions and other conventions regarding the use of machine registers and stack slots. *)
Require Export Conventions1.
(** The processor-dependent and EABI-dependent definitions are in [arch/abi/Conventions1.v].  This file adds various processor-independent definitions and lemmas. *)
(** ** Stack size of function arguments *)
(** [size_arguments s] returns the number of [Outgoing] slots used to call a function with signature [s]. *)
Definition max_outgoing_1 (accu: Z) (l: loc) : Z :=
match l with
| S Outgoing ofs ty => Z.max accu (ofs + typesize ty)
| _ => accu
end.
Definition max_outgoing_2 (accu: Z) (rl: rpair loc) : Z :=
match rl with
| One l => max_outgoing_1 accu l
| Twolong l1 l2 => max_outgoing_1 (max_outgoing_1 accu l1) l2
end.
Definition size_arguments (s: signature) : Z :=
List.fold_left max_outgoing_2 (loc_arguments s) 0.
(** The offsets of [Outgoing] arguments are below [size_arguments s]. *)
Remark fold_max_outgoing_above:
forall l n, fold_left max_outgoing_2 l n >= n.
(** ** Location of function parameters *)
(** A function finds the values of its parameter in the same locations where its caller stored them, except that the stack-allocated arguments, viewed as [Outgoing] slots by the caller, are accessed via [Incoming] slots (at the same offsets and types) in the callee. *)
Definition parameter_of_argument (l: loc) : loc :=
match l with
| S Outgoing n ty => S Incoming n ty
| _ => l
end.
Definition loc_parameters (s: signature) : list (rpair loc) :=
List.map (map_rpair parameter_of_argument) (loc_arguments s).
(** * Tail calls *)
(** A tail-call is possible for a signature if the corresponding arguments are all passed in registers. *)
(** A tail-call is possible for a signature if the corresponding arguments are all passed in registers. *)
Definition tailcall_possible (s: signature) : Prop :=
forall l, In l (regs_of_rpairs (loc_arguments s)) ->
match l with R _ => True | S _ _ _ => False end.
(** Decide whether a tailcall is possible. *)
Definition tailcall_is_possible (sg: signature) : bool :=
List.forallb
(fun l => match l with R _ => true | S _ _ _ => false end)
(regs_of_rpairs (loc_arguments sg)).

Lemma tailcall_is_possible_correct:
forall s, tailcall_is_possible s = true -> tailcall_possible s.