[llvm] [Xtensa] Fix code generation for TLS variables. (PR #202822)

Andrei Safronov via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 11:54:03 PDT 2026


https://github.com/andreisfr updated https://github.com/llvm/llvm-project/pull/202822

>From 32afb2d1dc1bab6010d7af37ab8a1affab98a5c4 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Wed, 10 Jun 2026 03:03:04 +0300
Subject: [PATCH 1/2] [Xtensa] Fix code generation for TLS variables.

---
 .../Xtensa/AsmParser/XtensaAsmParser.cpp      |  6 +--
 .../Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp   |  4 ++
 .../MCTargetDesc/XtensaTargetStreamer.cpp     |  5 +-
 llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp   |  7 ---
 llvm/test/CodeGen/Xtensa/tls.ll               | 30 +++++++++++
 llvm/test/MC/Xtensa/tls.s                     | 50 +++++++++++++++++++
 6 files changed, 89 insertions(+), 13 deletions(-)
 create mode 100644 llvm/test/CodeGen/Xtensa/tls.ll
 create mode 100644 llvm/test/MC/Xtensa/tls.s

diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index dc33295c16f28..16eb24f59260b 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -676,12 +676,8 @@ ParseStatus XtensaAsmParser::parseImmediate(OperandVector &Operands) {
       return ParseStatus::Failure;
     break;
   case AsmToken::Identifier: {
-    StringRef Identifier;
-    if (getParser().parseIdentifier(Identifier))
+    if (getParser().parseExpression(Res))
       return ParseStatus::Failure;
-
-    MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
-    Res = MCSymbolRefExpr::create(Sym, getContext());
     break;
   }
   case AsmToken::Percent:
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp
index ec4477ad80fe2..de15486337343 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp
@@ -18,6 +18,8 @@
 
 using namespace llvm;
 
+const MCAsmInfo::AtSpecifier atSpecifiers[] = {{Xtensa::S_TPOFF, "TPOFF"}};
+
 XtensaMCAsmInfo::XtensaMCAsmInfo(const Triple &TT,
                                  const MCTargetOptions &Options)
     : MCAsmInfoELF(Options) {
@@ -32,6 +34,8 @@ XtensaMCAsmInfo::XtensaMCAsmInfo(const Triple &TT,
   SupportsDebugInformation = true;
   ExceptionsType = ExceptionHandling::DwarfCFI;
   AlignmentIsInBytes = false;
+
+  initializeAtSpecifiers(atSpecifiers);
 }
 
 void XtensaMCAsmInfo::printSpecifierExpr(raw_ostream &OS,
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp
index 0ea70cff4d404..ba266057d3a5e 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "XtensaTargetStreamer.h"
+#include "MCTargetDesc/XtensaMCAsmInfo.h"
 #include "XtensaInstPrinter.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/MCAssembler.h"
@@ -61,7 +62,9 @@ void XtensaTargetAsmStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value,
     LiteralStr << CE->getValue() << "\n";
   } else if (auto SRE = dyn_cast<MCSymbolRefExpr>(Value)) {
     const MCSymbol &Sym = SRE->getSymbol();
-    LiteralStr << Sym.getName() << "\n";
+    Xtensa::Specifier Spec = (Xtensa::Specifier)SRE->getSpecifier();
+    StringRef Modifier = (Spec == Xtensa::S_TPOFF) ? "@TPOFF" : "";
+    LiteralStr << Sym.getName() << Modifier << "\n";
   } else {
     llvm_unreachable("unexpected constant pool entry type");
   }
diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
index c6e432fb9918c..710084289a3e0 100644
--- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp
@@ -97,13 +97,6 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue(
       static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
   auto Spec = getModifierSpecifier(XtensaCPV->getModifier());
 
-  if (XtensaCPV->getModifier() != XtensaCP::no_modifier) {
-    std::string SymName(MCSym->getName());
-    StringRef Modifier = XtensaCPV->getModifierText();
-    SymName += Modifier;
-    MCSym = OutContext.getOrCreateSymbol(SymName);
-  }
-
   const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, Spec, OutContext);
   TS->emitLiteral(LblSym, Expr, false);
 }
diff --git a/llvm/test/CodeGen/Xtensa/tls.ll b/llvm/test/CodeGen/Xtensa/tls.ll
new file mode 100644
index 0000000000000..0d59b8b2f7df0
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/tls.ll
@@ -0,0 +1,30 @@
+; RUN: llc -mtriple=xtensa -function-sections --mcpu=esp32 --filetype=obj < %s \
+; RUN: | llvm-objdump -r -s --triple=xtensa --mcpu=esp32 - | FileCheck -check-prefix=XTENSA-CHECK-OBJ %s
+; RUN: llc -mtriple=xtensa -function-sections --mcpu=esp32 --filetype=asm < %s | FileCheck -check-prefix=XTENSA-CHECK-ASM %s
+
+; XTENSA-CHECK-OBJ-LABEL: RELOCATION RECORDS FOR [.literal.get_tls]:
+; XTENSA-CHECK-OBJ:       OFFSET   TYPE                     VALUE
+; XTENSA-CHECK-OBJ-NEXT:  00000000 R_XTENSA_TLS_TPOFF       tls_var
+
+; XTENSA-CHECK-ASM-LABEL: .literal_position
+; XTENSA-CHECK-ASM:       .literal .LCPI0_0, tls_var at TPOFF
+; XTENSA-CHECK-ASM-LABEL: get_tls:
+; XTENSA-CHECK-ASM:       .cfi_startproc
+; XTENSA-CHECK-ASM-NEXT:  # %bb.0:
+; XTENSA-CHECK-ASM-NEXT:  entry	a1, 32
+; XTENSA-CHECK-ASM-NEXT:  .cfi_def_cfa_offset 32
+; XTENSA-CHECK-ASM-NEXT:  l32r	a8, .LCPI0_0
+; XTENSA-CHECK-ASM-NEXT:  rur	a9, threadptr
+; XTENSA-CHECK-ASM-NEXT:  add	a8, a9, a8
+; XTENSA-CHECK-ASM-NEXT:  l32i	a2, a8, 0
+; XTENSA-CHECK-ASM-NEXT:  retw.n
+
+
+ at tls_var = dso_local thread_local local_unnamed_addr global i32 42, align 4
+
+define dso_local i32 @get_tls() {
+entry:
+  %v = tail call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @tls_var)
+  %res = load i32, ptr %v, align 4
+  ret i32 %res
+}
diff --git a/llvm/test/MC/Xtensa/tls.s b/llvm/test/MC/Xtensa/tls.s
new file mode 100644
index 0000000000000..9ca2599c15491
--- /dev/null
+++ b/llvm/test/MC/Xtensa/tls.s
@@ -0,0 +1,50 @@
+# RUN: llvm-mc -triple=xtensa --mcpu=esp32 --filetype=obj < %s \
+# RUN: | llvm-objdump -r -s --triple=xtensa --mcpu=esp32 - | FileCheck -check-prefix=XTENSA-CHECK-OBJ %s
+# RUN: llvm-mc -triple=xtensa --mcpu=esp32 --filetype=asm < %s | FileCheck -check-prefix=XTENSA-CHECK-ASM %s
+
+# XTENSA-CHECK-OBJ-LABEL: RELOCATION RECORDS FOR [.literal]:
+# XTENSA-CHECK-OBJ:       OFFSET   TYPE                     VALUE
+# XTENSA-CHECK-OBJ-NEXT:  00000000 R_XTENSA_TLS_TPOFF       tls_var
+# XTENSA-CHECK-OBJ-LABEL: RELOCATION RECORDS FOR [.literal.get_tls]:
+# XTENSA-CHECK-OBJ:       OFFSET   TYPE                     VALUE
+# XTENSA-CHECK-OBJ-NEXT:  00000000 R_XTENSA_TLS_TPOFF       tls_var
+
+# XTENSA-CHECK-ASM-LABEL: .literal_position
+# XTENSA-CHECK-ASM:       .literal .LCPI0_0, tls_var at TPOFF
+# XTENSA-CHECK-ASM-LABEL: get_tls:
+# XTENSA-CHECK-ASM-NEXT:  entry	a1, 32
+# XTENSA-CHECK-ASM-NEXT:  or	a7, a1, a1
+# XTENSA-CHECK-ASM-NEXT:  l32r	a8, .LCPI0_0
+# XTENSA-CHECK-ASM-NEXT:  rur	a9, threadptr
+# XTENSA-CHECK-ASM-NEXT:  add	a8, a9, a8
+# XTENSA-CHECK-ASM-NEXT:  l32i	a2, a8, 0
+# XTENSA-CHECK-ASM-NEXT:  .literal .Ltmp0, tls_var at TPOFF
+# XTENSA-CHECK-ASM-NEXT:  l32r	a3, .Ltmp0
+# XTENSA-CHECK-ASM-NEXT:  retw.n
+
+	.literal_position
+	.literal .LCPI0_0, tls_var at TPOFF
+	.text
+	.section	.text.get_tls,"ax", at progbits
+	.global	get_tls                         # -- Begin function get_tls
+	.p2align	2
+	.type	get_tls, at function
+get_tls:
+	entry	a1, 32
+	or	a7, a1, a1
+	l32r	a8, .LCPI0_0
+	rur	a9, threadptr
+	add	a8, a9, a8
+	l32i	a2, a8, 0
+	movi a3, tls_var at TPOFF
+	retw.n
+.Lfunc_end0:
+	.size	get_tls, .Lfunc_end0-get_tls
+                                        # -- End function
+	.type	tls_var, at object                 # @tls_var
+	.section	.tdata,"awT", at progbits
+	.global	tls_var
+	.p2align	2, 0x0
+tls_var:
+	.long	42                              # 0x2a
+	.size	tls_var, 4

>From 71329af5b8cae59ee354635ac0bae0fc1a067308 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Wed, 10 Jun 2026 21:49:51 +0300
Subject: [PATCH 2/2] [Xtensa] Minor fix in XtensaTargetAsmStreamer.

---
 .../Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp  | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp
index ba266057d3a5e..6283d0f38211e 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp
@@ -62,9 +62,12 @@ void XtensaTargetAsmStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value,
     LiteralStr << CE->getValue() << "\n";
   } else if (auto SRE = dyn_cast<MCSymbolRefExpr>(Value)) {
     const MCSymbol &Sym = SRE->getSymbol();
-    Xtensa::Specifier Spec = (Xtensa::Specifier)SRE->getSpecifier();
-    StringRef Modifier = (Spec == Xtensa::S_TPOFF) ? "@TPOFF" : "";
-    LiteralStr << Sym.getName() << Modifier << "\n";
+    Xtensa::Specifier Spec =
+        static_cast<Xtensa::Specifier>(SRE->getSpecifier());
+    LiteralStr << Sym.getName();
+    if (Spec == Xtensa::S_TPOFF)
+      LiteralStr << "@TPOFF";
+    LiteralStr << '\n';
   } else {
     llvm_unreachable("unexpected constant pool entry type");
   }



More information about the llvm-commits mailing list