When expanding a constant constructor, don't call expand_constructor if it is more efficient to load the data from the memory via move by pieces.
gcc/ PR middle-end/90773 * expr.c (expand_expr_real_1): Don't call expand_constructor if it is more efficient to load the data from the memory. gcc/testsuite/ PR middle-end/90773 * gcc.target/i386/pr90773-24.c: New test. * gcc.target/i386/pr90773-25.c: Likewise. --- gcc/expr.c | 10 ++++++++++ gcc/testsuite/gcc.target/i386/pr90773-24.c | 22 ++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr90773-25.c | 20 ++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr90773-24.c create mode 100644 gcc/testsuite/gcc.target/i386/pr90773-25.c diff --git a/gcc/expr.c b/gcc/expr.c index 42ef5bdf5d5..6ad7265702e 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -10885,6 +10885,16 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, unsigned HOST_WIDE_INT ix; tree field, value; + /* Check if it is more efficient to load the data from + the memory directly. FIXME: How many stores do we + need here if not moved by pieces? */ + unsigned HOST_WIDE_INT bytes + = tree_to_uhwi (TYPE_SIZE_UNIT (type)); + if ((bytes / UNITS_PER_WORD) > 2 + && MOVE_MAX_PIECES > UNITS_PER_WORD + && can_move_by_pieces (bytes, TYPE_ALIGN (type))) + goto normal_inner_ref; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix, field, value) if (tree_int_cst_equal (field, index)) diff --git a/gcc/testsuite/gcc.target/i386/pr90773-24.c b/gcc/testsuite/gcc.target/i386/pr90773-24.c new file mode 100644 index 00000000000..4a4b62533dc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr90773-24.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=x86-64" } */ + +struct S +{ + long long s1 __attribute__ ((aligned (8))); + unsigned s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14; +}; + +const struct S array[] = { + { 0, 60, 640, 2112543726, 39682, 48, 16, 33, 10, 96, 2, 0, 0, 4 } +}; + +void +foo (struct S *x) +{ + x[0] = array[0]; +} +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, \\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 16\\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 32\\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 48\\(%\[\^,\]+\\)" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr90773-25.c b/gcc/testsuite/gcc.target/i386/pr90773-25.c new file mode 100644 index 00000000000..2520b670989 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr90773-25.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=skylake" } */ + +struct S +{ + long long s1 __attribute__ ((aligned (8))); + unsigned s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14; +}; + +const struct S array[] = { + { 0, 60, 640, 2112543726, 39682, 48, 16, 33, 10, 96, 2, 0, 0, 4 } +}; + +void +foo (struct S *x) +{ + x[0] = array[0]; +} +/* { dg-final { scan-assembler-times "vmovdqu\[\\t \]%ymm\[0-9\]+, \\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "vmovdqu\[\\t \]%ymm\[0-9\]+, 32\\(%\[\^,\]+\\)" 1 } } */ -- 2.31.1