]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix expand_expr_real_1 handling of BLKmode bitfield references
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 4 Jun 2018 15:02:07 +0000 (15:02 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 4 Jun 2018 15:02:07 +0000 (15:02 +0000)
The handling of bitfield references in expand_expr_real_1 includes:

            machine_mode ext_mode = mode;

            if (ext_mode == BLKmode
                && ! (target != 0 && MEM_P (op0)
                      && MEM_P (target)
                      && multiple_p (bitpos, BITS_PER_UNIT)))
              ext_mode = int_mode_for_size (bitsize, 1).else_blk ();

            if (ext_mode == BLKmode)
              {
                [...]
                gcc_assert (MEM_P (op0)

Here "mode" is the TYPE_MODE of the result, so when mode == BLKmode,
the target must be a MEM if nonnull, since no other rtl objects can
have BLKmode.  But there's no guarantee that the source value op0 is also
BLKmode and thus also a MEM: we can reach the assert for any source if
the bitsize being extracted is larger than the largest integer mode
(or larger than MAX_FIXED_MODE_SIZE).

This triggered for SVE with -msve-vector-bits=512, where we could
sometimes try to extract a BLKmode value from a 512-bit vector,
and where int_mode_for_size would rightly fail for large bitsizes.

The patch reuses the existing:

/* Otherwise, if this is a constant or the object is not in memory
   and need be, put it there.  */
else if (CONSTANT_P (op0) || (!MEM_P (op0) && must_force_mem))
  {
    memloc = assign_temp (TREE_TYPE (tem), 1, 1);
    emit_move_insn (memloc, op0);
    op0 = memloc;
    clear_mem_expr = true;
  }

to handle this case.

2018-05-29  Richard Sandiford  <richard.sandiford@linaro.org>

gcc/
* expr.c (expand_expr_real_1): Force the operand into memory if
its TYPE_MODE is BLKmode and if there is no integer mode for
the number of bits being extracted.

gcc/testsuite/
* gcc.target/aarch64/sve/extract_5.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@261150 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/expr.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/sve/extract_5.c [new file with mode: 0644]

index eea029814cdc59e6cd590bc8fe7d74de2f46e9b9..78541036ba9e2b1d3f3b37f57dc42ae85fbc4c06 100644 (file)
@@ -1,3 +1,9 @@
+2018-06-04  Richard Sandiford  <richard.sandiford@linaro.org>
+
+       * expr.c (expand_expr_real_1): Force the operand into memory if
+       its TYPE_MODE is BLKmode and if there is no integer mode for
+       the number of bits being extracted.
+
 2018-06-04  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/85832
index 1fa32275fdfe807e4e320eaabadb394ca931df28..f15037adfb63a7fab83af546bda5787451e2ce1e 100644 (file)
@@ -10579,6 +10579,8 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
           to a larger size.  */
        must_force_mem = (offset
                          || mode1 == BLKmode
+                         || (mode == BLKmode
+                             && !int_mode_for_size (bitsize, 1).exists ())
                          || maybe_gt (bitpos + bitsize,
                                       GET_MODE_BITSIZE (mode2)));
 
index 043a4f49495f8a8d7a1802a9a3e1f4405396b96b..459958eb5eaa88a9f7b74259752842c200e9581f 100644 (file)
@@ -1,3 +1,7 @@
+2018-06-04  Richard Sandiford  <richard.sandiford@linaro.org>
+
+       * gcc.target/aarch64/sve/extract_5.c: New test.
+
 2018-06-04  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/85832
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/extract_5.c b/gcc/testsuite/gcc.target/aarch64/sve/extract_5.c
new file mode 100644 (file)
index 0000000..652ba83
--- /dev/null
@@ -0,0 +1,71 @@
+/* Originally from gcc.dg/vect/vect-alias-check-10.c.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -msve-vector-bits=512" } */
+
+#define N 87
+#define M 6
+
+typedef signed char sc;
+typedef unsigned char uc;
+typedef signed short ss;
+typedef unsigned short us;
+typedef int si;
+typedef unsigned int ui;
+typedef signed long long sll;
+typedef unsigned long long ull;
+
+#define FOR_EACH_TYPE(M) \
+  M (sc) M (uc) \
+  M (ss) M (us) \
+  M (si) M (ui) \
+  M (sll) M (ull) \
+  M (float) M (double)
+
+#define TEST_VALUE(I) ((I) * 5 / 2)
+
+#define ADD_TEST(TYPE)                         \
+  void __attribute__((noinline, noclone))      \
+  test_##TYPE (TYPE *a, int step)              \
+  {                                            \
+    for (int i = 0; i < N; ++i)                        \
+      {                                                \
+       a[i * step + 0] = a[i * step + 0] + 1;  \
+       a[i * step + 1] = a[i * step + 1] + 2;  \
+       a[i * step + 2] = a[i * step + 2] + 4;  \
+       a[i * step + 3] = a[i * step + 3] + 8;  \
+      }                                                \
+  }                                            \
+  void __attribute__((noinline, noclone))      \
+  ref_##TYPE (TYPE *a, int step)               \
+  {                                            \
+    for (int i = 0; i < N; ++i)                        \
+      {                                                \
+       a[i * step + 0] = a[i * step + 0] + 1;  \
+       a[i * step + 1] = a[i * step + 1] + 2;  \
+       a[i * step + 2] = a[i * step + 2] + 4;  \
+       a[i * step + 3] = a[i * step + 3] + 8;  \
+       asm volatile ("");                      \
+      }                                                \
+  }
+
+#define DO_TEST(TYPE)                                  \
+  for (int j = -M; j <= M; ++j)                                \
+    {                                                  \
+      TYPE a[N * M], b[N * M];                         \
+      for (int i = 0; i < N * M; ++i)                  \
+       a[i] = b[i] = TEST_VALUE (i);                   \
+      int offset = (j < 0 ? N * M - 4 : 0);            \
+      test_##TYPE (a + offset, j);                     \
+      ref_##TYPE (b + offset, j);                      \
+      if (__builtin_memcmp (a, b, sizeof (a)) != 0)    \
+       __builtin_abort ();                             \
+    }
+
+FOR_EACH_TYPE (ADD_TEST)
+
+int
+main (void)
+{
+  FOR_EACH_TYPE (DO_TEST)
+  return 0;
+}