This is the mail archive of the
mailing list for the GCC project.
Re: [PATCH] Fix PR 40445: C++ ICE when using __builtin_unreachable() as only statement in a function.
Ian Lance Taylor wrote:
David Daney <email@example.com> writes:No.
Ian Lance Taylor wrote:
David Daney <firstname.lastname@example.org> writes:Let me try to explain the patch a little better.
--- 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.
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?
;; 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 2 3 4 2 NOTE_INSN_FUNCTION_BEG)
(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
(clobber (reg/i:SI 0 ax)) -1 (nil))
(insn 9 8 6 4
(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
(set (reg/i:SI 0 ax)
(reg:SI 58 [ <result> ])) -1 (nil))
(insn 10 7 0 5
(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.