xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
15ffd83dbSDimitry Andric //===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===//
25ffd83dbSDimitry Andric //
3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // This is a custom MCELFStreamer for PowerPC.
105ffd83dbSDimitry Andric //
115ffd83dbSDimitry Andric // The purpose of the custom ELF streamer is to allow us to intercept
125ffd83dbSDimitry Andric // instructions as they are being emitted and align all 8 byte instructions
135ffd83dbSDimitry Andric // to a 64 byte boundary if required (by adding a 4 byte nop). This is important
145ffd83dbSDimitry Andric // because 8 byte instructions are not allowed to cross 64 byte boundaries
155ffd83dbSDimitry Andric // and by aliging anything that is within 4 bytes of the boundary we can
165ffd83dbSDimitry Andric // guarantee that the 8 byte instructions do not cross that boundary.
175ffd83dbSDimitry Andric //
185ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
195ffd83dbSDimitry Andric 
205ffd83dbSDimitry Andric 
215ffd83dbSDimitry Andric #include "PPCELFStreamer.h"
22e8d8bef9SDimitry Andric #include "PPCFixupKinds.h"
235ffd83dbSDimitry Andric #include "PPCInstrInfo.h"
245ffd83dbSDimitry Andric #include "PPCMCCodeEmitter.h"
255ffd83dbSDimitry Andric #include "llvm/BinaryFormat/ELF.h"
265ffd83dbSDimitry Andric #include "llvm/MC/MCAsmBackend.h"
275ffd83dbSDimitry Andric #include "llvm/MC/MCAssembler.h"
285ffd83dbSDimitry Andric #include "llvm/MC/MCCodeEmitter.h"
295ffd83dbSDimitry Andric #include "llvm/MC/MCContext.h"
305ffd83dbSDimitry Andric #include "llvm/MC/MCInst.h"
315ffd83dbSDimitry Andric #include "llvm/MC/MCInstrDesc.h"
325ffd83dbSDimitry Andric #include "llvm/MC/MCObjectWriter.h"
335ffd83dbSDimitry Andric #include "llvm/MC/MCSymbolELF.h"
345ffd83dbSDimitry Andric #include "llvm/Support/Casting.h"
355ffd83dbSDimitry Andric #include "llvm/Support/SourceMgr.h"
365ffd83dbSDimitry Andric 
375ffd83dbSDimitry Andric using namespace llvm;
385ffd83dbSDimitry Andric 
395ffd83dbSDimitry Andric PPCELFStreamer::PPCELFStreamer(MCContext &Context,
405ffd83dbSDimitry Andric                                std::unique_ptr<MCAsmBackend> MAB,
415ffd83dbSDimitry Andric                                std::unique_ptr<MCObjectWriter> OW,
425ffd83dbSDimitry Andric                                std::unique_ptr<MCCodeEmitter> Emitter)
435ffd83dbSDimitry Andric     : MCELFStreamer(Context, std::move(MAB), std::move(OW),
445ffd83dbSDimitry Andric                     std::move(Emitter)), LastLabel(NULL) {
455ffd83dbSDimitry Andric }
465ffd83dbSDimitry Andric 
475ffd83dbSDimitry Andric void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst,
485ffd83dbSDimitry Andric                                              const MCSubtargetInfo &STI) {
495ffd83dbSDimitry Andric   // Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is
505ffd83dbSDimitry Andric   // before the boundary and the remaining 4-bytes are after the boundary). In
515ffd83dbSDimitry Andric   // order to achieve this, a nop is added prior to any such boundary-crossing
525ffd83dbSDimitry Andric   // prefixed instruction. Align to 64 bytes if possible but add a maximum of 4
535ffd83dbSDimitry Andric   // bytes when trying to do that. If alignment requires adding more than 4
545ffd83dbSDimitry Andric   // bytes then the instruction won't be aligned. When emitting a code alignment
555ffd83dbSDimitry Andric   // a new fragment is created for this alignment. This fragment will contain
565ffd83dbSDimitry Andric   // all of the nops required as part of the alignment operation. In the cases
575ffd83dbSDimitry Andric   // when no nops are added then The fragment is still created but it remains
585ffd83dbSDimitry Andric   // empty.
59*349cc55cSDimitry Andric   emitCodeAlignment(64, &STI, 4);
605ffd83dbSDimitry Andric 
615ffd83dbSDimitry Andric   // Emit the instruction.
625ffd83dbSDimitry Andric   // Since the previous emit created a new fragment then adding this instruction
635ffd83dbSDimitry Andric   // also forces the addition of a new fragment. Inst is now the first
645ffd83dbSDimitry Andric   // instruction in that new fragment.
655ffd83dbSDimitry Andric   MCELFStreamer::emitInstruction(Inst, STI);
665ffd83dbSDimitry Andric 
675ffd83dbSDimitry Andric   // The above instruction is forced to start a new fragment because it
685ffd83dbSDimitry Andric   // comes after a code alignment fragment. Get that new fragment.
695ffd83dbSDimitry Andric   MCFragment *InstructionFragment = getCurrentFragment();
705ffd83dbSDimitry Andric   SMLoc InstLoc = Inst.getLoc();
715ffd83dbSDimitry Andric   // Check if there was a last label emitted.
725ffd83dbSDimitry Andric   if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() &&
735ffd83dbSDimitry Andric       InstLoc.isValid()) {
745ffd83dbSDimitry Andric     const SourceMgr *SourceManager = getContext().getSourceManager();
755ffd83dbSDimitry Andric     unsigned InstLine = SourceManager->FindLineNumber(InstLoc);
765ffd83dbSDimitry Andric     unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc);
775ffd83dbSDimitry Andric     // If the Label and the Instruction are on the same line then move the
785ffd83dbSDimitry Andric     // label to the top of the fragment containing the aligned instruction that
795ffd83dbSDimitry Andric     // was just added.
805ffd83dbSDimitry Andric     if (InstLine == LabelLine) {
815ffd83dbSDimitry Andric       AssignFragment(LastLabel, InstructionFragment);
825ffd83dbSDimitry Andric       LastLabel->setOffset(0);
835ffd83dbSDimitry Andric     }
845ffd83dbSDimitry Andric   }
855ffd83dbSDimitry Andric }
865ffd83dbSDimitry Andric 
875ffd83dbSDimitry Andric void PPCELFStreamer::emitInstruction(const MCInst &Inst,
885ffd83dbSDimitry Andric                                      const MCSubtargetInfo &STI) {
895ffd83dbSDimitry Andric   PPCMCCodeEmitter *Emitter =
905ffd83dbSDimitry Andric       static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr());
915ffd83dbSDimitry Andric 
92e8d8bef9SDimitry Andric   // If the instruction is a part of the GOT to PC-Rel link time optimization
93e8d8bef9SDimitry Andric   // instruction pair, return a value, otherwise return None. A true returned
94e8d8bef9SDimitry Andric   // value means the instruction is the PLDpc and a false value means it is
95e8d8bef9SDimitry Andric   // the user instruction.
96e8d8bef9SDimitry Andric   Optional<bool> IsPartOfGOTToPCRelPair = isPartOfGOTToPCRelPair(Inst, STI);
97e8d8bef9SDimitry Andric 
98e8d8bef9SDimitry Andric   // User of the GOT-indirect address.
99e8d8bef9SDimitry Andric   // For example, the load that will get the relocation as follows:
100e8d8bef9SDimitry Andric   // .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
101e8d8bef9SDimitry Andric   //  lwa 3, 4(3)
102e8d8bef9SDimitry Andric   if (IsPartOfGOTToPCRelPair.hasValue() && !IsPartOfGOTToPCRelPair.getValue())
103e8d8bef9SDimitry Andric     emitGOTToPCRelReloc(Inst);
104e8d8bef9SDimitry Andric 
1055ffd83dbSDimitry Andric   // Special handling is only for prefixed instructions.
1065ffd83dbSDimitry Andric   if (!Emitter->isPrefixedInstruction(Inst)) {
1075ffd83dbSDimitry Andric     MCELFStreamer::emitInstruction(Inst, STI);
1085ffd83dbSDimitry Andric     return;
1095ffd83dbSDimitry Andric   }
1105ffd83dbSDimitry Andric   emitPrefixedInstruction(Inst, STI);
111e8d8bef9SDimitry Andric 
112e8d8bef9SDimitry Andric   // Producer of the GOT-indirect address.
113e8d8bef9SDimitry Andric   // For example, the prefixed load from the got that will get the label as
114e8d8bef9SDimitry Andric   // follows:
115e8d8bef9SDimitry Andric   //  pld 3, vec@got@pcrel(0), 1
116e8d8bef9SDimitry Andric   // .Lpcrel1:
117e8d8bef9SDimitry Andric   if (IsPartOfGOTToPCRelPair.hasValue() && IsPartOfGOTToPCRelPair.getValue())
118e8d8bef9SDimitry Andric     emitGOTToPCRelLabel(Inst);
1195ffd83dbSDimitry Andric }
1205ffd83dbSDimitry Andric 
1215ffd83dbSDimitry Andric void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
1225ffd83dbSDimitry Andric   LastLabel = Symbol;
1235ffd83dbSDimitry Andric   LastLabelLoc = Loc;
1245ffd83dbSDimitry Andric   MCELFStreamer::emitLabel(Symbol);
1255ffd83dbSDimitry Andric }
1265ffd83dbSDimitry Andric 
127e8d8bef9SDimitry Andric // This linker time GOT PC Relative optimization relocation will look like this:
128e8d8bef9SDimitry Andric //   pld <reg> symbol@got@pcrel
129e8d8bef9SDimitry Andric // <Label###>:
130e8d8bef9SDimitry Andric //   .reloc Label###-8,R_PPC64_PCREL_OPT,.-(Label###-8)
131e8d8bef9SDimitry Andric //   load <loadedreg>, 0(<reg>)
132e8d8bef9SDimitry Andric // The reason we place the label after the PLDpc instruction is that there
133e8d8bef9SDimitry Andric // may be an alignment nop before it since prefixed instructions must not
134e8d8bef9SDimitry Andric // cross a 64-byte boundary (please see
135e8d8bef9SDimitry Andric // PPCELFStreamer::emitPrefixedInstruction()). When referring to the
136e8d8bef9SDimitry Andric // label, we subtract the width of a prefixed instruction (8 bytes) to ensure
137e8d8bef9SDimitry Andric // we refer to the PLDpc.
138e8d8bef9SDimitry Andric void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {
139e8d8bef9SDimitry Andric   // Get the last operand which contains the symbol.
140e8d8bef9SDimitry Andric   const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
141e8d8bef9SDimitry Andric   assert(Operand.isExpr() && "Expecting an MCExpr.");
142e8d8bef9SDimitry Andric   // Cast the last operand to MCSymbolRefExpr to get the symbol.
143e8d8bef9SDimitry Andric   const MCExpr *Expr = Operand.getExpr();
144e8d8bef9SDimitry Andric   const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
145e8d8bef9SDimitry Andric   assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
146e8d8bef9SDimitry Andric          "Expecting a symbol of type VK_PPC_PCREL_OPT");
147e8d8bef9SDimitry Andric   MCSymbol *LabelSym =
148e8d8bef9SDimitry Andric       getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
149e8d8bef9SDimitry Andric   const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext());
150e8d8bef9SDimitry Andric   const MCExpr *Eight = MCConstantExpr::create(8, getContext());
151e8d8bef9SDimitry Andric   // SubExpr is just Label###-8
152e8d8bef9SDimitry Andric   const MCExpr *SubExpr =
153e8d8bef9SDimitry Andric       MCBinaryExpr::createSub(LabelExpr, Eight, getContext());
154e8d8bef9SDimitry Andric   MCSymbol *CurrentLocation = getContext().createTempSymbol();
155e8d8bef9SDimitry Andric   const MCExpr *CurrentLocationExpr =
156e8d8bef9SDimitry Andric       MCSymbolRefExpr::create(CurrentLocation, getContext());
157e8d8bef9SDimitry Andric   // SubExpr2 is .-(Label###-8)
158e8d8bef9SDimitry Andric   const MCExpr *SubExpr2 =
159e8d8bef9SDimitry Andric       MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, getContext());
160e8d8bef9SDimitry Andric 
161e8d8bef9SDimitry Andric   MCDataFragment *DF = static_cast<MCDataFragment *>(LabelSym->getFragment());
162e8d8bef9SDimitry Andric   assert(DF && "Expecting a valid data fragment.");
163e8d8bef9SDimitry Andric   MCFixupKind FixupKind = static_cast<MCFixupKind>(FirstLiteralRelocationKind +
164e8d8bef9SDimitry Andric                                                    ELF::R_PPC64_PCREL_OPT);
165e8d8bef9SDimitry Andric   DF->getFixups().push_back(
166e8d8bef9SDimitry Andric       MCFixup::create(LabelSym->getOffset() - 8, SubExpr2,
167e8d8bef9SDimitry Andric                       FixupKind, Inst.getLoc()));
168e8d8bef9SDimitry Andric   emitLabel(CurrentLocation, Inst.getLoc());
169e8d8bef9SDimitry Andric }
170e8d8bef9SDimitry Andric 
171e8d8bef9SDimitry Andric // Emit the label that immediately follows the PLDpc for a link time GOT PC Rel
172e8d8bef9SDimitry Andric // optimization.
173e8d8bef9SDimitry Andric void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {
174e8d8bef9SDimitry Andric   // Get the last operand which contains the symbol.
175e8d8bef9SDimitry Andric   const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
176e8d8bef9SDimitry Andric   assert(Operand.isExpr() && "Expecting an MCExpr.");
177e8d8bef9SDimitry Andric   // Cast the last operand to MCSymbolRefExpr to get the symbol.
178e8d8bef9SDimitry Andric   const MCExpr *Expr = Operand.getExpr();
179e8d8bef9SDimitry Andric   const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
180e8d8bef9SDimitry Andric   assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
181e8d8bef9SDimitry Andric          "Expecting a symbol of type VK_PPC_PCREL_OPT");
182e8d8bef9SDimitry Andric   MCSymbol *LabelSym =
183e8d8bef9SDimitry Andric       getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
184e8d8bef9SDimitry Andric   emitLabel(LabelSym, Inst.getLoc());
185e8d8bef9SDimitry Andric }
186e8d8bef9SDimitry Andric 
187e8d8bef9SDimitry Andric // This funciton checks if the parameter Inst is part of the setup for a link
188e8d8bef9SDimitry Andric // time GOT PC Relative optimization. For example in this situation:
189e8d8bef9SDimitry Andric // <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)>
190e8d8bef9SDimitry Andric //   <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
191e8d8bef9SDimitry Andric // <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282>
192e8d8bef9SDimitry Andric //   <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
193e8d8bef9SDimitry Andric // The above is a pair of such instructions and this function will not return
194e8d8bef9SDimitry Andric // None for either one of them. In both cases we are looking for the last
195e8d8bef9SDimitry Andric // operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an MCExpr
196e8d8bef9SDimitry Andric // and has the flag MCSymbolRefExpr::VK_PPC_PCREL_OPT. After that we just look
197e8d8bef9SDimitry Andric // at the opcode and in the case of PLDpc we will return true. For the load
198e8d8bef9SDimitry Andric // (or store) this function will return false indicating it has found the second
199e8d8bef9SDimitry Andric // instruciton in the pair.
200e8d8bef9SDimitry Andric Optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,
201e8d8bef9SDimitry Andric                                             const MCSubtargetInfo &STI) {
202e8d8bef9SDimitry Andric   // Need at least two operands.
203e8d8bef9SDimitry Andric   if (Inst.getNumOperands() < 2)
204e8d8bef9SDimitry Andric     return None;
205e8d8bef9SDimitry Andric 
206e8d8bef9SDimitry Andric   unsigned LastOp = Inst.getNumOperands() - 1;
207e8d8bef9SDimitry Andric   // The last operand needs to be an MCExpr and it needs to have a variant kind
208e8d8bef9SDimitry Andric   // of VK_PPC_PCREL_OPT. If it does not satisfy these conditions it is not a
209e8d8bef9SDimitry Andric   // link time GOT PC Rel opt instruction and we can ignore it and return None.
210e8d8bef9SDimitry Andric   const MCOperand &Operand = Inst.getOperand(LastOp);
211e8d8bef9SDimitry Andric   if (!Operand.isExpr())
212e8d8bef9SDimitry Andric     return None;
213e8d8bef9SDimitry Andric 
214e8d8bef9SDimitry Andric   // Check for the variant kind VK_PPC_PCREL_OPT in this expression.
215e8d8bef9SDimitry Andric   const MCExpr *Expr = Operand.getExpr();
216e8d8bef9SDimitry Andric   const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
217e8d8bef9SDimitry Andric   if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_PPC_PCREL_OPT)
218e8d8bef9SDimitry Andric     return None;
219e8d8bef9SDimitry Andric 
220e8d8bef9SDimitry Andric   return (Inst.getOpcode() == PPC::PLDpc);
221e8d8bef9SDimitry Andric }
222e8d8bef9SDimitry Andric 
2235ffd83dbSDimitry Andric MCELFStreamer *llvm::createPPCELFStreamer(
2245ffd83dbSDimitry Andric     MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
2255ffd83dbSDimitry Andric     std::unique_ptr<MCObjectWriter> OW,
2265ffd83dbSDimitry Andric     std::unique_ptr<MCCodeEmitter> Emitter) {
2275ffd83dbSDimitry Andric   return new PPCELFStreamer(Context, std::move(MAB), std::move(OW),
2285ffd83dbSDimitry Andric                             std::move(Emitter));
2295ffd83dbSDimitry Andric }
230