diff options
author | KAWASHIMA Takahiro <t-kawashima@fujitsu.com> | 2020-01-13 09:28:02 +0000 |
---|---|---|
committer | Peter Smith <peter.smith@linaro.org> | 2020-01-13 10:16:53 +0000 |
commit | 10c11e4e2d05cf0e8f8251f50d84ce77eb1e9b8d (patch) | |
tree | 77ec95e71e5e339ea077bf172e895f2de8dcb451 /llvm/lib/Target/AArch64 | |
parent | 96b8e1ac4674dd3035b6cc7b1b7ed8b946208ab1 (diff) | |
download | bcm5719-llvm-10c11e4e2d05cf0e8f8251f50d84ce77eb1e9b8d.tar.gz bcm5719-llvm-10c11e4e2d05cf0e8f8251f50d84ce77eb1e9b8d.zip |
This option allows selecting the TLS size in the local exec TLS model,
which is the default TLS model for non-PIC objects. This allows large/
many thread local variables or a compact/fast code in an executable.
Specification is same as that of GCC. For example, the code model
option precedes the TLS size option.
TLS access models other than local-exec are not changed. It means
supoort of the large code model is only in the local exec TLS model.
Patch By KAWASHIMA Takahiro (kawashima-fj <t-kawashima@fujitsu.com>)
Reviewers: dmgreen, mstorsjo, t.p.northover, peter.smith, ostannard
Reviewd By: peter.smith
Committed by: peter.smith
Differential Revision: https://reviews.llvm.org/D71688
Diffstat (limited to 'llvm/lib/Target/AArch64')
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 130 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64ISelLowering.h | 2 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64TargetMachine.cpp | 11 |
3 files changed, 117 insertions, 26 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 0fa1b7673f9..f4feceff092 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -4591,6 +4591,97 @@ AArch64TargetLowering::LowerDarwinGlobalTLSAddress(SDValue Op, return DAG.getCopyFromReg(Chain, DL, AArch64::X0, PtrVT, Chain.getValue(1)); } +/// Convert a thread-local variable reference into a sequence of instructions to +/// compute the variable's address for the local exec TLS model of ELF targets. +/// The sequence depends on the maximum TLS area size. +SDValue AArch64TargetLowering::LowerELFTLSLocalExec(const GlobalValue *GV, + SDValue ThreadBase, + const SDLoc &DL, + SelectionDAG &DAG) const { + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + SDValue TPOff, Addr; + + switch (DAG.getTarget().Options.TLSSize) { + default: + llvm_unreachable("Unexpected TLS size"); + + case 12: { + // mrs x0, TPIDR_EL0 + // add x0, x0, :tprel_lo12:a + SDValue Var = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_PAGEOFF); + return SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, ThreadBase, + Var, + DAG.getTargetConstant(0, DL, MVT::i32)), + 0); + } + + case 24: { + // mrs x0, TPIDR_EL0 + // add x0, x0, :tprel_hi12:a + // add x0, x0, :tprel_lo12_nc:a + SDValue HiVar = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_HI12); + SDValue LoVar = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, 0, + AArch64II::MO_TLS | AArch64II::MO_PAGEOFF | AArch64II::MO_NC); + Addr = SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, ThreadBase, + HiVar, + DAG.getTargetConstant(0, DL, MVT::i32)), + 0); + return SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, Addr, + LoVar, + DAG.getTargetConstant(0, DL, MVT::i32)), + 0); + } + + case 32: { + // mrs x1, TPIDR_EL0 + // movz x0, #:tprel_g1:a + // movk x0, #:tprel_g0_nc:a + // add x0, x1, x0 + SDValue HiVar = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_G1); + SDValue LoVar = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, 0, + AArch64II::MO_TLS | AArch64II::MO_G0 | AArch64II::MO_NC); + TPOff = SDValue(DAG.getMachineNode(AArch64::MOVZXi, DL, PtrVT, HiVar, + DAG.getTargetConstant(16, DL, MVT::i32)), + 0); + TPOff = SDValue(DAG.getMachineNode(AArch64::MOVKXi, DL, PtrVT, TPOff, LoVar, + DAG.getTargetConstant(0, DL, MVT::i32)), + 0); + return DAG.getNode(ISD::ADD, DL, PtrVT, ThreadBase, TPOff); + } + + case 48: { + // mrs x1, TPIDR_EL0 + // movz x0, #:tprel_g2:a + // movk x0, #:tprel_g1_nc:a + // movk x0, #:tprel_g0_nc:a + // add x0, x1, x0 + SDValue HiVar = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_G2); + SDValue MiVar = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, 0, + AArch64II::MO_TLS | AArch64II::MO_G1 | AArch64II::MO_NC); + SDValue LoVar = DAG.getTargetGlobalAddress( + GV, DL, PtrVT, 0, + AArch64II::MO_TLS | AArch64II::MO_G0 | AArch64II::MO_NC); + TPOff = SDValue(DAG.getMachineNode(AArch64::MOVZXi, DL, PtrVT, HiVar, + DAG.getTargetConstant(32, DL, MVT::i32)), + 0); + TPOff = SDValue(DAG.getMachineNode(AArch64::MOVKXi, DL, PtrVT, TPOff, MiVar, + DAG.getTargetConstant(16, DL, MVT::i32)), + 0); + TPOff = SDValue(DAG.getMachineNode(AArch64::MOVKXi, DL, PtrVT, TPOff, LoVar, + DAG.getTargetConstant(0, DL, MVT::i32)), + 0); + return DAG.getNode(ISD::ADD, DL, PtrVT, ThreadBase, TPOff); + } + } +} + /// When accessing thread-local variables under either the general-dynamic or /// local-dynamic system, we make a "TLS-descriptor" call. The variable will /// have a descriptor, accessible via a PC-relative ADRP, and whose first entry @@ -4628,15 +4719,7 @@ SDValue AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { assert(Subtarget->isTargetELF() && "This function expects an ELF target"); - if (getTargetMachine().getCodeModel() == CodeModel::Large) - report_fatal_error("ELF TLS only supported in small memory model"); - // Different choices can be made for the maximum size of the TLS area for a - // module. For the small address model, the default TLS size is 16MiB and the - // maximum TLS size is 4GiB. - // FIXME: add -mtls-size command line option and make it control the 16MiB - // vs. 4GiB code sequence generation. - // FIXME: add tiny codemodel support. We currently generate the same code as - // small, which may be larger than needed. + const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); TLSModel::Model Model = getTargetMachine().getTLSModel(GA->getGlobal()); @@ -4646,6 +4729,17 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op, Model = TLSModel::GeneralDynamic; } + if (getTargetMachine().getCodeModel() == CodeModel::Large && + Model != TLSModel::LocalExec) + report_fatal_error("ELF TLS only supported in small memory model or " + "in local exec TLS model"); + // Different choices can be made for the maximum size of the TLS area for a + // module. For the small address model, the default TLS size is 16MiB and the + // maximum TLS size is 4GiB. + // FIXME: add tiny and large code model support for TLS access models other + // than local exec. We currently generate the same code as small for tiny, + // which may be larger than needed. + SDValue TPOff; EVT PtrVT = getPointerTy(DAG.getDataLayout()); SDLoc DL(Op); @@ -4654,23 +4748,7 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op, SDValue ThreadBase = DAG.getNode(AArch64ISD::THREAD_POINTER, DL, PtrVT); if (Model == TLSModel::LocalExec) { - SDValue HiVar = DAG.getTargetGlobalAddress( - GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_HI12); - SDValue LoVar = DAG.getTargetGlobalAddress( - GV, DL, PtrVT, 0, - AArch64II::MO_TLS | AArch64II::MO_PAGEOFF | AArch64II::MO_NC); - - SDValue TPWithOff_lo = - SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, ThreadBase, - HiVar, - DAG.getTargetConstant(0, DL, MVT::i32)), - 0); - SDValue TPWithOff = - SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, TPWithOff_lo, - LoVar, - DAG.getTargetConstant(0, DL, MVT::i32)), - 0); - return TPWithOff; + return LowerELFTLSLocalExec(GV, ThreadBase, DL, DAG); } else if (Model == TLSModel::InitialExec) { TPOff = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, AArch64II::MO_TLS); TPOff = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, TPOff); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 2a8e5f4724e..df1d219a51a 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -696,6 +696,8 @@ private: SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerDarwinGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerELFGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerELFTLSLocalExec(const GlobalValue *GV, SDValue ThreadBase, + const SDLoc &DL, SelectionDAG &DAG) const; SDValue LowerELFTLSDescCallSeq(SDValue SymAddr, const SDLoc &DL, SelectionDAG &DAG) const; SDValue LowerWindowsGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp index 68f4ee08048..6048010ee0c 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -288,6 +288,17 @@ AArch64TargetMachine::AArch64TargetMachine(const Target &T, const Triple &TT, this->Options.TrapUnreachable = true; } + if (this->Options.TLSSize == 0) // default + this->Options.TLSSize = 24; + if ((getCodeModel() == CodeModel::Small || + getCodeModel() == CodeModel::Kernel) && + this->Options.TLSSize > 32) + // for the small (and kernel) code model, the maximum TLS size is 4GiB + this->Options.TLSSize = 32; + else if (getCodeModel() == CodeModel::Tiny && this->Options.TLSSize > 24) + // for the tiny code model, the maximum TLS size is 1MiB (< 16MiB) + this->Options.TLSSize = 24; + // Enable GlobalISel at or below EnableGlobalISelAt0, unless this is // MachO/CodeModel::Large, which GlobalISel does not support. if (getOptLevel() <= EnableGlobalISelAtO && |