Skip to content

Commit 76ad289

Browse files
authored
[PowerPC] 32-bit large code-model support for toc-data (#85129)
This patch adds the pseudo op ADDItocL for 32-bit large code-model support for toc-data.
1 parent 1fc72db commit 76ad289

File tree

7 files changed

+144
-36
lines changed

7 files changed

+144
-36
lines changed

llvm/lib/Target/PowerPC/P10InstrResources.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,7 @@ def : InstRW<[P10W_FX_3C, P10W_DISP_ANY],
881881
// 3 Cycles ALU operations, 1 input operands
882882
def : InstRW<[P10W_FX_3C, P10W_DISP_ANY, P10FX_Read],
883883
(instrs
884-
ADDI, ADDI8, ADDIdtprelL32, ADDItlsldLADDR32, ADDItocL8, LI, LI8,
884+
ADDI, ADDI8, ADDIdtprelL32, ADDItlsldLADDR32, ADDItocL, ADDItocL8, LI, LI8,
885885
ADDIC, ADDIC8,
886886
ADDIS, ADDIS8, ADDISdtprelHA32, ADDIStocHA, ADDIStocHA8, LIS, LIS8,
887887
ADDME, ADDME8,

llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,15 +1148,27 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
11481148

11491149
MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO);
11501150

1151-
// Always use TOC on AIX. Map the global address operand to be a reference
1152-
// to the TOC entry we will synthesize later. 'TOCEntry' is a label used to
1153-
// reference the storage allocated in the TOC which contains the address of
1154-
// 'MOSymbol'.
1155-
MCSymbol *TOCEntry =
1156-
lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK);
1157-
const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry,
1158-
MCSymbolRefExpr::VK_PPC_U,
1159-
OutContext);
1151+
// If the symbol isn't toc-data then use the TOC on AIX.
1152+
// Map the global address operand to be a reference to the TOC entry we
1153+
// will synthesize later. 'TOCEntry' is a label used to reference the
1154+
// storage allocated in the TOC which contains the address of 'MOSymbol'.
1155+
// If the toc-data attribute is used, the TOC entry contains the data
1156+
// rather than the address of the MOSymbol.
1157+
if (![](const MachineOperand &MO) {
1158+
if (!MO.isGlobal())
1159+
return false;
1160+
1161+
const GlobalVariable *GV = dyn_cast<GlobalVariable>(MO.getGlobal());
1162+
if (!GV)
1163+
return false;
1164+
1165+
return GV->hasAttribute("toc-data");
1166+
}(MO)) {
1167+
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK);
1168+
}
1169+
1170+
const MCExpr *Exp = MCSymbolRefExpr::create(
1171+
MOSymbol, MCSymbolRefExpr::VK_PPC_U, OutContext);
11601172
TmpInst.getOperand(2) = MCOperand::createExpr(Exp);
11611173
EmitToStreamer(*OutStreamer, TmpInst);
11621174
return;
@@ -1273,25 +1285,32 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
12731285
EmitToStreamer(*OutStreamer, TmpInst);
12741286
return;
12751287
}
1288+
case PPC::ADDItocL:
12761289
case PPC::ADDItocL8: {
1277-
// Transform %xd = ADDItocL8 %xs, @sym
1290+
// Transform %xd = ADDItocL %xs, @sym
12781291
LowerPPCMachineInstrToMCInst(MI, TmpInst, *this);
12791292

1280-
// Change the opcode to ADDI8. If the global address is external, then
1281-
// generate a TOC entry and reference that. Otherwise, reference the
1282-
// symbol directly.
1283-
TmpInst.setOpcode(PPC::ADDI8);
1293+
unsigned Op = MI->getOpcode();
1294+
1295+
// Change the opcode to load address for tocdata
1296+
TmpInst.setOpcode(Op == PPC::ADDItocL8 ? PPC::ADDI8 : PPC::LA);
12841297

12851298
const MachineOperand &MO = MI->getOperand(2);
1286-
assert((MO.isGlobal() || MO.isCPI()) && "Invalid operand for ADDItocL8.");
1299+
assert((Op == PPC::ADDItocL8)
1300+
? (MO.isGlobal() || MO.isCPI())
1301+
: MO.isGlobal() && "Invalid operand for ADDItocL8.");
1302+
assert(!(MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal())) &&
1303+
"Interposable definitions must use indirect accesses.");
12871304

