[llvm] 4c2ec08 - [m68k] Add TLS Support

via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 3 04:10:24 PDT 2023


Author: Sheng
Date: 2023-06-03T19:09:47+08:00
New Revision: 4c2ec08ebc62e70c872eb58f6adde77ed52c4cc9

URL: https://github.com/llvm/llvm-project/commit/4c2ec08ebc62e70c872eb58f6adde77ed52c4cc9
DIFF: https://github.com/llvm/llvm-project/commit/4c2ec08ebc62e70c872eb58f6adde77ed52c4cc9.diff

LOG: [m68k] Add TLS Support

This patch introduces TLS (Thread-Local Storage) support to the LLVM m68k backend.

Reviewed By: glaubitz

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

Added: 
    llvm/test/CodeGen/M68k/TLS/tlsgd.ll
    llvm/test/CodeGen/M68k/TLS/tlsie.ll
    llvm/test/CodeGen/M68k/TLS/tlsld.ll
    llvm/test/CodeGen/M68k/TLS/tlsle.ll

Modified: 
    llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
    llvm/lib/Target/M68k/M68kISelLowering.cpp
    llvm/lib/Target/M68k/M68kISelLowering.h
    llvm/lib/Target/M68k/M68kInstrArithmetic.td
    llvm/lib/Target/M68k/M68kInstrInfo.cpp
    llvm/lib/Target/M68k/M68kMCInstLower.cpp
    llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h
    llvm/lib/Target/M68k/MCTargetDesc/M68kELFObjectWriter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp b/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
index 346470ed60d80..075120b973473 100644
--- a/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
+++ b/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
@@ -666,6 +666,15 @@ void M68kDAGToDAGISel::Select(SDNode *Node) {
   default:
     break;
 
+  case ISD::GLOBAL_OFFSET_TABLE: {
+    SDValue GOT = CurDAG->getTargetExternalSymbol(
+        "_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);
+    MachineSDNode *Res =
+        CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT);
+    ReplaceNode(Node, Res);
+    return;
+  }
+
   case M68kISD::GLOBAL_BASE_REG:
     ReplaceNode(Node, getGlobalBaseReg());
     return;

diff  --git a/llvm/lib/Target/M68k/M68kISelLowering.cpp b/llvm/lib/Target/M68k/M68kISelLowering.cpp
index a2d27c0dcb4df..6c877f9dd8edd 100644
--- a/llvm/lib/Target/M68k/M68kISelLowering.cpp
+++ b/llvm/lib/Target/M68k/M68kISelLowering.cpp
@@ -1420,9 +1420,108 @@ SDValue M68kTargetLowering::LowerOperation(SDValue Op,
     return LowerShiftRightParts(Op, DAG, false);
   case ISD::ATOMIC_FENCE:
     return LowerATOMICFENCE(Op, DAG);
+  case ISD::GlobalTLSAddress:
+    return LowerGlobalTLSAddress(Op, DAG);
   }
 }
 
+SDValue M68kTargetLowering::LowerExternalSymbolCall(SelectionDAG &DAG,
+                                                    SDLoc Loc,
+                                                    llvm::StringRef SymbolName,
+                                                    ArgListTy &&ArgList) const {
+  PointerType *PtrTy = PointerType::get(*DAG.getContext(), 0);
+  CallLoweringInfo CLI(DAG);
+  CLI.setDebugLoc(Loc)
+      .setChain(DAG.getEntryNode())
+      .setLibCallee(CallingConv::C, PtrTy,
+                    DAG.getExternalSymbol(SymbolName.data(),
+                                          getPointerMemTy(DAG.getDataLayout())),
+                    std::move(ArgList));
+  return LowerCallTo(CLI).first;
+}
+
+SDValue M68kTargetLowering::getTLSGetAddr(GlobalAddressSDNode *GA,
+                                          SelectionDAG &DAG,
+                                          unsigned TargetFlags) const {
+  SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32);
+  SDValue TGA = DAG.getTargetGlobalAddress(
+      GA->getGlobal(), GA, GA->getValueType(0), GA->getOffset(), TargetFlags);
+  SDValue Arg = DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, GOT, TGA);
+
+  PointerType *PtrTy = PointerType::get(*DAG.getContext(), 0);
+
+  ArgListTy Args;
+  ArgListEntry Entry;
+  Entry.Node = Arg;
+  Entry.Ty = PtrTy;
+  Args.push_back(Entry);
+  return LowerExternalSymbolCall(DAG, SDLoc(GA), "__tls_get_addr",
+                                 std::move(Args));
+}
+
+SDValue M68kTargetLowering::getM68kReadTp(SDLoc Loc, SelectionDAG &DAG) const {
+  return LowerExternalSymbolCall(DAG, Loc, "__m68k_read_tp", ArgListTy());
+}
+
+SDValue M68kTargetLowering::LowerTLSGeneralDynamic(GlobalAddressSDNode *GA,
+                                                   SelectionDAG &DAG) const {
+  return getTLSGetAddr(GA, DAG, M68kII::MO_TLSGD);
+}
+
+SDValue M68kTargetLowering::LowerTLSLocalDynamic(GlobalAddressSDNode *GA,
+                                                 SelectionDAG &DAG) const {
+  SDValue Addr = getTLSGetAddr(GA, DAG, M68kII::MO_TLSLDM);
+  SDValue TGA =
+      DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0),
+                                 GA->getOffset(), M68kII::MO_TLSLD);
+  return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, Addr);
+}
+
+SDValue M68kTargetLowering::LowerTLSInitialExec(GlobalAddressSDNode *GA,
+                                                SelectionDAG &DAG) const {
+  SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32);
+  SDValue Tp = getM68kReadTp(SDLoc(GA), DAG);
+  SDValue TGA =
+      DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0),
+                                 GA->getOffset(), M68kII::MO_TLSIE);
+  SDValue Addr = DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, GOT);
+  SDValue Offset =
+      DAG.getLoad(MVT::i32, SDLoc(GA), DAG.getEntryNode(), Addr,
+                  MachinePointerInfo::getGOT(DAG.getMachineFunction()));
+
+  return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, Offset, Tp);
+}
+
+SDValue M68kTargetLowering::LowerTLSLocalExec(GlobalAddressSDNode *GA,
+                                              SelectionDAG &DAG) const {
+  SDValue Tp = getM68kReadTp(SDLoc(GA), DAG);
+  SDValue TGA =
+      DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0),
+                                 GA->getOffset(), M68kII::MO_TLSLE);
+  return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, Tp);
+}
+
+SDValue M68kTargetLowering::LowerGlobalTLSAddress(SDValue Op,
+                                                  SelectionDAG &DAG) const {
+  assert(Subtarget.isTargetELF());
+
+  auto *GA = cast<GlobalAddressSDNode>(Op);
+  TLSModel::Model AccessModel = DAG.getTarget().getTLSModel(GA->getGlobal());
+
+  switch (AccessModel) {
+  case TLSModel::GeneralDynamic:
+    return LowerTLSGeneralDynamic(GA, DAG);
+  case TLSModel::LocalDynamic:
+    return LowerTLSLocalDynamic(GA, DAG);
+  case TLSModel::InitialExec:
+    return LowerTLSInitialExec(GA, DAG);
+  case TLSModel::LocalExec:
+    return LowerTLSLocalExec(GA, DAG);
+  }
+
+  llvm_unreachable("Unexpected TLS access model type");
+}
+
 bool M68kTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT,
                                                 SDValue C) const {
   // Shifts and add instructions in M68000 and M68010 support

diff  --git a/llvm/lib/Target/M68k/M68kISelLowering.h b/llvm/lib/Target/M68k/M68kISelLowering.h
index d43160fe48d2e..5f279b3dcbd3e 100644
--- a/llvm/lib/Target/M68k/M68kISelLowering.h
+++ b/llvm/lib/Target/M68k/M68kISelLowering.h
@@ -245,6 +245,7 @@ class M68kTargetLowering : public TargetLowering {
                           const SmallVectorImpl<ISD::InputArg> &Ins,
                           const SDLoc &DL, SelectionDAG &DAG,
                           SmallVectorImpl<SDValue> &InVals) const;
+  SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
 
   /// LowerFormalArguments - transform physical registers into virtual
   /// registers and generate load operations for arguments places on the stack.
@@ -269,6 +270,20 @@ class M68kTargetLowering : public TargetLowering {
                       const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
                       SelectionDAG &DAG) const override;
 
+  SDValue LowerExternalSymbolCall(SelectionDAG &DAG, SDLoc loc,
+                                  llvm::StringRef SymbolName,
+                                  ArgListTy &&ArgList) const;
+  SDValue getTLSGetAddr(GlobalAddressSDNode *GA, SelectionDAG &DAG,
+                        unsigned TargetFlags) const;
+  SDValue getM68kReadTp(SDLoc Loc, SelectionDAG &DAG) const;
+
+  SDValue LowerTLSGeneralDynamic(GlobalAddressSDNode *GA,
+                                 SelectionDAG &DAG) const;
+  SDValue LowerTLSLocalDynamic(GlobalAddressSDNode *GA,
+                               SelectionDAG &DAG) const;
+  SDValue LowerTLSInitialExec(GlobalAddressSDNode *GA, SelectionDAG &DAG) const;
+  SDValue LowerTLSLocalExec(GlobalAddressSDNode *GA, SelectionDAG &DAG) const;
+
   bool decomposeMulByConstant(LLVMContext &Context, EVT VT,
                               SDValue C) const override;
 

diff  --git a/llvm/lib/Target/M68k/M68kInstrArithmetic.td b/llvm/lib/Target/M68k/M68kInstrArithmetic.td
index 13ecacfa6f442..c5a95b4bed123 100644
--- a/llvm/lib/Target/M68k/M68kInstrArithmetic.td
+++ b/llvm/lib/Target/M68k/M68kInstrArithmetic.td
@@ -312,6 +312,12 @@ defm ADD : MxBiArOp_AF<"adda", MxAdd, 0xD>;
 defm SUB : MxBiArOp_DF<"sub",  MxSub, 0, 0x9, 0x4>;
 defm SUB : MxBiArOp_AF<"suba", MxSub, 0x9>;
 
+// This pattern is used to enable the instruction selector to select ADD32ab
+// for global values that are allocated in thread-local storage, i.e.:
+//   t8: i32 = ISD::ADD GLOBAL_OFFSET_TABLE, TargetGlobalTLSAddress:i32<ptr @myvar>
+//     ====>
+//   t8: i32,i8 = ADD32ab GLOBAL_OFFSET_TABLE, TargetGlobalTLSAddress:i32<ptr @myvar>
+def : Pat<(add MxARD32:$src, tglobaltlsaddr:$opd), (ADD32ab MxARD32:$src, MxAL32:$opd)>;
 
 let Uses = [CCR], Defs = [CCR] in {
 let Constraints = "$src = $dst" in {

diff  --git a/llvm/lib/Target/M68k/M68kInstrInfo.cpp b/llvm/lib/Target/M68k/M68kInstrInfo.cpp
index 6dd2766e88c52..1803a936701fb 100644
--- a/llvm/lib/Target/M68k/M68kInstrInfo.cpp
+++ b/llvm/lib/Target/M68k/M68kInstrInfo.cpp
@@ -809,7 +809,12 @@ M68kInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
       {MO_GOT, "m68k-got"},
       {MO_GOTOFF, "m68k-gotoff"},
       {MO_GOTPCREL, "m68k-gotpcrel"},
-      {MO_PLT, "m68k-plt"}};
+      {MO_PLT, "m68k-plt"},
+      {MO_TLSGD, "m68k-tlsgd"},
+      {MO_TLSLD, "m68k-tlsld"},
+      {MO_TLSLDM, "m68k-tlsldm"},
+      {MO_TLSIE, "m68k-tlsie"},
+      {MO_TLSLE, "m68k-tlsle"}};
   return ArrayRef(TargetFlags);
 }
 

