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

Jeff Law via Gcc-cvs <[email protected]> Thu, 6 Aug 2026 03:03:01 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:9a72a88b4a5f4c271e78e6ff3ddc76e793dfa69c

commit r17-3001-g9a72a88b4a5f4c271e78e6ff3ddc76e793dfa69c
Author: Matt Turner <[email protected]>
Date:   Wed Aug 5 21:02:38 2026 -0600

    [PATCH 2/2] alpha: keep the exception receiver's gpdisp pair together [PR124495]
    
    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.

Diff:
---
 gcc/config/alpha/alpha.md                 | 19 +++++++++++++++++--
 gcc/testsuite/g++.target/alpha/pr124495.C | 19 +++++++++++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md
index e567bba066c0..30a9f613e378 100644
--- a/gcc/config/alpha/alpha.md
+++ b/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
@@ -5081,6 +5082,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")
@@ -5213,7 +5228,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]),
@@ -5266,7 +5281,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 a/gcc/testsuite/g++.target/alpha/pr124495.C b/gcc/testsuite/g++.target/alpha/pr124495.C
new file mode 100644
index 000000000000..6b1fb397a8b8
--- /dev/null
+++ b/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);
+}