1288-
LLVM_DEBUG(assert(
1289-
!(MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal())) &&
1290-
"Interposable definitions must use indirect access."));
1305+
// Map the operand to its corresponding MCSymbol.
1306+
const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
1307+
1308+
const MCExpr *Exp = MCSymbolRefExpr::create(
1309+
MOSymbol,
1310+
Op == PPC::ADDItocL8 ? MCSymbolRefExpr::VK_PPC_TOC_LO
1311+
: MCSymbolRefExpr::VK_PPC_L,
1312+
OutContext);
12911313

1292-
const MCExpr *Exp =
1293-
MCSymbolRefExpr::create(getMCSymbolForTOCPseudoMO(MO, *this),
1294-
MCSymbolRefExpr::VK_PPC_TOC_LO, OutContext);
12951314
TmpInst.getOperand(2) = MCOperand::createExpr(Exp);
12961315
EmitToStreamer(*OutStreamer, TmpInst);
12971316
return;

llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ SDNode *PPCDAGToDAGISel::getGlobalBaseReg() {
510510
}
511511

512512
// Check if a SDValue has the toc-data attribute.
513-
static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
513+
static bool hasTocDataAttr(SDValue Val) {
514514
GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Val);
515515
if (!GA)
516516
return false;
@@ -6115,8 +6115,7 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
61156115

61166116
assert(isAIXABI && "ELF ABI already handled");
61176117

