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;
+}

Reply via email to