]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
vregs: Use force_subreg when instantiating subregs [PR120721]
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 23 Jun 2025 07:46:27 +0000 (08:46 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Mon, 23 Jun 2025 07:46:27 +0000 (08:46 +0100)
In this PR, we started with:

    (subreg:V2DI (reg:DI virtual-reg) 0)

and vregs instantiated the virtual register to the argument pointer.
But:

    (subreg:V2DI (reg:DI ap) 0)

is not a sensible subreg, since the argument pointer certainly can't
be referenced in V2DImode.  This is (IMO correctly) rejected after
g:2dcc6dbd8a00caf7cfa8cac17b3fd1c33d658016.

The vregs code that instantiates the subreg above is specific to
rvalues and already creates new instructions for nonzero offsets.
It is therefore safe to use force_subreg instead of simplify_gen_subreg.

I did wonder whether we should instead say that a subreg of a
virtual register is invalid if the same subreg would be invalid
for the associated hard registers.  But the point of virtual registers
is that the offsets from the hard registers are not known until after
expand has finished, and if an offset is nonzero, the virtual register
will be instantiated into a pseudo that contains the sum of the hard
register and the offset.  The subreg would then be correct for that
pseudo.  The subreg is only invalid in this case because there is
no offset.

gcc/
PR rtl-optimization/120721
* function.cc (instantiate_virtual_regs_in_insn): Use force_subreg
instead of simplify_gen_subreg when instantiating an rvalue SUBREG.

gcc/testsuite/
PR rtl-optimization/120721
* g++.dg/torture/pr120721.C: New test.

gcc/function.cc
gcc/testsuite/g++.dg/torture/pr120721.C [new file with mode: 0644]

index a3a74b44b9165eb2b682b001676f8414d087e578..48167b0c20721660a71124a0cea26fb33dfff00f 100644 (file)
@@ -1722,19 +1722,17 @@ instantiate_virtual_regs_in_insn (rtx_insn *insn)
          new_rtx = instantiate_new_reg (SUBREG_REG (x), &offset);
          if (new_rtx == NULL)
            continue;
+         start_sequence ();
          if (maybe_ne (offset, 0))
-           {
-             start_sequence ();
-             new_rtx = expand_simple_binop
-               (GET_MODE (new_rtx), PLUS, new_rtx,
-                gen_int_mode (offset, GET_MODE (new_rtx)),
-                NULL_RTX, 1, OPTAB_LIB_WIDEN);
-             seq = end_sequence ();
-             emit_insn_before (seq, insn);
-           }
-         x = simplify_gen_subreg (recog_data.operand_mode[i], new_rtx,
-                                  GET_MODE (new_rtx), SUBREG_BYTE (x));
+           new_rtx = expand_simple_binop
+             (GET_MODE (new_rtx), PLUS, new_rtx,
+              gen_int_mode (offset, GET_MODE (new_rtx)),
+              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+         x = force_subreg (recog_data.operand_mode[i], new_rtx,
+                           GET_MODE (new_rtx), SUBREG_BYTE (x));
          gcc_assert (x);
+         seq = end_sequence ();
+         emit_insn_before (seq, insn);
          break;
 
        default:
diff --git a/gcc/testsuite/g++.dg/torture/pr120721.C b/gcc/testsuite/g++.dg/torture/pr120721.C
new file mode 100644 (file)
index 0000000..37dc46c
--- /dev/null
@@ -0,0 +1,39 @@
+// { dg-additional-options "-w -fno-vect-cost-model" }
+
+template <int __v> struct integral_constant {
+  static constexpr int value = __v;
+};
+template <bool __v> using __bool_constant = integral_constant<__v>;
+template <bool> using enable_if_t = int;
+struct function_ref {
+  template <typename Callable>
+  function_ref(
+      Callable,
+      enable_if_t<__bool_constant<__is_same(int, int)>::value> * = nullptr);
+};
+struct ArrayRef {
+  int Data;
+  long Length;
+  int *begin();
+  int *end();
+};
+struct StringRef {
+  char Data;
+  long Length;
+};
+void attributeObject(function_ref);
+struct ScopedPrinter {
+  virtual void printBinaryImpl(StringRef, StringRef, ArrayRef, bool, unsigned);
+};
+struct JSONScopedPrinter : ScopedPrinter {
+  JSONScopedPrinter();
+  void printBinaryImpl(StringRef, StringRef, ArrayRef Value, bool,
+                       unsigned StartOffset) {
+    attributeObject([&] {
+      StartOffset;
+      for (char Val : Value)
+        ;
+    });
+  }
+};
+JSONScopedPrinter::JSONScopedPrinter() {}