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.

Reply via email to