[llvm] [DebugInfo][COFF] Use SECREL for TLS offsets in DWARF (PR #228107)

via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 10:59:27 PDT 2026


https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/228107

>From f81917a9c47aa43c52a74b35a55417431fcae92a Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 1 Oct 2026 16:23:33 +0200
Subject: [PATCH] [DebugInfo][COFF] Use SECREL for TLS offsets in DWARF

---
 .../CodeGen/TargetLoweringObjectFileImpl.h    |  1 +
 .../llvm/Target/TargetLoweringObjectFile.h    |  6 ++
 .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp   | 10 +++-
 .../CodeGen/TargetLoweringObjectFileImpl.cpp  |  6 ++
 .../AArch64/AArch64TargetObjectFile.cpp       |  5 ++
 .../Target/AArch64/AArch64TargetObjectFile.h  |  7 ++-
 .../AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp |  2 +
 .../AArch64/MCTargetDesc/AArch64MCAsmInfo.h   |  3 +
 .../AArch64WinCOFFObjectWriter.cpp            |  3 +
 llvm/lib/Target/ARM/ARMTargetMachine.cpp      |  2 +-
 llvm/lib/Target/ARM/ARMTargetObjectFile.cpp   |  5 ++
 llvm/lib/Target/ARM/ARMTargetObjectFile.h     |  7 +++
 .../Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp  |  3 +
 llvm/lib/Target/X86/X86TargetMachine.cpp      |  2 +-
 llvm/lib/Target/X86/X86TargetObjectFile.cpp   |  5 ++
 llvm/lib/Target/X86/X86TargetObjectFile.h     |  7 +++
 llvm/test/DebugInfo/AArch64/coff-tls-dwarf.ll | 51 +++++++++++++++++
 llvm/test/DebugInfo/ARM/coff-tls-dwarf.ll     | 51 +++++++++++++++++
 llvm/test/DebugInfo/X86/coff-tls-dwarf.ll     | 55 +++++++++++++++++++
 19 files changed, 226 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/DebugInfo/AArch64/coff-tls-dwarf.ll
 create mode 100644 llvm/test/DebugInfo/ARM/coff-tls-dwarf.ll
 create mode 100644 llvm/test/DebugInfo/X86/coff-tls-dwarf.ll

diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index e76a1ac17205791..bfd08631a2ce0b5 100644
--- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
+++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
@@ -190,6 +190,7 @@ class LLVM_ABI TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile {
   mutable unsigned NextUniqueID = 0;
 
 public:
+  TargetLoweringObjectFileCOFF();
   ~TargetLoweringObjectFileCOFF() override = default;
 
   void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
index 3cce5974e670579..89260f2ab21be04 100644
--- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h
+++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
@@ -52,6 +52,7 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo {
   bool SupportIndirectSymViaGOTPCRel = false;
   bool SupportGOTPCRelWithOffset = true;
   bool SupportDebugThreadLocalLocation = true;
+  bool Support64BitDebugThreadLocalLocation = true;
   uint32_t PLTPCRelativeSpecifier = 0;
 
   /// PersonalityEncoding, LSDAEncoding, TTypeEncoding - Some encoding values
@@ -248,6 +249,11 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo {
     return SupportDebugThreadLocalLocation;
   }
 
+  /// Target supports 64 bit TLS offset relocations in debug section?
+  bool support64bitDebugThreadLocalLocation() const {
+    return Support64BitDebugThreadLocalLocation;
+  }
+
   /// Returns the register used as static base in RWPI variants.
   virtual MCRegister getStaticBase() const { return MCRegister::NoRegister; }
 
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index bb7dba9f375850d..7a7358cc96dd6ea 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -276,7 +276,7 @@ void DwarfCompileUnit::addLocationAttribute(
       const MCSymbol *Sym = Asm->getSymbol(Global);
       // 16-bit platforms like MSP430 and AVR take this path, so sink this
       // assert to platforms that use it.
-      auto GetPointerSizedFormAndOp = [this]() {
+      auto GetPointerSizedFormAndOp = [this, Global]() {
         unsigned PointerSize = Asm->MAI.getCodePointerSize();
         assert((PointerSize == 4 || PointerSize == 8) &&
                "Add support for other sizes if necessary");
@@ -284,7 +284,13 @@ void DwarfCompileUnit::addLocationAttribute(
           dwarf::Form Form;
           dwarf::LocationAtom Op;
         };
-        return PointerSize == 4
+
+        bool UseFourByteConst =
+            PointerSize == 4 ||
+            (Global->isThreadLocal() &&
+             !Asm->getObjFileLowering().support64bitDebugThreadLocalLocation());
+
+        return UseFourByteConst
                    ? FormAndOp{dwarf::DW_FORM_data4, dwarf::DW_OP_const4u}
                    : FormAndOp{dwarf::DW_FORM_data8, dwarf::DW_OP_const8u};
       };
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index d47b35cfa7bcfda..c11d08084bb6261 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -1693,6 +1693,12 @@ void TargetLoweringObjectFileMachO::getNameWithPrefix(
 //                                  COFF
 //===----------------------------------------------------------------------===//
 
+TargetLoweringObjectFileCOFF::TargetLoweringObjectFileCOFF() {
+  // COFF only supports 32 bit section relative relocations, so all TLS offsets
+  // need to be encoded as 32 bit.
+  Support64BitDebugThreadLocalLocation = false;
+}
+
 static unsigned
 getCOFFSectionFlags(SectionKind K, const TargetMachine &TM) {
   unsigned Flags = 0;
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
index 2d01b321ce013a5..305045de34029cf 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
@@ -194,3 +194,8 @@ const MCExpr *AArch64_ELFTargetObjectFile::getDebugThreadLocalSymbol(
     const MCSymbol *Sym) const {
   return MCSpecifierExpr::create(Sym, AArch64::S_DTPREL, getContext());
 }
+
+const MCExpr *AArch64_COFFTargetObjectFile::getDebugThreadLocalSymbol(
+    const MCSymbol *Sym) const {
+  return MCSpecifierExpr::create(Sym, AArch64::S_COFF_SECREL, getContext());
+}
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
index 78c0c22da8d1b72..3006e84f220d698 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
@@ -76,7 +76,12 @@ class AArch64_MachoTargetObjectFile : public TargetLoweringObjectFileMachO {
 };
 
 /// This implementation is used for AArch64 COFF targets.
-class AArch64_COFFTargetObjectFile : public TargetLoweringObjectFileCOFF {};
+class AArch64_COFFTargetObjectFile : public TargetLoweringObjectFileCOFF {
+public:
+  AArch64_COFFTargetObjectFile() = default;
+
+  const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
+};
 
 } // end namespace llvm
 
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
index deff9f2eae32109..39069bda870e4db 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
@@ -120,6 +120,8 @@ StringRef AArch64::getSpecifierName(AArch64::Specifier S) {
   case AArch64::S_PLT:                 return "%pltpcrel";
   case AArch64::S_DTPREL:              return "%dtprel";
   case AArch64::S_FUNCINIT:            return "%funcinit";
+
+  case AArch64::S_COFF_SECREL:         return ":SECREL32:";
   default:
     llvm_unreachable("Invalid relocation specifier");
   }
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
index 7a914967df63615..eb95b0adbb727df 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
@@ -176,6 +176,9 @@ enum {
   S_MACHO_TLVPPAGE,
   S_MACHO_TLVPPAGEOFF,
 
+  // COFF relocation specifiers:
+  S_COFF_SECREL,
+
   S_INVALID  = 0xfff
   // clang-format on
 };
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp
index 5fe999389ce791b..b4555322cb48bbe 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp
@@ -6,6 +6,7 @@
 //
 //===---------------------------------------------------------------------===//
 
+#include "AArch64MCAsmInfo.h"
 #include "AArch64MCTargetDesc.h"
 #include "MCTargetDesc/AArch64FixupKinds.h"
 #include "MCTargetDesc/AArch64MCAsmInfo.h"
@@ -104,6 +105,8 @@ unsigned AArch64WinCOFFObjectWriter::getRelocType(
       return COFF::IMAGE_REL_ARM64_ADDR32;
     case MCSymbolRefExpr::VK_COFF_IMGREL32:
       return COFF::IMAGE_REL_ARM64_ADDR32NB;
+    case AArch64::S_COFF_SECREL:
+      return COFF::IMAGE_REL_ARM64_SECREL;
     }
 
   case FK_Data_8:
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index 6bc7cd019e0f589..5b0f90c8e94fa8a 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -123,7 +123,7 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
   if (TT.isOSBinFormatMachO())
     return std::make_unique<TargetLoweringObjectFileMachO>();
   if (TT.isOSWindows())
-    return std::make_unique<TargetLoweringObjectFileCOFF>();
+    return std::make_unique<ARMCOFFTargetObjectFile>();
   return std::make_unique<ARMElfTargetObjectFile>();
 }
 
diff --git a/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp b/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp
index 44040be9c8db9e5..f5c475fe1554d5b 100644
--- a/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp
@@ -126,3 +126,8 @@ MCSection *ARMElfTargetObjectFile::SelectSectionForGlobal(
 
   return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, SK, TM);
 }
+
+const MCExpr *
+ARMCOFFTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
+  return MCSpecifierExpr::create(Sym, ARM::S_COFF_SECREL, getContext());
+}
diff --git a/llvm/lib/Target/ARM/ARMTargetObjectFile.h b/llvm/lib/Target/ARM/ARMTargetObjectFile.h
index 02cd138cf5c04de..33541c0a11b7b58 100644
--- a/llvm/lib/Target/ARM/ARMTargetObjectFile.h
+++ b/llvm/lib/Target/ARM/ARMTargetObjectFile.h
@@ -48,6 +48,13 @@ class ARMElfTargetObjectFile : public TargetLoweringObjectFileELF {
                                     const TargetMachine &TM) const override;
 };
 
+class ARMCOFFTargetObjectFile : public TargetLoweringObjectFileCOFF {
+public:
+  ARMCOFFTargetObjectFile() = default;
+
+  const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
+};
+
 } // end namespace llvm
 
 #endif // LLVM_LIB_TARGET_ARM_ARMTARGETOBJECTFILE_H
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp
index c2fd9e98d168c52..a30998bcce43a38 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp
@@ -182,6 +182,9 @@ void ARM::printSpecifierExpr(const MCAsmInfo &MAI, raw_ostream &OS,
   case ARM::S_LO_0_7:
     OS << ":lower0_7:";
     break;
+  case ARM::S_COFF_SECREL:
+    OS << ":SECREL32:";
+    break;
   }
 
   const MCExpr *Sub = Expr.getSubExpr();
diff --git a/llvm/lib/Target/X86/X86TargetMachine.cpp b/llvm/lib/Target/X86/X86TargetMachine.cpp
index 72dab51b67eced2..ac093de34e48b63 100644
--- a/llvm/lib/Target/X86/X86TargetMachine.cpp
+++ b/llvm/lib/Target/X86/X86TargetMachine.cpp
@@ -120,7 +120,7 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
   }
 
   if (TT.isOSBinFormatCOFF())
