diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 71fa0a51ac9..27bf01b5dff 100644 --- a/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -902,6 +902,8 @@ getModifierVariantKind(ARMCP::ARMCPModifier Modifier) { return MCSymbolRefExpr::VK_GOTTPOFF; case ARMCP::GOT_PREL: return MCSymbolRefExpr::VK_ARM_GOT_PREL; + case ARMCP::SECREL: + return MCSymbolRefExpr::VK_SECREL; } llvm_unreachable("Invalid ARMCPModifier!"); } diff --git a/lib/Target/ARM/ARMConstantPoolValue.cpp b/lib/Target/ARM/ARMConstantPoolValue.cpp index 2dbe236cc77..c0db001cb6f 100644 --- a/lib/Target/ARM/ARMConstantPoolValue.cpp +++ b/lib/Target/ARM/ARMConstantPoolValue.cpp @@ -60,6 +60,8 @@ const char *ARMConstantPoolValue::getModifierText() const { return "gottpoff"; case ARMCP::TPOFF: return "tpoff"; + case ARMCP::SECREL: + return "secrel32"; } llvm_unreachable("Unknown modifier!"); } diff --git a/lib/Target/ARM/ARMConstantPoolValue.h b/lib/Target/ARM/ARMConstantPoolValue.h index f719df8fe04..c07331d71da 100644 --- a/lib/Target/ARM/ARMConstantPoolValue.h +++ b/lib/Target/ARM/ARMConstantPoolValue.h @@ -42,6 +42,7 @@ namespace ARMCP { GOT_PREL, /// Global Offset Table, PC Relative GOTTPOFF, /// Global Offset Table, Thread Pointer Offset TPOFF, /// Thread Pointer Offset + SECREL, /// Section Relative (Windows TLS) }; } diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 6a05e5473bb..a5c698bc4ed 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -2622,6 +2622,7 @@ SDValue ARMTargetLowering::LowerGlobalTLSAddressWindows(SDValue Op, SelectionDAG &DAG) const { assert(Subtarget->isTargetWindows() && "Windows specific TLS lowering"); + SDValue Chain = DAG.getEntryNode(); EVT PtrVT = getPointerTy(DAG.getDataLayout()); SDLoc DL(Op); @@ -2663,8 +2664,17 @@ ARMTargetLowering::LowerGlobalTLSAddressWindows(SDValue Op, DAG.getNode(ISD::ADD, DL, PtrVT, TLSArray, Slot), MachinePointerInfo(), false, false, false, 0); - return DAG.getNode(ISD::ADD, DL, PtrVT, TLS, - LowerGlobalAddressWindows(Op, DAG)); + // Get the offset of the start of the .tls section (section base) + const auto *GA = cast(Op); + auto *CPV = ARMConstantPoolConstant::Create(GA->getGlobal(), ARMCP::SECREL); + SDValue Offset = + DAG.getLoad(PtrVT, DL, Chain, + DAG.getNode(ARMISD::Wrapper, DL, MVT::i32, + DAG.getTargetConstantPool(CPV, PtrVT, 4)), + MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), + false, false, false, 0); + + return DAG.getNode(ISD::ADD, DL, PtrVT, TLS, Offset); } // Lower ISD::GlobalTLSAddress using the "general dynamic" model diff --git a/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h b/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h index 4289a73e9d6..5bc10d613a3 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h +++ b/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h @@ -295,12 +295,18 @@ namespace ARMII { /// MO_OPTION_MASK - Most flags are mutually exclusive; this mask selects /// just that part of the flag set. - MO_OPTION_MASK = 0x3f, + MO_OPTION_MASK = 0x1f, /// MO_DLLIMPORT - On a symbol operand, this represents that the reference /// to the symbol is for an import stub. This is used for DLL import /// storage class indication on Windows. - MO_DLLIMPORT = 0x40, + MO_DLLIMPORT = 0x20, + + /// MO_SECREL - On a symbol operand this indicates that the immediate is + /// the offset from beginning of section. + /// + /// This is the TLS offset for the COFF/Windows TLS mechanism. + MO_SECREL = 0x40, /// MO_NONLAZY - This is an independent flag, on a symbol operand "FOO" it /// represents a symbol which, if indirect, will get special Darwin mangling diff --git a/test/CodeGen/ARM/Windows/tls.ll b/test/CodeGen/ARM/Windows/tls.ll index 9022f8af9f5..689f4e29187 100644 --- a/test/CodeGen/ARM/Windows/tls.ll +++ b/test/CodeGen/ARM/Windows/tls.ll @@ -1,4 +1,4 @@ -; RUN: llc -mtriple thumbv7--windows %s -o - | FileCheck %s +; RUN: llc -mtriple thumbv7--windows-itanium %s -o - | FileCheck %s @i = thread_local global i32 0 @j = external thread_local global i32 @@ -22,11 +22,13 @@ define i32 @f() { ; CHECK: ldr [[TLS_POINTER:r[0-9]]], {{\[}}[[TEB]], #44] ; CHECK-NEXT: ldr{{.w}} [[TLS:r[0-9]]], {{\[}}[[TLS_POINTER]], [[INDEX]], lsl #2] -; CHECK-NEXT: movw [[SLOT:r[0-9]]], :lower16:i -; CHECK-NEXT: movt [[SLOT]], :upper16:i +; CHECK-NEXT: ldr [[SLOT:r[0-9]]], [[CPI:LCPI[0-9]+_[0-9]+]] ; CHECK-NEXT: ldr r0, {{\[}}[[TLS]], [[SLOT]]] +; CHECK: [[CPI]]: +; CHECK-NEXT: .long i(SECREL32) + define i32 @e() { %1 = load i32, i32* @j ret i32 %1 @@ -41,11 +43,13 @@ define i32 @e() { ; CHECK: ldr [[TLS_POINTER:r[0-9]]], {{\[}}[[TEB]], #44] ; CHECK-NEXT: ldr{{.w}} [[TLS:r[0-9]]], {{\[}}[[TLS_POINTER]], [[INDEX]], lsl #2] -; CHECK-NEXT: movw [[SLOT:r[0-9]]], :lower16:j -; CHECK-NEXT: movt [[SLOT]], :upper16:j +; CHECK-NEXT: ldr [[SLOT:r[0-9]]], [[CPI:LCPI[0-9]+_[0-9]+]] ; CHECK-NEXT: ldr r0, {{\[}}[[TLS]], [[SLOT]]] +; CHECK: [[CPI]]: +; CHECK-NEXT: .long j(SECREL32) + define i32 @d() { %1 = load i32, i32* @k ret i32 %1 @@ -60,11 +64,13 @@ define i32 @d() { ; CHECK: ldr [[TLS_POINTER:r[0-9]]], {{\[}}[[TEB]], #44] ; CHECK-NEXT: ldr{{.w}} [[TLS:r[0-9]]], {{\[}}[[TLS_POINTER]], [[INDEX]], lsl #2] -; CHECK-NEXT: movw [[SLOT:r[0-9]]], :lower16:k -; CHECK-NEXT: movt [[SLOT]], :upper16:k +; CHECK-NEXT: ldr [[SLOT:r[0-9]]], [[CPI:LCPI[0-9]+_[0-9]+]] ; CHECK-NEXT: ldr r0, {{\[}}[[TLS]], [[SLOT]]] +; CHECK: [[CPI]]: +; CHECK-NEXT: .long k(SECREL32) + define i32 @c() { %1 = load i32, i32* @l ret i32 %1 @@ -79,11 +85,13 @@ define i32 @c() { ; CHECK: ldr [[TLS_POINTER:r[0-9]]], {{\[}}[[TEB]], #44] ; CHECK-NEXT: ldr{{.w}} [[TLS:r[0-9]]], {{\[}}[[TLS_POINTER]], [[INDEX]], lsl #2] -; CHECK-NEXT: movw [[SLOT:r[0-9]]], :lower16:l -; CHECK-NEXT: movt [[SLOT]], :upper16:l +; CHECK-NEXT: ldr [[SLOT:r[0-9]]], [[CPI:LCPI[0-9]+_[0-9]+]] ; CHECK-NEXT: ldr r0, {{\[}}[[TLS]], [[SLOT]]] +; CHECK: [[CPI]]: +; CHECK-NEXT: .long l(SECREL32) + define i32 @b() { %1 = load i32, i32* @m ret i32 %1 @@ -98,11 +106,13 @@ define i32 @b() { ; CHECK: ldr [[TLS_POINTER:r[0-9]]], {{\[}}[[TEB]], #44] ; CHECK-NEXT: ldr{{.w}} [[TLS:r[0-9]]], {{\[}}[[TLS_POINTER]], [[INDEX]], lsl #2] -; CHECK-NEXT: movw [[SLOT:r[0-9]]], :lower16:m -; CHECK-NEXT: movt [[SLOT]], :upper16:m +; CHECK-NEXT: ldr [[SLOT:r[0-9]]], [[CPI:LCPI[0-9]+_[0-9]+]] ; CHECK-NEXT: ldr r0, {{\[}}[[TLS]], [[SLOT]]] +; CHECK: [[CPI]]: +; CHECK: .long m(SECREL32) + define i16 @a() { %1 = load i16, i16* @n ret i16 %1 @@ -117,11 +127,13 @@ define i16 @a() { ; CHECK: ldr [[TLS_POINTER:r[0-9]]], {{\[}}[[TEB]], #44] ; CHECK-NEXT: ldr{{.w}} [[TLS:r[0-9]]], {{\[}}[[TLS_POINTER]], [[INDEX]], lsl #2] -; CHECK-NEXT: movw [[SLOT:r[0-9]]], :lower16:n -; CHECK-NEXT: movt [[SLOT]], :upper16:n +; CHECK-NEXT: ldr [[SLOT:r[0-9]]], [[CPI:LCPI[0-9]+_[0-9]+]] ; CHECK-NEXT: ldrh r0, {{\[}}[[TLS]], [[SLOT]]] +; CHECK: [[CPI]]: +; CHECK: .long n(SECREL32) + define i8 @Z() { %1 = load i8, i8* @o ret i8 %1 @@ -136,8 +148,10 @@ define i8 @Z() { ; CHECK: ldr [[TLS_POINTER:r[0-9]]], {{\[}}[[TEB]], #44] ; CHECK-NEXT: ldr{{.w}} [[TLS:r[0-9]]], {{\[}}[[TLS_POINTER]], [[INDEX]], lsl #2] -; CHECK-NEXT: movw [[SLOT:r[0-9]]], :lower16:o -; CHECK-NEXT: movt [[SLOT]], :upper16:o +; CHECK-NEXT: ldr [[SLOT:r[0-9]]], [[CPI:LCPI[0-9]+_[0-9]+]] ; CHECK-NEXT: ldrb r0, {{\[}}[[TLS]], [[SLOT]]] +; CHECK: [[CPI]]: +; CHECK-NEXT: .long o(SECREL32) +