[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