-    return std::make_unique<TargetLoweringObjectFileCOFF>();
+    return std::make_unique<X86COFFTargetObjectFile>();
 
   if (TT.isX86_64())
     return std::make_unique<X86_64ELFTargetObjectFile>();
diff --git a/llvm/lib/Target/X86/X86TargetObjectFile.cpp b/llvm/lib/Target/X86/X86TargetObjectFile.cpp
index fc3c06fcc1c9bc6..f6998a517c8d420 100644
--- a/llvm/lib/Target/X86/X86TargetObjectFile.cpp
+++ b/llvm/lib/Target/X86/X86TargetObjectFile.cpp
@@ -71,3 +71,8 @@ const MCExpr *X86_64ELFTargetObjectFile::getIndirectSymViaGOTPCRel(
   const MCExpr *Off = MCConstantExpr::create(FinalOffset, getContext());
   return MCBinaryExpr::createAdd(Res, Off, getContext());
 }
+
+const MCExpr *
+X86COFFTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
+  return MCSymbolRefExpr::create(Sym, X86::S_COFF_SECREL, getContext());
+}
diff --git a/llvm/lib/Target/X86/X86TargetObjectFile.h b/llvm/lib/Target/X86/X86TargetObjectFile.h
index cb096f4a9febbc9..0dc6df4486b2761 100644
--- a/llvm/lib/Target/X86/X86TargetObjectFile.h
+++ b/llvm/lib/Target/X86/X86TargetObjectFile.h
@@ -58,6 +58,13 @@ namespace llvm {
                               MCStreamer &Streamer) const override;
   };
 