diff  --git a/llvm/lib/Target/M68k/M68kMCInstLower.cpp b/llvm/lib/Target/M68k/M68kMCInstLower.cpp
index 40844803aead1..b24d2d231c454 100644
--- a/llvm/lib/Target/M68k/M68kMCInstLower.cpp
+++ b/llvm/lib/Target/M68k/M68kMCInstLower.cpp
@@ -96,6 +96,21 @@ MCOperand M68kMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
   case M68kII::MO_PLT:
     RefKind = MCSymbolRefExpr::VK_PLT;
     break;
+  case M68kII::MO_TLSGD:
+    RefKind = MCSymbolRefExpr::VK_TLSGD;
+    break;
+  case M68kII::MO_TLSLD:
+    RefKind = MCSymbolRefExpr::VK_TLSLD;
+    break;
+  case M68kII::MO_TLSLDM:
+    RefKind = MCSymbolRefExpr::VK_TLSLDM;
+    break;
+  case M68kII::MO_TLSIE:
+    RefKind = MCSymbolRefExpr::VK_GOTTPOFF;
+    break;
+  case M68kII::MO_TLSLE:
+    RefKind = MCSymbolRefExpr::VK_TPOFF;
+    break;
   }
 
   if (!Expr) {

diff  --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h b/llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h
index 3703d86519de6..e52b4961e3c84 100644
--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h
+++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h
@@ -157,6 +157,37 @@ enum TOF {
   ///
   ///    name at PLT
   MO_PLT,
+
+  /// On a symbol operand, this indicates that the immediate is the offset to
+  /// the slot in GOT which stores the information for accessing the TLS
+  /// variable. This is used when operating in Global Dynamic mode.
+  ///    name at TLSGD
+  MO_TLSGD,
+
+  /// On a symbol operand, this indicates that the immediate is the offset to
+  /// variable within the thread local storage when operating in Local Dynamic
+  /// mode.
+  ///    name at TLSLD
+  MO_TLSLD,
+
+  /// On a symbol operand, this indicates that the immediate is the offset to
+  /// the slot in GOT which stores the information for accessing the TLS
+  /// variable. This is used when operating in Local Dynamic mode.
+  ///    name at TLSLDM
+  MO_TLSLDM,
+
+  /// On a symbol operand, this indicates that the immediate is the offset to
+  /// the variable within the thread local storage when operating in Initial
+  /// Exec mode.
+  ///    name at TLSIE
+  MO_TLSIE,
+
+  /// On a symbol operand, this indicates that the immediate is the offset to
+  /// the variable within in the thread local storage when operating in Local
+  /// Exec mode.
+  ///    name at TLSLE
+  MO_TLSLE,
+
 }; // enum TOF
 
 /// Return true if the specified TargetFlag operand is a reference to a stub

diff  --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kELFObjectWriter.cpp b/llvm/lib/Target/M68k/MCTargetDesc/M68kELFObjectWriter.cpp
index 27f1b3a3fac80..cac068e4dddf8 100644
--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kELFObjectWriter.cpp
+++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kELFObjectWriter.cpp
@@ -70,6 +70,57 @@ unsigned M68kELFObjectWriter::getRelocType(MCContext &Ctx,
   switch (Modifier) {
   default:
     llvm_unreachable("Unimplemented");
+
+  case MCSymbolRefExpr::VK_TLSGD:
+    switch (Type) {
+    case RT_32:
+      return ELF::R_68K_TLS_GD32;
+    case RT_16:
+      return ELF::R_68K_TLS_GD16;
+    case RT_8:
+      return ELF::R_68K_TLS_GD8;
+    }
+    llvm_unreachable("Unrecognized size");
+  case MCSymbolRefExpr::VK_TLSLDM:
+    switch (Type) {
+    case RT_32:
+      return ELF::R_68K_TLS_LDM32;
+    case RT_16:
+      return ELF::R_68K_TLS_LDM16;
+    case RT_8:
+      return ELF::R_68K_TLS_LDM8;
+    }
+    llvm_unreachable("Unrecognized size");
+  case MCSymbolRefExpr::VK_TLSLD:
+    switch (Type) {
+    case RT_32:
+      return ELF::R_68K_TLS_LDO32;
+    case RT_16:
+      return ELF::R_68K_TLS_LDO16;
+    case RT_8:
+      return ELF::R_68K_TLS_LDO8;
+    }
+    llvm_unreachable("Unrecognized size");
+  case MCSymbolRefExpr::VK_GOTTPOFF:
+    switch (Type) {
+    case RT_32:
+      return ELF::R_68K_TLS_IE32;
+    case RT_16:
+      return ELF::R_68K_TLS_IE16;
+    case RT_8:
+      return ELF::R_68K_TLS_IE8;
+    }
+    llvm_unreachable("Unrecognized size");
+  case MCSymbolRefExpr::VK_TPOFF:
+    switch (Type) {
+    case RT_32:
+      return ELF::R_68K_TLS_LE32;
+    case RT_16:
+      return ELF::R_68K_TLS_LE16;
+    case RT_8:
+      return ELF::R_68K_TLS_LE8;
+    }
+    llvm_unreachable("Unrecognized size");
   case MCSymbolRefExpr::VK_None:
     switch (Type) {
     case RT_32:

diff  --git a/llvm/test/CodeGen/M68k/TLS/tlsgd.ll b/llvm/test/CodeGen/M68k/TLS/tlsgd.ll
new file mode 100644
index 0000000000000..ed891dd6bb40f
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/TLS/tlsgd.ll
@@ -0,0 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=m68k --relocation-model=pic -o - %s | FileCheck %s
+
+ at myvar = external thread_local global i32, align 4
+
+define ptr @get_addr() nounwind {
+; CHECK-LABEL: get_addr:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    adda.l myvar at TLSGD, %a0
+; CHECK-NEXT:    move.l %a0, (%sp)
+; CHECK-NEXT:    jsr (__tls_get_addr at PLT,%pc)
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+  %0 = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @myvar)
+  ret ptr %0
+}
+
+declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)

diff  --git a/llvm/test/CodeGen/M68k/TLS/tlsie.ll b/llvm/test/CodeGen/M68k/TLS/tlsie.ll
new file mode 100644
index 0000000000000..db4000ee7b171
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/TLS/tlsie.ll
@@ -0,0 +1,23 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=m68k -o - %s | FileCheck %s
+
+ at myvar = external thread_local global i32, align 4
+
+define dso_local ptr @get_addr() nounwind {
+; CHECK-LABEL: get_addr:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    jsr __m68k_read_tp at PLT
+; CHECK-NEXT:    move.l %a0, %d0
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    add.l (0,myvar at GOTTPOFF,%a0), %d0
+; CHECK-NEXT:    move.l %d0, %a0
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+
+entry:
+  %0 = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @myvar)
+  ret ptr %0
+}
+
+declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)

