Changes from v2:
        * Update tprel_ld_QI_signed to use gen_lowpart to correctly
          obtain the low QImode part of the destination

Changes from v1:
        * update tprel_ld_QI_signed to use define_insn_and_split
        * renamed PR27479.c to pr27479.c and removed dead code

Reduce TLS variable access from 3 to 2 instructions by adding
combine patterns that merge address calculation with load.

Before:
    addis 9,13,x@tprel@ha
    addi 9,9,x@tprel@l
    lwz 3,0(9)

After:
    addis 9,13,x@tprel@ha
    lwz 3,x@tprel@l(9)

Bootstrapped and tested on powerpc64le-linux-gnu with no regressions.
Bootstrapped and tested on powerpc64-linux-gnu with no regressions.

2026-04-15  Vijay Shankar  <[email protected]>

gcc/ChangeLog:
        PR target/27479
        * config/rs6000/rs6000.md (*tprel_ld_<az>_<HSI:mode>): New pattern.
        (*tprel_ld_QI_signed): likewise.
        (*tprel_ld_QI): likewise.
        (*tprel_ld_DI): likewise.
        (*tprel_ld_<SFDF:mode>): likewise.

gcc/testsuite/ChangeLog:
        PR target/27479
        * gcc.target/powerpc/pr27479.c: New Test.
---
 gcc/config/rs6000/rs6000.md                | 73 +++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/pr27479.c | 95 ++++++++++++++++++++++
 2 files changed, 168 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/pr27479.c

diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index ddfed3b63bc..8f694ac4d1c 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -10650,6 +10650,79 @@
   "la %0,%1@got@tlsgd@pcrel"
   [(set_attr "prefixed" "yes")])
 
+;;combine patterns for tls access
+(define_insn "*tprel_ld_<az>_<HSI:mode>"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (any_extend:DI
+         (mem:HSI
+           (unspec:P
+             [(match_operand:P 1 "gpc_reg_operand" "b")
+              (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+             UNSPEC_TLSTPRELLO))))]
+  "HAVE_AS_TLS"
+  "l<HSI:wd><az> %0,%2@tprel@l(%1)"
+  [(set_attr "type" "load")])
+
+;; Two instructions needed: lbz (zero-extend load byte) + extsb (sign-extend)
+;; because there is no sign-extended load byte instruction, only zero-extended.
+(define_insn_and_split "*tprel_ld_QI_signed"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+        (sign_extend:DI
+          (mem:QI
+            (unspec:P
+              [(match_operand:P 1 "gpc_reg_operand" "b")
+               (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+              UNSPEC_TLSTPRELLO))))]
+  "HAVE_AS_TLS"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0)
+        (zero_extend:DI
+          (mem:QI
+            (unspec:P
+              [(match_dup 1)
+               (match_dup 2)]
+              UNSPEC_TLSTPRELLO))))
+   (set (match_dup 0)
+        (sign_extend:DI (match_dup 3)))]
+  {
+   operands[3] = gen_lowpart (QImode, operands[0]);
+  })
+
+(define_insn "*tprel_ld_QI"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (zero_extend:DI
+         (mem:QI
+           (unspec:P
+             [(match_operand:P 1 "gpc_reg_operand" "b")
+              (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+             UNSPEC_TLSTPRELLO))))]
+  "HAVE_AS_TLS"
+  "lbz %0,%2@tprel@l(%1)"
+  [(set_attr "type" "load")])
+
+(define_insn "*tprel_ld_DI"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (mem:DI
+         (unspec:P
+           [(match_operand:P 1 "gpc_reg_operand" "b")
+            (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+           UNSPEC_TLSTPRELLO)))]
+  "HAVE_AS_TLS"
+  "ld %0,%2@tprel@l(%1)"
+  [(set_attr "type" "load")])
+
+(define_insn "*tprel_ld_<SFDF:mode>"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=f")
+       (mem:SFDF
+         (unspec:P
+           [(match_operand:P 1 "gpc_reg_operand" "b")
+            (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+           UNSPEC_TLSTPRELLO)))]
+  "HAVE_AS_TLS"
+  "lf<SFDF:sd> %0,%2@tprel@l(%1)"
+  [(set_attr "type" "fpload")])
+
 (define_insn_and_split "*tls_gd<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
        (unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
diff --git a/gcc/testsuite/gcc.target/powerpc/pr27479.c 
b/gcc/testsuite/gcc.target/powerpc/pr27479.c
new file mode 100644
index 00000000000..de05237ba5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr27479.c
@@ -0,0 +1,95 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power9" } */
+
+/*  verify TLS access for PR27479  */
+
+/* TLS variables of many types.  */
+__thread unsigned char t_uc;
+__thread signed char t_sc;
+__thread unsigned short t_us;
+__thread short t_ss;
+__thread unsigned int t_ui;
+__thread int t_si;
+__thread unsigned long t_ul;
+__thread long t_sl;
+__thread _Bool t_bool;
+__thread int *t_ptr;
+
+/* Floating-point.  */
+__thread float t_f;
+__thread double t_d;
+
+unsigned long
+foo_uc (void)
+{
+  return t_uc;
+}
+
+long
+foo_sc (void)
+{
+  return t_sc;
+}
+
+unsigned long
+foo_us (void)
+{
+  return t_us;
+}
+
+long
+foo_ss (void)
+{
+  return t_ss;
+}
+
+unsigned long
+foo_ui (void)
+{
+  return t_ui;
+}
+
+long
+foo_si (void)
+{
+  return t_si;
+}
+
+unsigned long
+foo_ul (void)
+{
+  return t_ul;
+}
+
+long
+foo_sl (void)
+{
+  return t_sl;
+}
+
+unsigned long
+foo_bool (void)
+{
+  return t_bool;
+}
+
+int *
+foo_ptr (void)
+{
+  return t_ptr;
+}
+
+/* Floating-point accessors.  */
+float
+foo_f (void)
+{
+  return t_f;
+}
+
+double
+foo_d (void)
+{
+  return t_d;
+}
+
+/* { dg-final { scan-assembler-not {\maddi\M} } } */
-- 
2.52.0

Reply via email to