From 1d929c7915bcb563f39c0012b752572428958186 Mon Sep 17 00:00:00 2001 From: Mikhail Kashkarov Date: Thu, 15 Jun 2017 17:03:07 +0300 Subject: Implement AAPCS64 updates for alignment attribute. PR target/77728 gcc/ * config/aarch64/aarch64.c(aarch64_function_arg_alignmentq): Rewrite, looking one level down for records and arrays. Ignore TYPE_FIELDS chain decls other than FIELD_DECLs. (aarch64_layout_arg): Adjust aarch64_function_arg_alignment caller. (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. Backported from trunk: be35fa06e8f976e1cb880988d5c82813106922fd 32cb614ad1f60267f914e38da26a73259299d720 26312b0ea5f3dfc6e3d8d8d18c76d464d6fa328e Change-Id: I4293167468353e9730dc918b87edda4484af8315 --- gcc/config/aarch64/aarch64.c | 54 ++++++------ gcc/testsuite/g++.dg/abi/pr77728-2.C | 165 +++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/g++.dg/abi/pr77728-2.C diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index f0970f29c41..bd75ef205f3 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -2246,22 +2246,24 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, static unsigned int aarch64_function_arg_alignment (machine_mode mode, const_tree type) { - unsigned int alignment; + if (!type) + return GET_MODE_ALIGNMENT (mode); - if (type) - { - if (!integer_zerop (TYPE_SIZE (type))) - { - if (TYPE_MODE (type) == mode) - alignment = TYPE_ALIGN (type); - else - alignment = GET_MODE_ALIGNMENT (mode); - } - else - alignment = 0; - } - else - alignment = GET_MODE_ALIGNMENT (mode); + if (integer_zerop (TYPE_SIZE (type))) + return 0; + + gcc_assert (TYPE_MODE (type) == mode); + + if (!AGGREGATE_TYPE_P (type)) + return TYPE_ALIGN (TYPE_MAIN_VARIANT (type)); + + if (TREE_CODE (type) == ARRAY_TYPE) + return TYPE_ALIGN (TREE_TYPE (type)); + + unsigned int alignment = 0; + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + alignment = std::max (alignment, DECL_ALIGN (field)); return alignment; } @@ -2350,24 +2352,28 @@ 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) + if (nregs == 2 + && ncrn % 2 + /* The == 16 * BITS_PER_UNIT instead of >= 16 * BITS_PER_UNIT + 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) == 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; @@ -2395,6 +2401,7 @@ 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) pcum->aapcs_stack_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD); @@ -2487,12 +2494,7 @@ static unsigned int aarch64_function_arg_boundary (machine_mode mode, const_tree type) { unsigned int alignment = aarch64_function_arg_alignment (mode, type); - - if (alignment < PARM_BOUNDARY) - alignment = PARM_BOUNDARY; - if (alignment > STACK_BOUNDARY) - alignment = STACK_BOUNDARY; - return alignment; + return MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); } /* For use by FUNCTION_ARG_PADDING (MODE, TYPE). diff --git a/gcc/testsuite/g++.dg/abi/pr77728-2.C b/gcc/testsuite/g++.dg/abi/pr77728-2.C new file mode 100644 index 00000000000..ffe6910bd91 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/pr77728-2.C @@ -0,0 +1,165 @@ +// { dg-do compile { target { { aarch64-*-* } && c++11 } } } +// { dg-options "" } + +#include + +template +struct alignas (16) A { char p[16]; }; + +A<0> v; + +template +struct B +{ + typedef A 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 +struct K : public D { typedef A T; int i, j; }; + +struct L { static int h alignas (16); int i, j, k, l; }; + +int +fn1 (int a, B<0> b) +{ + return a + b.i; +} + +int +fn2 (int a, B<1> b) +{ + return a + b.i; +} + +int +fn3 (int a, L b) +{ + 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, ...) +{ + 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, ...) +{ + 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, ...) +{ + 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); + fn2 (1, b1); + fn3 (1, l); + fn4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, b0, 1, 2, 3, 4); + 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); + fn11 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, k0, 1, 2, 3, 4); + fn12 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, k2, 1, 2, 3, 4); +} -- cgit v1.2.3