#define bit(obj,st) (((obj) >> (st)) & 1)
#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
-/* Pseudo register base numbers. */
-#define AARCH64_Q0_REGNUM 0
-#define AARCH64_D0_REGNUM (AARCH64_Q0_REGNUM + AARCH64_D_REGISTER_COUNT)
-#define AARCH64_S0_REGNUM (AARCH64_D0_REGNUM + 32)
-#define AARCH64_H0_REGNUM (AARCH64_S0_REGNUM + 32)
-#define AARCH64_B0_REGNUM (AARCH64_H0_REGNUM + 32)
-#define AARCH64_SVE_V0_REGNUM (AARCH64_B0_REGNUM + 32)
-
/* A Homogeneous Floating-Point or Short-Vector Aggregate may have at most
four members. */
#define HA_MAX_NUM_FLDS 4
}
}
-/* Return 1 if *TY is a homogeneous floating-point aggregate or
- homogeneous short-vector aggregate as defined in the AAPCS64 ABI
- document; otherwise return 0. */
-
-static int
-is_hfa_or_hva (struct type *ty)
-{
- switch (TYPE_CODE (ty))
- {
- case TYPE_CODE_ARRAY:
- {
- struct type *target_ty = TYPE_TARGET_TYPE (ty);
-
- if (TYPE_VECTOR (ty))
- return 0;
-
- if (TYPE_LENGTH (ty) <= 4 /* HFA or HVA has at most 4 members. */
- && (TYPE_CODE (target_ty) == TYPE_CODE_FLT /* HFA */
- || (TYPE_CODE (target_ty) == TYPE_CODE_ARRAY /* HVA */
- && TYPE_VECTOR (target_ty))))
- return 1;
- break;
- }
-
- case TYPE_CODE_UNION:
- case TYPE_CODE_STRUCT:
- {
- /* HFA or HVA has at most four members. */
- if (TYPE_NFIELDS (ty) > 0 && TYPE_NFIELDS (ty) <= 4)
- {
- struct type *member0_type;
-
- member0_type = check_typedef (TYPE_FIELD_TYPE (ty, 0));
- if (TYPE_CODE (member0_type) == TYPE_CODE_FLT
- || (TYPE_CODE (member0_type) == TYPE_CODE_ARRAY
- && TYPE_VECTOR (member0_type)))
- {
- int i;
-
- for (i = 0; i < TYPE_NFIELDS (ty); i++)
- {
- struct type *member1_type;
-
- member1_type = check_typedef (TYPE_FIELD_TYPE (ty, i));
- if (TYPE_CODE (member0_type) != TYPE_CODE (member1_type)
- || (TYPE_LENGTH (member0_type)
- != TYPE_LENGTH (member1_type)))
- return 0;
- }
- return 1;
- }
- }
- return 0;
- }
-
- default:
- break;
- }
-
- return 0;
-}
-
/* Worker function for aapcs_is_vfp_call_or_return_candidate.
Return the number of register required, or -1 on failure.
Note that HFAs and HVAs can include nested structures and arrays. */
-bool
+static bool
aapcs_is_vfp_call_or_return_candidate (struct type *type, int *count,
struct type **fundamental_type)
{
if (info->nsrn < 8)
{
int regnum = AARCH64_V0_REGNUM + info->nsrn;
- gdb_byte reg[V_REGISTER_SIZE];
+ /* Enough space for a full vector register. */
+ gdb_byte reg[register_size (gdbarch, regnum)];
+ gdb_assert (len <= sizeof (reg));
info->argnum++;
info->nsrn++;
}
}
-/* Pass a value in a V register, or on the stack if insufficient are
- available. */
-
-static void
-pass_in_v_or_stack (struct gdbarch *gdbarch,
- struct regcache *regcache,
- struct aarch64_call_info *info,
- struct type *type,
- struct value *arg)
+/* Pass a value, which is of type arg_type, in a V register. Assumes value is a
+ aapcs_is_vfp_call_or_return_candidate and there are enough spare V
+ registers. A return value of false is an error state as the value will have
+ been partially passed to the stack. */
+static bool
+pass_in_v_vfp_candidate (struct gdbarch *gdbarch, struct regcache *regcache,
+ struct aarch64_call_info *info, struct type *arg_type,
+ struct value *arg)
{
- if (!pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (type),
- value_contents (arg)))
- pass_on_stack (info, type, arg);
+ switch (TYPE_CODE (arg_type))
+ {
+ case TYPE_CODE_FLT:
+ return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (arg_type),
+ value_contents (arg));
+ break;
+
+ case TYPE_CODE_COMPLEX:
+ {
+ const bfd_byte *buf = value_contents (arg);
+ struct type *target_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
+
+ if (!pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (target_type),
+ buf))
+ return false;
+
+ return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (target_type),
+ buf + TYPE_LENGTH (target_type));
+ }
+
+ case TYPE_CODE_ARRAY:
+ if (TYPE_VECTOR (arg_type))
+ return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (arg_type),
+ value_contents (arg));
+ /* fall through. */
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ for (int i = 0; i < TYPE_NFIELDS (arg_type); i++)
+ {
+ struct value *field = value_primitive_field (arg, 0, i, arg_type);
+ struct type *field_type = check_typedef (value_type (field));
+
+ if (!pass_in_v_vfp_candidate (gdbarch, regcache, info, field_type,
+ field))
+ return false;
+ }
+ return true;
+
+ default:
+ return false;
+ }
}
/* Implement the "push_dummy_call" gdbarch method. */
for (argnum = 0; argnum < nargs; argnum++)
{
struct value *arg = args[argnum];
- struct type *arg_type;
- int len;
+ struct type *arg_type, *fundamental_type;
+ int len, elements;
arg_type = check_typedef (value_type (arg));
len = TYPE_LENGTH (arg_type);
+ /* If arg can be passed in v registers as per the AAPCS64, then do so if
+ if there are enough spare registers. */
+ if (aapcs_is_vfp_call_or_return_candidate (arg_type, &elements,
+ &fundamental_type))
+ {
+ if (info.nsrn + elements <= 8)
+ {
+ /* We know that we have sufficient registers available therefore
+ this will never need to fallback to the stack. */
+ if (!pass_in_v_vfp_candidate (gdbarch, regcache, &info, arg_type,
+ arg))
+ gdb_assert_not_reached ("Failed to push args");
+ }
+ else
+ {
+ info.nsrn = 8;
+ pass_on_stack (&info, arg_type, arg);
+ }
+ continue;
+ }
+
switch (TYPE_CODE (arg_type))
{
case TYPE_CODE_INT:
pass_in_x_or_stack (gdbarch, regcache, &info, arg_type, arg);
break;
- case TYPE_CODE_COMPLEX:
- if (info.nsrn <= 6)
- {
- const bfd_byte *buf = value_contents (arg);
- struct type *target_type =
- check_typedef (TYPE_TARGET_TYPE (arg_type));
-
- pass_in_v (gdbarch, regcache, &info,
- TYPE_LENGTH (target_type), buf);
- pass_in_v (gdbarch, regcache, &info,
- TYPE_LENGTH (target_type),
- buf + TYPE_LENGTH (target_type));
- }
- else
- {
- info.nsrn = 8;
- pass_on_stack (&info, arg_type, arg);
- }
- break;
- case TYPE_CODE_FLT:
- pass_in_v_or_stack (gdbarch, regcache, &info, arg_type, arg);
- break;
-
case TYPE_CODE_STRUCT:
case TYPE_CODE_ARRAY:
case TYPE_CODE_UNION:
- if (is_hfa_or_hva (arg_type))
- {
- int elements = TYPE_NFIELDS (arg_type);
-
- /* Homogeneous Aggregates */
- if (info.nsrn + elements < 8)
- {
- int i;
-
- for (i = 0; i < elements; i++)
- {
- /* We know that we have sufficient registers
- available therefore this will never fallback
- to the stack. */
- struct value *field =
- value_primitive_field (arg, 0, i, arg_type);
- struct type *field_type =
- check_typedef (value_type (field));
-
- pass_in_v_or_stack (gdbarch, regcache, &info,
- field_type, field);
- }
- }
- else
- {
- info.nsrn = 8;
- pass_on_stack (&info, arg_type, arg);
- }
- }
- else if (TYPE_CODE (arg_type) == TYPE_CODE_ARRAY
- && TYPE_VECTOR (arg_type) && (len == 16 || len == 8))
- {
- /* Short vector types are passed in V registers. */
- pass_in_v_or_stack (gdbarch, regcache, &info, arg_type, arg);
- }
- else if (len > 16)
+ if (len > 16)
{
/* PCS B.7 Aggregates larger than 16 bytes are passed by
invisible reference. */
{
struct gdbarch *gdbarch = regs->arch ();
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int elements;
+ struct type *fundamental_type;
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
+ &fundamental_type))
{
- bfd_byte buf[V_REGISTER_SIZE];
- int len = TYPE_LENGTH (type);
+ int len = TYPE_LENGTH (fundamental_type);
+
+ for (int i = 0; i < elements; i++)
+ {
+ int regno = AARCH64_V0_REGNUM + i;
+ /* Enough space for a full vector register. */
+ gdb_byte buf[register_size (gdbarch, regno)];
+ gdb_assert (len <= sizeof (buf));
- regs->cooked_read (AARCH64_V0_REGNUM, buf);
- memcpy (valbuf, buf, len);
+ if (aarch64_debug)
+ {
+ debug_printf ("read HFA or HVA return value element %d from %s\n",
+ i + 1,
+ gdbarch_register_name (gdbarch, regno));
+ }
+ regs->cooked_read (regno, buf);
+
+ memcpy (valbuf, buf, len);
+ valbuf += len;
+ }
}
else if (TYPE_CODE (type) == TYPE_CODE_INT
|| TYPE_CODE (type) == TYPE_CODE_CHAR
valbuf += X_REGISTER_SIZE;
}
}
- else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX)
- {
- int regno = AARCH64_V0_REGNUM;
- bfd_byte buf[V_REGISTER_SIZE];
- struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
- int len = TYPE_LENGTH (target_type);
-
- regs->cooked_read (regno, buf);
- memcpy (valbuf, buf, len);
- valbuf += len;
- regs->cooked_read (regno + 1, buf);
- memcpy (valbuf, buf, len);
- valbuf += len;
- }
- else if (is_hfa_or_hva (type))
- {
- int elements = TYPE_NFIELDS (type);
- struct type *member_type = check_typedef (TYPE_FIELD_TYPE (type, 0));
- int len = TYPE_LENGTH (member_type);
- int i;
-
- for (i = 0; i < elements; i++)
- {
- int regno = AARCH64_V0_REGNUM + i;
- bfd_byte buf[V_REGISTER_SIZE];
-
- if (aarch64_debug)
- {
- debug_printf ("read HFA or HVA return value element %d from %s\n",
- i + 1,
- gdbarch_register_name (gdbarch, regno));
- }
- regs->cooked_read (regno, buf);
-
- memcpy (valbuf, buf, len);
- valbuf += len;
- }
- }
- else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
- && (TYPE_LENGTH (type) == 16 || TYPE_LENGTH (type) == 8))
- {
- /* Short vector is returned in V register. */
- gdb_byte buf[V_REGISTER_SIZE];
-
- regs->cooked_read (AARCH64_V0_REGNUM, buf);
- memcpy (valbuf, buf, TYPE_LENGTH (type));
- }
else
{
/* For a structure or union the behaviour is as if the value had
aarch64_return_in_memory (struct gdbarch *gdbarch, struct type *type)
{
type = check_typedef (type);
+ int elements;
+ struct type *fundamental_type;
- if (is_hfa_or_hva (type))
+ if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
+ &fundamental_type))
{
/* v0-v7 are used to return values and one register is allocated
for one member. However, HFA or HVA has at most four members. */
{
struct gdbarch *gdbarch = regs->arch ();
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int elements;
+ struct type *fundamental_type;
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
+ &fundamental_type))
{
- bfd_byte buf[V_REGISTER_SIZE];
- int len = TYPE_LENGTH (type);
+ int len = TYPE_LENGTH (fundamental_type);
+
+ for (int i = 0; i < elements; i++)
+ {
+ int regno = AARCH64_V0_REGNUM + i;
+ /* Enough space for a full vector register. */
+ gdb_byte tmpbuf[register_size (gdbarch, regno)];
+ gdb_assert (len <= sizeof (tmpbuf));
- memcpy (buf, valbuf, len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len);
- regs->cooked_write (AARCH64_V0_REGNUM, buf);
+ if (aarch64_debug)
+ {
+ debug_printf ("write HFA or HVA return value element %d to %s\n",
+ i + 1,
+ gdbarch_register_name (gdbarch, regno));
+ }
+
+ memcpy (tmpbuf, valbuf,
+ len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len);
+ regs->cooked_write (regno, tmpbuf);
+ valbuf += len;
+ }
}
else if (TYPE_CODE (type) == TYPE_CODE_INT
|| TYPE_CODE (type) == TYPE_CODE_CHAR
}
}
}
- else if (is_hfa_or_hva (type))
- {
- int elements = TYPE_NFIELDS (type);
- struct type *member_type = check_typedef (TYPE_FIELD_TYPE (type, 0));
- int len = TYPE_LENGTH (member_type);
- int i;
-
- for (i = 0; i < elements; i++)
- {
- int regno = AARCH64_V0_REGNUM + i;
- bfd_byte tmpbuf[V_REGISTER_SIZE];
-
- if (aarch64_debug)
- {
- debug_printf ("write HFA or HVA return value element %d to %s\n",
- i + 1,
- gdbarch_register_name (gdbarch, regno));
- }
-
- memcpy (tmpbuf, valbuf, len);
- regs->cooked_write (regno, tmpbuf);
- valbuf += len;
- }
- }
- else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
- && (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 16))
- {
- /* Short vector. */
- gdb_byte buf[V_REGISTER_SIZE];
-
- memcpy (buf, valbuf, TYPE_LENGTH (type));
- regs->cooked_write (AARCH64_V0_REGNUM, buf);
- }
else
{
/* For a structure or union the behaviour is as if the value had