[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