[regehr@babel tmp31]$ current-gcc -O3 small.c current-gcc: Internal error: Segmentation fault (program cc1) Please submit a full bug report. See <http://gcc.gnu.org/bugs.html> for instructions. [regehr@babel tmp31]$ current-gcc -v Using built-in specs. Target: i686-pc-linux-gnu Configured with: ../configure --program-prefix=current- --enable-languages=c,c++ --prefix=/home/regehr Thread model: posix gcc version 4.4.0 20080625 (experimental) (GCC) [regehr@babel tmp31]$ cat small.c typedef int int32_t; typedef unsigned char uint8_t; typedef unsigned int uint32_t; static inline unsigned int lshift_u_u (unsigned int left, unsigned int right) { if ((right >= sizeof (unsigned int)) || (left > ((2147483647 * 2U + 1U) >> right))) return left; } static inline unsigned long int mod_rhs (const long int rhs) { return rhs; } static inline unsigned long int div_rhs (const long int rhs) { return rhs; } uint32_t g_22; int32_t func_53 (uint32_t p_54, uint32_t p_55, uint32_t p_56, uint8_t p_57) { int32_t l_58 = 0xB8BF5144L; for (0; 1; p_56 -= 0) { uint32_t l_59 = -1L; if (((lshift_u_u ((g_22 / div_rhs (l_58)), (1 % mod_rhs (l_59)))))) return 1; for (l_59 = 0; (l_59 <= -20); l_59 += 1) { } } }
Confirmed. We endlessly recurse in cse_cc_succs.
Created attachment 15859 [details] Patch for cse.c I have looked at the debug dumps for the testcase. This seems like a very rare case: 1. -O3 turns on the loop unswitching pass (-funswitch-loops), which transforms the function into two loops guarded by a conditional branch from a header block. 2. During cse2 (the immediately next pass), cse.c:cse_main() transforms that conditional branch into a jump, cutting off the connection to one of the loops. 3. The cut off loop becomes segregated from the other basic blocks, and becomes a circular loop, with a single edge acting as both the entry and latch edge. 4. This cut off loop still contains control flow, and sets CC within. cse.c:cse_condition_reg() calls the recursive cse_cc_succs() to delete redundant CC setters on this circular loop. 5. cse.c:cse_cc_succs() uses the "single predecessor edge" condition as the stopping control flow test, which in this case of a single edge circular loop (a "ring" like control flow structure), fails to properly stop the recursion. cse_cc_succs() then blows up the stack and segfaults. The proposed fix is to record visited basic blocks during the recursive traversal, see the enclosed patch.
This one isn't reproducible for me on the trunk.
I've reproduced PR37341 though. And I believe your patch is an overkill, as cse_cc_succs only recurses if edge destination has a single predecessor. So IMHO you don't need to keep a bitmap of visited blocks, as the only way to reach endless recursion is if you eventually reach the original bb cse_condition_code_reg called cse_cc_succs with, as if there is a smaller loop there would be some bb with more than one predecessor. To fix this, we can either add an extra argument to cse_cc_succs (the original bb) and bail if e->dest is equal to orig_bb; IMHO this is the cheapest variant), or we could call find_unreachable_blocks () if tem > 0 before cse_condition_code_reg and disregard (bb->flags & BB_REACHABLE) == 0 bb's (or delete_unreachable_blocks ()).
Subject: Bug 36635 Author: jakub Date: Wed Oct 8 08:12:25 2008 New Revision: 140966 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=140966 Log: PR target/36635 PR target/37290 PR rtl-optimization/37341 * cse.c (cse_cc_succs): Add ORIG_BB argument, don't follow edges to ORIG_BB, pass through ORIG_BB recursively. (cse_condition_code_reg): Adjust caller. * gcc.c-torture/compile/pr37341.c: New test. Added: trunk/gcc/testsuite/gcc.c-torture/compile/pr37341.c Modified: trunk/gcc/ChangeLog trunk/gcc/cse.c trunk/gcc/testsuite/ChangeLog
Fixed.