Skip to content

Commit 1880ff0

Browse files
committed
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 <[email protected]> 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. (cherry picked from commit 8b5919b)
1 parent ff84211 commit 1880ff0

File tree

7 files changed

+41
-7
lines changed

7 files changed

+41
-7
lines changed

gcc/gimple-fold.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4235,7 +4235,8 @@ clear_padding_flush (clear_padding_struct *buf, bool full)
42354235
i -= wordsize;
42364236
continue;
42374237
}
4238-
for (size_t j = i; j < i + wordsize && j < end; j++)
4238+
size_t endsize = end - i > wordsize ? wordsize : end - i;
4239+
for (size_t j = i; j < i + endsize; j++)
42394240
{
42404241
if (buf->buf[j])
42414242
{
@@ -4264,12 +4265,12 @@ clear_padding_flush (clear_padding_struct *buf, bool full)
42644265
if (padding_bytes)
42654266
{
42664267
if (nonzero_first == 0
4267-
&& nonzero_last == wordsize
4268+
&& nonzero_last == endsize
42684269
&& all_ones)
42694270
{
42704271
/* All bits are padding and we had some padding
42714272
before too. Just extend it. */
4272-
padding_bytes += wordsize;
4273+
padding_bytes += endsize;
42734274
continue;
42744275
}
42754276
if (all_ones && nonzero_first == 0)
@@ -4309,7 +4310,7 @@ clear_padding_flush (clear_padding_struct *buf, bool full)
43094310
if (nonzero_first == wordsize)
43104311
/* All bits in a word are 0, there are no padding bits. */
43114312
continue;
4312-
if (all_ones && nonzero_last == wordsize)
4313+
if (all_ones && nonzero_last == endsize)
43134314
{
43144315
/* All bits between nonzero_first and end of word are padding
43154316
bits, start counting padding_bytes. */
@@ -4351,7 +4352,7 @@ clear_padding_flush (clear_padding_struct *buf, bool full)
43514352
j = k;
43524353
}
43534354
}
4354-
if (nonzero_last == wordsize)
4355+
if (nonzero_last == endsize)
43554356
padding_bytes = nonzero_last - zero_last;
43564357
continue;
43574358
}
@@ -4802,6 +4803,7 @@ clear_padding_type (clear_padding_struct *buf, tree type,
48024803
buf->off = 0;
48034804
buf->size = 0;
48044805
clear_padding_emit_loop (buf, elttype, end, for_auto_init);
4806+
off += sz;
48054807
buf->base = base;
48064808
buf->sz = prev_sz;
48074809
buf->align = prev_align;

gcc/testsuite/c-c++-common/torture/builtin-clear-padding-1.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* PR libstdc++/88101 */
2+
/* { dg-do run } */
23

34
int i1, i2;
45
long double l1, l2;

gcc/testsuite/c-c++-common/torture/builtin-clear-padding-2.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* PR libstdc++/88101 */
2+
/* { dg-do run } */
23

34
typedef int T __attribute__((aligned (16384)));
45
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* PR libstdc++/88101 */
2+
/* { dg-do run } */
23

34
union V { char a; signed char b; unsigned char c; };
45
struct T { char a; int b; union V c; };

gcc/testsuite/c-c++-common/torture/builtin-clear-padding-4.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
/* { dg-require-effective-target alloca } */
2-
31
/* PR libstdc++/88101 */
2+
/* { dg-do run } */
3+
/* { dg-require-effective-target alloca } */
44

55
struct S { char a; short b; char c; };
66

gcc/testsuite/c-c++-common/torture/builtin-clear-padding-5.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* PR libstdc++/88101 */
2+
/* { dg-do run } */
23

34
struct S { char a; short b; char c; } s1[24], s2[24];
45
struct T { char a; long long b; char c; struct S d[3]; long long e; char f; } t1, t2;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* PR middle-end/115527 */
2+
/* { dg-do run } */
3+
4+
struct T { struct S { double a; signed char b; long c; } d[3]; int e; } t1, t2;
5+
6+
__attribute__((noipa)) void
7+
foo (struct T *t)
8+
{
9+
for (int i = 0; i < 3; ++i)
10+
{
11+
t->d[i].a = 1. + 3 * i;
12+
t->d[i].b = 2 + 3 * i;
13+
t->d[i].c = 3 + 3 * i;
14+
}
15+
t->e = 10;
16+
}
17+
18+
int
19+
main ()
20+
{
21+
__builtin_memset (&t2, -1, sizeof (t2));
22+
foo (&t1);
23+
foo (&t2);
24+
__builtin_clear_padding (&t2);
25+
if (__builtin_memcmp (&t1, &t2, sizeof (t1)))
26+
__builtin_abort ();
27+
return 0;
28+
}

0 commit comments

Comments
 (0)