https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128090

            Bug ID: 128090
           Summary: [ARM] -g -fno-var-tracking changes forced minipool
                    barrier placement
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: compare-debug-failure
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: yqtian668 at gmail dot com
  Target Milestone: ---
              Host: x86_64-pc-linux-gnu
            Target: arm-none-eabi
             Build: GCC 17.0.0 20261022 (experimental), revision
                    1bfdd3ecb3d7109d059212491a934eadf8cb33c2

Created attachment 65924
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65924&action=edit
Candidate fix and regression test

On `arm-none-eabi`, adding debug information changes where GCC places forced
literal-pool barriers.  This reproduces on GCC master
`1bfdd3ecb3d7109d059212491a934eadf8cb33c2`.

Reduced reproducer:

```c
extern volatile double vd;

#define S(k) if (p[i + k] == k) { vd = k##.75; b = b; } l##k: b = b;
#define S10(k) S(k##0) S(k##1) S(k##2) S(k##3) S(k##4) \
               S(k##5) S(k##6) S(k##7) S(k##8) S(k##9)

void
f (int *p, int b)
{
  for (int i = 0; i < b; i++)
    {
      S10(1) S10(2) S10(3) S10(4) S10(5) S10(6)
    }
}
```

Command:

```text
arm-none-eabi-gcc -O2 -g -fno-var-tracking -fcompare-debug \
  -mthumb -march=armv7-a -S source.c
```

Actual result:

```text
arm-none-eabi-gcc: error: source.c: '-fcompare-debug' failure
```

The first ordinary-code difference appears during the `mach` pass, when the
Arm backend places its minipools.  After debug-only assembler directives are
removed, four pool-skipping branches move across an `ldr`/`cmp`/`bne`
sequence.  One of the differences has this form:

```diff
-       b       .L150
        ldr     r3, [r0, #196]
        cmp     r3, #60
        bne     .L53
+       b       .L150
```

The observed difference is in code layout; I have not found a wrong-code
effect.  The problem is that debug information changes an ordinary
code-generation decision and makes `-fcompare-debug` fail.

The apparent cause is `barrier_cost` in `gcc/config/arm/minipool.cc`.
`minipool::create_fix_barrier` prefers an instruction immediately followed by
a label because that is a cheaper place to insert the branch around a literal
pool.  `barrier_cost` currently finds the following instruction with
`next_nonnote_insn`, which does not skip debug instructions.

With `-g -fno-var-tracking`, a non-executing statement-frontier debug
instruction can remain between an ordinary instruction and its following
label until machine reorg.  It hides the label from `barrier_cost`, raising
that position's cost from 30 to 50.  A later position is then selected and the
pool-skipping branch moves.

A candidate fix uses `next_nonnote_nondebug_insn` in `barrier_cost`.  The
reduced test fails before this one-line change and passes afterwards.  A full
`arm.exp` before/after comparison changed only the new test from failure to
pass.  A broader parallel `check-gcc` differential run likewise found no
other changed failure or unresolved outcome after normalizing one generated
temporary pathname.  That broader run used a container without
`arm-none-eabi-as` and `arm-none-eabi-ld`, so it had extensive baseline
environment failures; a clean ARM cross regression run with the target
binutils is still pending.

I also considered skipping debug instructions as candidate insertion points
inside `create_fix_barrier`, but found no independent trigger for that change.
A temporary instrumented compiler and approximately 7,700 compilations of the
Arm target tests at `-O2` and `-Os` never selected a debug instruction as the
final insertion point.  The attached candidate patch therefore contains only
the root-cause change above and its regression test.

Expected result: non-executing debug instructions should not affect the
minipool barrier cost or the generated ordinary instruction sequence.

I searched Bugzilla for `minipool debug`, `barrier_cost`,
`create_fix_barrier`, and `minipool compare-debug`, and did not find a matching
report.  PR127988 and PR127227 concern different minipool problems.

This issue was found by a non-AI automated testing tool.  AI assisted with the
analysis and development of the candidate fix.

Reply via email to