[llvm] r327220 - [AArch64] Implement native TLS for Windows

Martin Storsjo via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 10 11:05:21 PST 2018


Author: mstorsjo
Date: Sat Mar 10 11:05:21 2018
New Revision: 327220

URL: http://llvm.org/viewvc/llvm-project?rev=327220&view=rev
Log:
[AArch64] Implement native TLS for Windows

Differential Revision: https://reviews.llvm.org/D43971

Added:
    llvm/trunk/test/CodeGen/AArch64/win-tls.ll
Modified:
    llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp
    llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h
    llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td
    llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp

Modified: llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp?rev=327220&r1=327219&r2=327220&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp Sat Mar 10 11:05:21 2018
@@ -3976,6 +3976,67 @@ AArch64TargetLowering::LowerELFGlobalTLS
   return DAG.getNode(ISD::ADD, DL, PtrVT, ThreadBase, TPOff);
 }
 
+SDValue
+AArch64TargetLowering::LowerWindowsGlobalTLSAddress(SDValue Op,
+                                                    SelectionDAG &DAG) const {
+  assert(Subtarget->isTargetWindows() && "Windows specific TLS lowering");
+
+  SDValue Chain = DAG.getEntryNode();
+  EVT PtrVT = getPointerTy(DAG.getDataLayout());
+  SDLoc DL(Op);
+
+  SDValue TEB = DAG.getRegister(AArch64::X18, MVT::i64);
+
+  // Load the ThreadLocalStoragePointer from the TEB
+  // A pointer to the TLS array is located at offset 0x58 from the TEB.
+  SDValue TLSArray =
+      DAG.getNode(ISD::ADD, DL, PtrVT, TEB, DAG.getIntPtrConstant(0x58, DL));
+  TLSArray = DAG.getLoad(PtrVT, DL, Chain, TLSArray, MachinePointerInfo());
+  Chain = TLSArray.getValue(1);
+
+  // Load the TLS index from the C runtime;
+  // This does the same as getAddr(), but without having a GlobalAddressSDNode.
+  // This also does the same as LOADgot, but using a generic i32 load,
+  // while LOADgot only loads i64.
+  SDValue TLSIndexHi =
+      DAG.getTargetExternalSymbol("_tls_index", PtrVT, AArch64II::MO_PAGE);
+  SDValue TLSIndexLo = DAG.getTargetExternalSymbol(
+      "_tls_index", PtrVT, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
+  SDValue ADRP = DAG.getNode(AArch64ISD::ADRP, DL, PtrVT, TLSIndexHi);
+  SDValue TLSIndex =
+      DAG.getNode(AArch64ISD::ADDlow, DL, PtrVT, ADRP, TLSIndexLo);
+  TLSIndex = DAG.getLoad(MVT::i32, DL, Chain, TLSIndex, MachinePointerInfo());
+  Chain = TLSIndex.getValue(1);
+
+  // The pointer to the thread's TLS data area is at the TLS Index scaled by 8
+  // offset into the TLSArray.
+  TLSIndex = DAG.getNode(ISD::ZERO_EXTEND, DL, PtrVT, TLSIndex);
+  SDValue Slot = DAG.getNode(ISD::SHL, DL, PtrVT, TLSIndex,
+                             DAG.getConstant(3, DL, PtrVT));
+  SDValue TLS = DAG.getLoad(PtrVT, DL, Chain,
+                            DAG.getNode(ISD::ADD, DL, PtrVT, TLSArray, Slot),
+                            MachinePointerInfo());
+  Chain = TLS.getValue(1);
+
+  const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
+  const GlobalValue *GV = GA->getGlobal();
+  SDValue TGAHi = DAG.getTargetGlobalAddress(
+      GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_HI12);
+  SDValue TGALo = DAG.getTargetGlobalAddress(
+      GV, DL, PtrVT, 0,
+      AArch64II::MO_TLS | AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
+
+  // Add the offset from the start of the .tls section (section base).
+  SDValue Addr =
+      SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, TLS, TGAHi,
+                                 DAG.getTargetConstant(0, DL, MVT::i32)),
+              0);
+  Addr = SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, Addr, TGALo,
+                                    DAG.getTargetConstant(0, DL, MVT::i32)),
+                 0);
+  return Addr;
+}
+
 SDValue AArch64TargetLowering::LowerGlobalTLSAddress(SDValue Op,
                                                      SelectionDAG &DAG) const {
   const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
@@ -3986,6 +4047,8 @@ SDValue AArch64TargetLowering::LowerGlob
     return LowerDarwinGlobalTLSAddress(Op, DAG);
   if (Subtarget->isTargetELF())
     return LowerELFGlobalTLSAddress(Op, DAG);
+  if (Subtarget->isTargetWindows())
+    return LowerWindowsGlobalTLSAddress(Op, DAG);
 
   llvm_unreachable("Unexpected platform trying to use TLS");
 }

Modified: llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h?rev=327220&r1=327219&r2=327220&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h Sat Mar 10 11:05:21 2018
@@ -560,6 +560,7 @@ private:
   SDValue LowerELFGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerELFTLSDescCallSeq(SDValue SymAddr, const SDLoc &DL,
                                  SelectionDAG &DAG) const;
+  SDValue LowerWindowsGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const;

Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td?rev=327220&r1=327219&r2=327220&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td Sat Mar 10 11:05:21 2018
@@ -1331,6 +1331,7 @@ def ADRP : ADRI<1, "adrp", adrplabel,
 // page address of a constant pool entry, block address
 def : Pat<(AArch64adrp tconstpool:$cp), (ADRP tconstpool:$cp)>;
 def : Pat<(AArch64adrp tblockaddress:$cp), (ADRP tblockaddress:$cp)>;
