From d55ce33a34a8e33d17285228b32cf1e564241a70 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 16 Mar 2021 18:46:20 +0100 Subject: [PATCH] i386: Avoid mutual recursion between two peephole2s [PR99600] As the testcase shows, the compiler hangs and eats all memory when compiling it. This is because in r11-7274-gdecd8fb0128870d0d768ba53dae626913d6d9c54 I have changed the ix86_avoid_lea_for_addr splitting from a splitter into a peephole2 (because during splitting passes we don't have guaranteed df, while during peephole2 we do). The problem is we have another peephole2 that works in the opposite way, when seeing split lea (in particular ASHIFT followed by PLUS) it attempts to turn it back into a lea. In the past, they were fighting against each other, but as they were in different passes, simply the last one won. So, split after reload split the lea into shift left and plus, peephole2 reverted that (but, note not perfectly, the peephole2 doesn't understand that something can be placed into lea disp; to be fixed for GCC12) and then another split pass split the lea appart again. But my changes and the way peephole2 works means that we endlessly iterate over those two, the first peephole2 splits the lea, the second one reverts it, the first peephole2 splits the new lea back into new 2 insns and so forth forever. So, we need to break the cycle somehow. This patch does that by not emitting an ASHIFT insn from ix86_split_lea_for_addr but emitting a corresponding MULT by constant instead, and splitting that later back into ASHIFT. 2021-03-16 Jakub Jelinek PR target/99600 * config/i386/i386-expand.c (ix86_split_lea_for_addr): Emit a MULT rather than ASHIFT. * config/i386/i386.md (mult by 1248 into ashift): New splitter. * gcc.target/i386/pr99600.c: New test. --- gcc/config/i386/i386-expand.c | 7 ++++--- gcc/config/i386/i386.md | 12 ++++++++++++ gcc/testsuite/gcc.target/i386/pr99600.c | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr99600.c diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index 33b8822..ac69eed 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -1348,9 +1348,10 @@ ix86_split_lea_for_addr (rtx_insn *insn, rtx operands[], machine_mode mode) if (regno0 != regno2) emit_insn (gen_rtx_SET (target, parts.index)); - /* Use shift for scaling. */ - ix86_emit_binop (ASHIFT, mode, target, - GEN_INT (exact_log2 (parts.scale))); + /* Use shift for scaling, but emit it as MULT instead + to avoid it being immediately peephole2 optimized back + into lea. */ + ix86_emit_binop (MULT, mode, target, GEN_INT (parts.scale)); if (parts.base) ix86_emit_binop (PLUS, mode, target, parts.base); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 2820f6d..9ff35d9 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -5219,6 +5219,18 @@ DONE; }) + +;; ix86_split_lea_for_addr emits the shifts as MULT to avoid it from being +;; peephole2 optimized back into a lea. Split that into the shift during +;; the following split pass. +(define_split + [(set (match_operand:SWI48 0 "general_reg_operand") + (mult:SWI48 (match_dup 0) (match_operand:SWI48 1 "const1248_operand"))) + (clobber (reg:CC FLAGS_REG))] + "reload_completed" + [(parallel [(set (match_dup 0) (ashift:SWI48 (match_dup 0) (match_dup 1))) + (clobber (reg:CC FLAGS_REG))])] + "operands[1] = GEN_INT (exact_log2 (INTVAL (operands[1])));") ;; Add instructions diff --git a/gcc/testsuite/gcc.target/i386/pr99600.c b/gcc/testsuite/gcc.target/i386/pr99600.c new file mode 100644 index 0000000..c2f2b22 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr99600.c @@ -0,0 +1,16 @@ +/* PR target/99600 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=atom" } */ + +char a, b; +long c; + +long +foo (void) +{ + if (a) + c = b == 1 ? 1 << 3 : 1 << 2; + else + c = 0; + return 0; +} -- 2.7.4