Commit 2ec07fa6 by Ramana Radhakrishnan Committed by Jakub Jelinek

re PR target/77728 (Miscompilation multiple vector iteration on ARM)

	PR target/77728
	* config/aarch64/aarch64.c (struct aarch64_fn_arg_alignment): New
	type.
	(aarch64_function_arg_alignment): Return aarch64_fn_arg_alignment
	struct.  Ignore DECL_ALIGN of decls other than FIELD_DECL for
	the alignment computation, but return their maximum in warn_alignment.
	(aarch64_layout_arg): Adjust aarch64_function_arg_alignment caller.
	Emit a -Wpsabi note if warn_alignment is 16 bytes, but alignment
	is smaller.
	(aarch64_function_arg_boundary): Likewise.  Simplify using MIN/MAX.
	(aarch64_gimplify_va_arg_expr): Adjust aarch64_function_arg_alignment
	caller.
testsuite/
	* g++.dg/abi/pr77728-2.C: New test.

Co-Authored-By: Jakub Jelinek <jakub@redhat.com>

From-SVN: r247239
parent eb2d5ccc
2017-04-25 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
Jakub Jelinek <jakub@redhat.com>
PR target/77728
* config/aarch64/aarch64.c (struct aarch64_fn_arg_alignment): New
type.
(aarch64_function_arg_alignment): Return aarch64_fn_arg_alignment
struct. Ignore DECL_ALIGN of decls other than FIELD_DECL for
the alignment computation, but return their maximum in warn_alignment.
(aarch64_layout_arg): Adjust aarch64_function_arg_alignment caller.
Emit a -Wpsabi note if warn_alignment is 16 bytes, but alignment
is smaller.
(aarch64_function_arg_boundary): Likewise. Simplify using MIN/MAX.
(aarch64_gimplify_va_arg_expr): Adjust aarch64_function_arg_alignment
caller.
2017-04-25 Claudiu Zissulescu <claziss@synopsys.com> 2017-04-25 Claudiu Zissulescu <claziss@synopsys.com>
* config/arc/simdext.md (dmpyh): Fix typo. * config/arc/simdext.md (dmpyh): Fix typo.
......
...@@ -2256,33 +2256,58 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, ...@@ -2256,33 +2256,58 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode,
NULL); NULL);
} }
/* Given MODE and TYPE of a function argument, return the alignment in struct aarch64_fn_arg_alignment
{
/* Alignment for FIELD_DECLs in function arguments. */
unsigned int alignment;
/* Alignment for decls other than FIELD_DECLs in function arguments. */
unsigned int warn_alignment;
};
/* Given MODE and TYPE of a function argument, return a pair of alignments in
bits. The idea is to suppress any stronger alignment requested by bits. The idea is to suppress any stronger alignment requested by
the user and opt for the natural alignment (specified in AAPCS64 \S 4.1). the user and opt for the natural alignment (specified in AAPCS64 \S 4.1).
This is a helper function for local use only. */ This is a helper function for local use only. */
static unsigned int static struct aarch64_fn_arg_alignment
aarch64_function_arg_alignment (machine_mode mode, const_tree type) aarch64_function_arg_alignment (machine_mode mode, const_tree type)
{ {
struct aarch64_fn_arg_alignment aa;
aa.alignment = 0;
aa.warn_alignment = 0;
if (!type) if (!type)
return GET_MODE_ALIGNMENT (mode); {
aa.alignment = GET_MODE_ALIGNMENT (mode);
return aa;
}
if (integer_zerop (TYPE_SIZE (type))) if (integer_zerop (TYPE_SIZE (type)))
return 0; return aa;
gcc_assert (TYPE_MODE (type) == mode); gcc_assert (TYPE_MODE (type) == mode);
if (!AGGREGATE_TYPE_P (type)) if (!AGGREGATE_TYPE_P (type))
return TYPE_ALIGN (TYPE_MAIN_VARIANT (type)); {
aa.alignment = TYPE_ALIGN (TYPE_MAIN_VARIANT (type));
return aa;
}
if (TREE_CODE (type) == ARRAY_TYPE) if (TREE_CODE (type) == ARRAY_TYPE)
return TYPE_ALIGN (TREE_TYPE (type)); {
aa.alignment = TYPE_ALIGN (TREE_TYPE (type));
unsigned int alignment = 0; return aa;
}
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
alignment = std::max (alignment, DECL_ALIGN (field)); {
if (TREE_CODE (field) == FIELD_DECL)
aa.alignment = std::max (aa.alignment, DECL_ALIGN (field));
else
aa.warn_alignment = std::max (aa.warn_alignment, DECL_ALIGN (field));
}
return alignment; return aa;
} }
/* Layout a function argument according to the AAPCS64 rules. The rule /* Layout a function argument according to the AAPCS64 rules. The rule
...@@ -2369,24 +2394,39 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode, ...@@ -2369,24 +2394,39 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode,
entirely general registers. */ entirely general registers. */
if (allocate_ncrn && (ncrn + nregs <= NUM_ARG_REGS)) if (allocate_ncrn && (ncrn + nregs <= NUM_ARG_REGS))
{ {
unsigned int alignment = aarch64_function_arg_alignment (mode, type);
gcc_assert (nregs == 0 || nregs == 1 || nregs == 2); gcc_assert (nregs == 0 || nregs == 1 || nregs == 2);
/* C.8 if the argument has an alignment of 16 then the NGRN is /* C.8 if the argument has an alignment of 16 then the NGRN is
rounded up to the next even number. */ rounded up to the next even number. */
if (nregs == 2 && alignment == 16 * BITS_PER_UNIT && ncrn % 2) if (nregs == 2 && ncrn % 2)
{
struct aarch64_fn_arg_alignment aa
= aarch64_function_arg_alignment (mode, type);
/* The == 16 * BITS_PER_UNIT instead of >= 16 * BITS_PER_UNIT
comparisons are there because for > 16 * BITS_PER_UNIT
alignment nregs should be > 2 and therefore it should be
passed by reference rather than value. */
if (aa.warn_alignment == 16 * BITS_PER_UNIT
&& aa.alignment < aa.warn_alignment
&& warn_psabi
&& currently_expanding_gimple_stmt)
inform (input_location,
"parameter passing for argument of type %qT "
"changed in GCC 7.1", type);
else if (aa.alignment == 16 * BITS_PER_UNIT)
{ {
++ncrn; ++ncrn;
gcc_assert (ncrn + nregs <= NUM_ARG_REGS); gcc_assert (ncrn + nregs <= NUM_ARG_REGS);
} }
}
/* NREGS can be 0 when e.g. an empty structure is to be passed. /* NREGS can be 0 when e.g. an empty structure is to be passed.
A reg is still generated for it, but the caller should be smart A reg is still generated for it, but the caller should be smart
enough not to use it. */ enough not to use it. */
if (nregs == 0 || nregs == 1 || GET_MODE_CLASS (mode) == MODE_INT) if (nregs == 0 || nregs == 1 || GET_MODE_CLASS (mode) == MODE_INT)
{
pcum->aapcs_reg = gen_rtx_REG (mode, R0_REGNUM + ncrn); pcum->aapcs_reg = gen_rtx_REG (mode, R0_REGNUM + ncrn);
}
else else
{ {
rtx par; rtx par;
...@@ -2414,7 +2454,10 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode, ...@@ -2414,7 +2454,10 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode,
this argument and align the total size if necessary. */ this argument and align the total size if necessary. */
on_stack: on_stack:
pcum->aapcs_stack_words = size / UNITS_PER_WORD; pcum->aapcs_stack_words = size / UNITS_PER_WORD;
if (aarch64_function_arg_alignment (mode, type) == 16 * BITS_PER_UNIT) struct aarch64_fn_arg_alignment aa
= aarch64_function_arg_alignment (mode, type);
if (aa.alignment == 16 * BITS_PER_UNIT)
pcum->aapcs_stack_size = ROUND_UP (pcum->aapcs_stack_size, pcum->aapcs_stack_size = ROUND_UP (pcum->aapcs_stack_size,
16 / UNITS_PER_WORD); 16 / UNITS_PER_WORD);
return; return;
...@@ -2505,13 +2548,17 @@ aarch64_function_arg_regno_p (unsigned regno) ...@@ -2505,13 +2548,17 @@ aarch64_function_arg_regno_p (unsigned regno)
static unsigned int static unsigned int
aarch64_function_arg_boundary (machine_mode mode, const_tree type) aarch64_function_arg_boundary (machine_mode mode, const_tree type)
{ {
unsigned int alignment = aarch64_function_arg_alignment (mode, type); struct aarch64_fn_arg_alignment aa
= aarch64_function_arg_alignment (mode, type);
aa.alignment = MIN (MAX (aa.alignment, PARM_BOUNDARY), STACK_BOUNDARY);
aa.warn_alignment
= MIN (MAX (aa.warn_alignment, PARM_BOUNDARY), STACK_BOUNDARY);
if (warn_psabi && aa.warn_alignment > aa.alignment)
inform (input_location, "parameter passing for argument of type %qT "
"changed in GCC 7.1", type);
if (alignment < PARM_BOUNDARY) return aa.alignment;
alignment = PARM_BOUNDARY;
if (alignment > STACK_BOUNDARY)
alignment = STACK_BOUNDARY;
return alignment;
} }
/* For use by FUNCTION_ARG_PADDING (MODE, TYPE). /* For use by FUNCTION_ARG_PADDING (MODE, TYPE).
...@@ -10211,7 +10258,9 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, ...@@ -10211,7 +10258,9 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
stack = build3 (COMPONENT_REF, TREE_TYPE (f_stack), unshare_expr (valist), stack = build3 (COMPONENT_REF, TREE_TYPE (f_stack), unshare_expr (valist),
f_stack, NULL_TREE); f_stack, NULL_TREE);
size = int_size_in_bytes (type); size = int_size_in_bytes (type);
align = aarch64_function_arg_alignment (mode, type) / BITS_PER_UNIT; struct aarch64_fn_arg_alignment aa
= aarch64_function_arg_alignment (mode, type);
align = aa.alignment / BITS_PER_UNIT;
dw_align = false; dw_align = false;
adjust = 0; adjust = 0;
......
2017-04-25 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
Jakub Jelinek <jakub@redhat.com>
PR target/77728
* g++.dg/abi/pr77728-2.C: New test.
2017-04-25 David Malcolm <dmalcolm@redhat.com> 2017-04-25 David Malcolm <dmalcolm@redhat.com>
PR c++/80177 PR c++/80177
......
// { dg-do compile { target { { aarch64-*-* } && c++11 } } }
// { dg-options "-Wpsabi" }
#include <stdarg.h>
template <int N>
struct alignas (16) A { char p[16]; };
A<0> v;
template <int N>
struct B
{
typedef A<N> T;
int i, j, k, l;
};
struct C : public B<0> {};
struct D {};
struct E : public D, C {};
struct F : public B<1> {};
struct G : public F { static int y alignas (16); };
struct H : public G {};
struct I : public D { int z alignas (16); };
struct J : public D { static int z alignas (16); int i, j, k, l; };
template <int N>
struct K : public D { typedef A<N> T; int i, j; };
struct L { static int h alignas (16); int i, j, k, l; };
int
fn1 (int a, B<0> b) // { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" }
{
return a + b.i;
}
int
fn2 (int a, B<1> b)
{
return a + b.i;
}
int
fn3 (int a, L b) // { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" }
{
return a + b.i;
}
int
fn4 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, B<0> n, ...)
// { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" "" { target *-*-* } .-1 }
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
int
fn5 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, B<1> n, ...)
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
int
fn6 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, C n, ...)
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
int
fn7 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, E n, ...)
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
int
fn8 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, H n, ...)
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
int
fn9 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, I n, ...)
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
int
fn10 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, J n, ...)
// { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" "" { target *-*-* } .-1 }
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
int
fn11 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, K<0> n, ...)
// { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" "" { target *-*-* } .-1 }
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
int
fn12 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, K<2> n, ...)
{
va_list ap;
va_start (ap, n);
int x = va_arg (ap, int);
va_end (ap);
return x;
}
void
test ()
{
static B<0> b0;
static B<1> b1;
static L l;
static C c;
static E e;
static H h;
static I i;
static J j;
static K<0> k0;
static K<2> k2;
fn1 (1, b0); // { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" }
fn2 (1, b1);
fn3 (1, l); // { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" }
fn4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, b0, 1, 2, 3, 4);
// { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" "" { target *-*-* } .-1 }
fn5 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, b1, 1, 2, 3, 4);
fn6 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, c, 1, 2, 3, 4);
fn7 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, e, 1, 2, 3, 4);
fn8 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, h, 1, 2, 3, 4);
fn9 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, i, 1, 2, 3, 4);
fn10 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, j, 1, 2, 3, 4);
// { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" "" { target *-*-* } .-1 }
fn11 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, k0, 1, 2, 3, 4);
// { dg-message "note: parameter passing for argument of type \[^\n\r]* changed in GCC 7\.1" "" { target *-*-* } .-1 }
fn12 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, k2, 1, 2, 3, 4);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment