[llvm] [AArch64][GlobalISel] Add support for TLS for ELF (PR #220236)

Kristina Bessonova via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 11 04:41:26 PDT 2026


https://github.com/chbessonova updated https://github.com/llvm/llvm-project/pull/220236

>From a5399136ea32d160269344a68d904925082cd72b Mon Sep 17 00:00:00 2001
From: Kristina Bessonova <kbessonova at accesssoftek.com>
Date: Sun, 23 Aug 2026 22:56:09 +0200
Subject: [PATCH] [AArch64][GlobalISel] Add support for TLS for ELF

Mirror the existing DAGISel lowering for the TLS access sequences.
'AArch64 local-dynamic TLS cleanup pass' moved to
`AArch64PassConfig::addMachineSSAOptimization()` hook to make it
runing for both instruction selection pipelines.

The generated bu GlobalISel code matches DAGISel for the existing TLS
test cases.
---
 .../Target/AArch64/AArch64ISelLowering.cpp    |  41 ++--
 llvm/lib/Target/AArch64/AArch64ISelLowering.h |   5 +
 .../Target/AArch64/AArch64TargetMachine.cpp   |  14 +-
 .../GISel/AArch64InstructionSelector.cpp      | 189 ++++++++++++++++--
 llvm/test/CodeGen/AArch64/O3-pipeline.ll      |   2 +-
 .../CodeGen/AArch64/arm64-tls-dynamics.ll     |  17 +-
 .../CodeGen/AArch64/arm64-tls-initial-exec.ll |   7 +
 .../CodeGen/AArch64/arm64-tls-local-exec.ll   |  29 ++-
 .../AArch64/ptrauth-arm64-tls-dynamics.ll     |   8 +-
 9 files changed, 262 insertions(+), 50 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 05b79f99610ae..4f53df7dcff20 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -11796,26 +11796,17 @@ SDValue AArch64TargetLowering::LowerELFTLSDescCallSeq(SDValue SymAddr,
   return DAG.getCopyFromReg(Chain, DL, AArch64::X0, PtrVT, Glue);
 }
 
-SDValue
-AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op,
-                                                SelectionDAG &DAG) const {
-  assert(Subtarget->isTargetELF() && "This function expects an ELF target");
+TLSModel::Model AArch64::getELFTLSModel(const GlobalValue *GV,
+                                        const TargetMachine &TM,
+                                        bool HasELFSignedGOT) {
+  TLSModel::Model Model =
+      HasELFSignedGOT ? TLSModel::GeneralDynamic : TM.getTLSModel(GV);
 
-  const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
-  AArch64FunctionInfo *MFI =
-      DAG.getMachineFunction().getInfo<AArch64FunctionInfo>();
-
-  TLSModel::Model Model = MFI->hasELFSignedGOT()
-                              ? TLSModel::GeneralDynamic
-                              : getTargetMachine().getTLSModel(GA->getGlobal());
+  if (!EnableAArch64ELFLocalDynamicTLSGeneration &&
+      Model == TLSModel::LocalDynamic)
+    Model = TLSModel::GeneralDynamic;
 
-  if (!EnableAArch64ELFLocalDynamicTLSGeneration) {
-    if (Model == TLSModel::LocalDynamic)
-      Model = TLSModel::GeneralDynamic;
-  }
-
-  if (getTargetMachine().getCodeModel() == CodeModel::Large &&
-      Model != TLSModel::LocalExec)
+  if (TM.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
@@ -11825,6 +11816,20 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op,
   // than local exec. We currently generate the same code as small for tiny,
   // which may be larger than needed.
 
+  return Model;
+}
+
+SDValue
+AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op,
+                                                SelectionDAG &DAG) const {
+  assert(Subtarget->isTargetELF() && "This function expects an ELF target");
+
+  const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
+  AArch64FunctionInfo *MFI =
+      DAG.getMachineFunction().getInfo<AArch64FunctionInfo>();
+  TLSModel::Model Model = AArch64::getELFTLSModel(
+      GA->getGlobal(), getTargetMachine(), MFI->hasELFSignedGOT());
+
   SDValue TPOff;
   EVT PtrVT = getPointerTy(DAG.getDataLayout());
   SDLoc DL(Op);
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 1b622e93480ec..1f4ea02e80401 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -981,6 +981,11 @@ namespace AArch64 {
 FastISel *createFastISel(FunctionLoweringInfo &funcInfo,
                          const TargetLibraryInfo *libInfo,
                          const LibcallLoweringInfo *libcallLowering);
+
+// Determine the effective TLS model for an ELF global, applying
+// AArch64-specific restrictions and configuration.
+TLSModel::Model getELFTLSModel(const GlobalValue *GV, const TargetMachine &TM,
+                               bool HasELFSignedGOT);
 } // end namespace AArch64
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 2e833f6729737..004ff0fb97bbf 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -770,13 +770,6 @@ void AArch64PassConfig::addCodeGenPrepare() {
 
 bool AArch64PassConfig::addInstSelector() {
   addPass(createAArch64ISelDag(getAArch64TargetMachine(), getOptLevel()));
-
-  // For ELF, cleanup any local-dynamic TLS accesses (i.e. combine as many
-  // references to _TLS_MODULE_BASE_ as possible.
-  if (TM->getTargetTriple().isOSBinFormatELF() &&
-      getOptLevel() != CodeGenOptLevel::None)
-    addPass(createAArch64CleanupLocalDynamicTLSPass());
-
   return false;
 }
 
@@ -822,10 +815,17 @@ bool AArch64PassConfig::addGlobalInstructionSelect() {
   addPass(new InstructionSelectLegacy(getOptLevel()));
   if (!getAArch64TargetMachine().isGlobalISelOptNone())
     addPass(createAArch64PostSelectOptimize());
+
   return false;
 }
 
 void AArch64PassConfig::addMachineSSAOptimization() {
+  // For ELF, cleanup any local-dynamic TLS accesses
+  // (i.e. combine as many references to _TLS_MODULE_BASE_ as possible.
+  if (TM->getTargetTriple().isOSBinFormatELF() &&
+      getOptLevel() != CodeGenOptLevel::None)
+    addPass(createAArch64CleanupLocalDynamicTLSPass());
+
   if (TM->getOptLevel() != CodeGenOptLevel::None)
     addPass(createMachineSMEABIPass(TM->getOptLevel()));
 
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 442d061e71cb8..0499d7771683e 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -223,6 +223,10 @@ class AArch64InstructionSelector : public InstructionSelector {
   bool selectIntrinsic(MachineInstr &I, MachineRegisterInfo &MRI);
   bool selectJumpTable(MachineInstr &I, MachineRegisterInfo &MRI);
   bool selectBrJT(MachineInstr &I, MachineRegisterInfo &MRI);
+  bool selectTLSGlobalValueELF(MachineInstr &I, MachineRegisterInfo &MRI);
+  bool selectTLSLocalExecELF(const GlobalValue *GV, MachineInstr &I,
+                             MachineRegisterInfo &MRI);
+  bool selectTLSGlobalValueMachO(MachineInstr &I, MachineRegisterInfo &MRI);
   bool selectTLSGlobalValue(MachineInstr &I, MachineRegisterInfo &MRI);
   bool selectPtrAuthGlobalValue(MachineInstr &I,
                                 MachineRegisterInfo &MRI) const;
@@ -2905,12 +2909,9 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
       assert(OpFlags == AArch64II::MO_GOT);
     } else {
       GV = I.getOperand(1).getGlobal();
-      if (GV->isThreadLocal()) {
-        // We don't support instructions with emulated TLS variables yet
-        if (TM.useEmulatedTLS())
-          return false;
+      if (GV->isThreadLocal())
         return selectTLSGlobalValue(I, MRI);
-      }
+
       OpFlags = STI.ClassifyGlobalReference(GV, TM);
     }
 
@@ -3738,18 +3739,165 @@ bool AArch64InstructionSelector::selectJumpTable(MachineInstr &I,
   return true;
 }
 
-bool AArch64InstructionSelector::selectTLSGlobalValue(
+bool AArch64InstructionSelector::selectTLSLocalExecELF(
+    const GlobalValue *GV, MachineInstr &I, MachineRegisterInfo &MRI) {
+  auto ConstrainRegOps = [&](MachineInstrBuilder MIB) {
+    constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
+  };
+  Register ThreadBase = MRI.createGenericVirtualRegister(LLT::pointer(0, 64));
+  ConstrainRegOps(MIB.buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {}));
+
+  switch (MF->getTarget().Options.TLSSize) {
+  default:
+    llvm_unreachable("Unexpected TLS size");
+  case 12: {
+    // add x0, x0, :tprel_lo12:a
+    ConstrainRegOps(
+        MIB.buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()},
+                       {ThreadBase})
+            .addGlobalAddress(GV, 0, AArch64II::MO_TLS | AArch64II::MO_PAGEOFF)
+            .addImm(0));
+    break;
+  }
+  case 24: {
+    // add x0, x0, :tprel_hi12:a
+    // add x0, x0, :tprel_lo12_nc:a
+    Register Addr = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
+    ConstrainRegOps(
+        MIB.buildInstr(AArch64::ADDXri, {Addr}, {ThreadBase})
+            .addGlobalAddress(GV, 0, AArch64II::MO_TLS | AArch64II::MO_HI12)
+            .addImm(0));
+    ConstrainRegOps(
+        MIB.buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()}, {Addr})
+            .addGlobalAddress(GV, 0,
+                              AArch64II::MO_TLS | AArch64II::MO_PAGEOFF |
+                                  AArch64II::MO_NC)
+            .addImm(0));
+    break;
+  }
+  case 32: {
+    // movz x0, #:tprel_g1:a
+    // movk x0, #:tprel_g0_nc:a
+    // add x0, x1, x0
+    Register Addr = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
+    ConstrainRegOps(
+        MIB.buildInstr(AArch64::MOVZXi, {Addr}, {})
+            .addGlobalAddress(GV, 0, AArch64II::MO_TLS | AArch64II::MO_G1)
+            .addImm(16));
+    Register Addr2 = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
+    ConstrainRegOps(MIB.buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
+                        .addGlobalAddress(GV, 0,
+                                          AArch64II::MO_TLS | AArch64II::MO_G0 |
+                                              AArch64II::MO_NC)
+                        .addImm(0));
+    ConstrainRegOps(MIB.buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
+                                   {ThreadBase, Addr2}));
+    break;
+  }
+  case 48: {
+    // movz x0, #:tprel_g2:a
+    // movk x0, #:tprel_g1_nc:a
+    // movk x0, #:tprel_g0_nc:a
+    // add x0, x1, x0
+    Register Addr = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
+    ConstrainRegOps(
+        MIB.buildInstr(AArch64::MOVZXi, {Addr}, {})
+            .addGlobalAddress(GV, 0, AArch64II::MO_TLS | AArch64II::MO_G2)
+            .addImm(32));
+    Register Addr2 = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
+    ConstrainRegOps(MIB.buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
+                        .addGlobalAddress(GV, 0,
+                                          AArch64II::MO_TLS | AArch64II::MO_G1 |
+                                              AArch64II::MO_NC)
+                        .addImm(16));
+    Register Addr3 = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
+    ConstrainRegOps(MIB.buildInstr(AArch64::MOVKXi, {Addr3}, {Addr2})
+                        .addGlobalAddress(GV, 0,
+                                          AArch64II::MO_TLS | AArch64II::MO_G0 |
+                                              AArch64II::MO_NC)
+                        .addImm(0));
+    ConstrainRegOps(MIB.buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
+                                   {ThreadBase, Addr3}));
+    break;
+  }
+  }
+  I.eraseFromParent();
+  return true;
+}
+
+// TLS lowering below mirrors the corresponding DAGISel implementation.
+// See LowerELFTLSModel() for details.
+bool AArch64InstructionSelector::selectTLSGlobalValueELF(
     MachineInstr &I, MachineRegisterInfo &MRI) {
-  if (!STI.isTargetMachO())
-    return false;
-  MachineFunction &MF = *I.getParent()->getParent();
-  MF.getFrameInfo().setAdjustsStack(true);
+  const GlobalValue *GV = I.getOperand(1).getGlobal();
+  auto *FuncInfo = MF->getInfo<AArch64FunctionInfo>();
+  TLSModel::Model Model =
+      AArch64::getELFTLSModel(GV, TM, FuncInfo->hasELFSignedGOT());
+
+  Register TPOff = MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
+  switch (Model) {
+  case TLSModel::LocalExec:
+    return selectTLSLocalExecELF(GV, I, MRI);
+  case TLSModel::InitialExec:
+    MIB.buildInstr(AArch64::LOADgot, {TPOff}, {})
+        .addGlobalAddress(GV, 0, AArch64II::MO_TLS);
+    break;
+  case TLSModel::LocalDynamic:
+  case TLSModel::GeneralDynamic: {
+#ifndef NDEBUG
+    SMEAttrs Attrs = MF->getInfo<AArch64FunctionInfo>()->getSMEFnAttrs();
+    assert(!Attrs.hasZAState() && !Attrs.hasStreamingInterfaceOrBody() &&
+           !Attrs.hasStreamingCompatibleInterface() &&
+           "unsupported SME features reached GlobalISel TLS lowering");
+#endif
+    unsigned Opcode = FuncInfo->hasELFSignedGOT()
+                          ? AArch64::TLSDESC_AUTH_CALLSEQ
+                          : AArch64::TLSDESC_CALLSEQ;
+
+    if (TLSModel::GeneralDynamic == Model) {
+      MIB.buildInstr(Opcode, {}, {}).addGlobalAddress(GV, 0, AArch64II::MO_TLS);
+      MIB.buildCopy(TPOff, Register(AArch64::X0));
+      break;
+    }
+    assert(TLSModel::LocalDynamic == Model);
+    // These accesses will need deduplicating if there's more than one.
+    FuncInfo->incNumLocalDynamicTLSAccesses();
+
+    MIB.buildInstr(Opcode, {}, {})
+        .addExternalSymbol("_TLS_MODULE_BASE_", AArch64II::MO_TLS);
+    auto Copy = MIB.buildCopy(LLT::scalar(64), Register(AArch64::X0));
+    auto Add1 =
+        MIB.buildInstr(AArch64::ADDXri, {LLT::scalar(64)}, {Copy.getReg(0)})
+            .addGlobalAddress(GV, 0, AArch64II::MO_TLS | AArch64II::MO_HI12)
+            .addImm(0);
+    auto Add2 =
+        MIB.buildInstr(AArch64::ADDXri, {TPOff}, {Add1.getReg(0)})
+            .addGlobalAddress(GV, 0,
+                              AArch64II::MO_TLS | AArch64II::MO_PAGEOFF |
+                                  AArch64II::MO_NC)
+            .addImm(0);
+    constrainSelectedInstRegOperands(*Add1, TII, TRI, RBI);
+    constrainSelectedInstRegOperands(*Add2, TII, TRI, RBI);
+  }
+  }
+  Register ThreadBase = MRI.createGenericVirtualRegister(LLT::pointer(0, 64));
+  MIB.buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {});
+  auto Add = MIB.buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
+                            {ThreadBase, TPOff});
+  constrainSelectedInstRegOperands(*Add, TII, TRI, RBI);
+
+  I.eraseFromParent();
+  return true;
+}
 
