Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp
35294 views
1
//===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This is a custom MCELFStreamer for PowerPC.
10
//
11
// The purpose of the custom ELF streamer is to allow us to intercept
12
// instructions as they are being emitted and align all 8 byte instructions
13
// to a 64 byte boundary if required (by adding a 4 byte nop). This is important
14
// because 8 byte instructions are not allowed to cross 64 byte boundaries
15
// and by aliging anything that is within 4 bytes of the boundary we can
16
// guarantee that the 8 byte instructions do not cross that boundary.
17
//
18
//===----------------------------------------------------------------------===//
19
20
#include "PPCELFStreamer.h"
21
#include "PPCFixupKinds.h"
22
#include "PPCMCCodeEmitter.h"
23
#include "PPCMCTargetDesc.h"
24
#include "llvm/BinaryFormat/ELF.h"
25
#include "llvm/MC/MCAsmBackend.h"
26
#include "llvm/MC/MCAssembler.h"
27
#include "llvm/MC/MCCodeEmitter.h"
28
#include "llvm/MC/MCContext.h"
29
#include "llvm/MC/MCInst.h"
30
#include "llvm/MC/MCInstrDesc.h"
31
#include "llvm/MC/MCObjectWriter.h"
32
#include "llvm/MC/MCSymbolELF.h"
33
#include "llvm/Support/Casting.h"
34
#include "llvm/Support/SourceMgr.h"
35
36
using namespace llvm;
37
38
PPCELFStreamer::PPCELFStreamer(MCContext &Context,
39
std::unique_ptr<MCAsmBackend> MAB,
40
std::unique_ptr<MCObjectWriter> OW,
41
std::unique_ptr<MCCodeEmitter> Emitter)
42
: MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(Emitter)),
43
LastLabel(nullptr) {}
44
45
void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst,
46
const MCSubtargetInfo &STI) {
47
// Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is
48
// before the boundary and the remaining 4-bytes are after the boundary). In
49
// order to achieve this, a nop is added prior to any such boundary-crossing
50
// prefixed instruction. Align to 64 bytes if possible but add a maximum of 4
51
// bytes when trying to do that. If alignment requires adding more than 4
52
// bytes then the instruction won't be aligned. When emitting a code alignment
53
// a new fragment is created for this alignment. This fragment will contain
54
// all of the nops required as part of the alignment operation. In the cases
55
// when no nops are added then The fragment is still created but it remains
56
// empty.
57
emitCodeAlignment(Align(64), &STI, 4);
58
59
// Emit the instruction.
60
// Since the previous emit created a new fragment then adding this instruction
61
// also forces the addition of a new fragment. Inst is now the first
62
// instruction in that new fragment.
63
MCELFStreamer::emitInstruction(Inst, STI);
64
65
// The above instruction is forced to start a new fragment because it
66
// comes after a code alignment fragment. Get that new fragment.
67
MCFragment *InstructionFragment = getCurrentFragment();
68
SMLoc InstLoc = Inst.getLoc();
69
// Check if there was a last label emitted.
70
if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() &&
71
InstLoc.isValid()) {
72
const SourceMgr *SourceManager = getContext().getSourceManager();
73
unsigned InstLine = SourceManager->FindLineNumber(InstLoc);
74
unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc);
75
// If the Label and the Instruction are on the same line then move the
76
// label to the top of the fragment containing the aligned instruction that
77
// was just added.
78
if (InstLine == LabelLine) {
79
LastLabel->setFragment(InstructionFragment);
80
LastLabel->setOffset(0);
81
}
82
}
83
}
84
85
void PPCELFStreamer::emitInstruction(const MCInst &Inst,
86
const MCSubtargetInfo &STI) {
87
PPCMCCodeEmitter *Emitter =
88
static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr());
89
90
// If the instruction is a part of the GOT to PC-Rel link time optimization
91
// instruction pair, return a value, otherwise return std::nullopt. A true
92
// returned value means the instruction is the PLDpc and a false value means
93
// it is the user instruction.
94
std::optional<bool> IsPartOfGOTToPCRelPair =
95
isPartOfGOTToPCRelPair(Inst, STI);
96
97
// User of the GOT-indirect address.
98
// For example, the load that will get the relocation as follows:
99
// .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
100
// lwa 3, 4(3)
101
if (IsPartOfGOTToPCRelPair && !*IsPartOfGOTToPCRelPair)
102
emitGOTToPCRelReloc(Inst);
103
104
// Special handling is only for prefixed instructions.
105
if (!Emitter->isPrefixedInstruction(Inst)) {
106
MCELFStreamer::emitInstruction(Inst, STI);
107
return;
108
}
109
emitPrefixedInstruction(Inst, STI);
110
111
// Producer of the GOT-indirect address.
112
// For example, the prefixed load from the got that will get the label as
113
// follows:
114
// pld 3, vec@got@pcrel(0), 1
115
// .Lpcrel1:
116
if (IsPartOfGOTToPCRelPair && *IsPartOfGOTToPCRelPair)
117
emitGOTToPCRelLabel(Inst);
118
}
119
120
void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
121
LastLabel = Symbol;
122
LastLabelLoc = Loc;
123
MCELFStreamer::emitLabel(Symbol);
124
}
125
126
// This linker time GOT PC Relative optimization relocation will look like this:
127
// pld <reg> symbol@got@pcrel
128
// <Label###>:
129
// .reloc Label###-8,R_PPC64_PCREL_OPT,.-(Label###-8)
130
// load <loadedreg>, 0(<reg>)
131
// The reason we place the label after the PLDpc instruction is that there
132
// may be an alignment nop before it since prefixed instructions must not
133
// cross a 64-byte boundary (please see
134
// PPCELFStreamer::emitPrefixedInstruction()). When referring to the
135
// label, we subtract the width of a prefixed instruction (8 bytes) to ensure
136
// we refer to the PLDpc.
137
void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {
138
// Get the last operand which contains the symbol.
139
const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
140
assert(Operand.isExpr() && "Expecting an MCExpr.");
141
// Cast the last operand to MCSymbolRefExpr to get the symbol.
142
const MCExpr *Expr = Operand.getExpr();
143
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
144
assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
145
"Expecting a symbol of type VK_PPC_PCREL_OPT");
146
MCSymbol *LabelSym =
147
getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
148
const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext());
149
const MCExpr *Eight = MCConstantExpr::create(8, getContext());
150
// SubExpr is just Label###-8
151
const MCExpr *SubExpr =
152
MCBinaryExpr::createSub(LabelExpr, Eight, getContext());
153
MCSymbol *CurrentLocation = getContext().createTempSymbol();
154
const MCExpr *CurrentLocationExpr =
155
MCSymbolRefExpr::create(CurrentLocation, getContext());
156
// SubExpr2 is .-(Label###-8)
157
const MCExpr *SubExpr2 =
158
MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, getContext());
159
160
MCDataFragment *DF = static_cast<MCDataFragment *>(LabelSym->getFragment());
161
assert(DF && "Expecting a valid data fragment.");
162
MCFixupKind FixupKind = static_cast<MCFixupKind>(FirstLiteralRelocationKind +
163
ELF::R_PPC64_PCREL_OPT);
164
DF->getFixups().push_back(
165
MCFixup::create(LabelSym->getOffset() - 8, SubExpr2,
166
FixupKind, Inst.getLoc()));
167
emitLabel(CurrentLocation, Inst.getLoc());
168
}
169
170
// Emit the label that immediately follows the PLDpc for a link time GOT PC Rel
171
// optimization.
172
void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {
173
// Get the last operand which contains the symbol.
174
const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
175
assert(Operand.isExpr() && "Expecting an MCExpr.");
176
// Cast the last operand to MCSymbolRefExpr to get the symbol.
177
const MCExpr *Expr = Operand.getExpr();
178
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
179
assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
180
"Expecting a symbol of type VK_PPC_PCREL_OPT");
181
MCSymbol *LabelSym =
182
getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
183
emitLabel(LabelSym, Inst.getLoc());
184
}
185
186
// This function checks if the parameter Inst is part of the setup for a link
187
// time GOT PC Relative optimization. For example in this situation:
188
// <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)>
189
// <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
190
// <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282>
191
// <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
192
// The above is a pair of such instructions and this function will not return
193
// std::nullopt for either one of them. In both cases we are looking for the
194
// last operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an
195
// MCExpr and has the flag MCSymbolRefExpr::VK_PPC_PCREL_OPT. After that we just
196
// look at the opcode and in the case of PLDpc we will return true. For the load
197
// (or store) this function will return false indicating it has found the second
198
// instruciton in the pair.
199
std::optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,
200
const MCSubtargetInfo &STI) {
201
// Need at least two operands.
202
if (Inst.getNumOperands() < 2)
203
return std::nullopt;
204
205
unsigned LastOp = Inst.getNumOperands() - 1;
206
// The last operand needs to be an MCExpr and it needs to have a variant kind
207
// of VK_PPC_PCREL_OPT. If it does not satisfy these conditions it is not a
208
// link time GOT PC Rel opt instruction and we can ignore it and return
209
// std::nullopt.
210
const MCOperand &Operand = Inst.getOperand(LastOp);
211
if (!Operand.isExpr())
212
return std::nullopt;
213
214
// Check for the variant kind VK_PPC_PCREL_OPT in this expression.
215
const MCExpr *Expr = Operand.getExpr();
216
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
217
if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_PPC_PCREL_OPT)
218
return std::nullopt;
219
220
return (Inst.getOpcode() == PPC::PLDpc);
221
}
222
223
MCELFStreamer *llvm::createPPCELFStreamer(
224
MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
225
std::unique_ptr<MCObjectWriter> OW,
226
std::unique_ptr<MCCodeEmitter> Emitter) {
227
return new PPCELFStreamer(Context, std::move(MAB), std::move(OW),
228
std::move(Emitter));
229
}
230
231