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.
Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed. PR tree-optimization/112282 * tree-if-conv.cc (ifcvt_hoist_invariants): Only hoist from the loop header. * gcc.dg/torture/pr112282.c: New testcase. --- gcc/testsuite/gcc.dg/torture/pr112282.c | 132 ++++++++++++++++++++++++ gcc/tree-if-conv.cc | 44 ++++---- 2 files changed, 153 insertions(+), 23 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr112282.c diff --git a/gcc/testsuite/gcc.dg/torture/pr112282.c b/gcc/testsuite/gcc.dg/torture/pr112282.c new file mode 100644 index 00000000000..23e0ed64b82 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr112282.c @@ -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; +} diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc index 0190cf2369e..0bde281c246 100644 --- a/gcc/tree-if-conv.cc +++ b/gcc/tree-if-conv.cc @@ -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 -- 2.35.3