I took an ill-advised short-cut with the recent ext-dce improvement to
detect certain shift pairs as sign/zero extensions. Specifically I was
adjusting the SET_SRC of an object.
Often we can get away with that, but as this case shows it's simply not
safe for RTL. The core issue is the right shift we're modifying into a
simple reg->reg move may have things like CLOBBERs outside the set
resulting in
(parallel
(set (dstreg) (srcreg))
(clobber (whatever)))
Even that is often OK as targets which have these kinds of clobbers
often need them on their basic moves because those moves often set
condition codes. But that's not true for GCN.
On GCN that transformation leads to an unrecognizable insn as seen in
the pr. The fix is pretty simple. Just emit a new move and delete the
shift. Of course we have to be prepared to handle multiple insns once
we use emit_move_insn, but that's not too bad.
Bootstrapped and regression tested on x86 & riscv64. Pushing to the trunk.
Jeff
commit f73b1b0831fe8f071761cc2c6696d92e258d2b4f
Author: Jeff Law <[email protected]>
Date: Sat Nov 22 11:33:57 2025 -0700
[PR 122701] Emit fresh reg->reg copy rather than modifying existing insnO
I took an ill-advised short-cut with the recent ext-dce improvement to
detect
certain shift pairs as sign/zero extensions. Specifically I was adjusting
the
SET_SRC of an object.
Often we can get away with that, but as this case shows it's simply not safe
for RTL. The core issue is the right shift we're modifying into a simple
reg->reg move may have things like CLOBBERs outside the set resulting in
(parallel
(set (dstreg) (srcreg))
(clobber (whatever)))
Even that is often OK as targets which have these kinds of clobbers often
need them on their basic moves because those moves often set condition codes.
But that's not true for GCN.
On GCN that transformation leads to an unrecognizable insn as seen in the
pr.
The fix is pretty simple. Just emit a new move and delete the shift. Of
course we have to be prepared to handle multiple insns once we use
emit_move_insn, but that's not too bad.
PR rtl-optimization/122701
gcc/
* ext-dce.cc (ext_dce_try_optimize_rshift): Emit a fresh reg->reg
copy rather than modifying the existing right shift.
gcc/testsuite/
* gcc.dg/torture/pr122701.c: New test.
diff --git a/gcc/ext-dce.cc b/gcc/ext-dce.cc
index 851b56454cee..e6189f973bfc 100644
--- a/gcc/ext-dce.cc
+++ b/gcc/ext-dce.cc
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "memmodel.h"
#include "insn-config.h"
#include "emit-rtl.h"
+#include "expr.h"
#include "recog.h"
#include "cfganal.h"
#include "tree-pass.h"
@@ -421,13 +422,12 @@ ext_dce_try_optimize_rshift (rtx_insn *insn, rtx set, rtx
new_src, rtx_insn *new
return;
}
- /* Replace SET_SRC (set) with NEW_SRC. This changes the form of INSN, so
- force rerecognition. We also need to force DF to rescan INSN. */
- SET_SRC (set) = new_src;
- INSN_CODE (insn) = -1;
- df_insn_rescan (insn);
-
- rtx new_pattern = PATTERN (insn);
+ /* We're going to generate a fresh insn for the move, so put it
+ into a sequence that we can emit after the current insn. */
+ start_sequence ();
+ emit_move_insn (SET_DEST (set), new_src);
+ rtx_insn *seq = end_sequence ();
+ emit_insn_after (seq, insn);
/* Mark the destination as changed. */
rtx x = SET_DEST (set);
@@ -439,14 +439,11 @@ ext_dce_try_optimize_rshift (rtx_insn *insn, rtx set, rtx
new_src, rtx_insn *new
if (dump_file)
{
fprintf (dump_file, "Successfully transformed to:\n");
- print_rtl_single (dump_file, new_pattern);
+ print_rtl_single (dump_file, PATTERN (seq));
fprintf (dump_file, "\n");
}
- /* INSN may have a REG_EQUAL note indicating that the value was
- sign or zero extended. That note is no longer valid since we've
- just removed the extension. Just wipe the notes. */
- remove_reg_equal_equiv_notes (insn, false);
+ delete_insn (insn);
/* If NEW_SRC died in its prior location, then we need to remove the
death note and move it to the new location. */
diff --git a/gcc/testsuite/gcc.dg/torture/pr122701.c
b/gcc/testsuite/gcc.dg/torture/pr122701.c
new file mode 100644
index 000000000000..62d3e3d9a0c5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr122701.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+
+char _strtoimax_r_c;
+void _strtoimax_r() {
+ for (;; _strtoimax_r_c++) {
+ if (_strtoimax_r_c <= '9')
+ _strtoimax_r_c -= '0';
+ if (_strtoimax_r_c >= 'A')
+ break;
+ }
+}