(* *********************************************************************)
(*                                                                     *)
(*              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.     *)
(*                                                                     *)
(* *********************************************************************)
(** RTL function inlining *)
(** ** Environment of inlinable functions *)
(** We maintain a mapping from function names to their definitions. In this mapping, we only include internal functions that are eligible for inlining, as determined by the external heuristic [should_inline]. *)
Definition funenv : Type := PTree.t function.
Definition size_fenv (fenv: funenv) := PTree_Properties.cardinal fenv.
Parameter inlining_info: Type.  (* abstract type, implemented on the Caml side *)
Parameter inlining_analysis: program -> inlining_info.
Parameter should_inline: inlining_info -> ident -> function -> bool.
Definition add_globdef (io: inlining_info) (fenv: funenv) (idg: ident * globdef fundef unit) : funenv :=
match idg with
| (id, Gfun (Internal f)) =>
if should_inline io id f
then PTree.set id f fenv
else PTree.remove id fenv
| (id, _) =>
PTree.remove id fenv
end.
Definition funenv_program (p: program) : funenv :=
let io := inlining_analysis p in
List.fold_left (add_globdef io) p.(prog_defs) (PTree.empty function).
(** State monad *)
(** To construct incrementally the CFG of a function after inlining, we use a state monad similar to that used in module [RTLgen]. It records the current state of the CFG, plus counters to generate fresh pseudo-registers and fresh CFG nodes.  It also records the stack size needed for the inlined function. *)
Record state : Type := mkstate {
st_nextreg: positive;                 (**r last used pseudo-register *)
st_nextnode: positive;                (**r last used CFG node *)
st_code: code;                        (**r current CFG  *)
st_stksize: Z                         (**r current stack size *)
}.
(** Monotone evolution of the state. *)
Inductive sincr (s1 s2: state) : Prop :=
Sincr (NEXTREG: Ple s1.(st_nextreg) s2.(st_nextreg))
(NEXTNODE: Ple s1.(st_nextnode) s2.(st_nextnode))
(STKSIZE: s1.(st_stksize) <= s2.(st_stksize)).
Remark sincr_refl: forall s, sincr s s.

Lemma sincr_trans: forall s1 s2 s3, sincr s1 s2 -> sincr s2 s3 -> sincr s1 s3.
Inductive res {A: Type} {s: state}: Type := R (x: A) (s': state) (I: sincr s s').