Skip to content

Commit 4c2ec08

Browse files
committed
[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
1 parent 40d89de commit 4c2ec08

File tree

12 files changed

+317
-1
lines changed

12 files changed

+317
-1
lines changed

llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,15 @@ void M68kDAGToDAGISel::Select(SDNode *Node) {
666666
default:
667667
break;
668668

669+
case ISD::GLOBAL_OFFSET_TABLE: {
670+
SDValue GOT = CurDAG->getTargetExternalSymbol(
671+
"_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);
672+
MachineSDNode *Res =
673+
CurDAG->getMachineNode(M68k::LEA32q, DL, MVT::i32, GOT);
674+
ReplaceNode(Node, Res);
675+
return;
676+
}
677+
669678
case M68kISD::GLOBAL_BASE_REG:
670679
ReplaceNode(Node, getGlobalBaseReg());
671680
return;

llvm/lib/Target/M68k/M68kISelLowering.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,9 +1420,108 @@ SDValue M68kTargetLowering::LowerOperation(SDValue Op,
14201420
return LowerShiftRightParts(Op, DAG, false);
14211421
case ISD::ATOMIC_FENCE:
14221422
return LowerATOMICFENCE(Op, DAG);
1423+
case ISD::GlobalTLSAddress:
1424+
return LowerGlobalTLSAddress(Op, DAG);
14231425
}
14241426
}
14251427

1428+
SDValue M68kTargetLowering::LowerExternalSymbolCall(SelectionDAG &DAG,
1429+
SDLoc Loc,
1430+
llvm::StringRef SymbolName,
1431+
ArgListTy &&ArgList) const {
1432+
PointerType *PtrTy = PointerType::get(*DAG.getContext(), 0);
1433+
CallLoweringInfo CLI(DAG);
1434+
CLI.setDebugLoc(Loc)
1435+
.setChain(DAG.getEntryNode())
1436+
.setLibCallee(CallingConv::C, PtrTy,
1437+
DAG.getExternalSymbol(SymbolName.data(),
1438+
getPointerMemTy(DAG.getDataLayout())),
1439+
std::move(ArgList));
1440+
return LowerCallTo(CLI).first;
1441+
}
1442+
1443+
SDValue M68kTargetLowering::getTLSGetAddr(GlobalAddressSDNode *GA,
1444+
SelectionDAG &DAG,
1445+
unsigned TargetFlags) const {
1446+
SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32);
1447+
SDValue TGA = DAG.getTargetGlobalAddress(
1448+
GA->getGlobal(), GA, GA->getValueType(0), GA->getOffset(), TargetFlags);
1449+
SDValue Arg = DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, GOT, TGA);
1450+
1451+
PointerType *PtrTy = PointerType::get(*DAG.getContext(), 0);
1452+
1453+
ArgListTy Args;
1454+
ArgListEntry Entry;
1455+
Entry.Node = Arg;
1456+
Entry.Ty = PtrTy;
1457+
Args.push_back(Entry);
1458+
return LowerExternalSymbolCall(DAG, SDLoc(GA), "__tls_get_addr",
1459+
std::move(Args));
1460+
}
1461+
1462+
SDValue M68kTargetLowering::getM68kReadTp(SDLoc Loc, SelectionDAG &DAG) const {
1463+
return LowerExternalSymbolCall(DAG, Loc, "__m68k_read_tp", ArgListTy());
1464+
}
1465+
1466+
SDValue M68kTargetLowering::LowerTLSGeneralDynamic(GlobalAddressSDNode *GA,
1467+
SelectionDAG &DAG) const {
1468+
return getTLSGetAddr(GA, DAG, M68kII::MO_TLSGD);
1469+
}
1470+
1471+
SDValue M68kTargetLowering::LowerTLSLocalDynamic(GlobalAddressSDNode *GA,
1472+
SelectionDAG &DAG) const {
1473+
SDValue Addr = getTLSGetAddr(GA, DAG, M68kII::MO_TLSLDM);
1474+
SDValue TGA =
1475+
DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0),
1476+
GA->getOffset(), M68kII::MO_TLSLD);
1477+
return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, Addr);
1478+
}
1479+
1480+
SDValue M68kTargetLowering::LowerTLSInitialExec(GlobalAddressSDNode *GA,
1481+
SelectionDAG &DAG) const {
1482+
SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32);
1483+
SDValue Tp = getM68kReadTp(SDLoc(GA), DAG);
1484+
SDValue TGA =
1485+
DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0),
1486+
GA->getOffset(), M68kII::MO_TLSIE);
1487+
SDValue Addr = DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, GOT);
1488+
SDValue Offset =
1489+
DAG.getLoad(MVT::i32, SDLoc(GA), DAG.getEntryNode(), Addr,
1490+
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
1491+
1492+
return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, Offset, Tp);
1493+
}
1494+
1495+
SDValue M68kTargetLowering::LowerTLSLocalExec(GlobalAddressSDNode *GA,
1496+
SelectionDAG &DAG) const {
1497+
SDValue Tp = getM68kReadTp(SDLoc(GA), DAG);
1498+
SDValue TGA =
1499+
DAG.getTargetGlobalAddress(GA->getGlobal(), GA, GA->getValueType(0),
1500+
GA->getOffset(), M68kII::MO_TLSLE);
1501+
return DAG.getNode(ISD::ADD, SDLoc(GA), MVT::i32, TGA, Tp);
1502+
}
1503+
1504+
SDValue M68kTargetLowering::LowerGlobalTLSAddress(SDValue Op,
1505+
SelectionDAG &DAG) const {
1506+
assert(Subtarget.isTargetELF());
1507+
1508+
auto *GA = cast<GlobalAddressSDNode>(Op);
1509+
TLSModel::Model AccessModel = DAG.getTarget().getTLSModel(GA->getGlobal());
1510+
1511+
switch (AccessModel) {
1512+
case TLSModel::GeneralDynamic:
1513+
return LowerTLSGeneralDynamic(GA, DAG);
1514+
case TLSModel::LocalDynamic:
1515+
return LowerTLSLocalDynamic(GA, DAG);
1516+
case TLSModel::InitialExec:
1517+
return LowerTLSInitialExec(GA, DAG);
1518+
case TLSModel::LocalExec:
1519+
return LowerTLSLocalExec(GA, DAG);
1520+
}
1521+
1522+
llvm_unreachable("Unexpected TLS access model type");
1523+
}
1524+
14261525
bool M68kTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT,
14271526
SDValue C) const {
14281527
// Shifts and add instructions in M68000 and M68010 support

llvm/lib/Target/M68k/M68kISelLowering.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ class M68kTargetLowering : public TargetLowering {
245245
const SmallVectorImpl<ISD::InputArg> &Ins,
246246
const SDLoc &DL, SelectionDAG &DAG,
247247
SmallVectorImpl<SDValue> &InVals) const;
248+
SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
248249

249250
/// LowerFormalArguments - transform physical registers into virtual
250251
/// registers and generate load operations for arguments places on the stack.
@@ -269,6 +270,20 @@ class M68kTargetLowering : public TargetLowering {
269270
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
270271
SelectionDAG &DAG) const override;
271272

273+
SDValue LowerExternalSymbolCall(SelectionDAG &DAG, SDLoc loc,
274+
llvm::StringRef SymbolName,
275+
ArgListTy &&ArgList) const;
276+
SDValue getTLSGetAddr(GlobalAddressSDNode *GA, SelectionDAG &DAG,
277+
unsigned TargetFlags) const;
278+
SDValue getM68kReadTp(SDLoc Loc, SelectionDAG &DAG) const;
279+
280+
SDValue LowerTLSGeneralDynamic(GlobalAddressSDNode *GA,
281+
SelectionDAG &DAG) const;
282+
SDValue LowerTLSLocalDynamic(GlobalAddressSDNode *GA,
283+
SelectionDAG &DAG) const;
284+
SDValue LowerTLSInitialExec(GlobalAddressSDNode *GA, SelectionDAG &DAG) const;
285+
SDValue LowerTLSLocalExec(GlobalAddressSDNode *GA, SelectionDAG &DAG) const;
286+
272287
bool decomposeMulByConstant(LLVMContext &Context, EVT VT,
273288
SDValue C) const override;
274289

llvm/lib/Target/M68k/M68kInstrArithmetic.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,12 @@ defm ADD : MxBiArOp_AF<"adda", MxAdd, 0xD>;
312312
defm SUB : MxBiArOp_DF<"sub", MxSub, 0, 0x9, 0x4>;
313313
defm SUB : MxBiArOp_AF<"suba", MxSub, 0x9>;
314314

315+
// This pattern is used to enable the instruction selector to select ADD32ab
316+
// for global values that are allocated in thread-local storage, i.e.:
317+
// t8: i32 = ISD::ADD GLOBAL_OFFSET_TABLE, TargetGlobalTLSAddress:i32<ptr @myvar>
318+
// ====>
319+
// t8: i32,i8 = ADD32ab GLOBAL_OFFSET_TABLE, TargetGlobalTLSAddress:i32<ptr @myvar>
320+
def : Pat<(add MxARD32:$src, tglobaltlsaddr:$opd), (ADD32ab MxARD32:$src, MxAL32:$opd)>;
315321

316322
let Uses = [CCR], Defs = [CCR] in {
317323
let Constraints = "$src = $dst" in {

llvm/lib/Target/M68k/M68kInstrInfo.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,12 @@ M68kInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
809809
{MO_GOT, "m68k-got"},
810810
{MO_GOTOFF, "m68k-gotoff"},
811811
{MO_GOTPCREL, "m68k-gotpcrel"},
812-
{MO_PLT, "m68k-plt"}};
812+
{MO_PLT, "m68k-plt"},
813+
{MO_TLSGD, "m68k-tlsgd"},
814+
{MO_TLSLD, "m68k-tlsld"},
815+
{MO_TLSLDM, "m68k-tlsldm"},
816+
{MO_TLSIE, "m68k-tlsie"},
817+
{MO_TLSLE, "m68k-tlsle"}};
813818
return ArrayRef(TargetFlags);
814819
}
815820

