https://gcc.gnu.org/g:7b18a7c536e62dffdbdbeb5f7457ff22f1cc44dc

commit r17-2497-g7b18a7c536e62dffdbdbeb5f7457ff22f1cc44dc
Author: Matt Turner <[email protected]>
Date:   Fri Jul 17 07:26:12 2026 -0600

    [PATCH] alpha: do not gate cannot_copy_insn_p on reload_completed
    
    alpha_legitimize_address emits movdi_er_tlsgd and movdi_er_tlsldm together
    with their paired call_value_osf_tlsgd/tlsldm at expand time, and both 
halves
    already carry the sequence number that ties the pair together.  Those 
patterns
    are marked with the cannot_copy attribute, but alpha_cannot_copy_insn_p
    returned false whenever !reload_completed, so the hook had no effect on any
    pass running before register allocation.
    
    Unrolling a loop whose body contains such a pair therefore copies the 
sequence
    number along with it.  With
    
      extern __thread int tv;
      extern int cond (int);
      int f (int n)
      {
        int s = 0;
        for (int i = 0; i < n; i++)
          if (cond (i))
            s += tv;
        return s;
      }
    
    compiled with -O2 -funroll-loops -fno-move-loop-invariants -fPIC
    -ftls-model=global-dynamic, the unroller produces seven copies of !tlsgd!1 
and
    the assembler rejects the result:
    
      Error: duplicate !tlsgd!1
      Error: too many lituse insns for !lituse_tlsgd!1
    
    Drop the reload_completed test.  The gpdisp pairs are only created after
    reload, so this does not change their handling; it only lets the hook 
protect
    the TLS pairs that already exist before register allocation.  This is
    independent of the register allocator: the failure reproduces identically 
with
    both reload and LRA.
    
    gcc/
            * config/alpha/alpha.cc (alpha_cannot_copy_insn_p): Do not return
            false before reload_completed.  Update comment.
    
    gcc/testsuite/
            * gcc.target/alpha/tlsgd-dup-1.c: New test.

Diff:
---
 gcc/config/alpha/alpha.cc                    | 17 +++++++++++++----
 gcc/testsuite/gcc.target/alpha/tlsgd-dup-1.c | 22 ++++++++++++++++++++++
 2 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc
index 9b8433c5bb04..90e4c21dd11b 100644
--- a/gcc/config/alpha/alpha.cc
+++ b/gcc/config/alpha/alpha.cc
@@ -1242,8 +1242,8 @@ split_small_symbolic_operand (rtx x)
 }
 
 /* Indicate that INSN cannot be duplicated.  This is true for any insn
-   that we've marked with gpdisp relocs, since those have to stay in
-   1-1 correspondence with one another.
+   that we've marked with a relocation sequence number, since those have
+   to stay in 1-1 correspondence with one another.
 
    Technically we could copy them if we could set up a mapping from one
    sequence number to another, across the set of insns to be duplicated.
@@ -1253,12 +1253,21 @@ split_small_symbolic_operand (rtx x)
    Also cannot allow jsr insns to be duplicated.  If they throw exceptions,
    then they'll be in a different block from their ldgp.  Which could lead
    the bb reorder code to think that it would be ok to copy just the block
-   containing the call and branch to the block containing the ldgp.  */
+   containing the call and branch to the block containing the ldgp.
+
+   Note this must not be gated on reload_completed.  While the gpdisp pairs
+   are only created after reload, alpha_legitimize_address emits
+   movdi_er_tlsgd and movdi_er_tlsldm together with their paired
+   call_value_osf_tlsgd/tlsldm at expand time, and those already carry the
+   sequence number that ties each pair together.  Returning false before
+   reload lets the pre-RA duplicators reach them: unrolling a loop whose
+   body holds such a pair copies the sequence number along with it, and the
+   assembler then rejects the result with "duplicate !tlsgd!N".  */
 
 static bool
 alpha_cannot_copy_insn_p (rtx_insn *insn)
 {
-  if (!reload_completed || !TARGET_EXPLICIT_RELOCS)
+  if (!TARGET_EXPLICIT_RELOCS)
     return false;
   if (recog_memoized (insn) >= 0)
     return get_attr_cannot_copy (insn);
diff --git a/gcc/testsuite/gcc.target/alpha/tlsgd-dup-1.c 
b/gcc/testsuite/gcc.target/alpha/tlsgd-dup-1.c
new file mode 100644
index 000000000000..33ffc4d5deaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/alpha/tlsgd-dup-1.c
@@ -0,0 +1,22 @@
+/* Verify that a TLS sequence insn and its paired call are not duplicated by
+   the pre-RA passes.  Each movdi_er_tlsgd carries a sequence number that must
+   stay in 1-1 correspondence with the !lituse_tlsgd of its call; duplicating
+   the loop body used to copy both halves and make the assembler reject the
+   result with "duplicate !tlsgd!1".  */
+/* { dg-do assemble } */
+/* { dg-require-effective-target tls_native } */
+/* { dg-require-effective-target fpic } */
+/* { dg-options "-O2 -funroll-loops -fno-move-loop-invariants -fPIC 
-ftls-model=global-dynamic" } */
+
+extern __thread int tv;
+extern int cond (int);
+
+int
+f (int n)
+{
+  int s = 0;
+  for (int i = 0; i < n; i++)
+    if (cond (i))
+      s += tv;
+  return s;
+}

Reply via email to