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>
* config/arc/simdext.md (dmpyh): Fix typo.
......
......@@ -2256,33 +2256,58 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode,
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
the user and opt for the natural alignment (specified in AAPCS64 \S 4.1).
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)
{
struct aarch64_fn_arg_alignment aa;
aa.alignment = 0;
aa.warn_alignment = 0;
if (!type)
return GET_MODE_ALIGNMENT (mode);
{
aa.alignment = GET_MODE_ALIGNMENT (mode);
return aa;
}
if (integer_zerop (TYPE_SIZE (type)))
return 0;
return aa;
gcc_assert (TYPE_MODE (type) == mode);
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)
return TYPE_ALIGN (TREE_TYPE (type));
unsigned int alignment = 0;
{
aa.alignment = TYPE_ALIGN (TREE_TYPE (type));
return aa;
}
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
......@@ -2369,24 +2394,39 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode,
entirely general registers. */
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);
/* C.8 if the argument has an alignment of 16 then the NGRN is
rounded up to the next even number. */
if (nregs == 2 && alignment == 16 * BITS_PER_UNIT && ncrn % 2)
{
++ncrn;
gcc_assert (ncrn + nregs <= NUM_ARG_REGS);
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;
gcc_assert (ncrn + nregs <= NUM_ARG_REGS);
}
}
/* 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
enough not to use it. */
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
{
rtx par;
......@@ -2414,7 +2454,10 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode,
this argument and align the total size if necessary. */
on_stack:
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,
16 / UNITS_PER_WORD);
return;
......@@ -2505,13 +2548,17 @@ aarch64_function_arg_regno_p (unsigned regno)
static unsigned int
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)
alignment = PARM_BOUNDARY;
if (alignment > STACK_BOUNDARY)
alignment = STACK_BOUNDARY;
return alignment;
return aa.alignment;
}
/* 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,
stack = build3 (COMPONENT_REF, TREE_TYPE (f_stack), unshare_expr (valist),
f_stack, NULL_TREE);
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;
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>
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