From: Matt Turner Date: Fri, 17 Jul 2026 13:26:12 +0000 (-0600) Subject: [PATCH] alpha: do not gate cannot_copy_insn_p on reload_completed X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7b18a7c536e62dffdbdbeb5f7457ff22f1cc44dc;p=thirdparty%2Fgcc.git [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 --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc index 9b8433c5bb0..90e4c21dd11 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 00000000000..33ffc4d5dea --- /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; +}