[PATCH 2/2] alpha: keep the exception receiver's gpdisp pair together [PR124495]

Matt Turner <[email protected]> Wed, 5 Aug 2026 11:59:21 -0400
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
exception_receiver and builtin_setjmp_receiver split into an ldah/lda
pair that shares a !gpdisp relocation sequence number, so the two insns
have to stay in 1-1 correspondence.  The first half is an unspec_volatile
(*ldgp_er_1), but the second half was a plain unspec (*ldgp_er_2), which
makes the halves unequally deletable: once the landing pad turns out not
to use $29, the DCE run at the start of the peephole2 pass removes the
lda and leaves the ldah behind.  The assembler then rejects the result:

  Error: No lda !gpdisp!1188 was found

Compiling C++ with -fassume-sane-operators-new-delete, which is the
default, makes this much easier to hit, since it lets more of the cleanup
code in a landing pad be optimized away.

Add an unspec_volatile variant of *ldgp_er_2 and use it for both
receivers.  The gpdisp pair emitted after a call needs no such treatment:
there the ldah is part of the call insn and both halves are plain
unspecs, so they are deleted together.

gcc/ChangeLog:

	PR target/124495
	* config/alpha/alpha.md (UNSPECV_LDGP2): New unspec_volatile.
	(*ldgp_er_2_v): New insn.
	(*builtin_setjmp_receiver_1): Split the second half of the gpdisp
	pair to it instead of *ldgp_er_2.
	(*exception_receiver_1): Ditto.

gcc/testsuite/ChangeLog:

	PR target/124495
	* g++.target/alpha/pr124495.C: New test.
---
 gcc/config/alpha/alpha.md                 | 19 +++++++++++++++++--
 gcc/testsuite/g++.target/alpha/pr124495.C | 19 +++++++++++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/alpha/pr124495.C

diff --git ./gcc/config/alpha/alpha.md ./gcc/config/alpha/alpha.md
index e9a05bece4d..2ca9dd65835 100644
--- ./gcc/config/alpha/alpha.md
+++ ./gcc/config/alpha/alpha.md
@@ -74,6 +74,7 @@
   UNSPECV_MCOUNT
   UNSPECV_FORCE_MOV
   UNSPECV_LDGP1
+  UNSPECV_LDGP2
   UNSPECV_PLDGP2	; prologue ldgp
   UNSPECV_SET_TP
   UNSPECV_RPCC
@@ -5088,6 +5089,20 @@
   "lda %0,0(%1)\t\t!gpdisp!%2"
   [(set_attr "cannot_copy" "true")])
 
+;; Same as *ldgp_er_2, but for the pairs whose first half is the
+;; unspec_volatile *ldgp_er_1.  Both halves of a gpdisp pair have to be
+;; equally deletable: a plain unspec here is removed by DCE as soon as $29
+;; turns out to be unused, and the ldah left behind makes the assembler
+;; complain about a missing lda.
+(define_insn "*ldgp_er_2_v"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")
+			     (match_operand 2 "const_int_operand")]
+			    UNSPECV_LDGP2))]
+  "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+  "lda %0,0(%1)\t\t!gpdisp!%2"
+  [(set_attr "cannot_copy" "true")])
+
 (define_insn "*prologue_ldgp_er_2"
   [(set (match_operand:DI 0 "register_operand" "=r")
 	(unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")
@@ -5220,7 +5235,7 @@
   [(set (match_dup 1)
 	(unspec_volatile:DI [(match_dup 2) (match_dup 3)] UNSPECV_LDGP1))
    (set (match_dup 1)
-	(unspec:DI [(match_dup 1) (match_dup 3)] UNSPEC_LDGP2))]
+	(unspec_volatile:DI [(match_dup 1) (match_dup 3)] UNSPECV_LDGP2))]
 {
   if (prev_nonnote_insn (curr_insn) != XEXP (operands[0], 0))
     emit_insn (gen_rtx_UNSPEC_VOLATILE (VOIDmode, gen_rtvec (1, operands[0]),
@@ -5273,7 +5288,7 @@
   [(set (match_dup 0)
 	(unspec_volatile:DI [(match_dup 1) (match_dup 2)] UNSPECV_LDGP1))
    (set (match_dup 0)
-	(unspec:DI [(match_dup 0) (match_dup 2)] UNSPEC_LDGP2))]
+	(unspec_volatile:DI [(match_dup 0) (match_dup 2)] UNSPECV_LDGP2))]
 {
   operands[0] = pic_offset_table_rtx;
   operands[1] = gen_rtx_REG (Pmode, 26);
diff --git ./gcc/testsuite/g++.target/alpha/pr124495.C ./gcc/testsuite/g++.target/alpha/pr124495.C
new file mode 100644
index 00000000000..6b1fb397a8b
--- /dev/null
+++ ./gcc/testsuite/g++.target/alpha/pr124495.C
@@ -0,0 +1,19 @@
+/* PR target/124495 */
+/* { dg-do assemble } */
+/* { dg-options "-O2 -std=c++17" } */
+
+/* The exception receiver expands to an ldah/lda pair sharing a !gpdisp
+   relocation sequence number.  If the landing pad turns out not to use $29,
+   neither half may be deleted on its own.  */
+
+#include <memory>
+#include <variant>
+#include <vector>
+
+struct S { std::variant<int, std::vector<int>> v; };
+
+S *
+f (S *first, S *last, S *result)
+{
+  return std::uninitialized_copy (first, last, result);
+}
-- 
2.54.0