[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.
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)))
static inline unsigned long int
mod_rhs (const long int rhs)
static inline unsigned long int
div_rhs (const long int rhs)
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))))))
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
Date: Wed Oct 8 08:12:25 2008
New Revision: 140966
* 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.