This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Fix PR 40445: C++ ICE when using __builtin_unreachable() as only statement in a function.

Ian Lance Taylor wrote:
David Daney <> writes:

Ian Lance Taylor wrote:
David Daney <> writes:

Index: cfgcleanup.c
--- cfgcleanup.c	(revision 148867)
+++ cfgcleanup.c	(working copy)
@@ -1903,7 +1903,8 @@ try_optimize_cfg (int mode)
 		  /* Note that forwarder_block_p true ensures that
 		     there is a successor for this block.  */
 		  && (single_succ_edge (b)->flags & EDGE_FALLTHRU)
-		  && n_basic_blocks > NUM_FIXED_BLOCKS + 1)
+		  && n_basic_blocks > NUM_FIXED_BLOCKS + 1
+		  && single_pred_edge (b)->src != ENTRY_BLOCK_PTR)
I don't see why this test is sufficient for what you are trying to
prevent.  It seems to me that this empty block could be followed by a
number of other blocks.

Let me try to explain the patch a little better.

There are several parts of the rtl optimizers that cannot handle a
function that contains zero basic blocks.  They include, but are not
limited to: record_effective_endpoints and

One approach would be to fix all of the issues related to such empty
functions.  I considered doing that, but the patch was getting large,
so I did this patch (which is admittedly a bit of a hack) instead.

If we can prevent the first block of the function from being deleted,
there will never be functions with zero basic blocks, and none of the
related problems will be exposed.

Certainly the empty first block could be followed by other non-empty
blocks and the patch would prevent it from being removed.  But it is
empty so no code results and the compiler output is not (in theory)

I think I got all that, but why not simply also test whether the successor block is the exit block? If it isn't, then it should be fine to go ahead and delete the block. Shouldn't it?


Consider this:

;; Function const char* f() (_Z1fv)

;; Generating RTL for gimple basic block 2

;; ;; Full RTL generated for this function: ;; (note 1 0 3 NOTE_INSN_DELETED)

(note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)


(note 4 2 5 3 [bb 3] NOTE_INSN_BASIC_BLOCK)

(barrier 5 4 11)

(note 11 5 8 4 [bb 4] NOTE_INSN_BASIC_BLOCK)

(insn 8 11 9 4 /home/daney/gccsvn/t1/gcc/testsuite/g++.dg/other/builtin-unreachable-1.C:11 (clobber (reg/i:SI 0 ax)) -1 (nil))

(insn 9 8 6 4 /home/daney/gccsvn/t1/gcc/testsuite/g++.dg/other/builtin-unreachable-1.C:11 (clobber (reg:SI 58 [ <result> ])) -1 (nil))

(code_label 6 9 12 5 1 "" [0 uses])

(note 12 6 7 5 [bb 5] NOTE_INSN_BASIC_BLOCK)

(insn 7 12 10 5 /home/daney/gccsvn/t1/gcc/testsuite/g++.dg/other/builtin-unreachable-1.C:11 (set (reg/i:SI 0 ax)
(reg:SI 58 [ <result> ])) -1 (nil))

(insn 10 7 0 5 /home/daney/gccsvn/t1/gcc/testsuite/g++.dg/other/builtin-unreachable-1.C:11 (use (reg/i:SI 0 ax)) -1 (nil))

In the eh pass bb-2 is removed as it is empty and falls through to bb-3. Then bb-3 is removed as it is empty and has no successor edges. This leaves us with the ENTRY_BLOCK having no successors. Blocks 4 and 5 are unreachable and are also deleted.

So after the eh pass we are left with a function with zero basic blocks and no edges.

There are many RTL passes that assume that the ENTRY_BLOCK has successors. I have patched up dfinit and outof_cfglayout to handle this, but this pushes the ICE into ira...

In the case of a C program (instead of c++), into_cfglayout is the first time try_optimize_cfg is called. In this case the mode is CLEANUP_CFGLAYOUT. This prevents bb-2 from being removed, and bb-3 is removed first. This causes the logic to change. By removing bb-3, bb-2 no longer has a successor and cannot be removed by the empty-with-fall-through rule. If bb-2 is never removed, the ENTRY_BLOCK will have an outgoing edge and all the RTL passes are happy.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]