llvm/lib/Target/M68k/M68kMCInstLower.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,21 @@ MCOperand M68kMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
9696
case M68kII::MO_PLT:
9797
RefKind = MCSymbolRefExpr::VK_PLT;
9898
break;
99+
case M68kII::MO_TLSGD:
100+
RefKind = MCSymbolRefExpr::VK_TLSGD;
101+
break;
102+
case M68kII::MO_TLSLD:
103+
RefKind = MCSymbolRefExpr::VK_TLSLD;
104+
break;
105+
case M68kII::MO_TLSLDM:
106+
RefKind = MCSymbolRefExpr::VK_TLSLDM;
107+
break;
108+
case M68kII::MO_TLSIE:
109+
RefKind = MCSymbolRefExpr::VK_GOTTPOFF;
110+
break;
111+
case M68kII::MO_TLSLE:
112+
RefKind = MCSymbolRefExpr::VK_TPOFF;
113+
break;
99114
}
100115

101116
if (!Expr) {

llvm/lib/Target/M68k/MCTargetDesc/M68kBaseInfo.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,37 @@ enum TOF {
157157
///
158158
/// name@PLT
159159
MO_PLT,
160+
161+
/// On a symbol operand, this indicates that the immediate is the offset to
162+
/// the slot in GOT which stores the information for accessing the TLS
163+
/// variable. This is used when operating in Global Dynamic mode.
164+
/// name@TLSGD
165+
MO_TLSGD,
166+
167+
/// On a symbol operand, this indicates that the immediate is the offset to
168+
/// variable within the thread local storage when operating in Local Dynamic
169+
/// mode.
170+
/// name@TLSLD
171+
MO_TLSLD,
172+
173+
/// On a symbol operand, this indicates that the immediate is the offset to
174+
/// the slot in GOT which stores the information for accessing the TLS
175+
/// variable. This is used when operating in Local Dynamic mode.
176+
/// name@TLSLDM
177+
MO_TLSLDM,
178+
179+
/// On a symbol operand, this indicates that the immediate is the offset to
180+
/// the variable within the thread local storage when operating in Initial
181+
/// Exec mode.
182+
/// name@TLSIE
183+
MO_TLSIE,
184+
185+
/// On a symbol operand, this indicates that the immediate is the offset to
186+
/// the variable within in the thread local storage when operating in Local
187+
/// Exec mode.
188+
/// name@TLSLE
189+
MO_TLSLE,
190+
160191
}; // enum TOF
161192

162193
/// Return true if the specified TargetFlag operand is a reference to a stub

llvm/lib/Target/M68k/MCTargetDesc/M68kELFObjectWriter.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,57 @@ unsigned M68kELFObjectWriter::getRelocType(MCContext &Ctx,
7070
switch (Modifier) {
7171
default:
7272
llvm_unreachable("Unimplemented");
73+
74+
case MCSymbolRefExpr::VK_TLSGD:
75+
switch (Type) {
76+
case RT_32:
77+
return ELF::R_68K_TLS_GD32;
78+
case RT_16:
79+
return ELF::R_68K_TLS_GD16;
80+
case RT_8:
81+
return ELF::R_68K_TLS_GD8;
82+
}
83+
llvm_unreachable("Unrecognized size");
84+
case MCSymbolRefExpr::VK_TLSLDM:
85+
switch (Type) {
86+
case RT_32:
87+
return ELF::R_68K_TLS_LDM32;
88+
case RT_16:
89+
return ELF::R_68K_TLS_LDM16;
90+
case RT_8:
91+
return ELF::R_68K_TLS_LDM8;
92+
}
93+
llvm_unreachable("Unrecognized size");
94+
case MCSymbolRefExpr::VK_TLSLD:
95+
switch (Type) {
96+
case RT_32:
97+
return ELF::R_68K_TLS_LDO32;
98+
case RT_16:
99+
return ELF::R_68K_TLS_LDO16;
100+
case RT_8:
101+
return ELF::R_68K_TLS_LDO8;
102+
}
103+
llvm_unreachable("Unrecognized size");
104+
case MCSymbolRefExpr::VK_GOTTPOFF:
105+
switch (Type) {
106+
case RT_32:
107+
return ELF::R_68K_TLS_IE32;
108+
case RT_16:
109+
return ELF::R_68K_TLS_IE16;
110+
case RT_8:
111+
return ELF::R_68K_TLS_IE8;
112+
}
113+
llvm_unreachable("Unrecognized size");
114+
case MCSymbolRefExpr::VK_TPOFF:
115+
switch (Type) {
116+
case RT_32:
117+
return ELF::R_68K_TLS_LE32;
118+
case RT_16:
119+
return ELF::R_68K_TLS_LE16;
120+
case RT_8:
121+
return ELF::R_68K_TLS_LE8;
122+
}
123+
llvm_unreachable("Unrecognized size");
73124
case MCSymbolRefExpr::VK_None:
74125
switch (Type) {
75126
case RT_32:

llvm/test/CodeGen/M68k/TLS/tlsgd.ll

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=m68k --relocation-model=pic -o - %s | FileCheck %s
3+
4+
@myvar = external thread_local global i32, align 4
5+
6+
define ptr @get_addr() nounwind {
7+
; CHECK-LABEL: get_addr:
8+
; CHECK: ; %bb.0: ; %entry
9+
; CHECK-NEXT: suba.l #4, %sp
10+
; CHECK-NEXT: lea (_GLOBAL_OFFSET_TABLE_@GOTPCREL,%pc), %a0
11+
; CHECK-NEXT: adda.l myvar@TLSGD, %a0
12+
; CHECK-NEXT: move.l %a0, (%sp)
13+
; CHECK-NEXT: jsr (__tls_get_addr@PLT,%pc)
14+
; CHECK-NEXT: adda.l #4, %sp
15+
; CHECK-NEXT: rts
16+
entry:
17+
%0 = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @myvar)
18+
ret ptr %0
19+
}
20+
21+
declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)

llvm/test/CodeGen/M68k/TLS/tlsie.ll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=m68k -o - %s | FileCheck %s
3+
4+
@myvar = external thread_local global i32, align 4
5+
6+
define dso_local ptr @get_addr() nounwind {
7+
; CHECK-LABEL: get_addr:
8+
; CHECK: ; %bb.0: ; %entry
9+
; CHECK-NEXT: suba.l #4, %sp
10+
; CHECK-NEXT: jsr __m68k_read_tp@PLT
11+
; CHECK-NEXT: move.l %a0, %d0
12+
; CHECK-NEXT: lea (_GLOBAL_OFFSET_TABLE_@GOTPCREL,%pc), %a0
13+
; CHECK-NEXT: add.l (0,myvar@GOTTPOFF,%a0), %d0
14+
; CHECK-NEXT: move.l %d0, %a0
15+
; CHECK-NEXT: adda.l #4, %sp
16+
; CHECK-NEXT: rts
17+
18+
entry:
19+
%0 = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @myvar)
20+
ret ptr %0
21+
}
22+
23+
declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)

