[AArch64] Handle arguments and return types with partial SVE modes

Partial SVE modes can be picked up and used by the vector_size(N)
attribute.[*] This means that we need to cope with arguments and return
values with partial SVE modes, which previously triggered asserts like:

  /* Generic vectors that map to SVE modes with -msve-vector-bits=N are
     passed by reference, not by value.  */
  gcc_assert (!aarch64_sve_mode_p (mode));

The ABI for these types is fixed from pre-SVE days, and must in any case
be the same for all -msve-vector-bits=N values.  All we need to do is
ensure that the vectors are passed and returned in the traditional way.

[*] Advanced SIMD always wins for 64-bit and 128-bit vectors though.

2019-12-19  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* config/aarch64/aarch64.c (aarch64_function_value_1): New function,
	split out from...
	(aarch64_function_value): ...here.  Handle partial SVE modes by
	pretending that they have the associated/traditional integer mode,
	then wrap the result in the real mode.
	(aarch64_layout_arg): Take an orig_mode argument and pass it to
	aarch64_function_arg_alignment.  Handle partial SVE modes analogously
	to aarch64_function_value.
	(aarch64_function_arg): Update call accordingly.
	(aarch64_function_arg_advance): Likewise.

gcc/testsuite/
	* gcc.target/aarch64/sve/pcs/gnu_vectors_3.c: New test.

From-SVN: r279571
This commit is contained in:
Richard Sandiford 2019-12-19 13:25:22 +00:00 committed by Richard Sandiford
parent 022d11a3b5
commit 6aa5370ccc
4 changed files with 150 additions and 20 deletions

View file

@ -1,3 +1,16 @@
2019-12-19 Richard Sandiford <richard.sandiford@arm.com>
* config/aarch64/aarch64.c (aarch64_function_value_1): New function,
split out from...
(aarch64_function_value): ...here. Handle partial SVE modes by
pretending that they have the associated/traditional integer mode,
then wrap the result in the real mode.
(aarch64_layout_arg): Take an orig_mode argument and pass it to
aarch64_function_arg_alignment. Handle partial SVE modes analogously
to aarch64_function_value.
(aarch64_function_arg): Update call accordingly.
(aarch64_function_arg_advance): Likewise.
2019-12-19 Jan Hubicka <hubicka@ucw.cz>
Xi Ruoyao <xry111@mengyan1223.wang>

View file

