[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