diff options
author | Saleem Abdulrasool <compnerd@compnerd.org> | 2016-02-03 18:21:59 +0000 |
---|---|---|
committer | Saleem Abdulrasool <compnerd@compnerd.org> | 2016-02-03 18:21:59 +0000 |
commit | f36005a358472f99da74de37bbf1a3e6661694f3 (patch) | |
tree | 7caac02bd2676e510c38070bdb4f72847a9528c9 | |
parent | 97de385868d73e5ea81494fc380c35507798893f (diff) | |
download | bcm5719-llvm-f36005a358472f99da74de37bbf1a3e6661694f3.tar.gz bcm5719-llvm-f36005a358472f99da74de37bbf1a3e6661694f3.zip |
ARM: support TLS for WoA
Add support for TLS access for Windows on ARM. This generates a similar access
to MSVC for ARM.
The changes to the tablegen data is needed to support loading an external symbol
global that is not for a call. The adjustments to the DAG to DAG transforms are
needed to preserve the 32-bit move.
llvm-svn: 259676
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.cpp | 52 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMInstrInfo.td | 2 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMInstrThumb2.td | 2 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/Windows/tls.ll | 143 |
6 files changed, 205 insertions, 0 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp index 89e0bab3d0b..afeee047048 100644 --- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -623,6 +623,7 @@ bool ARMDAGToDAGISel::SelectAddrModeImm12(SDValue N, if (N.getOpcode() == ARMISD::Wrapper && N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress && + N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol && N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) { Base = N.getOperand(0); } else @@ -803,6 +804,7 @@ AddrMode2Type ARMDAGToDAGISel::SelectAddrMode2Worker(SDValue N, FI, TLI->getPointerTy(CurDAG->getDataLayout())); } else if (N.getOpcode() == ARMISD::Wrapper && N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress && + N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol && N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) { Base = N.getOperand(0); } @@ -1070,6 +1072,7 @@ bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N, FI, TLI->getPointerTy(CurDAG->getDataLayout())); } else if (N.getOpcode() == ARMISD::Wrapper && N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress && + N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol && N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) { Base = N.getOperand(0); } @@ -1190,6 +1193,7 @@ ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, return false; // We want to select register offset instead } else if (N.getOpcode() == ARMISD::Wrapper && N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress && + N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol && N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) { Base = N.getOperand(0); } else { @@ -1297,6 +1301,7 @@ bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue N, if (N.getOpcode() == ARMISD::Wrapper && N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress && + N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol && N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) { Base = N.getOperand(0); if (Base.getOpcode() == ISD::TargetConstantPool) diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 496358ea609..228b18bbbd4 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2613,6 +2613,55 @@ ARMTargetLowering::LowerGlobalTLSAddressDarwin(SDValue Op, return DAG.getCopyFromReg(Chain, DL, ARM::R0, MVT::i32, Chain.getValue(1)); } +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); + + // Load the current TEB (thread environment block) + SDValue Ops[] = {Chain, + DAG.getConstant(Intrinsic::arm_mrc, DL, MVT::i32), + DAG.getConstant(15, DL, MVT::i32), + DAG.getConstant(0, DL, MVT::i32), + DAG.getConstant(13, DL, MVT::i32), + DAG.getConstant(0, DL, MVT::i32), + DAG.getConstant(2, DL, MVT::i32)}; + SDValue CurrentTEB = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL, + DAG.getVTList(MVT::i32, MVT::Other), Ops); + + SDValue TEB = CurrentTEB.getValue(0); + Chain = CurrentTEB.getValue(1); + + // Load the ThreadLocalStoragePointer from the TEB + // A pointer to the TLS array is located at offset 0x2c from the TEB. + SDValue TLSArray = + DAG.getNode(ISD::ADD, DL, PtrVT, TEB, DAG.getIntPtrConstant(0x2c, DL)); + TLSArray = DAG.getLoad(PtrVT, DL, Chain, TLSArray, MachinePointerInfo(), + false, false, false, 0); + + // The pointer to the thread's TLS data area is at the TLS Index scaled by 4 + // offset into the TLSArray. + + // Load the TLS index from the C runtime + SDValue TLSIndex = + DAG.getTargetExternalSymbol("_tls_index", PtrVT, ARMII::MO_NO_FLAG); + TLSIndex = DAG.getNode(ARMISD::Wrapper, DL, PtrVT, TLSIndex); + TLSIndex = DAG.getLoad(PtrVT, DL, Chain, TLSIndex, MachinePointerInfo(), + false, false, false, 0); + + SDValue Slot = DAG.getNode(ISD::SHL, DL, PtrVT, TLSIndex, + DAG.getConstant(2, DL, MVT::i32)); + SDValue TLS = DAG.getLoad(PtrVT, DL, Chain, + DAG.getNode(ISD::ADD, DL, PtrVT, TLSArray, Slot), + MachinePointerInfo(), false, false, false, 0); + + return DAG.getNode(ISD::ADD, DL, PtrVT, TLS, + LowerGlobalAddressWindows(Op, DAG)); +} + // Lower ISD::GlobalTLSAddress using the "general dynamic" model SDValue ARMTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, @@ -2717,6 +2766,9 @@ ARMTargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { if (Subtarget->isTargetDarwin()) return LowerGlobalTLSAddressDarwin(Op, DAG); + if (Subtarget->isTargetWindows()) + return LowerGlobalTLSAddressWindows(Op, DAG); + // TODO: implement the "local dynamic" model assert(Subtarget->isTargetELF() && "Only ELF implemented here"); GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h index 96b56c3ec33..a502ca12fa8 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/llvm/lib/Target/ARM/ARMISelLowering.h @@ -527,6 +527,7 @@ namespace llvm { SelectionDAG &DAG, TLSModel::Model model) const; SDValue LowerGlobalTLSAddressDarwin(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalTLSAddressWindows(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const; SDValue LowerXALUO(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td index 776e53bc459..32513e90043 100644 --- a/llvm/lib/Target/ARM/ARMInstrInfo.td +++ b/llvm/lib/Target/ARM/ARMInstrInfo.td @@ -5453,6 +5453,8 @@ def : Pat<(load (ARMWrapperPIC tglobaltlsaddr:$addr)), def : ARMPat<(ARMWrapper tconstpool :$dst), (LEApcrel tconstpool :$dst)>; def : ARMPat<(ARMWrapper tglobaladdr :$dst), (MOVi32imm tglobaladdr :$dst)>, Requires<[IsARM, UseMovt]>; +def : ARMPat<(ARMWrapper texternalsym :$dst), (MOVi32imm texternalsym :$dst)>, + Requires<[IsARM, UseMovt]>; def : ARMPat<(ARMWrapperJT tjumptable:$dst), (LEApcrelJT tjumptable:$dst)>; diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td index a63bf9abcdf..48c72beb73f 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb2.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td @@ -3906,6 +3906,8 @@ def : T2Pat<(ARMWrapper tglobaltlsaddr:$dst), // ConstantPool, GlobalAddress, and JumpTable def : T2Pat<(ARMWrapper tconstpool :$dst), (t2LEApcrel tconstpool :$dst)>; +def : T2Pat<(ARMWrapper texternalsym :$dst), (t2MOVi32imm texternalsym : $dst)>, + Requires<[IsThumb, HasV8MBaseline, UseMovt]>; def : T2Pat<(ARMWrapper tglobaladdr :$dst), (t2MOVi32imm tglobaladdr :$dst)>, Requires<[IsThumb, HasV8MBaseline, UseMovt]>; diff --git a/llvm/test/CodeGen/ARM/Windows/tls.ll b/llvm/test/CodeGen/ARM/Windows/tls.ll new file mode 100644 index 00000000000..9022f8af9f5 --- /dev/null +++ b/llvm/test/CodeGen/ARM/Windows/tls.ll @@ -0,0 +1,143 @@ +; RUN: llc -mtriple thumbv7--windows %s -o - | FileCheck %s + +@i = thread_local global i32 0 +@j = external thread_local global i32 +@k = internal thread_local global i32 0 +@l = hidden thread_local global i32 0 +@m = external hidden thread_local global i32 +@n = thread_local global i16 0 +@o = thread_local global i8 0 + +define i32 @f() { + %1 = load i32, i32* @i + ret i32 %1 +} + +; CHECK: mrc p15, #0, [[TEB:r[0-9]]], c13, c0, #2 + +; CHECK: movw [[TLS_INDEX:r[0-9]]], :lower16:_tls_index +; CHECK-NEXT: movt [[TLS_INDEX]], :upper16:_tls_index +; CHECK-NEXT: ldr [[INDEX:r[0-9]]], {{\[}}[[TLS_INDEX]]] + +; 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 r0, {{\[}}[[TLS]], [[SLOT]]] + +define i32 @e() { + %1 = load i32, i32* @j + ret i32 %1 +} + +; CHECK: mrc p15, #0, [[TEB:r[0-9]]], c13, c0, #2 + +; CHECK: movw [[TLS_INDEX:r[0-9]]], :lower16:_tls_index +; CHECK-NEXT: movt [[TLS_INDEX]], :upper16:_tls_index +; CHECK-NEXT: ldr [[INDEX:r[0-9]]], {{\[}}[[TLS_INDEX]]] + +; 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 r0, {{\[}}[[TLS]], [[SLOT]]] + +define i32 @d() { + %1 = load i32, i32* @k + ret i32 %1 +} + +; CHECK: mrc p15, #0, [[TEB:r[0-9]]], c13, c0, #2 + +; CHECK: movw [[TLS_INDEX:r[0-9]]], :lower16:_tls_index +; CHECK-NEXT: movt [[TLS_INDEX]], :upper16:_tls_index +; CHECK-NEXT: ldr [[INDEX:r[0-9]]], {{\[}}[[TLS_INDEX]]] + +; 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 r0, {{\[}}[[TLS]], [[SLOT]]] + +define i32 @c() { + %1 = load i32, i32* @l + ret i32 %1 +} + +; CHECK: mrc p15, #0, [[TEB:r[0-9]]], c13, c0, #2 + +; CHECK: movw [[TLS_INDEX:r[0-9]]], :lower16:_tls_index +; CHECK-NEXT: movt [[TLS_INDEX]], :upper16:_tls_index +; CHECK-NEXT: ldr [[INDEX:r[0-9]]], {{\[}}[[TLS_INDEX]]] + +; 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 r0, {{\[}}[[TLS]], [[SLOT]]] + +define i32 @b() { + %1 = load i32, i32* @m + ret i32 %1 +} + +; CHECK: mrc p15, #0, [[TEB:r[0-9]]], c13, c0, #2 + +; CHECK: movw [[TLS_INDEX:r[0-9]]], :lower16:_tls_index +; CHECK-NEXT: movt [[TLS_INDEX]], :upper16:_tls_index +; CHECK-NEXT: ldr [[INDEX:r[0-9]]], {{\[}}[[TLS_INDEX]]] + +; 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 r0, {{\[}}[[TLS]], [[SLOT]]] + +define i16 @a() { + %1 = load i16, i16* @n + ret i16 %1 +} + +; CHECK: mrc p15, #0, [[TEB:r[0-9]]], c13, c0, #2 + +; CHECK: movw [[TLS_INDEX:r[0-9]]], :lower16:_tls_index +; CHECK-NEXT: movt [[TLS_INDEX]], :upper16:_tls_index +; CHECK-NEXT: ldr [[INDEX:r[0-9]]], {{\[}}[[TLS_INDEX]]] + +; 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: ldrh r0, {{\[}}[[TLS]], [[SLOT]]] + +define i8 @Z() { + %1 = load i8, i8* @o + ret i8 %1 +} + +; CHECK: mrc p15, #0, [[TEB:r[0-9]]], c13, c0, #2 + +; CHECK: movw [[TLS_INDEX:r[0-9]]], :lower16:_tls_index +; CHECK-NEXT: movt [[TLS_INDEX]], :upper16:_tls_index +; CHECK-NEXT: ldr [[INDEX:r[0-9]]], {{\[}}[[TLS_INDEX]]] + +; 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: ldrb r0, {{\[}}[[TLS]], [[SLOT]]] + |