+def : Pat<(AArch64adrp texternalsym:$sym), (ADRP texternalsym:$sym)>;
 
 //===----------------------------------------------------------------------===//
 // Unconditional branch (register) instructions.

Modified: llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp?rev=327220&r1=327219&r2=327220&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp Sat Mar 10 11:05:21 2018
@@ -173,11 +173,20 @@ MCOperand AArch64MCInstLower::lowerSymbo
 
 MCOperand AArch64MCInstLower::lowerSymbolOperandCOFF(const MachineOperand &MO,
                                                      MCSymbol *Sym) const {
-  MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
-  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
+  AArch64MCExpr::VariantKind RefKind = AArch64MCExpr::VK_NONE;
+  if (MO.getTargetFlags() & AArch64II::MO_TLS) {
+    if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) == AArch64II::MO_PAGEOFF)
+      RefKind = AArch64MCExpr::VK_SECREL_LO12;
+    else if ((MO.getTargetFlags() & AArch64II::MO_FRAGMENT) ==
+             AArch64II::MO_HI12)
+      RefKind = AArch64MCExpr::VK_SECREL_HI12;
+  }
+  const MCExpr *Expr =
+      MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
   if (!MO.isJTI() && MO.getOffset())
     Expr = MCBinaryExpr::createAdd(
         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
+  Expr = AArch64MCExpr::create(Expr, RefKind, Ctx);
   return MCOperand::createExpr(Expr);
 }
 

Added: llvm/trunk/test/CodeGen/AArch64/win-tls.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/win-tls.ll?rev=327220&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/win-tls.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/win-tls.ll Sat Mar 10 11:05:21 2018
@@ -0,0 +1,72 @@
+; RUN: llc -mtriple aarch64-windows %s -o - | FileCheck %s
+
+ at tlsVar = thread_local global i32 0
+ at tlsVar8 = thread_local global i8 0
+ at tlsVar64 = thread_local global i64 0
+
+define i32 @getVar() {
+  %1 = load i32, i32* @tlsVar
+  ret i32 %1
+}
+
+define i32* @getPtr() {
+  ret i32* @tlsVar
+}
+
+define void @setVar(i32 %val) {
+  store i32 %val, i32* @tlsVar
+  ret void
+}
+
+define i8 @getVar8() {
+  %1 = load i8, i8* @tlsVar8
+  ret i8 %1
+}
+
+define i64 @getVar64() {
+  %1 = load i64, i64* @tlsVar64
+  ret i64 %1
+}
+
+; CHECK-LABEL: getVar
+; CHECK: adrp [[TLS_INDEX_ADDR:x[0-9]+]], _tls_index
+; CHECK: ldr w[[TLS_INDEX:[0-9]+]], {{\[}}[[TLS_INDEX_ADDR]], _tls_index]
+; CHECK: ldr [[TLS_POINTER:x[0-9]+]], [x18, #88]
+
+; CHECK: ldr [[TLS:x[0-9]+]], {{\[}}[[TLS_POINTER]], x[[TLS_INDEX]], lsl #3]
+; CHECK: add [[TLS]], [[TLS]], :secrel_hi12:tlsVar
+; This add+ldr could also be folded into a single ldr with a :secrel_lo12:
+; offset.
+; CHECK: add [[TLS]], [[TLS]], :secrel_lo12:tlsVar
+; CHECK: ldr w0, {{\[}}[[TLS]]{{\]}}
+
+; CHECK-LABEL: getPtr
+; CHECK: adrp [[TLS_INDEX_ADDR:x[0-9]+]], _tls_index
+; CHECK: ldr w[[TLS_INDEX:[0-9]+]], {{\[}}[[TLS_INDEX_ADDR]], _tls_index]
+; CHECK: ldr [[TLS_POINTER:x[0-9]+]], [x18, #88]
+
+; CHECK: ldr [[TLS:x[0-9]+]], {{\[}}[[TLS_POINTER]], x[[TLS_INDEX]], lsl #3]
+; CHECK: add [[TLS]], [[TLS]], :secrel_hi12:tlsVar
+; CHECK: add x0, [[TLS]], :secrel_lo12:tlsVar
+
+; CHECK-LABEL: setVar
+; CHECK: adrp [[TLS_INDEX_ADDR:x[0-9]+]], _tls_index
+; CHECK: ldr w[[TLS_INDEX:[0-9]+]], {{\[}}[[TLS_INDEX_ADDR]], _tls_index]
+; CHECK: ldr [[TLS_POINTER:x[0-9]+]], [x18, #88]
+
+; CHECK: ldr [[TLS:x[0-9]+]], {{\[}}[[TLS_POINTER]], x[[TLS_INDEX]], lsl #3]
+; CHECK: add [[TLS]], [[TLS]], :secrel_hi12:tlsVar
+; This add+ldr could also be folded into a single ldr with a :secrel_lo12:
+; offset.
+; CHECK: add [[TLS]], [[TLS]], :secrel_lo12:tlsVar
+; CHECK: str w0, {{\[}}[[TLS]]{{\]}}
+
+; CHECK-LABEL: getVar8
+; CHECK: add [[TLS:x[0-9]+]], [[TLS]], :secrel_hi12:tlsVar8
+; CHECK: add [[TLS]], [[TLS]], :secrel_lo12:tlsVar8
+; CHECK: ldrb w0, {{\[}}[[TLS]]{{\]}}
+
+; CHECK-LABEL: getVar64
+; CHECK: add [[TLS:x[0-9]+]], [[TLS]], :secrel_hi12:tlsVar64
+; CHECK: add [[TLS]], [[TLS]], :secrel_lo12:tlsVar64
+; CHECK: ldr x0, {{\[}}[[TLS]]{{\]}}




More information about the llvm-commits mailing list