Hi!
force_nonfallthru_and_redirect has some extra code to handle asm gotos
if we are forcing or redirecting the EDGE_FALLTHRU in case. This was
done for PR51767, PR53589, PR54127.
It is done for the cases where some asm goto label points to the bb
after the fallthru edge (i.e. there is edge sharing between the fallthru
and the label, partly or fully degenerate asm goto) and/or if the label
points to the TARGET bb (before/after).
In such case it changes the label from e->dest's label to target's label
and similarly to the case of 2+ successor e->src a new bb is created
as new fallthru from e->src and in the asm goto case an additional edge
is added, so there is
|
asm goto -----+ maybe other edges
| fallthru \
v v
jumpblock -> target
and the jumpblock -> target edge isn't EDGE_FALLTHRU.
This was done that way to fix various ICEs with the degenerate asm gotos,
see above for list.
I believe it will still ICE if we decide to force_nonfallthru_and_redirect
E bb5->bb6 to l2, because in that case there are already two+ edges, one
pointing from bb5->l2 and we create another edge bb5->l2:
bb5:
asm goto ("" : : : : (l2));
bb6:
...
l2:
but maybe nothing tries that in that case. Anyway, the reason why
the following two (PR116600 and PR123386) testcases are miscompiled is
that we try to (during shrink-wrapping) emit some insns on the bb3->bb7
edge, and see bb7 predecessor edge is EDGE_FALLTHRU in:
bb3:
__asm__ goto ("" : : : : d);
if (c)
bar (a);
bb6:
__asm__ goto ("" : : : : d);
d: // == bb7
in rtl_split_edge:
/* We are going to place the new block in front of edge destination.
Avoid existence of fallthru predecessors. */
if ((edge_in->flags & EDGE_FALLTHRU) == 0)
{
edge e = find_fallthru_edge (edge_in->dest->preds);
if (e)
force_nonfallthru (e);
}
Now, the asm goto in bb6 is degenerate, so shrink-wrapping isn't aware
that there would be multiple edges from it, there is just single one.
But we still while splitting the bb3->bb7 edge in order to emit there
pending insns on that edge turn the single successor asm goto bb into
one with two successors (initially with two different ways to reach
the same destination). But unfortunately such change confuses the
shrink-wrapping logic which isn't aware of such a change and so the
separate shrink wrapping insns end up just on one of the paths instead
of being on both, and we then ICE in dwarf2 pass because there is an
disagreement on the CFI state (of course it is a wrong-code too).
Note, force_nonfallthru calls force_nonfallthru_and_redirect with
target set to e->dest.
The following patch reworks this.
Instead of creating that
|
asm goto -----+ maybe other edges
| fallthru \
v v
jumpblock -> target
for initially degenerate asm goto we now create
|
asm goto maybe other edges
| fallthru
v
jumpblock -> target
i.e. the asm goto keeps being degenerate, all we've changed is adding
a new bb on the fallthru edge and making the edge from that new bb
non-fallthru. Furthermore, for the case where there would be before
an asm goto -> target edge before for the e->dest != target case,
those edges are untouched.
For the immediate effect after the operation, the asm goto keeps
the existing behavior, if it falls through, it will reach target
by hopping through jumpblock, if it jumps to that label, previously
it jumped directly to target, now it jumps to jumpblock and from there
to target. But shrink-wrapping etc. then put the right fixups everywhere
where it belongs.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2026-02-10 Jakub Jelinek <[email protected]>
PR rtl-optimization/116600
PR middle-end/123386
* cfgrtl.cc (force_nonfallthru_and_redirect): Don't do any
asm goto adjustments early, only note in asm_goto_edge if
any labels point originally to e->dest head. After jumpblock
creation don't add an extra edge for asm_goto_edge, instead
adjust those labels pointing to former e->dest head to point
to jumpblock instead.
* gcc.c-torture/compile/pr116600.c: New test.
* gcc.c-torture/compile/pr123386.c: New test.
--- gcc/cfgrtl.cc.jj 2026-01-09 21:59:08.701543900 +0100
+++ gcc/cfgrtl.cc 2026-02-10 11:04:06.811401150 +0100
@@ -1594,54 +1594,20 @@ force_nonfallthru_and_redirect (edge e,
}
/* If e->src ends with asm goto, see if any of the ASM_OPERANDS_LABELs
- don't point to the target or fallthru label. */
+ don't point to the fallthru label. */
if (JUMP_P (BB_END (e->src))
&& target != EXIT_BLOCK_PTR_FOR_FN (cfun)
&& (e->flags & EDGE_FALLTHRU)
&& (note = extract_asm_operands (PATTERN (BB_END (e->src)))))
{
- int i, n = ASM_OPERANDS_LABEL_LENGTH (note);
- bool adjust_jump_target = false;
+ int n = ASM_OPERANDS_LABEL_LENGTH (note);
- for (i = 0; i < n; ++i)
- {
- if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest))
- {
- LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))--;
- XEXP (ASM_OPERANDS_LABEL (note, i), 0) = block_label (target);
- LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))++;
- adjust_jump_target = true;
- }
- if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (target))
+ for (int i = 0; i < n; ++i)
+ if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest))
+ {
asm_goto_edge = true;
- }
- if (adjust_jump_target)
- {
- rtx_insn *insn = BB_END (e->src);
- rtx note;
- rtx_insn *old_label = BB_HEAD (e->dest);
- rtx_insn *new_label = BB_HEAD (target);
-
- if (JUMP_LABEL (insn) == old_label)
- {
- JUMP_LABEL (insn) = new_label;
- note = find_reg_note (insn, REG_LABEL_TARGET, new_label);
- if (note)
- remove_note (insn, note);
- }
- else
- {
- note = find_reg_note (insn, REG_LABEL_TARGET, old_label);
- if (note)
- remove_note (insn, note);
- if (JUMP_LABEL (insn) != new_label
- && !find_reg_note (insn, REG_LABEL_TARGET, new_label))
- add_reg_note (insn, REG_LABEL_TARGET, new_label);
- }
- while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label))
- != NULL_RTX)
- XEXP (note, 0) = new_label;
- }
+ break;
+ }
}
if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || asm_goto_edge)
@@ -1680,15 +1646,45 @@ force_nonfallthru_and_redirect (edge e,
and the reg crossing note should be removed. */
fixup_partition_crossing (new_edge);
- /* If asm goto has any label refs to target's label,
- add also edge from asm goto bb to target. */
+ /* If asm goto has any label refs to e->dest, change them to point
+ to jump_block instead. */
if (asm_goto_edge)
{
- new_edge->probability /= 2;
- jump_block->count /= 2;
- edge new_edge2 = make_edge (new_edge->src, target,
- e->flags & ~EDGE_FALLTHRU);
- new_edge2->probability = probability - new_edge->probability;
+ int n = ASM_OPERANDS_LABEL_LENGTH (note);
+
+ for (int i = 0; i < n; ++i)
+ if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest))
+ {
+ LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))--;
+ XEXP (ASM_OPERANDS_LABEL (note, i), 0)
+ = block_label (jump_block);
+ LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))++;
+ }
+
+ rtx_insn *insn = BB_END (new_edge->src);
+ rtx note;
+ rtx_insn *old_label = BB_HEAD (e->dest);
+ rtx_insn *new_label = BB_HEAD (jump_block);
+
+ if (JUMP_LABEL (insn) == old_label)
+ {
+ JUMP_LABEL (insn) = new_label;
+ note = find_reg_note (insn, REG_LABEL_TARGET, new_label);
+ if (note)
+ remove_note (insn, note);
+ }
+ else
+ {
+ note = find_reg_note (insn, REG_LABEL_TARGET, old_label);
+ if (note)
+ remove_note (insn, note);
+ if (JUMP_LABEL (insn) != new_label
+ && !find_reg_note (insn, REG_LABEL_TARGET, new_label))
+ add_reg_note (insn, REG_LABEL_TARGET, new_label);
+ }
+ while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label))
+ != NULL_RTX)
+ XEXP (note, 0) = new_label;
}
new_bb = jump_block;
--- gcc/testsuite/gcc.c-torture/compile/pr116600.c.jj 2026-02-10
11:24:22.840629711 +0100
+++ gcc/testsuite/gcc.c-torture/compile/pr116600.c 2026-02-10
11:24:15.386757048 +0100
@@ -0,0 +1,24 @@
+/* PR rtl-optimization/116600 */
+
+int a, b;
+int foo ();
+
+int
+bar ()
+{
+ int c = ({ int d = 0, e = foo ();
+ b = __builtin_expect (e, 1); if (b) ; else d = 4; d; });
+ if (c)
+ return c;
+ foo ();
+ if (a)
+ __asm__ goto ("" : : : : l);
+l:
+ return 0;
+}
+
+void
+baz ()
+{
+ bar ();
+}
--- gcc/testsuite/gcc.c-torture/compile/pr123386.c.jj 2026-02-10
11:13:55.634344133 +0100
+++ gcc/testsuite/gcc.c-torture/compile/pr123386.c 2026-02-10
11:13:34.528704662 +0100
@@ -0,0 +1,25 @@
+/* PR middle-end/123386 */
+
+char *a;
+int b;
+
+void
+foo (char *)
+{
+ if (b)
+ __builtin_abort ();
+}
+
+void
+bar (char *c)
+{
+ __asm__ goto ("" : : : : d);
+ foo (a);
+ __asm__ goto ("" : : : : d);
+ if (c)
+ bar (a);
+ __asm__ goto ("" : : : : d);
+d:
+ if (b)
+ __builtin_abort ();
+}
Jakub