Skip to content

Commit a60251d

Browse files
[PowerPC] Add linker opt for PC Relative GOT indirect accesses
A linker optimization is available on PowerPC for GOT indirect PCRelative loads. The idea is that we can mark a usual GOT indirect load: pld 3, vec@got@pcrel(0), 1 lwa 3, 4(3) With a relocation to say that if we don't need to go through the GOT we can let the linker further optimize this and replace a load with a nop. pld 3, vec@got@pcrel(0), 1 .Lpcrel1: .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8) lwa 3, 4(3) This patch adds the logic that allows the compiler to add the R_PPC64_PCREL_OPT. Reviewers: nemanjai, lei, hfinkel, sfertile, efriedma, tstellar, grosbach Reviewed By: nemanjai Differential Revision: https://reviews.llvm.org/D79864
1 parent b98b170 commit a60251d

15 files changed

+794
-4
lines changed

llvm/include/llvm/MC/MCExpr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ class MCSymbolRefExpr : public MCExpr {
302302
VK_PPC_TLSLD, // symbol@tlsld
303303
VK_PPC_LOCAL, // symbol@local
304304
VK_PPC_NOTOC, // symbol@notoc
305+
VK_PPC_PCREL_OPT, // .reloc expr, R_PPC64_PCREL_OPT, expr
305306

306307
VK_COFF_IMGREL32, // symbol@imgrel (image-relative)
307308

llvm/lib/MC/MCExpr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
324324
case VK_PPC_TLSLD: return "tlsld";
325325
case VK_PPC_LOCAL: return "local";
326326
case VK_PPC_NOTOC: return "notoc";
327+
case VK_PPC_PCREL_OPT: return "<<invalid>>";
327328
case VK_COFF_IMGREL32: return "IMGREL";
328329
case VK_Hexagon_LO16: return "LO16";
329330
case VK_Hexagon_HI16: return "HI16";

llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121

2222
#include "PPCELFStreamer.h"
23+
#include "PPCFixupKinds.h"
2324
#include "PPCInstrInfo.h"
2425
#include "PPCMCCodeEmitter.h"
2526
#include "llvm/BinaryFormat/ELF.h"
@@ -89,12 +90,33 @@ void PPCELFStreamer::emitInstruction(const MCInst &Inst,
8990
PPCMCCodeEmitter *Emitter =
9091
static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr());
9192

93+
// If the instruction is a part of the GOT to PC-Rel link time optimization
94+
// instruction pair, return a value, otherwise return None. A true returned
95+
// value means the instruction is the PLDpc and a false value means it is
96+
// the user instruction.
97+
Optional<bool> IsPartOfGOTToPCRelPair = isPartOfGOTToPCRelPair(Inst, STI);
98+
99+
// User of the GOT-indirect address.
100+
// For example, the load that will get the relocation as follows:
101+
// .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
102+
// lwa 3, 4(3)
103+
if (IsPartOfGOTToPCRelPair.hasValue() && !IsPartOfGOTToPCRelPair.getValue())
104+
emitGOTToPCRelReloc(Inst);
105+
92106
// Special handling is only for prefixed instructions.
93107
if (!Emitter->isPrefixedInstruction(Inst)) {
94108
MCELFStreamer::emitInstruction(Inst, STI);
95109
return;
96110
}
97111
emitPrefixedInstruction(Inst, STI);
112+
113+
// Producer of the GOT-indirect address.
114+
// For example, the prefixed load from the got that will get the label as
115+
// follows:
116+
// pld 3, vec@got@pcrel(0), 1
117+
// .Lpcrel1:
118+
if (IsPartOfGOTToPCRelPair.hasValue() && IsPartOfGOTToPCRelPair.getValue())
119+
emitGOTToPCRelLabel(Inst);
98120
}
99121

100122
void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
@@ -103,6 +125,102 @@ void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
103125
MCELFStreamer::emitLabel(Symbol);
104126
}
105127

