xref: /freebsd/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
34 using namespace llvm;
35 
PPCELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> MAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)36 PPCELFStreamer::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 
emitPrefixedInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)43 void 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(Align(64), &STI, 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(InstLoc);
72     unsigned LabelLine = SourceManager->FindLineNumber(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 
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)83 void 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(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 
emitLabel(MCSymbol * Symbol,SMLoc Loc)118 void 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.
emitGOTToPCRelReloc(const MCInst & Inst)135 void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {
136   // Get the last operand which contains the symbol.
137   const MCOperand &Operand = Inst.getOperand(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(SymExpr->getSymbol().getName());
146   const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext());
147   const MCExpr *Eight = MCConstantExpr::create(8, getContext());
148   // SubExpr is just Label###-8
149   const MCExpr *SubExpr =
150       MCBinaryExpr::createSub(LabelExpr, Eight, getContext());
151   MCSymbol *CurrentLocation = getContext().createTempSymbol();
152   const MCExpr *CurrentLocationExpr =
153       MCSymbolRefExpr::create(CurrentLocation, getContext());
154   // SubExpr2 is .-(Label###-8)
155   const MCExpr *SubExpr2 =
156       MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, 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(MCFixup::create(LabelSym->getOffset() - 8, SubExpr2, FixupKind));
163   emitLabel(CurrentLocation, Inst.getLoc());
164 }
165 
166 // Emit the label that immediately follows the PLDpc for a link time GOT PC Rel
167 // optimization.
emitGOTToPCRelLabel(const MCInst & Inst)168 void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {
169   // Get the last operand which contains the symbol.
170   const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
171   assert(Operand.isExpr() && "Expecting an MCExpr.");
172   // Cast the last operand to MCSymbolRefExpr to get the symbol.
173   const MCExpr *Expr = Operand.getExpr();
174   const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
175   assert(getSpecifier(SymExpr) == PPC::S_PCREL_OPT &&
176          "Expecting a symbol of type VK_PCREL_OPT");
177   MCSymbol *LabelSym =
178       getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
179   emitLabel(LabelSym, Inst.getLoc());
180 }
181 
182 // This function checks if the parameter Inst is part of the setup for a link
183 // time GOT PC Relative optimization. For example in this situation:
184 // <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)>
185 //   <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
186 // <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282>
187 //   <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
188 // The above is a pair of such instructions and this function will not return
189 // std::nullopt for either one of them. In both cases we are looking for the
190 // last operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an
191 // MCExpr and has the flag PPC::S_PCREL_OPT. After that we just
192 // look at the opcode and in the case of PLDpc we will return true. For the load
193 // (or store) this function will return false indicating it has found the second
194 // instruciton in the pair.
isPartOfGOTToPCRelPair(const MCInst & Inst,const MCSubtargetInfo & STI)195 std::optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,
196                                                  const MCSubtargetInfo &STI) {
197   // Need at least two operands.
198   if (Inst.getNumOperands() < 2)
199     return std::nullopt;
200 
201   unsigned LastOp = Inst.getNumOperands() - 1;
202   // The last operand needs to be an MCExpr and it needs to have a variant kind
203   // of VK_PCREL_OPT. If it does not satisfy these conditions it is not a
204   // link time GOT PC Rel opt instruction and we can ignore it and return
205   // std::nullopt.
206   const MCOperand &Operand = Inst.getOperand(LastOp);
207   if (!Operand.isExpr())
208     return std::nullopt;
209 
210   // Check for the variant kind VK_PCREL_OPT in this expression.
211   const MCExpr *Expr = Operand.getExpr();
212   const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
213   if (!SymExpr || getSpecifier(SymExpr) != PPC::S_PCREL_OPT)
214     return std::nullopt;
215 
216   return (Inst.getOpcode() == PPC::PLDpc);
217 }
218 
219 MCStreamer *
createPPCELFStreamer(const Triple & T,MCContext & C,std::unique_ptr<MCAsmBackend> && MAB,std::unique_ptr<MCObjectWriter> && OW,std::unique_ptr<MCCodeEmitter> && Emitter)220 llvm::createPPCELFStreamer(const Triple &T, MCContext &C,
221                            std::unique_ptr<MCAsmBackend> &&MAB,
222                            std::unique_ptr<MCObjectWriter> &&OW,
223                            std::unique_ptr<MCCodeEmitter> &&Emitter) {
224   return new PPCELFStreamer(C, std::move(MAB), std::move(OW),
225                             std::move(Emitter));
226 }
227