llvm/test/CodeGen/M68k/TLS/tlsld.ll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=m68k --relocation-model=pic -o - %s | FileCheck %s
3+
4+
@myvar = internal thread_local global i32 2, align 4
5+
6+
define dso_local ptr @get_addr() nounwind {
7+
; CHECK-LABEL: get_addr:
8+
; CHECK: ; %bb.0: ; %entry
9+
; CHECK-NEXT: suba.l #4, %sp
10+
; CHECK-NEXT: lea (_GLOBAL_OFFSET_TABLE_@GOTPCREL,%pc), %a0
11+
; CHECK-NEXT: adda.l myvar@TLSLDM, %a0
12+
; CHECK-NEXT: move.l %a0, (%sp)
13+
; CHECK-NEXT: jsr (__tls_get_addr@PLT,%pc)
14+
; CHECK-NEXT: adda.l myvar@TLSLD, %a0
15+
; CHECK-NEXT: adda.l #4, %sp
16+
; CHECK-NEXT: rts
17+
entry:
18+
%0 = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @myvar)
19+
ret ptr %0
20+
}
21+
22+
declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)

llvm/test/CodeGen/M68k/TLS/tlsle.ll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=m68k -o - %s | FileCheck %s
3+
4+
@myvar = internal thread_local global i32 2, align 4
5+
6+
define dso_local ptr @get_addr() nounwind {
7+
; CHECK-LABEL: get_addr:
8+
; CHECK: ; %bb.0: ; %entry
9+
; CHECK-NEXT: suba.l #4, %sp
10+
; CHECK-NEXT: jsr __m68k_read_tp@PLT
11+
; CHECK-NEXT: adda.l myvar@TPOFF, %a0
12+
; CHECK-NEXT: adda.l #4, %sp
13+
; CHECK-NEXT: rts
14+
entry:
15+
%0 = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @myvar)
16+
ret ptr %0
17+
}
18+
19+
declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)

0 commit comments

Comments
 (0)