tree-optimization/112282 - wrong-code with ifcvt hoisting

The following avoids hoisting of invariants from conditionally
executed parts of an if-converted loop.  That now makes a difference
since we perform bitfield lowering even when we do not actually
if-convert the loop.  if-conversion deals with resetting flow-sensitive
info when necessary already.

	PR tree-optimization/112282
	* tree-if-conv.cc (ifcvt_hoist_invariants): Only hoist from
	the loop header.

	* gcc.dg/torture/pr112282.c: New testcase.
This commit is contained in:
Richard Biener 2023-11-15 12:24:46 +01:00
parent bcef48b59e
commit 5cb8610d3a
2 changed files with 153 additions and 23 deletions

View file

@ -0,0 +1,132 @@
/* { dg-do run } */
int printf(const char *, ...);
void __assert_fail();
int a, g, h, i, v, w = 2, x, y, ab, ac, ad, ae, af, ag;
static int f, j, m, n, p, r, u, aa;
struct b {
int c : 20;
int d : 20;
int e : 10;
};
static struct b l, o, q = {3, 3, 5};
int s(int z) {
struct b ah;
int ai = 1, aj[7] = {1, 1, 1, 1, 1, 1, 1};
ak:
for (u = -22; u < 2; ++u) {
struct b al[8] = {{2, 7, 9}, {8, 7, 1}, {2, 7, 9}, {8, 7, 1}, {2, 7, 9}, {8, 7, 1}, {2, 7, 9}};
y = z = 0;
for (; z < 2; z++) {
int am[18], k;
ab = ac = 0;
for (; ac < 1; ac++)
for (k = 0; k < 9; k++)
am[k] = 0;
n = 0;
while (1) {
v = u < 0 || a;
h = z < ~u && 4 & q.c;
if ((aa <= l.c) > q.d && p)
return o.c;
if (w)
break;
return q.e;
}
a = j;
}
}
for (x = 0; x < 2; x++) {
struct b an = {1, 8, 4};
int ao[28] = {5, 0, 0, 9, 0, 3, 0, 5, 0, 0, 9, 0, 3, 0, 5, 0, 0, 9, 0, 3, 0, 5, 0, 0, 9, 0, 3, 0};
if (q.e) {
int ap = ai || l.c + q.c, aq = q.d, ar = p & f;
q.d = q.d || ar || ap;
p = 0;
if (!j && ai)
goto as;
if (q.d) {
printf("", l);
q.d = f >> j;
}
p = l.c = aq;
an = q;
} else {
int at[12][1] = {{9}, {9}, {5}, {9}, {9}, {5}, {9}, {9}, {5}, {9}, {9}, {5}};
struct b au;
if (o.c)
aa = ah.e;
if (an.d)
ah.e = (j & (aa * m)) ^ au.d;
o.c = m + aa;
int av = o.c || 0, aw = ai || q.c & l.c, ax = n;
if (q.e < ai)
q = an;
if (r)
break;
ai = aw - av;
an.e = 0;
if (ai) {
an.e = l.c || 0;
f = q.c;
ah.e = l.c % q.d;
q.c = au.e;
if ((q.d && q.c) || ah.e)
__assert_fail();
q.c = 0;
if (au.d > m || ah.e)
w = au.c | (n & ah.c);
as:
ae = af = ah.c;
int ay = au.d & q.e & au.c || o.c, az = 0 || o.c, ba = m & ah.d;
if (n)
au.c = au.e = (q.e || ah.d) ^ (o.c + (az / au.e));
n = au.c || au.e;
if (ba) {
printf("", ax);
x = q.e | m;
continue;
}
m = ay;
n = printf("", au);
}
if (ah.d)
o.c = l.c & o.c & q.c;
if (q.d)
__assert_fail();
printf("", an);
printf("", q);
printf("", au);
if (ah.e)
while (u++) {
struct b al[7] = {{7, 9, 8}, {7, 1, 2}, {7, 9, 8}, {7, 1, 2}, {7, 9, 8}, {7, 1, 2}, {7, 9, 0}};
if (an.d) {
int d[8] = {0, 1, 0, 1, 0, 1, 0, 1};
if (ad)
goto ak;
while (ag)
g = an.d = i = m;
f = j;
}
n++;
}
f = q.d;
}
if (l.c && m) {
int d[7] = {1, 0, 1, 0, 1, 0, 1};
if (x)
h = an.d;
else
g = 0;
}
}
int bb = (q.d ^ ah.c) | aa | (q.e & q.c) | (f & ah.d);
if (bb)
return x;
return 0;
}
int main() {
j = 1;
s(0);
return 0;
}

View file

@ -3468,30 +3468,28 @@ ifcvt_can_hoist (class loop *loop, edge pe, gimple *stmt)
static void
ifcvt_hoist_invariants (class loop *loop, edge pe)
{
/* Only hoist from the now unconditionally executed part of the loop. */
basic_block bb = loop->header;
gimple_stmt_iterator hoist_gsi = {};
unsigned int num_blocks = loop->num_nodes;
basic_block *body = get_loop_body (loop);
for (unsigned int i = 0; i < num_blocks; ++i)
for (gimple_stmt_iterator gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi);)
{
gimple *stmt = gsi_stmt (gsi);
if (ifcvt_can_hoist (loop, pe, stmt))
{
/* Once we've hoisted one statement, insert other statements
after it. */
gsi_remove (&gsi, false);
if (hoist_gsi.ptr)
gsi_insert_after (&hoist_gsi, stmt, GSI_NEW_STMT);
else
{
gsi_insert_on_edge_immediate (pe, stmt);
hoist_gsi = gsi_for_stmt (stmt);
}
continue;
}
gsi_next (&gsi);
}
free (body);
for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
{
gimple *stmt = gsi_stmt (gsi);
if (ifcvt_can_hoist (loop, pe, stmt))
{
/* Once we've hoisted one statement, insert other statements
after it. */
gsi_remove (&gsi, false);
if (hoist_gsi.ptr)
gsi_insert_after (&hoist_gsi, stmt, GSI_NEW_STMT);
else
{
gsi_insert_on_edge_immediate (pe, stmt);
hoist_gsi = gsi_for_stmt (stmt);
}
continue;
}
gsi_next (&gsi);
}
}
/* Returns the DECL_FIELD_BIT_OFFSET of the bitfield accesse in stmt iff its