128+
// This linker time GOT PC Relative optimization relocation will look like this:
129+
// pld <reg> symbol@got@pcrel
130+
// <Label###>:
131+
// .reloc Label###-8,R_PPC64_PCREL_OPT,.-(Label###-8)
132+
// load <loadedreg>, 0(<reg>)
133+
// The reason we place the label after the PLDpc instruction is that there
134+
// may be an alignment nop before it since prefixed instructions must not
135+
// cross a 64-byte boundary (please see
136+
// PPCELFStreamer::emitPrefixedInstruction()). When referring to the
137+
// label, we subtract the width of a prefixed instruction (8 bytes) to ensure
138+
// we refer to the PLDpc.
139+
void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {
140+
// Get the last operand which contains the symbol.
141+
const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
142+
assert(Operand.isExpr() && "Expecting an MCExpr.");
143+
// Cast the last operand to MCSymbolRefExpr to get the symbol.
144+
const MCExpr *Expr = Operand.getExpr();
145+
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
146+
assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
147+
"Expecting a symbol of type VK_PPC_PCREL_OPT");
148+
MCSymbol *LabelSym =
149+
getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
150+
const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext());
151+
const MCExpr *Eight = MCConstantExpr::create(8, getContext());
152+
// SubExpr is just Label###-8
153+
const MCExpr *SubExpr =
154+
MCBinaryExpr::createSub(LabelExpr, Eight, getContext());
155+
MCSymbol *CurrentLocation = getContext().createTempSymbol();
156+
const MCExpr *CurrentLocationExpr =
157+
MCSymbolRefExpr::create(CurrentLocation, getContext());
158+
// SubExpr2 is .-(Label###-8)
159+
const MCExpr *SubExpr2 =
160+
MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, getContext());
161+
162+
MCDataFragment *DF = static_cast<MCDataFragment *>(LabelSym->getFragment());
163+
assert(DF && "Expecting a valid data fragment.");
164+
MCFixupKind FixupKind = static_cast<MCFixupKind>(FirstLiteralRelocationKind +
165+
ELF::R_PPC64_PCREL_OPT);
166+
DF->getFixups().push_back(
167+
MCFixup::create(LabelSym->getOffset() - 8, SubExpr2,
168+
FixupKind, Inst.getLoc()));
169+
emitLabel(CurrentLocation, Inst.getLoc());
170+
}
171+
172+
// Emit the label that immediately follows the PLDpc for a link time GOT PC Rel
173+
// optimization.
174+
void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {
175+
// Get the last operand which contains the symbol.
176+
const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
177+
assert(Operand.isExpr() && "Expecting an MCExpr.");
178+
// Cast the last operand to MCSymbolRefExpr to get the symbol.
179+
const MCExpr *Expr = Operand.getExpr();
180+
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
181+
assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
182+
"Expecting a symbol of type VK_PPC_PCREL_OPT");
183+
MCSymbol *LabelSym =
184+
getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
185+
emitLabel(LabelSym, Inst.getLoc());
186+
}
187+
188+
// This funciton checks if the parameter Inst is part of the setup for a link
189+
// time GOT PC Relative optimization. For example in this situation:
190+
// <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)>
191+
// <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
192+
// <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282>
193+
// <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
194+
// The above is a pair of such instructions and this function will not return
195+
// None for either one of them. In both cases we are looking for the last
196+
// operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an MCExpr
197+
// and has the flag MCSymbolRefExpr::VK_PPC_PCREL_OPT. After that we just look
198+
// at the opcode and in the case of PLDpc we will return true. For the load
199+
// (or store) this function will return false indicating it has found the second
200+
// instruciton in the pair.
201+
Optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,
202+
const MCSubtargetInfo &STI) {
203+
// Need at least two operands.
204+
if (Inst.getNumOperands() < 2)
205+
return None;
206+
207+
unsigned LastOp = Inst.getNumOperands() - 1;
208+
// The last operand needs to be an MCExpr and it needs to have a variant kind
209+
// of VK_PPC_PCREL_OPT. If it does not satisfy these conditions it is not a
210+
// link time GOT PC Rel opt instruction and we can ignore it and return None.
211+
const MCOperand &Operand = Inst.getOperand(LastOp);
212+
if (!Operand.isExpr())
213+
return None;
214+
215+
// Check for the variant kind VK_PPC_PCREL_OPT in this expression.
216+
const MCExpr *Expr = Operand.getExpr();
217+
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
218+
if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_PPC_PCREL_OPT)
219+
return None;
220+
221+
return (Inst.getOpcode() == PPC::PLDpc);
222+
}
223+
106224
MCELFStreamer *llvm::createPPCELFStreamer(
107225
MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
108226
std::unique_ptr<MCObjectWriter> OW,

llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,15 @@ class PPCELFStreamer : public MCELFStreamer {
4343
void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
4444
private:
4545
void emitPrefixedInstruction(const MCInst &Inst, const MCSubtargetInfo &STI);
46+
void emitGOTToPCRelReloc(const MCInst &Inst);
47+
void emitGOTToPCRelLabel(const MCInst &Inst);
4648
};
4749

50+
// Check if the instruction Inst is part of a pair of instructions that make up
51+
// a link time GOT PC Rel optimization.
52+
Optional<bool> isPartOfGOTToPCRelPair(const MCInst &Inst,
53+
const MCSubtargetInfo &STI);
54+
4855
MCELFStreamer *createPPCELFStreamer(MCContext &Context,
4956
std::unique_ptr<MCAsmBackend> MAB,
5057
std::unique_ptr<MCObjectWriter> OW,

llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,36 @@ void PPCInstPrinter::printInst(const MCInst *MI, uint64_t Address,
9292
return;
9393
}
9494

95+
// Check if the last operand is an expression with the variant kind
96+
// VK_PPC_PCREL_OPT. If this is the case then this is a linker optimization
97+
// relocation and the .reloc directive needs to be added.
98+
unsigned LastOp = MI->getNumOperands() - 1;
99+
if (MI->getNumOperands() > 1) {
100+
const MCOperand &Operand = MI->getOperand(LastOp);
101+
if (Operand.isExpr()) {
102+
const MCExpr *Expr = Operand.getExpr();
103+
const MCSymbolRefExpr *SymExpr =
104+
static_cast<const MCSymbolRefExpr *>(Expr);
105+
106+
if (SymExpr && SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT) {
107+
const MCSymbol &Symbol = SymExpr->getSymbol();
108+
if (MI->getOpcode() == PPC::PLDpc) {
109+
printInstruction(MI, Address, O);
110+
O << "\n";
111+
Symbol.print(O, &MAI);
112+
O << ":";
113+
return;
114+
} else {
115+
O << "\t.reloc ";
116+
Symbol.print(O, &MAI);
117+
O << "-8,R_PPC64_PCREL_OPT,.-(";
118+
Symbol.print(O, &MAI);
119+
O << "-8)\n";
120+
}
121+
}
122+
}
123+
}
124+
95125
// Check for slwi/srwi mnemonics.
96126
if (MI->getOpcode() == PPC::RLWINM) {
97127
unsigned char SH = MI->getOperand(2).getImm();

llvm/lib/Target/PowerPC/PPC.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ namespace llvm {
107107
/// produce the relocation @got@pcrel. Fixup is VK_PPC_GOT_PCREL.
108108
MO_GOT_FLAG = 8,
109109

110+
// MO_PCREL_OPT_FLAG - If this bit is set the operand is part of a
111+
// PC Relative linker optimization.
112+
MO_PCREL_OPT_FLAG = 16,
113+
110114
/// The next are not flags but distinct values.
111115
MO_ACCESS_MASK = 0xf00,
112116

llvm/lib/Target/PowerPC/PPCInstrInfo.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2283,7 +2283,8 @@ PPCInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
22832283
{MO_PLT, "ppc-plt"},
22842284
{MO_PIC_FLAG, "ppc-pic"},
22852285
{MO_PCREL_FLAG, "ppc-pcrel"},
2286-
{MO_GOT_FLAG, "ppc-got"}};
2286+
{MO_GOT_FLAG, "ppc-got"},
2287+
{MO_PCREL_OPT_FLAG, "ppc-opt-pcrel"}};
22872288
return makeArrayRef(TargetFlags);
22882289
}
22892290

llvm/lib/Target/PowerPC/PPCMCInstLower.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol,
100100
MIOpcode == PPC::BL8_NOTOC) {
101101
RefKind = MCSymbolRefExpr::VK_PPC_NOTOC;
102102
}
103+
if (MO.getTargetFlags() == PPCII::MO_PCREL_OPT_FLAG)
104+
RefKind = MCSymbolRefExpr::VK_PPC_PCREL_OPT;
103105
}
104106

105107
const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, RefKind, Ctx);

0 commit comments

Comments
 (0)