https://gcc.gnu.org/g:3eec2d768d72944ed209b51ba60455d751b9aede

commit r11-11580-g3eec2d768d72944ed209b51ba60455d751b9aede
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Wed Jul 17 11:38:33 2024 +0200

    gimple-fold: Fix up __builtin_clear_padding lowering [PR115527]
    
    The builtin-clear-padding-6.c testcase fails as clear_padding_type
    doesn't correctly recompute the buf->size and buf->off members after
    expanding clearing of an array using a runtime loop.
    buf->size should be in that case the offset after which it should continue
    with next members or padding before them modulo UNITS_PER_WORD and
    buf->off that offset minus buf->size.  That is what the code was doing,
    but with off being the start of the loop cleared array, not its end.
    So, the last hunk in gimple-fold.cc fixes that.
    When adding the testcase, I've noticed that the
    c-c++-common/torture/builtin-clear-padding-* tests, although clearly
    written as runtime tests to test the builtins at runtime, didn't have
    { dg-do run } directive and were just compile tests because of that.
    When adding that to the tests, builtin-clear-padding-1.c was already
    failing without that clear_padding_type hunk too, but
    builtin-clear-padding-5.c was still failing even after the change.
    That is due to a bug in clear_padding_flush which the patch fixes as
    well - when clear_padding_flush is called with full=true (that happens
    at the end of the whole __builtin_clear_padding or on those array
    padding clears done by a runtime loop), it wants to flush all the pending
    padding clearings rather than just some.  If it is at the end of the whole
    object, it decreases wordsize when needed to make sure the code never writes
    including RMW cycles to something outside of the object:
          if ((unsigned HOST_WIDE_INT) (buf->off + i + wordsize)
              > (unsigned HOST_WIDE_INT) buf->sz)
            {
              gcc_assert (wordsize > 1);
              wordsize /= 2;
              i -= wordsize;
              continue;
            }
    but if it is full==true flush in the middle, this doesn't happen, but we
    still process just the buffer bytes before the current end.  If that end
    is not on a wordsize boundary, e.g. on the builtin-clear-padding-5.c test
    the last chunk is 2 bytes, '\0', '\xff', i is 16 and end is 18,
    nonzero_last might be equal to the end - i, i.e. 2 here, but still all_ones
    might be true, so in some spots we just didn't emit any clearing in that
    last chunk.
    
    2024-07-17  Jakub Jelinek  <ja...@redhat.com>
    
            PR middle-end/115527
            * gimple-fold.c (clear_padding_flush): Introduce endsize
            variable and use it instead of wordsize when comparing it against
            nonzero_last.
            (clear_padding_type): Increment off by sz.
    
            * c-c++-common/torture/builtin-clear-padding-1.c: Add dg-do run
            directive.
            * c-c++-common/torture/builtin-clear-padding-2.c: Likewise.
            * c-c++-common/torture/builtin-clear-padding-3.c: Likewise.
            * c-c++-common/torture/builtin-clear-padding-4.c: Likewise.
            * c-c++-common/torture/builtin-clear-padding-5.c: Likewise.
            * c-c++-common/torture/builtin-clear-padding-6.c: New test.
    
    (cherry picked from commit 8b5919bae11754f4b65a17e63663d3143f9615ac)

Diff:
---
 gcc/gimple-fold.c                                  | 12 ++++++----
 .../c-c++-common/torture/builtin-clear-padding-1.c |  1 +
 .../c-c++-common/torture/builtin-clear-padding-2.c |  1 +
 .../c-c++-common/torture/builtin-clear-padding-3.c |  1 +
 .../c-c++-common/torture/builtin-clear-padding-4.c |  2 ++
 .../c-c++-common/torture/builtin-clear-padding-5.c |  1 +
 .../c-c++-common/torture/builtin-clear-padding-6.c | 28 ++++++++++++++++++++++
 7 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index bb4db5af2809..0449d67dae1a 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -4084,7 +4084,8 @@ clear_padding_flush (clear_padding_struct *buf, bool full)
          i -= wordsize;
          continue;
        }
