(* *********************************************************************)
(*                                                                     *)
(*              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)).
(** * Callee-save locations *)
(** We classify locations as either - callee-save, i.e. preserved across function calls: callee-save registers, [Local] and [Incoming] stack slots; - caller-save, i.e. possibly modified by a function call: non-callee-save registers, [Outgoing] stack slots.  Concerning [Outgoing] stack slots: several ABIs allow a function to modify the stack slots used for passing parameters to this function. The code currently generated by CompCert never does so, but the code generated by other compilers often does so (e.g. GCC for x86-32). Hence, CompCert-generated code must not assume that [Outgoing] stack slots are preserved across function calls, because they might not be preserved if the called function was compiled by another compiler. *)
Definition callee_save_loc (l: loc) :=
match l with
| R r => is_callee_save r = true
| S sl ofs ty => sl <> Outgoing
end.
Definition agree_callee_save (ls1 ls2: Locmap.t) : Prop :=
forall l, callee_save_loc l -> ls1 l = ls2 l.
(** * Assigning result locations *)
(** Useful lemmas to reason about the result of an external call. *)

Lemma locmap_get_set_loc_result:
forall sg v rs l,
match l with R r => is_callee_save r = true | S _ _ _ => True end ->
Locmap.setpair (loc_result sg) v rs l = rs l.