https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127808
Bug ID: 127808
Summary: [SPARC] DEBUG_INSN hides BARRIER in relax_delay_slots
and changes delay-slot decisions
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: yqtian668 at gmail dot com
Target Milestone: ---
Host: x86_64-pc-linux-gnu
Target: sparc-elf (also reproduced on sh-elf and mips-elf)
Build: x86_64-pc-linux-gnu
Created attachment 65796
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65796&action=edit
patch
While following up Jeff Law's review of the patch for PR
rtl-optimization/127795, I checked the BARRIER queries he pointed out in
relax_delay_slots. Jeff noted that these checks could potentially cause a
-fcompare-debug difference if a DEBUG_INSN appeared between a BARRIER and a
CODE_LABEL. I also found the potential issue before submitting that patch, but
I failed to find an concrete bug triggering input, and thus I initially replied
that I had not seen GCC produce that position.
This report corrects that reply: pass_cleanup_barriers can create exactly that
sequence, and both queries can change behavior.
This reproduces with GCC trunk at revision
a02e2004cb707155d5b9b0a82dd428ded0ee2f6f using a sparc-elf cross compiler.
Reproducer A:
void
foo (int b, int c)
{
void *x = &&lab;
if (b < 5)
goto l2;
l1:
if (c < 0)
goto l1;
l2:
if (b)
{
lab:
__builtin_unreachable ();
}
if (c)
x = &&l1;
goto *x;
}
Compile with:
sparc-elf-gcc -O2 -g -fno-var-tracking -fcompare-debug -S site-a.c
Reproducer B:
int h;
void
foo (int b, int c)
{
int i = b * 3;
void *x = &&lab;
if (b == 3)
goto l2;
lab:
__builtin_unreachable ();
l1:
while (b < i)
h = c;
l2:
if (c)
x = &&l1;
goto *x;
}
Compile with:
sparc-elf-gcc -O1 -g -fno-var-tracking -fcompare-debug -S site-b.c
Both commands report a compare-debug failure. At the first site, the -g RTL
keeps a stale BARRIER in fall-through code. At the second site, a filled jump
is deleted only with -g. The ordinary code-generation decision therefore
depends on the presence of a debug instruction.
The relevant sequence at dbr entry is:
BARRIER; NOTE; DEBUG_INSN; CODE_LABEL
cleanup_barriers moves the BARRIER after the preceding non-debug instruction,
in front of the block's debug instructions. Variable tracking normally converts
these markers to notes before dbr, which is why the reproducer uses
-fno-var-tracking.
Root cause:
relax_delay_slots uses prev_nonnote_insn when checking for a BARRIER before a
target label at two sites. A DEBUG_INSN hides the BARRIER. Using
prev_nonnote_nondebug_insn at both sites makes the decision independent of
debug information.
Testing of the candidate fix:
* Two targeted gcc.target/sparc tests fail before the fix and pass after it.
* A complete sparc-elf check-gcc comparison has no new unexpected results.
* An x86_64-pc-linux-gnu native bootstrap and complete make -k check, with and
without the patch at the revision above, have identical test outcomes after
normalizing build paths.
This is a sibling of PR rtl-optimization/127795 and was found after following
Jeff's review suggestion there. A related issue in
jump.cc::delete_related_insns was found during the same audit and will be
reported separately.
I will submit the patch soon.