https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127422
--- Comment #2 from H.J. Lu <hjl.tools at gmail dot com> ---
(In reply to Yongqiang Tian from comment #0)
> Created attachment 65601 [details]
> Standalone AArch64 C testcase
>
> GCC trunk fails its -fcompare-debug check for the attached standalone C
> testcase when targeting AArch64.
>
> Tested revision:
>
> 2c3724c84c139c70c034816cc37f5dfb7f256815
>
> Command:
>
> aarch64-linux-gnu-gcc -std=gnu11 -w -O2 -mno-track-speculation \
> -fcompare-debug -S repro.c
>
> Actual result:
>
> xgcc: error: repro.c: '-fcompare-debug' failure (length)
>
> The testcase is header-free and does not require Csmith or a target sysroot.
>
> The ordinary RTL is identical between the two profiles through ext_dce and
> first differs in combine. The relevant sequence contains two volatile loads.
> After Combine folds the second load into its consumer and deletes the
> ordinary
> load, the no-debug profile can retry and combine the first load.
>
> With variable tracking enabled, propagate_for_debug retains the deleted
> second
> load's volatile MEM in a DEBUG_INSN. can_combine_p then scans the open
> interval
> using raw INSN_P membership:
>
> for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
> if (INSN_P (p) && p != succ && p != succ2
> && is_volatile_p (PATTERN (p)))
> return false;
>
> Because INSN_P includes DEBUG_INSN, the non-executing debug value is treated
> as another volatile access and blocks the retry. At that point the debug
> instruction is the only volatile reference in the interval; there is no
> ordinary volatile instruction there.
>
> As a causal check, changing only this membership test from INSN_P to
> NONDEBUG_INSN_P has the following results:
>
You can submit a patch with a test like
diff --git a/gcc/combine.cc b/gcc/combine.cc
index 35c6a529950..11427f5a920 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -2024,7 +2024,10 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn
*pred ATTRIBUTE_UNUSED,
: volatile_insn_p;
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
- if (INSN_P (p) && p != succ && p != succ2 && is_volatile_p (PATTERN (p)))
+ if (NONDEBUG_INSN_P (p)
+ && p != succ
+ && p != succ2
+ && is_volatile_p (PATTERN (p)))
return false;
/* If INSN contains an autoincrement or autodecrement, make sure that
diff --git a/gcc/testsuite/gcc.dg/pr127422.c b/gcc/testsuite/gcc.dg/pr127422.c
new file mode 100644
index 00000000000..379d1b87e0b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr127422.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcompare-debug" } */
+
+static int ordinary_0 = 3;
+static int ordinary_1 = 22;
+static volatile int effect_0 = 6;
+static volatile int effect_1 = 23;
+static int ordinary_2 = 41;
+__attribute__ ((used)) int *ordinary_escape[]
+ = { &ordinary_0, &ordinary_1, &ordinary_2 };
+
+static inline __attribute__ ((always_inline))
+unsigned long long
+accumulate (unsigned long long acc, unsigned long long val)
+{
+ return acc + val;
+}
+
+unsigned long long
+foo (void)
+{
+ int staged_ordinary_0 = ordinary_0;
+ int staged_ordinary_1 = ordinary_1;
+ int staged_effect_0 = effect_0;
+ int staged_effect_1 = effect_1;
+ int staged_ordinary_2 = ordinary_2;
+ unsigned long long sum = 0;
+ sum = accumulate (sum, staged_ordinary_0);
+ sum = accumulate (sum, staged_ordinary_1);
+ sum = accumulate (sum, staged_effect_0);
+ sum = accumulate (sum, staged_effect_1);
+ sum = accumulate (sum, staged_ordinary_2);
+ return sum;
+}