6118-
if (hasTocDataAttr(N->getOperand(0),
6119-
CurDAG->getDataLayout().getPointerSize())) {
6118+
if (hasTocDataAttr(N->getOperand(0))) {
61206119
replaceWith(PPC::ADDItoc, N, MVT::i32);
61216120
return;
61226121
}
@@ -6128,8 +6127,7 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
61286127
if (isPPC64 && CModel == CodeModel::Small) {
61296128
assert(isAIXABI && "ELF ABI handled in common SelectCode");
61306129

6131-
if (hasTocDataAttr(N->getOperand(0),
6132-
CurDAG->getDataLayout().getPointerSize())) {
6130+
if (hasTocDataAttr(N->getOperand(0))) {
61336131
replaceWith(PPC::ADDItoc8, N, MVT::i64);
61346132
return;
61356133
}
@@ -6144,23 +6142,44 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
61446142
" ELF/AIX or 32-bit AIX in the following.");
61456143

61466144
// Transforms the ISD::TOC_ENTRY node for 32-bit AIX large code model mode
6147-
// or 64-bit medium (ELF-only) or large (ELF and AIX) code model code. We
6148-
// generate two instructions as described below. The first source operand
6149-
// is a symbol reference. If it must be toc-referenced according to
6145+
// or 64-bit medium (ELF-only) or large (ELF and AIX) code model code non
6146+
// toc-data symbols.
6147+
// We generate two instructions as described below. The first source
6148+
// operand is a symbol reference. If it must be toc-referenced according to
61506149
// Subtarget, we generate:
61516150
// [32-bit AIX]
61526151
// LWZtocL(@sym, ADDIStocHA(%r2, @sym))
61536152
// [64-bit ELF/AIX]
61546153
// LDtocL(@sym, ADDIStocHA8(%x2, @sym))
61556154
// Otherwise we generate:
61566155
// ADDItocL8(ADDIStocHA8(%x2, @sym), @sym)
6156+
6157+
// For large code model toc-data symbols we generate:
6158+
// [32-bit AIX]
6159+
// ADDItocL(ADDIStocHA(%x2, @sym), @sym)
6160+
// [64-bit AIX]
6161+
// Currently not supported.
6162+
61576163
SDValue GA = N->getOperand(0);
61586164
SDValue TOCbase = N->getOperand(1);
61596165

61606166
EVT VT = isPPC64 ? MVT::i64 : MVT::i32;
61616167
SDNode *Tmp = CurDAG->getMachineNode(
61626168
isPPC64 ? PPC::ADDIStocHA8 : PPC::ADDIStocHA, dl, VT, TOCbase, GA);
61636169

6170+
// On AIX if the symbol has the toc-data attribute it will be defined
6171+
// in the TOC entry, so we use an ADDItocL similar to the medium code
6172+
// model ELF abi.
6173+
if (isAIXABI && hasTocDataAttr(GA)) {
6174+
if (isPPC64)
6175+
report_fatal_error(
6176+
"64-bit large code model toc-data not yet supported");
6177+
6178+
ReplaceNode(N, CurDAG->getMachineNode(PPC::ADDItocL, dl, VT,
6179+
SDValue(Tmp, 0), GA));
6180+
return;
6181+
}
6182+
61646183
if (PPCLowering->isAccessedAsGotIndirect(GA)) {
61656184
// If it is accessed as got-indirect, we need an extra LWZ/LD to load
61666185
// the address.

llvm/lib/Target/PowerPC/PPCInstrInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,7 @@ bool PPCInstrInfo::isReallyTriviallyReMaterializable(
10901090
case PPC::LIS8:
10911091
case PPC::ADDIStocHA:
10921092
case PPC::ADDIStocHA8:
1093+
case PPC::ADDItocL:
10931094
case PPC::ADDItocL8:
10941095
case PPC::LOAD_STACK_GUARD:
10951096
case PPC::PPCLdFixedAddr:

llvm/lib/Target/PowerPC/PPCInstrInfo.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3346,11 +3346,13 @@ def ADDIStocHA : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, tocentr
33463346
"#ADDIStocHA",
33473347
[(set i32:$rD,
33483348
(PPCtoc_entry i32:$reg, tglobaladdr:$disp))]>;
3349-
// Local Data Transform
3349+
// TOC Data Transform AIX
33503350
def ADDItoc : PPCEmitTimePseudo<(outs gprc:$rD), (ins tocentry32:$disp, gprc:$reg),
33513351
"#ADDItoc",
33523352
[(set i32:$rD,
33533353
(PPCtoc_entry tglobaladdr:$disp, i32:$reg))]>;
3354+
def ADDItocL : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, tocentry32:$disp),
3355+
"#ADDItocL", []>;
33543356

33553357
// Get Global (GOT) Base Register offset, from the word immediately preceding
33563358
// the function label.

llvm/lib/Target/PowerPC/PPCMacroFusion.def

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
// {addi} followed by one of these {lxvd2x, lxvw4x, lxvdsx, lvebx, lvehx,
3333
// lvewx, lvx, lxsdx}
3434
FUSION_FEATURE(AddiLoad, hasAddiLoadFusion, 2, \
35-
FUSION_OP_SET(ADDI, ADDI8, ADDItocL8), \
35+
FUSION_OP_SET(ADDI, ADDI8, ADDItocL, ADDItocL8), \
3636
FUSION_OP_SET(LXVD2X, LXVW4X, LXVDSX, LVEBX, LVEHX, LVEWX, \
3737
LVX, LXSDX))
3838

@@ -134,13 +134,13 @@ FUSION_FEATURE(XorisXori, hasWideImmFusion, 1, FUSION_OP_SET(XORIS, XORIS8),
134134

135135
// addis rx,ra,si - addi rt,rx,SI, SI >= 0
136136
FUSION_FEATURE(AddisAddi, hasWideImmFusion, 1,
137-
FUSION_OP_SET(ADDIS, ADDIS8, ADDIStocHA8),
138-
FUSION_OP_SET(ADDI, ADDI8, ADDItocL8))
137+
FUSION_OP_SET(ADDIS, ADDIS8, ADDIStocHA8, ADDIStocHA),
138+
FUSION_OP_SET(ADDI, ADDI8, ADDItocL8, ADDItocL))
139139

140140
// addi rx,ra,si - addis rt,rx,SI, ra > 0, SI >= 2
141141
FUSION_FEATURE(AddiAddis, hasWideImmFusion, 1,
142-
FUSION_OP_SET(ADDI, ADDI8, ADDItocL8),
143-
FUSION_OP_SET(ADDIS, ADDIS8, ADDIStocHA8))
142+
FUSION_OP_SET(ADDI, ADDI8, ADDItocL8, ADDItocL),
143+
FUSION_OP_SET(ADDIS, ADDIS8, ADDIStocHA8, ADDIStocHA))
144144

145145
// mtctr - { bcctr,bcctrl }
146146
FUSION_FEATURE(ZeroMoveCTR, hasZeroMoveFusion, -1,

llvm/test/CodeGen/PowerPC/toc-data.ll

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212
; RUN: llc -mtriple powerpc-ibm-aix-xcoff -verify-machineinstrs -O0 < %s | FileCheck %s --check-prefix TEST32
1313
; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -verify-machineinstrs -O0 < %s | FileCheck %s --check-prefix TEST64
1414

15+
; RUN: llc -mtriple powerpc-ibm-aix-xcoff -code-model=large -verify-machineinstrs < %s \
16+
; RUN: -stop-before=ppc-vsx-copy | FileCheck %s --check-prefix CHECK32LARGE
17+
; RUN: llc -mtriple powerpc-ibm-aix-xcoff -code-model=large -verify-machineinstrs < %s | FileCheck %s --check-prefix TEST32LARGE
18+
19+
; Global variables i and f have the toc-data attribute.
20+
; In the following functions, those writing to or reading from
21+
; variables i and f should use the toc-data access pattern.
22+
; All remaining variables should use the regular toc access sequence.
1523
@i = dso_local global i32 0, align 4 #0
1624
@d = dso_local local_unnamed_addr global double 3.141590e+00, align 8
1725
@f = dso_local local_unnamed_addr global float 0x4005BE76C0000000, align 4 #0
@@ -44,6 +52,16 @@ define dso_local void @write_int(i32 signext %in) {
4452
; TEST64: la 4, i[TD](2)
4553
; TEST64-NEXT: stw 3, 0(4)
4654

55+
; CHECK32LARGE: name: write_int
56+
; CHECK32LARGE: %[[SCRATCH1:[0-9]+]]:gprc_and_gprc_nor0 = ADDIStocHA $r2, @i
57+
; CHECK32LARGE-NEXT: %[[SCRATCH2:[0-9]+]]:gprc_and_gprc_nor0 = ADDItocL killed %[[SCRATCH1]], @i
58+
; CHECK32LARGE-NEXT: STW %{{[0-9]+}}, 0, killed %[[SCRATCH2]] :: (store (s32) into @i)
59+
60+
; FIXME: peephole optimization opportunity for lower part relocation @l to the consuming stw
61+
; TEST32LARGE: .write_int:
62+
; TEST32LARGE: addis 4, i[TD]@u(2)
63+
; TEST32LARGE-NEXT: la 4, i[TD]@l(4)
64+
; TEST32LARGE-NEXT: stw 3, 0(4)
4765

4866
define dso_local i64 @read_ll() {
4967
entry:
@@ -70,6 +88,15 @@ define dso_local i64 @read_ll() {
7088
; TEST64: ld 3, L..C0(2)
7189
; TEST64-NEXT: ld 3, 0(3)
7290

91+
; CHECK32LARGE: name: read_ll
92+
; CHECK32LARGE: %[[SCRATCH1:[0-9]+]]:gprc_and_gprc_nor0 = ADDIStocHA $r2, @ll
93+
; CHECK32LARGE: LWZtocL @ll, killed %[[SCRATCH1]] :: (load (s32) from got)
94+
95+
; TEST32LARGE: .read_ll:
96+
; TEST32LARGE: addis 3, L..C0@u(2)
97+
; TEST32LARGE-NEXT: lwz 4, L..C0@l(3)
98+
; TEST32LARGE-NEXT: lwz 3, 0(4)
99+
; TEST32LARGE-NEXT: lwz 4, 4(4)
73100

74101
define dso_local float @read_float() {
75102
entry:
@@ -96,6 +123,16 @@ define dso_local float @read_float() {
96123
; TEST64: la 3, f[TD](2)
97124
; TEST64-NEXT: lfs 1, 0(3)
98125

126+
; CHECK32LARGE: name: read_float
127+
; CHECK32LARGE: %[[SCRATCH1:[0-9]+]]:gprc_and_gprc_nor0 = ADDIStocHA $r2, @f
128+
; CHECK32LARGE-NEXT: %[[SCRATCH2:[0-9]+]]:gprc_and_gprc_nor0 = ADDItocL killed %[[SCRATCH1]], @f
129+
; CHECK32LARGE-NEXT: LFS 0, killed %[[SCRATCH2]] :: (dereferenceable load (s32) from @f)
130+
131+
; FIXME: peephole optimization opportunity for lower part relocation @l to the consuming lfs
132+
; TEST32LARGE: .read_float:
133+
; TEST32LARGE: addis 3, f[TD]@u(2)
134+
; TEST32LARGE-NEXT: la 3, f[TD]@l(3)
135+
; TEST32LARGE-NEXT: lfs 1, 0(3)
99136

100137
define dso_local void @write_double(double %in) {
101138
entry:
@@ -121,6 +158,14 @@ define dso_local void @write_double(double %in) {
121158
; TEST64: ld 3, L..C1(2)
122159
; TEST64-NEXT: stfd 1, 0(3)
123160

161+
; CHECK32LARGE: name: write_double
162+
; CHECK32LARGE: %[[SCRATCH1:[0-9]+]]:gprc_and_gprc_nor0 = ADDIStocHA $r2, @d
163+
; CHECK32LARGE: LWZtocL @d, killed %[[SCRATCH1]] :: (load (s32) from got)
164+
165+
; TEST32LARGE: .write_double:
166+
; TEST32LARGE: addis 3, L..C1@u(2)
167+
; TEST32LARGE-NEXT: lwz 3, L..C1@l(3)
168+
; TEST32LARGE-NEXT: stfd 1, 0(3)
124169

125170
define dso_local nonnull ptr @addr() {
126171
entry:
@@ -144,6 +189,15 @@ define dso_local nonnull ptr @addr() {
144189
; TEST64: .addr
145190
; TEST64: la 3, i[TD](2)
146191

192+
; CHECK32LARGE: name: addr
193+
; CHECK32LARGE: %[[SCRATCH1:[0-9]+]]:gprc_and_gprc_nor0 = ADDIStocHA $r2, @i
194+
; CHECK32LARGE-NEXT: %[[SCRATCH2:[0-9]+]]:gprc = ADDItocL killed %[[SCRATCH1]], @i
195+
; CHECK32LARGE-NEXT: $r3 = COPY %[[SCRATCH2]]
196+
197+
; TEST32LARGE: .addr:
198+
; TEST32LARGE: addis 3, i[TD]@u(2)
199+
; TEST32LARGE-NEXT: la 3, i[TD]@l(3)
200+
147201
; TEST32: .toc
148202
; TEST32: .tc ll[TC],ll[RW]
149203
; TEST32-NOT: .csect ll[TD]
@@ -170,4 +224,17 @@ define dso_local nonnull ptr @addr() {
170224
; TEST64-NEXT: .globl f[TD]
171225
; TEST64-NOT: .tc f[TD],f[RW]
172226

227+
; TEST32LARGE: .toc
228+
; TEST32LARGE: .tc ll[TE],ll[RW]
229+
; TEST32LARGE-NOT: .csect ll[TD]
230+
; TEST32LARGE: .tc d[TE],d[RW]
231+
; TEST32LARGE-NOT: .csect d[TD],2
232+
; TEST32LARGE: .csect i[TD],2
233+
; TEST32LARGE-NEXT: .globl i[TD]
234+
; TEST32LARGE-NEXT: .align 2
235+
; TEST32LARGE-NOT: .tc i[TE],i[RW]
236+
; TEST32LARGE: .csect f[TD],2
237+
; TEST32LARGE-NEXT: .globl f[TD]
238+
; TEST32LARGE-NOT: .tc f[TE],f[RW]
239+
173240
attributes #0 = { "toc-data" }

0 commit comments

Comments
 (0)