/* Convert n to bits to make the rest of the code simpler. */
n = n * BITS_PER_UNIT;
+ /* Maximum amount to copy in one go. The AArch64 back-end has integer modes
+ larger than TImode, but we should not use them for loads/stores here. */
+ const int copy_limit = GET_MODE_BITSIZE (TImode);
+
while (n > 0)
{
/* Find the largest mode in which to do the copy in without over reading
or writing. */
opt_scalar_int_mode mode_iter;
FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_INT)
- if (GET_MODE_BITSIZE (mode_iter.require ()) <= n)
+ if (GET_MODE_BITSIZE (mode_iter.require ()) <= MIN (n, copy_limit))
cur_mode = mode_iter.require ();
gcc_assert (cur_mode != BLKmode);
cheaper. i.e. less instructions to do so. For instance doing a 15
byte copy it's more efficient to do two overlapping 8 byte copies than
8 + 6 + 1. */
- next_mode = smallest_mode_for_size (n, MODE_INT);
- int n_bits = GET_MODE_BITSIZE (next_mode).to_constant ();
- if (n > 0 && n_bits > n && n_bits <= 8 * BITS_PER_UNIT)
+ if (n > 0 && n <= 8 * BITS_PER_UNIT)
{
+ next_mode = smallest_mode_for_size (n, MODE_INT);
+ int n_bits = GET_MODE_BITSIZE (next_mode).to_constant ();
src = aarch64_move_pointer (src, (n - n_bits) / BITS_PER_UNIT);
dst = aarch64_move_pointer (dst, (n - n_bits) / BITS_PER_UNIT);
n = n_bits;
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef unsigned __attribute__((mode(DI))) uint64_t;
+
+struct S0 {
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+} a;
+struct S2 {
+ uint64_t f0;
+ uint64_t f2;
+ struct S0 f3;
+};
+
+void fn1 () {
+ struct S2 b = {0, 1, 7, 4073709551611, 4, 8, 7};
+ a = b.f3;
+}
+
+/* { dg-final { scan-assembler-times {ldp\s+x[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {stp\s+x[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {ld[1-3]} } } */