(** ** Location of function arguments *)
(** The PowerPC EABI states the following convention for passing arguments to a function: - The first 8 integer arguments are passed in registers [R3] to [R10]. - The first 8 float arguments are passed in registers [F1] to [F8]. - The first 4 long integer arguments are passed in register pairs [R3,R4] ... [R9,R10]. - Extra arguments are passed on the stack, in [Outgoing] slots, consecutively assigned (1 word for an integer argument, 2 words for a float), starting at word offset 0. - No stack space is reserved for the arguments that are passed in registers. *)
Definition int_param_regs :=
R3 :: R4 :: R5 :: R6 :: R7 :: R8 :: R9 :: R10 :: nil.
Definition float_param_regs :=
F1 :: F2 :: F3 :: F4 :: F5 :: F6 :: F7 :: F8 :: nil.
Fixpoint loc_arguments_rec
(tyl: list typ) (ir fr ofs: Z) {struct tyl} : list (rpair loc) :=
match tyl with
| nil => nil
| (Tint | Tany32) as ty :: tys =>
match list_nth_z int_param_regs ir with
| None =>
One (S Outgoing ofs ty) :: loc_arguments_rec tys ir fr (ofs + 1)
| Some ireg =>
One (R ireg) :: loc_arguments_rec tys (ir + 1) fr ofs
end
| (Tfloat | Tsingle | Tany64) as ty :: tys =>
match list_nth_z float_param_regs fr with
| None =>
let ofs := align ofs 2 in
One (S Outgoing ofs ty) :: loc_arguments_rec tys ir fr (ofs + 2)
| Some freg =>
One (R freg) :: loc_arguments_rec tys ir (fr + 1) ofs
end
| Tlong :: tys =>
let ir := align ir 2 in
match list_nth_z int_param_regs ir, list_nth_z int_param_regs (ir + 1) with
| Some r1, Some r2 =>
Twolong (R r1) (R r2) :: loc_arguments_rec tys (ir + 2) fr ofs
| _, _ =>
let ofs := align ofs 2 in
(if Archi.ptr64
then One (S Outgoing ofs Tlong)
else Twolong (S Outgoing ofs Tint) (S Outgoing (ofs + 1) Tint)) ::
loc_arguments_rec tys ir fr (ofs + 2)
end
end.
(** [loc_arguments s] returns the list of locations where to store arguments when calling a function with signature [s].  *)
Definition loc_arguments (s: signature) : list (rpair loc) :=
loc_arguments_rec s.(sig_args) 0 0 0.
(** [size_arguments s] returns the number of [Outgoing] slots used to call a function with signature [s]. *)
Fixpoint size_arguments_rec (tyl: list typ) (ir fr ofs: Z) {struct tyl} : Z :=
match tyl with
| nil => ofs
| (Tint | Tany32) :: tys =>
match list_nth_z int_param_regs ir with
| None => size_arguments_rec tys ir fr (ofs + 1)
| Some ireg => size_arguments_rec tys (ir + 1) fr ofs
end
| (Tfloat | Tsingle | Tany64) :: tys =>
match list_nth_z float_param_regs fr with
| None => size_arguments_rec tys ir fr (align ofs 2 + 2)
| Some freg => size_arguments_rec tys ir (fr + 1) ofs
end
| Tlong :: tys =>
let ir := align ir 2 in
match list_nth_z int_param_regs ir, list_nth_z int_param_regs (ir + 1) with
| Some r1, Some r2 => size_arguments_rec tys (ir + 2) fr ofs
| _, _ => size_arguments_rec tys ir fr (align ofs 2 + 2)
end
end.
Definition size_arguments (s: signature) : Z :=
size_arguments_rec s.(sig_args) 0 0 0.
(** Argument locations are either caller-save registers or [Outgoing] stack slots at nonnegative offsets. *)
Definition loc_argument_acceptable (l: loc) : Prop :=
match l with
| R r => is_callee_save r = false
| S Outgoing ofs ty => ofs >= 0 /\ (typealign ty | ofs)
| _ => False
end.
Definition loc_argument_charact (ofs: Z) (l: loc) : Prop :=
match l with
| R r => In r int_param_regs \/ In r float_param_regs
| S Outgoing ofs' ty => ofs' >= ofs /\ (typealign ty | ofs')
| _ => False
end.
Remark loc_arguments_rec_charact:
forall tyl ir fr ofs p,
In p (loc_arguments_rec tyl ir fr ofs) ->
forall_rpair (loc_argument_charact ofs) p.

Lemma loc_arguments_acceptable:
forall (s: signature) (p: rpair loc),
In p (loc_arguments s) -> forall_rpair loc_argument_acceptable p.