-      for (size_t j = i; j < i + wordsize && j < end; j++)
+      size_t endsize = end - i > wordsize ? wordsize : end - i;
+      for (size_t j = i; j < i + endsize; j++)
        {
          if (buf->buf[j])
            {
@@ -4113,12 +4114,12 @@ clear_padding_flush (clear_padding_struct *buf, bool 
full)
       if (padding_bytes)
        {
          if (nonzero_first == 0
-             && nonzero_last == wordsize
+             && nonzero_last == endsize
              && all_ones)
            {
              /* All bits are padding and we had some padding
                 before too.  Just extend it.  */
-             padding_bytes += wordsize;
+             padding_bytes += endsize;
              continue;
            }
          if (all_ones && nonzero_first == 0)
@@ -4158,7 +4159,7 @@ clear_padding_flush (clear_padding_struct *buf, bool full)
       if (nonzero_first == wordsize)
        /* All bits in a word are 0, there are no padding bits.  */
        continue;
-      if (all_ones && nonzero_last == wordsize)
+      if (all_ones && nonzero_last == endsize)
        {
          /* All bits between nonzero_first and end of word are padding
             bits, start counting padding_bytes.  */
@@ -4200,7 +4201,7 @@ clear_padding_flush (clear_padding_struct *buf, bool full)
                  j = k;
                }
            }
-         if (nonzero_last == wordsize)
+         if (nonzero_last == endsize)
            padding_bytes = nonzero_last - zero_last;
          continue;
        }
@@ -4630,6 +4631,7 @@ clear_padding_type (clear_padding_struct *buf, tree type, 
HOST_WIDE_INT sz)
          buf->off = 0;
          buf->size = 0;
          clear_padding_emit_loop (buf, elttype, end);
+         off += sz;
          buf->base = base;
          buf->sz = prev_sz;
          buf->align = prev_align;
diff --git a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-1.c 
b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-1.c
index 6b01a5614b53..f739963cc4df 100644
--- a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-1.c
+++ b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-1.c
@@ -1,4 +1,5 @@
 /* PR libstdc++/88101 */
+/* { dg-do run } */
 
 int i1, i2;
 long double l1, l2;
diff --git a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c 
b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c
index 1188bc07ed27..099f202ebc75 100644
--- a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c
+++ b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c
@@ -1,4 +1,5 @@
 /* PR libstdc++/88101 */
+/* { dg-do run } */
 
 typedef int T __attribute__((aligned (16384)));
 struct S { char a; short b; long double c; T d; T e; long long f; };
diff --git a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-3.c 
b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-3.c
index edb7c8eb555a..27bf8f6dd734 100644
--- a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-3.c
+++ b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-3.c
@@ -1,4 +1,5 @@
 /* PR libstdc++/88101 */
+/* { dg-do run } */
 
 union V { char a; signed char b; unsigned char c; };
 struct T { char a; int b; union V c; };
diff --git a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c 
b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c
index d24f3b59d7b8..ebc589327387 100644
--- a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c
+++ b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c
@@ -1,4 +1,6 @@
 /* PR libstdc++/88101 */
+/* { dg-do run } */
+/* { dg-require-effective-target alloca } */
 
 struct S { char a; short b; char c; };
 
diff --git a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c 
b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c
index d5dbafe1c748..3f7d40fddf8c 100644
--- a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c
+++ b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c
@@ -1,4 +1,5 @@
 /* PR libstdc++/88101 */
+/* { dg-do run } */
 
 struct S { char a; short b; char c; } s1[24], s2[24];
 struct T { char a; long long b; char c; struct S d[3]; long long e; char f; } 
t1, t2;
diff --git a/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-6.c 
b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-6.c
new file mode 100644
index 000000000000..db1f00eca737
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/builtin-clear-padding-6.c
@@ -0,0 +1,28 @@
+/* PR middle-end/115527 */
+/* { dg-do run } */
+
+struct T { struct S { double a; signed char b; long c; } d[3]; int e; } t1, t2;
+
+__attribute__((noipa)) void
+foo (struct T *t)
+{
+  for (int i = 0; i < 3; ++i)
+    {
+      t->d[i].a = 1. + 3 * i;
+      t->d[i].b = 2 + 3 * i;
+      t->d[i].c = 3 + 3 * i;
+    }
+  t->e = 10;
+}
+
+int
+main ()
+{
+  __builtin_memset (&t2, -1, sizeof (t2));
+  foo (&t1);
+  foo (&t2);
+  __builtin_clear_padding (&t2);
+  if (__builtin_memcmp (&t1, &t2, sizeof (t1)))
+    __builtin_abort ();
+  return 0;
+}

Reply via email to