On Wed, 17 Jul 2024, Jakub Jelinek wrote:

> Hi!
> 
> 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.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk
> and release branches?  This affects even 11 branch, dunno if we want to
> change it even there or just ignore.  It is a wrong-code issue though, where
> it can overwrite random non-padding bits or bytes instead of the padding
> one.

OK.  It's a bit late for the 11 branch without some soaking on trunk - 
when do we use __builtin_clear_padding?  IIRC for C++ atomics?

Thanks,
Richard.

> 2024-07-17  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR middle-end/115527
>       * gimple-fold.cc (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.
> 
> --- gcc/gimple-fold.cc.jj     2024-07-16 13:36:36.000000000 +0200
> +++ gcc/gimple-fold.cc        2024-07-16 19:27:06.776641459 +0200
> @@ -4242,7 +4242,8 @@ clear_padding_flush (clear_padding_struc
>         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])
>           {
> @@ -4271,12 +4272,12 @@ clear_padding_flush (clear_padding_struc
>        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)
> @@ -4316,7 +4317,7 @@ clear_padding_flush (clear_padding_struc
>        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.  */
> @@ -4358,7 +4359,7 @@ clear_padding_flush (clear_padding_struc
>                 j = k;
>               }
>           }
> -       if (nonzero_last == wordsize)
> +       if (nonzero_last == endsize)
>           padding_bytes = nonzero_last - zero_last;
>         continue;
>       }
> @@ -4832,6 +4833,7 @@ clear_padding_type (clear_padding_struct
>         buf->off = 0;
>         buf->size = 0;
>         clear_padding_emit_loop (buf, elttype, end, for_auto_init);
> +       off += sz;
>         buf->base = base;
>         buf->sz = prev_sz;
>         buf->align = prev_align;
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-1.c.jj   
> 2020-11-20 12:28:10.105680922 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-1.c      
> 2024-07-16 17:05:39.950485611 +0200
> @@ -1,4 +1,5 @@
>  /* PR libstdc++/88101 */
> +/* { dg-do run } */
>  
>  int i1, i2;
>  long double l1, l2;
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c.jj   
> 2020-11-20 12:28:10.105680922 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c      
> 2024-07-16 17:05:52.710323728 +0200
> @@ -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; };
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-3.c.jj   
> 2020-11-20 12:28:10.105680922 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-3.c      
> 2024-07-16 17:06:05.366163163 +0200
> @@ -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; };
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c.jj   
> 2022-02-11 11:20:24.285392974 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c      
> 2024-07-16 17:06:37.671753308 +0200
> @@ -1,6 +1,6 @@
> -/* { dg-require-effective-target alloca } */
> -
>  /* PR libstdc++/88101 */
> +/* { dg-do run } */
> +/* { dg-require-effective-target alloca } */
>  
>  struct S { char a; short b; char c; };
>  
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c.jj   
> 2020-11-20 12:28:10.106680911 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c      
> 2024-07-16 17:06:49.216606833 +0200
> @@ -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;
> --- gcc/testsuite/c-c++-common/torture/builtin-clear-padding-6.c.jj   
> 2024-07-16 16:55:10.331460214 +0200
> +++ gcc/testsuite/c-c++-common/torture/builtin-clear-padding-6.c      
> 2024-07-16 17:06:56.940508833 +0200
> @@ -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;
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to