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