Aarch64: Float register detection for return values

Use aapcs_is_vfp_call_or_return_candidate to detect float register
args.

gdb/
	PR gdb/22943:
	* aarch64-tdep.c (is_hfa_or_hva): Remove function.
	(aarch64_extract_return_value): Use
	aapcs_is_vfp_call_or_return_candidate.
	(aarch64_return_in_memory): Likewise.
	(aarch64_store_return_value): Likewise.
This commit is contained in:
Alan Hayward 2018-08-29 11:41:45 +01:00
parent 0e745c6011
commit 4f4aedebed
2 changed files with 56 additions and 153 deletions

View File

@ -1,3 +1,12 @@
2018-08-29 Alan Hayward <alan.hayward@arm.com>
PR gdb/22943:
* aarch64-tdep.c (is_hfa_or_hva): Remove function.
(aarch64_extract_return_value): Use
aapcs_is_vfp_call_or_return_candidate.
(aarch64_return_in_memory): Likewise.
(aarch64_store_return_value): Likewise.
2018-08-29 Alan Hayward <alan.hayward@arm.com>
* aarch64-tdep.c

View File

@ -1151,68 +1151,6 @@ aarch64_type_align (struct type *t)
}
}
/* 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.
@ -1988,14 +1926,30 @@ aarch64_extract_return_value (struct type *type, struct regcache *regs,
{
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);
regs->cooked_read (AARCH64_V0_REGNUM, buf);
memcpy (valbuf, buf, len);
for (int 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_INT
|| TYPE_CODE (type) == TYPE_CODE_CHAR
@ -2023,53 +1977,6 @@ aarch64_extract_return_value (struct type *type, struct regcache *regs,
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
@ -2098,8 +2005,11 @@ static int
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. */
@ -2126,14 +2036,31 @@ aarch64_store_return_value (struct type *type, struct regcache *regs,
{
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);
memcpy (buf, valbuf, len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len);
regs->cooked_write (AARCH64_V0_REGNUM, buf);
for (int 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 > 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
@ -2168,39 +2095,6 @@ aarch64_store_return_value (struct type *type, struct regcache *regs,
}
}
}
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