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.
---
gcc/config/alpha/alpha.cc | 17 +++++++++++----
gcc/testsuite/gcc.target/alpha/tlsgd-dup-1.c | 22 ++++++++++++++++++++
2 files changed, 35 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/alpha/tlsgd-dup-1.c
diff --git ./gcc/config/alpha/alpha.cc ./gcc/config/alpha/alpha.cc
index 9b8433c5bb0..90e4c21dd11 100644
--- ./gcc/config/alpha/alpha.cc
+++ ./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 ./gcc/testsuite/gcc.target/alpha/tlsgd-dup-1.c
./gcc/testsuite/gcc.target/alpha/tlsgd-dup-1.c
new file mode 100644
index 00000000000..33ffc4d5dea
--- /dev/null
+++ ./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;
+}
--
2.54.0