@ -4948,22 +4948,12 @@ aarch64_return_in_msb (const_tree valtype)
return true;
}
/* Implement TARGET_FUNCTION_VALUE.
Define how to find the value returned by a function. */
/* Subroutine of aarch64_function_value. MODE is the mode of the argument
after promotion, and after partial SVE types have been replaced by
their integer equivalents. */
static rtx
aarch64_function_value (const_tree type, const_tree func,
bool outgoing ATTRIBUTE_UNUSED)
aarch64_function_value_1 (const_tree type, machine_mode mode)
{
machine_mode mode;
int unsignedp;
int count;
machine_mode ag_mode;
mode = TYPE_MODE (type);
if (INTEGRAL_TYPE_P (type))
mode = promote_function_mode (type, mode, &unsignedp, func, 1);
unsigned int num_zr, num_pr;
if (type && aarch64_sve_argument_p (type, &num_zr, &num_pr))
{
@ -4998,6 +4988,8 @@ aarch64_function_value (const_tree type, const_tree func,
}
}
int count;
machine_mode ag_mode;
if (aarch64_vfp_is_call_or_return_candidate (mode, type,
&ag_mode, &count, NULL))
{
@ -5026,6 +5018,42 @@ aarch64_function_value (const_tree type, const_tree func,
return gen_rtx_REG (mode, R0_REGNUM);
}
/* Implement TARGET_FUNCTION_VALUE.
Define how to find the value returned by a function. */
static rtx
aarch64_function_value (const_tree type, const_tree func,
bool outgoing ATTRIBUTE_UNUSED)
{
machine_mode mode;
int unsignedp;
mode = TYPE_MODE (type);
if (INTEGRAL_TYPE_P (type))
mode = promote_function_mode (type, mode, &unsignedp, func, 1);
/* Vector types can acquire a partial SVE mode using things like
__attribute__((vector_size(N))), and this is potentially useful.
However, the choice of mode doesn't affect the type's ABI identity,
so we should treat the types as though they had the associated
integer mode, just like they did before SVE was introduced.
We know that the vector must be 128 bits or smaller, otherwise we'd
have returned it in memory instead. */
unsigned int vec_flags = aarch64_classify_vector_mode (mode);
if ((vec_flags & VEC_ANY_SVE) && (vec_flags & VEC_PARTIAL))
{
scalar_int_mode int_mode = int_mode_for_mode (mode).require ();
rtx reg = aarch64_function_value_1 (type, int_mode);
/* Vector types are never returned in the MSB and are never split. */
gcc_assert (REG_P (reg) && GET_MODE (reg) == int_mode);
rtx pair = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, pair));
}
return aarch64_function_value_1 (type, mode);
}
/* Implements TARGET_FUNCTION_VALUE_REGNO_P.
Return true if REGNO is the number of a hard register in which the values
of called function may come back. */
@ -5151,10 +5179,14 @@ aarch64_function_arg_alignment (machine_mode mode, const_tree type,
}
/* Layout a function argument according to the AAPCS64 rules. The rule
numbers refer to the rule numbers in the AAPCS64. */
numbers refer to the rule numbers in the AAPCS64. ORIG_MODE is the
mode that was originally given to us by the target hook, whereas the
mode in ARG might be the result of replacing partial SVE modes with
the equivalent integer mode. */
static void
aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg,
machine_mode orig_mode)
{
CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
tree type = arg.type;
@ -5168,6 +5200,29 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
if (pcum->aapcs_arg_processed)
return;
/* Vector types can acquire a partial SVE mode using things like
__attribute__((vector_size(N))), and this is potentially useful.
However, the choice of mode doesn't affect the type's ABI identity,
so we should treat the types as though they had the associated
integer mode, just like they did before SVE was introduced.
We know that the vector must be 128 bits or smaller, otherwise we'd
have passed it by reference instead. */
unsigned int vec_flags = aarch64_classify_vector_mode (mode);
if ((vec_flags & VEC_ANY_SVE) && (vec_flags & VEC_PARTIAL))
{
function_arg_info tmp_arg = arg;
tmp_arg.mode = int_mode_for_mode (mode).require ();
aarch64_layout_arg (pcum_v, tmp_arg, orig_mode);
if (rtx reg = pcum->aapcs_reg)
{
gcc_assert (REG_P (reg) && GET_MODE (reg) == tmp_arg.mode);
rtx pair = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
pcum->aapcs_reg = gen_rtx_PARALLEL (mode, gen_rtvec (1, pair));
}
return;
}
pcum->aapcs_arg_processed = true;
unsigned int num_zr, num_pr;
@ -5289,7 +5344,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
comparison is there because for > 16 * BITS_PER_UNIT
alignment nregs should be > 2 and therefore it should be
passed by reference rather than value. */
&& (aarch64_function_arg_alignment (mode, type, &abi_break)
&& (aarch64_function_arg_alignment (orig_mode, type, &abi_break)
== 16 * BITS_PER_UNIT))
{
if (abi_break && warn_psabi && currently_expanding_gimple_stmt)
@ -5332,7 +5387,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
on_stack:
pcum->aapcs_stack_words = size / UNITS_PER_WORD;
if (aarch64_function_arg_alignment (mode, type, &abi_break)
if (aarch64_function_arg_alignment (orig_mode, type, &abi_break)
== 16 * BITS_PER_UNIT)
{
int new_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD);
@ -5360,7 +5415,7 @@ aarch64_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
if (arg.end_marker_p ())
return gen_int_mode (pcum->pcs_variant, DImode);
aarch64_layout_arg (pcum_v, arg);
aarch64_layout_arg (pcum_v, arg, arg.mode);
return pcum->aapcs_reg;
}
@ -5425,7 +5480,7 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v,
|| pcum->pcs_variant == ARM_PCS_SIMD
|| pcum->pcs_variant == ARM_PCS_SVE)
{
aarch64_layout_arg (pcum_v, arg);
aarch64_layout_arg (pcum_v, arg, arg.mode);
gcc_assert ((pcum->aapcs_reg != NULL_RTX)
!= (pcum->aapcs_stack_words != 0));
pcum->aapcs_arg_processed = false;

View file

@ -1,3 +1,7 @@
2019-12-19 Richard Sandiford <richard.sandiford@arm.com>
* gcc.target/aarch64/sve/pcs/gnu_vectors_3.c: New test.
2019-12-19 Feng Xue <fxue@os.amperecomputing.com>
PR ipa/92794

View file

@ -0,0 +1,58 @@
/* { dg-options "-O -msve-vector-bits=256" } */
typedef unsigned char int8x4_t __attribute__((vector_size (4)));
/*
** passthru_x0:
** ret
*/
int8x4_t passthru_x0 (int8x4_t x0) { return x0; }
/*
** passthru_x1:
** mov w0, w1
** ret
*/
int8x4_t passthru_x1 (int8x4_t x0, int8x4_t x1) { return x1; }
int8x4_t load (int8x4_t *x0) { return *x0; }
void store (int8x4_t *x0, int8x4_t x1) { *x0 = x1; }
/*
** stack_callee:
** ptrue p[0-7], vl32
** ld1b (z[0-9]+\.d), \1/z, \[sp\]
** st1b \2, \1, \[x0\]
** ret
*/
__attribute__((noipa))
void stack_callee (int8x4_t *x0, int8x4_t x1, int8x4_t x2, int8x4_t x3,
int8x4_t x4, int8x4_t x5, int8x4_t x6, int8x4_t x7,
int8x4_t stack0)
{
*x0 = stack0;
}
/*
** stack_callee:
** \.\.\.
** ptrue p[0-7], vl32
** \.\.\.
** ld1b (z[0-9]+\.d), \1/z, \[x0\]
** \.\.\.
** st1b \2, \1, \[sp\]
** \.\.\.
** ret
*/
void stack_caller (int8x4_t *x0, int8x4_t x1)
{
stack_callee (x0, x1, x1, x1, x1, x1, x1, x1, *x0);
}
/* { dg-final { scan-assembler {\tmov\tw2, w} } } */
/* { dg-final { scan-assembler {\tmov\tw3, w} } } */
/* { dg-final { scan-assembler {\tmov\tw4, w} } } */
/* { dg-final { scan-assembler {\tmov\tw5, w} } } */
/* { dg-final { scan-assembler {\tmov\tw6, w} } } */
/* { dg-final { scan-assembler {\tmov\tw7, w} } } */