https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127726
Bug ID: 127726
Summary: -fcompare-debug failure when debug insns consume the
generic delay-slot live-search budget
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: compare-debug-failure
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: yqtian668 at gmail dot com
Target Milestone: ---
Target: sparc-elf, mips-elf
GCC trunk fails -fcompare-debug for the standalone C testcase below on both
SPARC and MIPS. Debug-only instructions consume
--param=max-delay-slot-live-search in find_basic_block, which can prevent an
ordinary instruction from being placed in a delay slot.
Tested revision:
5f9f8711bf791130fd30bc1f04b2097f3ef25f0b
Testcase (source.c):
/* find_basic_block (resource.cc) counts DEBUG_INSNs toward
--param=max-delay-slot-live-search (default 333). The 400 statements
below produce no code but leave a begin-stmt debug marker each. */
extern int g[64];
extern int h (int);
#define S1 t = a;
#define S10 S1 S1 S1 S1 S1 S1 S1 S1 S1 S1
#define S100 S10 S10 S10 S10 S10 S10 S10 S10 S10 S10
int
f0 (int a, int b, int c)
{
int x = a, y = b, z = c, t;
if (a > 0)
{
S100 S100 S100 S100
x = h (x);
y += 3;
}
else
{
z = z - x;
g[57] = z;
y = y | c;
x = x + a;
}
if (y == 0)
z = h (z) + x;
return x + y * z;
}
Commands:
sparc-elf-gcc -O2 -mcpu=v8 -S -fcompare-debug \
-fno-var-tracking source.c
mips-elf-gcc -Os -S -fcompare-debug \
-fno-var-tracking source.c
Both commands report:
xgcc: error: source.c: '-fcompare-debug' failure (length)
The testcase contains 400 dead assignments. They emit no ordinary code but
leave debug markers before a branch target when compiling with debug
information and variable tracking disabled.
On SPARC, the ordinary difference is an unfilled delay slot:
// -g0
bg .LL6
sethi %hi(g+228), %g1
// -g
bg .LL6
nop
sethi %hi(g+228), %g1
MIPS also changes delay-slot scheduling. Its -g0 assembly explicitly puts mult
$17,$6 in a conditional branch's delay slot under .set noreorder. The -g
assembly leaves the branch in reorder mode and keeps the mult after the target
label. Adding -fno-delayed-branch makes -fcompare-debug pass on both targets.
The backwards walk in gcc/resource.cc:133-135 uses prev_nonnote_insn and
decrements search_limit for every returned instruction:
for (insn = prev_nonnote_insn (insn);
insn && !BARRIER_P (insn) && search_limit != 0;
insn = prev_nonnote_insn (insn), --search_limit)
;
prev_nonnote_insn returns DEBUG_INSNs. Once they exhaust the budget,
find_basic_block returns -1; mark_target_live_regs then treats every register
as live, so fill_slots_from_thread rejects a delay-slot candidate. The forward
label walk at lines 148-150 has the analogous use of next_nonnote_insn.
As a causal check, changing only these walks to prev_nonnote_nondebug_insn and
next_nonnote_nondebug_insn makes the testcase pass -fcompare-debug. The fix was
also checked in isolation on MIPS: without it the testcase fails, and with only
the find_basic_block change it passes.
The affected walk is in target-independent resource.cc, not in a SPARC or MIPS
backend. Both SPARC and MIPS independently reach it and change ordinary
delay-slot scheduling. The current GCC source tree has define_delay
descriptions under 13 target directories. This report establishes concrete
effects on SPARC and MIPS; I don't think I can claim that every delay-slot
target reaches this decision. The same testcase did not trigger on SH or
PA-RISC in the tested configurations.
Expected result: non-executing debug instructions should not consume a search
budget used to make an ordinary delay-slot scheduling decision.