diff  --git a/llvm/test/CodeGen/M68k/TLS/tlsld.ll b/llvm/test/CodeGen/M68k/TLS/tlsld.ll
new file mode 100644
index 0000000000000..1a0588dc47d02
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/TLS/tlsld.ll
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=m68k --relocation-model=pic -o - %s | FileCheck %s
+
+ at myvar = internal thread_local global i32 2, align 4
+
+define dso_local ptr @get_addr() nounwind {
+; CHECK-LABEL: get_addr:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    adda.l myvar at TLSLDM, %a0
+; CHECK-NEXT:    move.l %a0, (%sp)
+; CHECK-NEXT:    jsr (__tls_get_addr at PLT,%pc)
+; CHECK-NEXT:    adda.l myvar at TLSLD, %a0
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+  %0 = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @myvar)
+  ret ptr %0
+}
+
+declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)

diff  --git a/llvm/test/CodeGen/M68k/TLS/tlsle.ll b/llvm/test/CodeGen/M68k/TLS/tlsle.ll
new file mode 100644
index 0000000000000..b0c2b3796626c
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/TLS/tlsle.ll
@@ -0,0 +1,19 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=m68k -o - %s | FileCheck %s
+
+ at myvar = internal thread_local global i32 2, align 4
+
+define dso_local ptr @get_addr() nounwind {
+; CHECK-LABEL: get_addr:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    jsr __m68k_read_tp at PLT
+; CHECK-NEXT:    adda.l myvar at TPOFF, %a0
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+  %0 = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @myvar)
+  ret ptr %0
+}
+
+declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)


        


More information about the llvm-commits mailing list