+  class X86COFFTargetObjectFile : public TargetLoweringObjectFileCOFF {
+  public:
+    X86COFFTargetObjectFile() = default;
+
+    const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
+  };
+
 } // end namespace llvm
 
 #endif
diff --git a/llvm/test/DebugInfo/AArch64/coff-tls-dwarf.ll b/llvm/test/DebugInfo/AArch64/coff-tls-dwarf.ll
new file mode 100644
index 000000000000000..a3428d6f81308b4
--- /dev/null
+++ b/llvm/test/DebugInfo/AArch64/coff-tls-dwarf.ll
@@ -0,0 +1,51 @@
+; RUN: llc -mtriple=aarch64-pc-windows-msvc -O0 -filetype=asm < %s | FileCheck --check-prefixes=CHECK %s
+
+; CHECK: 	.section	.debug_info
+
+; CHECK: // Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               // DW_AT_location
+; DW_OP_const4u
+; CHECK-NEXT: 	.byte	12
+; CHECK-NEXT: 	.word	:SECREL32:tls1
+; DW_OP_GNU_push_tls_address
+; CHECK-NEXT: 	.byte	224
+
+; CHECK: // Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               // DW_AT_location
+; DW_OP_const4u
+; CHECK: 	.byte	12
+; CHECK-NEXT: 	.word	:SECREL32:tls2
+; DW_OP_GNU_push_tls_address
+; CHECK: 	.byte	224
+
+; CHECK: // Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               // DW_AT_location
+; DW_OP_const4u
+; CHECK-NEXT: 	.byte	12
+; CHECK-NEXT: 	.word	:SECREL32:tls3
+; DW_OP_GNU_push_tls_address
+; CHECK-NEXT: 	.byte	224
+
+source_filename = "test/DebugInfo/AArch64/tls.ll"
+
+ at tls1 = thread_local global i32 1, align 4, !dbg !0
+ at tls2 = thread_local global i32 2, align 4, !dbg !2
+ at tls3 = thread_local global i64 3, align 8, !dbg !4
+
+!llvm.dbg.cu = !{!9}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = !DIGlobalVariable(name: "tls1", scope: null, file: !6, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = !DIGlobalVariableExpression(var: !3, expr: !DIExpression())
+!3 = !DIGlobalVariable(name: "tls2", scope: null, file: !6, line: 2, type: !7, isLocal: false, isDefinition: true)
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = !DIGlobalVariable(name: "tls3", scope: null, file: !6, line: 3, type: !8, isLocal: false, isDefinition: true)
+!6 = !DIFile(filename: "tls.cpp", directory: "/tmp")
+!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!8 = !DIBasicType(name: "long long", size: 64, align: 64, encoding: DW_ATE_signed)
+!9 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !10, retainedTypes: !10, globals: !11, imports: !10)
+!10 = !{}
+!11 = !{!0,!2,!4}
+!12 = !{i32 7, !"Dwarf Version", i32 4}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
diff --git a/llvm/test/DebugInfo/ARM/coff-tls-dwarf.ll b/llvm/test/DebugInfo/ARM/coff-tls-dwarf.ll
new file mode 100644
index 000000000000000..3b4f8867aa7e0c1
--- /dev/null
+++ b/llvm/test/DebugInfo/ARM/coff-tls-dwarf.ll
@@ -0,0 +1,51 @@
+; RUN: llc -mtriple=thumbv7-pc-windows-msvc -O0 -filetype=asm < %s | FileCheck --check-prefixes=CHECK %s
+
+; CHECK: 	.section	.debug_info
+
+; CHECK: @ Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               @ DW_AT_location
+; DW_OP_const4u
+; CHECK-NEXT: 	.byte	12
+; CHECK-NEXT: 	.long	:SECREL32:tls1
+; DW_OP_GNU_push_tls_address
+; CHECK-NEXT: 	.byte	224
+
+; CHECK: @ Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               @ DW_AT_location
+; DW_OP_const4u
+; CHECK: 	.byte	12
+; CHECK-NEXT: 	.long	:SECREL32:tls2
+; DW_OP_GNU_push_tls_address
+; CHECK: 	.byte	224
+
+; CHECK: @ Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               @ DW_AT_location
+; DW_OP_const4u
+; CHECK-NEXT: 	.byte	12
+; CHECK-NEXT: 	.long	:SECREL32:tls3
+; DW_OP_GNU_push_tls_address
+; CHECK-NEXT: 	.byte	224
+
+source_filename = "test/DebugInfo/ARM/tls.ll"
+
+ at tls1 = thread_local global i32 1, align 4, !dbg !0
+ at tls2 = thread_local global i32 2, align 4, !dbg !2
+ at tls3 = thread_local global i64 3, align 8, !dbg !4
+
+!llvm.dbg.cu = !{!9}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = !DIGlobalVariable(name: "tls1", scope: null, file: !6, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = !DIGlobalVariableExpression(var: !3, expr: !DIExpression())
+!3 = !DIGlobalVariable(name: "tls2", scope: null, file: !6, line: 2, type: !7, isLocal: false, isDefinition: true)
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = !DIGlobalVariable(name: "tls3", scope: null, file: !6, line: 3, type: !8, isLocal: false, isDefinition: true)
+!6 = !DIFile(filename: "tls.cpp", directory: "/tmp")
+!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!8 = !DIBasicType(name: "long long", size: 64, align: 64, encoding: DW_ATE_signed)
+!9 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !10, retainedTypes: !10, globals: !11, imports: !10)
+!10 = !{}
+!11 = !{!0,!2,!4}
+!12 = !{i32 7, !"Dwarf Version", i32 4}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
diff --git a/llvm/test/DebugInfo/X86/coff-tls-dwarf.ll b/llvm/test/DebugInfo/X86/coff-tls-dwarf.ll
new file mode 100644
index 000000000000000..0f8c468014f9a8a
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/coff-tls-dwarf.ll
@@ -0,0 +1,55 @@
+; RUN: llc -mtriple=x86_64-pc-windows-msvc -O0 -filetype=asm < %s | FileCheck --check-prefixes=CHECK,X86-64 %s
+; RUN: llc -mtriple=i686-pc-windows-msvc -O0 -filetype=asm < %s | FileCheck --check-prefixes=CHECK,I686 %s
+
+; CHECK: 	.section	.debug_info
+
+; CHECK: # Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               # DW_AT_location
+; DW_OP_const4u
+; CHECK-NEXT: 	.byte	12
+; X86-64-NEXT: 	.long	tls1 at SECREL32
+; I686-NEXT:  	.long	_tls1 at SECREL32
+; DW_OP_GNU_push_tls_address
+; CHECK-NEXT: 	.byte	224
+
+; CHECK: # Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               # DW_AT_location
+; DW_OP_const4u
+; CHECK: 	.byte	12
+; X86-64-NEXT: 	.long	tls2 at SECREL32
+; I686-NEXT:  	.long	_tls2 at SECREL32
+; DW_OP_GNU_push_tls_address
+; CHECK: 	.byte	224
+
+; CHECK: # Abbrev {{.*}} DW_TAG_variable
+; CHECK: 	.byte	6                               # DW_AT_location
+; DW_OP_const4u
+; CHECK-NEXT: 	.byte	12
+; X86-64-NEXT: 	.long	tls3 at SECREL32
+; I686-NEXT:  	.long	_tls3 at SECREL32
+; DW_OP_GNU_push_tls_address
+; CHECK-NEXT: 	.byte	224
+
+source_filename = "test/DebugInfo/X86/tls.ll"
+
+ at tls1 = thread_local global i32 1, align 4, !dbg !0
+ at tls2 = thread_local global i32 2, align 4, !dbg !2
+ at tls3 = thread_local global i64 3, align 8, !dbg !4
+
+!llvm.dbg.cu = !{!9}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = !DIGlobalVariable(name: "tls1", scope: null, file: !6, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = !DIGlobalVariableExpression(var: !3, expr: !DIExpression())
+!3 = !DIGlobalVariable(name: "tls2", scope: null, file: !6, line: 2, type: !7, isLocal: false, isDefinition: true)
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = !DIGlobalVariable(name: "tls3", scope: null, file: !6, line: 3, type: !8, isLocal: false, isDefinition: true)
+!6 = !DIFile(filename: "tls.cpp", directory: "/tmp")
+!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!8 = !DIBasicType(name: "long long", size: 64, align: 64, encoding: DW_ATE_signed)
+!9 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !10, retainedTypes: !10, globals: !11, imports: !10)
+!10 = !{}
+!11 = !{!0,!2,!4}
+!12 = !{i32 7, !"Dwarf Version", i32 4}
+!13 = !{i32 2, !"Debug Info Version", i32 3}



More information about the llvm-commits mailing list