+bool AArch64InstructionSelector::selectTLSGlobalValueMachO(
+    MachineInstr &I, MachineRegisterInfo &MRI) {
   const auto &GlobalOp = I.getOperand(1);
   assert(GlobalOp.getOffset() == 0 &&
          "Shouldn't have an offset on TLS globals!");
-  const GlobalValue &GV = *GlobalOp.getGlobal();
 
+  const GlobalValue &GV = *GlobalOp.getGlobal();
+  MF->getFrameInfo().setAdjustsStack(true);
   auto LoadGOT =
       MIB.buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
           .addGlobalAddress(&GV, 0, AArch64II::MO_TLS);
@@ -3762,10 +3910,10 @@ bool AArch64InstructionSelector::selectTLSGlobalValue(
   // TLS calls preserve all registers except those that absolutely must be
   // trashed: X0 (it takes an argument), LR (it's a call) and NZCV (let's not be
   // silly).
-  unsigned Opcode = getBLRCallOpcode(MF);
+  unsigned Opcode = getBLRCallOpcode(*MF);
 
   // With ptrauth-calls, the tlv access thunk pointer is authenticated (IA, 0).
-  if (MF.getFunction().hasFnAttribute("ptrauth-calls")) {
+  if (MF->getFunction().hasFnAttribute("ptrauth-calls")) {
     assert(Opcode == AArch64::BLR);
     Opcode = AArch64::BLRAAZ;
   }
@@ -3782,6 +3930,21 @@ bool AArch64InstructionSelector::selectTLSGlobalValue(
   return true;
 }
 
+bool AArch64InstructionSelector::selectTLSGlobalValue(
+    MachineInstr &I, MachineRegisterInfo &MRI) {
+  // We don't support instructions with emulated TLS variables yet.
+  if (TM.useEmulatedTLS())
+    return false;
+
+  if (STI.isTargetELF())
+    return selectTLSGlobalValueELF(I, MRI);
+
+  if (STI.isTargetMachO())
+    return selectTLSGlobalValueMachO(I, MRI);
+
+  return false;
+}
+
 MachineInstr *AArch64InstructionSelector::emitScalarToVector(
     unsigned EltSize, const TargetRegisterClass *DstRC, Register Scalar,
     MachineIRBuilder &MIRBuilder) const {
diff --git a/llvm/test/CodeGen/AArch64/O3-pipeline.ll b/llvm/test/CodeGen/AArch64/O3-pipeline.ll
index 9b36359c339c8..8b29a46ff5e07 100644
--- a/llvm/test/CodeGen/AArch64/O3-pipeline.ll
+++ b/llvm/test/CodeGen/AArch64/O3-pipeline.ll
@@ -131,9 +131,9 @@
 ; CHECK-NEXT:       ResetMachineFunction
 ; CHECK-NEXT:       Assignment Tracking Analysis
 ; CHECK-NEXT:       AArch64 Instruction Selection
+; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       MachineDominator Tree Construction
 ; CHECK-NEXT:       AArch64 Local Dynamic TLS Access Clean-up
-; CHECK-NEXT:       Finalize ISel and expand pseudo-instructions
 ; CHECK-NEXT:       Bundle Machine CFG Edges
 ; CHECK-NEXT:       Lazy Machine Block Frequency Analysis
 ; CHECK-NEXT:       Machine Optimization Remark Emitter
diff --git a/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll b/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
index 098d6a29c2390..171fd64159556 100644
--- a/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
@@ -1,15 +1,24 @@
 ; Verify the call site info. If the call site info is not
 ; in the valid state, an assert should be triggered.
 ; RUN: llc < %s -debug-entry-values -mtriple=arm64-none-linux-gnu -stop-after=machineverifier -relocation-model=pic -aarch64-elf-ldtls-generation=1 < %s
+; RUN: llc < %s -debug-entry-values -mtriple=arm64-none-linux-gnu -global-isel -stop-after=machineverifier -relocation-model=pic -aarch64-elf-ldtls-generation=1 < %s
 
 ; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -verify-machineinstrs < %s | FileCheck %s
 ; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-RELOC %s
 ; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -verify-machineinstrs < %s | FileCheck --check-prefix=CHECK-NOLD %s
 ; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-NOLD-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -relocation-model=pic -aarch64-elf-ldtls-generation=1 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -relocation-model=pic -aarch64-elf-ldtls-generation=1 -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -relocation-model=pic -verify-machineinstrs < %s | FileCheck --check-prefix=CHECK-NOLD %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -relocation-model=pic -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-NOLD-RELOC %s
+
 ; FIXME: We currently produce "small" code for the tiny model
 ; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -code-model=tiny -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -relocation-model=pic -aarch64-elf-ldtls-generation=1 -code-model=tiny -verify-machineinstrs < %s | FileCheck %s
+
 ; FIXME: We currently error for the large code model
 ; RUN: not --crash llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -code-model=large -verify-machineinstrs < %s 2>&1 | FileCheck %s --check-prefix=CHECK-LARGE
+; RUN: not --crash llc -mtriple=arm64-none-linux-gnu -global-isel -relocation-model=pic -aarch64-elf-ldtls-generation=1 -code-model=large -verify-machineinstrs < %s 2>&1 | FileCheck %s --check-prefix=CHECK-LARGE
 
 ; CHECK-LARGE: ELF TLS only supported in small memory model
 
@@ -26,16 +35,14 @@ define i32 @test_generaldynamic() {
 ; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var
 ; CHECK-NEXT: .tlsdesccall general_dynamic_var
 ; CHECK-NEXT: blr [[CALLEE]]
+; CHECK: mrs x[[TP:[0-9]+]], TPIDR_EL0
+; CHECK: ldr w0, [x[[TP]], x0]
 
 ; CHECK-NOLD: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:general_dynamic_var
 ; CHECK-NOLD-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var]
 ; CHECK-NOLD-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var
 ; CHECK-NOLD-NEXT: .tlsdesccall general_dynamic_var
 ; CHECK-NOLD-NEXT: blr [[CALLEE]]
-
-
-; CHECK: mrs x[[TP:[0-9]+]], TPIDR_EL0
-; CHECK: ldr w0, [x[[TP]], x0]
 ; CHECK-NOLD: mrs x[[TP:[0-9]+]], TPIDR_EL0
 ; CHECK-NOLD: ldr w0, [x[[TP]], x0]
 
@@ -126,7 +133,7 @@ define ptr @test_localdynamic_addr() {
 ; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_
 ; CHECK-NEXT: .tlsdesccall _TLS_MODULE_BASE_
 ; CHECK-NEXT: blr [[CALLEE]]
-; CHECK-NEXT: add x[[TPOFF:[0-9]+]], x0, :dtprel_hi12:local_dynamic_var
+; CHECK-DAG: add x[[TPOFF:[0-9]+]], x0, :dtprel_hi12:local_dynamic_var
 ; CHECK-DAG: add x[[TPOFF]], x[[TPOFF]], :dtprel_lo12_nc:local_dynamic_var
 ; CHECK-DAG: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0
 ; CHECK: add x0, x[[TPIDR]], x[[TPOFF]]
diff --git a/llvm/test/CodeGen/AArch64/arm64-tls-initial-exec.ll b/llvm/test/CodeGen/AArch64/arm64-tls-initial-exec.ll
index c5a1144964976..3fa18aa9c6a39 100644
--- a/llvm/test/CodeGen/AArch64/arm64-tls-initial-exec.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-tls-initial-exec.ll
@@ -2,8 +2,15 @@
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-RELOC %s
 ; RUN: llc -mtriple=arm64-none-linux-gnu -verify-machineinstrs -show-mc-encoding -code-model=tiny < %s | FileCheck %s --check-prefix=CHECK-TINY
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s -code-model=tiny | llvm-objdump -r - | FileCheck --check-prefix=CHECK-TINY-RELOC %s
+
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=tiny < %s | FileCheck %s --check-prefix=CHECK-TINY
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=tiny | llvm-objdump -r - | FileCheck --check-prefix=CHECK-TINY-RELOC %s
+
 ; FIXME: We currently error for the large code model
 ; RUN: not --crash llc -mtriple=arm64-none-linux-gnu -verify-machineinstrs -show-mc-encoding -code-model=large < %s 2>&1 | FileCheck %s --check-prefix=CHECK-LARGE
+; RUN: not --crash llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=large < %s 2>&1 | FileCheck %s --check-prefix=CHECK-LARGE
 
 ; CHECK-LARGE: ELF TLS only supported in small memory model
 
diff --git a/llvm/test/CodeGen/AArch64/arm64-tls-local-exec.ll b/llvm/test/CodeGen/AArch64/arm64-tls-local-exec.ll
index 59d5500ce534e..20f943e4bbf00 100644
--- a/llvm/test/CodeGen/AArch64/arm64-tls-local-exec.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-tls-local-exec.ll
@@ -7,7 +7,16 @@
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s -code-model=small -tls-size=32 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-32-RELOC %s
 ; RUN: llc -mtriple=arm64-none-linux-gnu -verify-machineinstrs -show-mc-encoding -code-model=large -tls-size=48 < %s | FileCheck %s --check-prefix=CHECK-48
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s -code-model=large -tls-size=48 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-48-RELOC %s
-;
+
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -tls-size=12 < %s | FileCheck %s --check-prefix=CHECK-12
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -tls-size=12 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-12-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=tiny -tls-size=24 < %s | FileCheck %s --check-prefix=CHECK-24
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=tiny -tls-size=24 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=small -tls-size=32 < %s | FileCheck %s --check-prefix=CHECK-32
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=small -tls-size=32 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-32-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=large -tls-size=48 < %s | FileCheck %s --check-prefix=CHECK-48
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=large -tls-size=48 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-48-RELOC %s
+
 ; Test the maximum TLS size for each code model (fallback to a smaller size from the specified size)
 ; RUN: llc -mtriple=arm64-none-linux-gnu -verify-machineinstrs -show-mc-encoding -tls-size=32 < %s | FileCheck %s --check-prefix=CHECK-32
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s -tls-size=32 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-32-RELOC %s
@@ -15,7 +24,14 @@
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s -code-model=tiny -tls-size=32 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
 ; RUN: llc -mtriple=arm64-none-linux-gnu -verify-machineinstrs -show-mc-encoding -code-model=small -tls-size=48 < %s | FileCheck %s --check-prefix=CHECK-32
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s -code-model=small -tls-size=48 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-32-RELOC %s
-;
+
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -tls-size=32 < %s | FileCheck %s --check-prefix=CHECK-32
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -tls-size=32 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-32-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=tiny -tls-size=32 < %s | FileCheck %s --check-prefix=CHECK-24
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=tiny -tls-size=32 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=small -tls-size=48 < %s | FileCheck %s --check-prefix=CHECK-32
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=small -tls-size=48 | llvm-objdump -r - | FileCheck --check-prefix=CHECK-32-RELOC %s
+
 ; Test the default TLS size for each code model
 ; RUN: llc -mtriple=arm64-none-linux-gnu -verify-machineinstrs -show-mc-encoding < %s | FileCheck --check-prefix=CHECK-24 %s
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
@@ -26,6 +42,15 @@
 ; RUN: llc -mtriple=arm64-none-linux-gnu -verify-machineinstrs -show-mc-encoding -code-model=large < %s | FileCheck %s --check-prefix=CHECK-24
 ; RUN: llc -mtriple=arm64-none-linux-gnu -filetype=obj < %s -code-model=large | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
 
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs < %s | FileCheck --check-prefix=CHECK-24 %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=tiny < %s | FileCheck %s --check-prefix=CHECK-24
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=tiny | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=small < %s | FileCheck %s --check-prefix=CHECK-24
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=small | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -verify-machineinstrs -code-model=large < %s | FileCheck %s --check-prefix=CHECK-24
+; RUN: llc -mtriple=arm64-none-linux-gnu -global-isel -filetype=obj < %s -code-model=large | llvm-objdump -r - | FileCheck --check-prefix=CHECK-24-RELOC %s
+
 @local_exec_var = thread_local(localexec) global i32 0
 
 define i32 @test_local_exec() {
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll b/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll
index 2d8085cf489b9..981864ce78cc4 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll
@@ -2,8 +2,10 @@
 ; RUN:   -verify-machineinstrs < %s | FileCheck %s
 ; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \
 ; RUN:   -filetype=obj < %s | llvm-readelf -r -s - | FileCheck --check-prefix=CHECK-OBJ %s
-; RUN: not llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \
-; RUN:   -global-isel=1 < %s 2>&1 | FileCheck --check-prefix=CHECK-ERR %s
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \
+; RUN:   -global-isel=1 -verify-machineinstrs < %s 2>&1 | FileCheck %s
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \
+; RUN:   -global-isel=1 -filetype=obj < %s | llvm-readelf -r -s - | FileCheck --check-prefix=CHECK-OBJ %s
 
 @general_dynamic_var = external thread_local global i32
 
@@ -24,8 +26,6 @@ define i32 @test_generaldynamic() {
 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12
 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12
 ; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL
-
-; CHECK-ERR: LLVM ERROR: cannot select: %1:gpr64sp(p0) = G_GLOBAL_VALUE @general_dynamic_var (in function: test_generaldynamic)
 }
 
 define ptr @test_generaldynamic_addr() {



More information about the llvm-commits mailing list