@@ -4591,6 +4591,97 @@ AArch64TargetLowering::LowerDarwinGlobalTLSAddress(SDValue Op,
4591
4591
return DAG.getCopyFromReg(Chain, DL, AArch64::X0, PtrVT, Chain.getValue(1));
4592
4592
}
4593
4593
4594
+ /// Convert a thread-local variable reference into a sequence of instructions to
4595
+ /// compute the variable's address for the local exec TLS model of ELF targets.
4596
+ /// The sequence depends on the maximum TLS area size.
4597
+ SDValue AArch64TargetLowering::LowerELFTLSLocalExec(const GlobalValue *GV,
4598
+ SDValue ThreadBase,
4599
+ const SDLoc &DL,
4600
+ SelectionDAG &DAG) const {
4601
+ EVT PtrVT = getPointerTy(DAG.getDataLayout());
4602
+ SDValue TPOff, Addr;
4603
+
4604
+ switch (DAG.getTarget().Options.TLSSize) {
4605
+ default:
4606
+ llvm_unreachable("Unexpected TLS size");
4607
+
4608
+ case 12: {
4609
+ // mrs x0, TPIDR_EL0
4610
+ // add x0, x0, :tprel_lo12:a
4611
+ SDValue Var = DAG.getTargetGlobalAddress(
4612
+ GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
4613
+ return SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, ThreadBase,
4614
+ Var,
4615
+ DAG.getTargetConstant(0, DL, MVT::i32)),
4616
+ 0);
4617
+ }
4618
+
4619
+ case 24: {
4620
+ // mrs x0, TPIDR_EL0
4621
+ // add x0, x0, :tprel_hi12:a
4622
+ // add x0, x0, :tprel_lo12_nc:a
4623
+ SDValue HiVar = DAG.getTargetGlobalAddress(
4624
+ GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_HI12);
4625
+ SDValue LoVar = DAG.getTargetGlobalAddress(
4626
+ GV, DL, PtrVT, 0,
4627
+ AArch64II::MO_TLS | AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
4628
+ Addr = SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, ThreadBase,
4629
+ HiVar,
4630
+ DAG.getTargetConstant(0, DL, MVT::i32)),
4631
+ 0);
4632
+ return SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, Addr,
4633
+ LoVar,
4634
+ DAG.getTargetConstant(0, DL, MVT::i32)),
4635
+ 0);
4636
+ }
4637
+
4638
+ case 32: {
4639
+ // mrs x1, TPIDR_EL0
4640
+ // movz x0, #:tprel_g1:a
4641
+ // movk x0, #:tprel_g0_nc:a
4642
+ // add x0, x1, x0
4643
+ SDValue HiVar = DAG.getTargetGlobalAddress(
4644
+ GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_G1);
4645
+ SDValue LoVar = DAG.getTargetGlobalAddress(
4646
+ GV, DL, PtrVT, 0,
4647
+ AArch64II::MO_TLS | AArch64II::MO_G0 | AArch64II::MO_NC);
4648
+ TPOff = SDValue(DAG.getMachineNode(AArch64::MOVZXi, DL, PtrVT, HiVar,
4649
+ DAG.getTargetConstant(16, DL, MVT::i32)),
4650
+ 0);
4651
+ TPOff = SDValue(DAG.getMachineNode(AArch64::MOVKXi, DL, PtrVT, TPOff, LoVar,
4652
+ DAG.getTargetConstant(0, DL, MVT::i32)),
4653
+ 0);
4654
+ return DAG.getNode(ISD::ADD, DL, PtrVT, ThreadBase, TPOff);
4655
+ }
4656
+
4657
+ case 48: {
4658
+ // mrs x1, TPIDR_EL0
4659
+ // movz x0, #:tprel_g2:a
4660
+ // movk x0, #:tprel_g1_nc:a
4661
+ // movk x0, #:tprel_g0_nc:a
4662
+ // add x0, x1, x0
4663
+ SDValue HiVar = DAG.getTargetGlobalAddress(
4664
+ GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_G2);
4665
+ SDValue MiVar = DAG.getTargetGlobalAddress(
4666
+ GV, DL, PtrVT, 0,
4667
+ AArch64II::MO_TLS | AArch64II::MO_G1 | AArch64II::MO_NC);
4668
+ SDValue LoVar = DAG.getTargetGlobalAddress(
4669
+ GV, DL, PtrVT, 0,
4670
+ AArch64II::MO_TLS | AArch64II::MO_G0 | AArch64II::MO_NC);
4671
+ TPOff = SDValue(DAG.getMachineNode(AArch64::MOVZXi, DL, PtrVT, HiVar,
4672
+ DAG.getTargetConstant(32, DL, MVT::i32)),
4673
+ 0);
4674
+ TPOff = SDValue(DAG.getMachineNode(AArch64::MOVKXi, DL, PtrVT, TPOff, MiVar,
4675
+ DAG.getTargetConstant(16, DL, MVT::i32)),
4676
+ 0);
4677
+ TPOff = SDValue(DAG.getMachineNode(AArch64::MOVKXi, DL, PtrVT, TPOff, LoVar,
4678
+ DAG.getTargetConstant(0, DL, MVT::i32)),
4679
+ 0);
4680
+ return DAG.getNode(ISD::ADD, DL, PtrVT, ThreadBase, TPOff);
4681
+ }
4682
+ }
4683
+ }
4684
+
4594
4685
/// When accessing thread-local variables under either the general-dynamic or
4595
4686
/// local-dynamic system, we make a "TLS-descriptor" call. The variable will
4596
4687
/// have a descriptor, accessible via a PC-relative ADRP, and whose first entry
@@ -4628,15 +4719,7 @@ SDValue
4628
4719
AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op,
4629
4720
SelectionDAG &DAG) const {
4630
4721
assert(Subtarget->isTargetELF() && "This function expects an ELF target");
4631
- if (getTargetMachine().getCodeModel() == CodeModel::Large)
4632
- report_fatal_error("ELF TLS only supported in small memory model");
4633
- // Different choices can be made for the maximum size of the TLS area for a
4634
- // module. For the small address model, the default TLS size is 16MiB and the
4635
- // maximum TLS size is 4GiB.
4636
- // FIXME: add -mtls-size command line option and make it control the 16MiB
4637
- // vs. 4GiB code sequence generation.
4638
- // FIXME: add tiny codemodel support. We currently generate the same code as
4639
- // small, which may be larger than needed.
4722
+
4640
4723
const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
4641
4724
4642
4725
TLSModel::Model Model = getTargetMachine().getTLSModel(GA->getGlobal());
@@ -4646,6 +4729,17 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op,
4646
4729
Model = TLSModel::GeneralDynamic;
4647
4730
}
4648
4731
4732
+ if (getTargetMachine().getCodeModel() == CodeModel::Large &&
4733
+ Model != TLSModel::LocalExec)
4734
+ report_fatal_error("ELF TLS only supported in small memory model or "
4735
+ "in local exec TLS model");
4736
+ // Different choices can be made for the maximum size of the TLS area for a
4737
+ // module. For the small address model, the default TLS size is 16MiB and the
4738
+ // maximum TLS size is 4GiB.
4739
+ // FIXME: add tiny and large code model support for TLS access models other
4740
+ // than local exec. We currently generate the same code as small for tiny,
4741
+ // which may be larger than needed.
4742
+
4649
4743
SDValue TPOff;
4650
4744
EVT PtrVT = getPointerTy(DAG.getDataLayout());
4651
4745
SDLoc DL(Op);
@@ -4654,23 +4748,7 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op,
4654
4748
SDValue ThreadBase = DAG.getNode(AArch64ISD::THREAD_POINTER, DL, PtrVT);
4655
4749
4656
4750
if (Model == TLSModel::LocalExec) {
4657
- SDValue HiVar = DAG.getTargetGlobalAddress(
4658
- GV, DL, PtrVT, 0, AArch64II::MO_TLS | AArch64II::MO_HI12);
4659
- SDValue LoVar = DAG.getTargetGlobalAddress(
4660
- GV, DL, PtrVT, 0,
4661
- AArch64II::MO_TLS | AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
4662
-
4663
- SDValue TPWithOff_lo =
4664
- SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, ThreadBase,
4665
- HiVar,
4666
- DAG.getTargetConstant(0, DL, MVT::i32)),
4667
- 0);
4668
- SDValue TPWithOff =
4669
- SDValue(DAG.getMachineNode(AArch64::ADDXri, DL, PtrVT, TPWithOff_lo,
4670
- LoVar,
4671
- DAG.getTargetConstant(0, DL, MVT::i32)),
4672
- 0);
4673
- return TPWithOff;
4751
+ return LowerELFTLSLocalExec(GV, ThreadBase, DL, DAG);
4674
4752
} else if (Model == TLSModel::InitialExec) {
4675
4753
TPOff = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, AArch64II::MO_TLS);
4676
4754
TPOff = DAG.getNode(AArch64ISD::LOADgot, DL, PtrVT, TPOff);
0 commit comments