(** ** 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.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.