xref: /openbsd-src/gnu/llvm/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
1097a140dSpatrick //===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===//
2097a140dSpatrick //
3*d415bd75Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*d415bd75Srobert // See https://llvm.org/LICENSE.txt for license information.
5*d415bd75Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6097a140dSpatrick //
7097a140dSpatrick //===----------------------------------------------------------------------===//
8097a140dSpatrick //
9097a140dSpatrick // This is a custom MCELFStreamer for PowerPC.
10097a140dSpatrick //
11097a140dSpatrick // The purpose of the custom ELF streamer is to allow us to intercept
12097a140dSpatrick // instructions as they are being emitted and align all 8 byte instructions
13097a140dSpatrick // to a 64 byte boundary if required (by adding a 4 byte nop). This is important
14097a140dSpatrick // because 8 byte instructions are not allowed to cross 64 byte boundaries
15097a140dSpatrick // and by aliging anything that is within 4 bytes of the boundary we can
16097a140dSpatrick // guarantee that the 8 byte instructions do not cross that boundary.
17097a140dSpatrick //
18097a140dSpatrick //===----------------------------------------------------------------------===//
19097a140dSpatrick 
20097a140dSpatrick 
21097a140dSpatrick #include "PPCELFStreamer.h"
2273471bf0Spatrick #include "PPCFixupKinds.h"
23097a140dSpatrick #include "PPCInstrInfo.h"
24097a140dSpatrick #include "PPCMCCodeEmitter.h"
25097a140dSpatrick #include "llvm/BinaryFormat/ELF.h"
26097a140dSpatrick #include "llvm/MC/MCAsmBackend.h"
27097a140dSpatrick #include "llvm/MC/MCAssembler.h"
28097a140dSpatrick #include "llvm/MC/MCCodeEmitter.h"
29097a140dSpatrick #include "llvm/MC/MCContext.h"
30097a140dSpatrick #include "llvm/MC/MCInst.h"
31097a140dSpatrick #include "llvm/MC/MCInstrDesc.h"
32097a140dSpatrick #include "llvm/MC/MCObjectWriter.h"
33097a140dSpatrick #include "llvm/MC/MCSymbolELF.h"
34097a140dSpatrick #include "llvm/Support/Casting.h"
35097a140dSpatrick #include "llvm/Support/SourceMgr.h"
36097a140dSpatrick 
37097a140dSpatrick using namespace llvm;
38097a140dSpatrick 
PPCELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> MAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)39097a140dSpatrick PPCELFStreamer::PPCELFStreamer(MCContext &Context,
40097a140dSpatrick                                std::unique_ptr<MCAsmBackend> MAB,
41097a140dSpatrick                                std::unique_ptr<MCObjectWriter> OW,
42097a140dSpatrick                                std::unique_ptr<MCCodeEmitter> Emitter)
43*d415bd75Srobert     : MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(Emitter)),
44*d415bd75Srobert       LastLabel(nullptr) {}
45097a140dSpatrick 
emitPrefixedInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)46097a140dSpatrick void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst,
47097a140dSpatrick                                              const MCSubtargetInfo &STI) {
48097a140dSpatrick   // Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is
49097a140dSpatrick   // before the boundary and the remaining 4-bytes are after the boundary). In
50097a140dSpatrick   // order to achieve this, a nop is added prior to any such boundary-crossing
51097a140dSpatrick   // prefixed instruction. Align to 64 bytes if possible but add a maximum of 4
52097a140dSpatrick   // bytes when trying to do that. If alignment requires adding more than 4
53097a140dSpatrick   // bytes then the instruction won't be aligned. When emitting a code alignment
54097a140dSpatrick   // a new fragment is created for this alignment. This fragment will contain
55097a140dSpatrick   // all of the nops required as part of the alignment operation. In the cases
56097a140dSpatrick   // when no nops are added then The fragment is still created but it remains
57097a140dSpatrick   // empty.
58*d415bd75Srobert   emitCodeAlignment(Align(64), &STI, 4);
59097a140dSpatrick 
60097a140dSpatrick   // Emit the instruction.
61097a140dSpatrick   // Since the previous emit created a new fragment then adding this instruction
62097a140dSpatrick   // also forces the addition of a new fragment. Inst is now the first
63097a140dSpatrick   // instruction in that new fragment.
64097a140dSpatrick   MCELFStreamer::emitInstruction(Inst, STI);
65097a140dSpatrick 
66097a140dSpatrick   // The above instruction is forced to start a new fragment because it
67097a140dSpatrick   // comes after a code alignment fragment. Get that new fragment.
68097a140dSpatrick   MCFragment *InstructionFragment = getCurrentFragment();
69097a140dSpatrick   SMLoc InstLoc = Inst.getLoc();
70097a140dSpatrick   // Check if there was a last label emitted.
71097a140dSpatrick   if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() &&
72097a140dSpatrick       InstLoc.isValid()) {
73097a140dSpatrick     const SourceMgr *SourceManager = getContext().getSourceManager();
74097a140dSpatrick     unsigned InstLine = SourceManager->FindLineNumber(InstLoc);
75097a140dSpatrick     unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc);
76097a140dSpatrick     // If the Label and the Instruction are on the same line then move the
77097a140dSpatrick     // label to the top of the fragment containing the aligned instruction that
78097a140dSpatrick     // was just added.
79097a140dSpatrick     if (InstLine == LabelLine) {
80*d415bd75Srobert       assignFragment(LastLabel, InstructionFragment);
81097a140dSpatrick       LastLabel->setOffset(0);
82097a140dSpatrick     }
83097a140dSpatrick   }
84097a140dSpatrick }
85097a140dSpatrick 
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)86097a140dSpatrick void PPCELFStreamer::emitInstruction(const MCInst &Inst,
87097a140dSpatrick                                      const MCSubtargetInfo &STI) {
88097a140dSpatrick   PPCMCCodeEmitter *Emitter =
89097a140dSpatrick       static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr());
90097a140dSpatrick 
9173471bf0Spatrick   // If the instruction is a part of the GOT to PC-Rel link time optimization
92*d415bd75Srobert   // instruction pair, return a value, otherwise return std::nullopt. A true
93*d415bd75Srobert   // returned value means the instruction is the PLDpc and a false value means
94*d415bd75Srobert   // it is the user instruction.
95*d415bd75Srobert   std::optional<bool> IsPartOfGOTToPCRelPair =
96*d415bd75Srobert       isPartOfGOTToPCRelPair(Inst, STI);
9773471bf0Spatrick 
9873471bf0Spatrick   // User of the GOT-indirect address.
9973471bf0Spatrick   // For example, the load that will get the relocation as follows:
10073471bf0Spatrick   // .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
10173471bf0Spatrick   //  lwa 3, 4(3)
102*d415bd75Srobert   if (IsPartOfGOTToPCRelPair && !*IsPartOfGOTToPCRelPair)
10373471bf0Spatrick     emitGOTToPCRelReloc(Inst);
10473471bf0Spatrick 
105097a140dSpatrick   // Special handling is only for prefixed instructions.
106097a140dSpatrick   if (!Emitter->isPrefixedInstruction(Inst)) {
107097a140dSpatrick     MCELFStreamer::emitInstruction(Inst, STI);
108097a140dSpatrick     return;
109097a140dSpatrick   }
110097a140dSpatrick   emitPrefixedInstruction(Inst, STI);
11173471bf0Spatrick 
11273471bf0Spatrick   // Producer of the GOT-indirect address.
11373471bf0Spatrick   // For example, the prefixed load from the got that will get the label as
11473471bf0Spatrick   // follows:
11573471bf0Spatrick   //  pld 3, vec@got@pcrel(0), 1
11673471bf0Spatrick   // .Lpcrel1:
117*d415bd75Srobert   if (IsPartOfGOTToPCRelPair && *IsPartOfGOTToPCRelPair)
11873471bf0Spatrick     emitGOTToPCRelLabel(Inst);
119097a140dSpatrick }
120097a140dSpatrick 
emitLabel(MCSymbol * Symbol,SMLoc Loc)121097a140dSpatrick void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
122097a140dSpatrick   LastLabel = Symbol;
123097a140dSpatrick   LastLabelLoc = Loc;
124097a140dSpatrick   MCELFStreamer::emitLabel(Symbol);
125097a140dSpatrick }
126097a140dSpatrick 
12773471bf0Spatrick // This linker time GOT PC Relative optimization relocation will look like this:
12873471bf0Spatrick //   pld <reg> symbol@got@pcrel
12973471bf0Spatrick // <Label###>:
13073471bf0Spatrick //   .reloc Label###-8,R_PPC64_PCREL_OPT,.-(Label###-8)
13173471bf0Spatrick //   load <loadedreg>, 0(<reg>)
13273471bf0Spatrick // The reason we place the label after the PLDpc instruction is that there
13373471bf0Spatrick // may be an alignment nop before it since prefixed instructions must not
13473471bf0Spatrick // cross a 64-byte boundary (please see
13573471bf0Spatrick // PPCELFStreamer::emitPrefixedInstruction()). When referring to the
13673471bf0Spatrick // label, we subtract the width of a prefixed instruction (8 bytes) to ensure
13773471bf0Spatrick // we refer to the PLDpc.
emitGOTToPCRelReloc(const MCInst & Inst)13873471bf0Spatrick void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {
13973471bf0Spatrick   // Get the last operand which contains the symbol.
14073471bf0Spatrick   const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
14173471bf0Spatrick   assert(Operand.isExpr() && "Expecting an MCExpr.");
14273471bf0Spatrick   // Cast the last operand to MCSymbolRefExpr to get the symbol.
14373471bf0Spatrick   const MCExpr *Expr = Operand.getExpr();
14473471bf0Spatrick   const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
14573471bf0Spatrick   assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
14673471bf0Spatrick          "Expecting a symbol of type VK_PPC_PCREL_OPT");
14773471bf0Spatrick   MCSymbol *LabelSym =
14873471bf0Spatrick       getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
14973471bf0Spatrick   const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext());
15073471bf0Spatrick   const MCExpr *Eight = MCConstantExpr::create(8, getContext());
15173471bf0Spatrick   // SubExpr is just Label###-8
15273471bf0Spatrick   const MCExpr *SubExpr =
15373471bf0Spatrick       MCBinaryExpr::createSub(LabelExpr, Eight, getContext());
15473471bf0Spatrick   MCSymbol *CurrentLocation = getContext().createTempSymbol();
15573471bf0Spatrick   const MCExpr *CurrentLocationExpr =
15673471bf0Spatrick       MCSymbolRefExpr::create(CurrentLocation, getContext());
15773471bf0Spatrick   // SubExpr2 is .-(Label###-8)
15873471bf0Spatrick   const MCExpr *SubExpr2 =
15973471bf0Spatrick       MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, getContext());
16073471bf0Spatrick 
16173471bf0Spatrick   MCDataFragment *DF = static_cast<MCDataFragment *>(LabelSym->getFragment());
16273471bf0Spatrick   assert(DF && "Expecting a valid data fragment.");
16373471bf0Spatrick   MCFixupKind FixupKind = static_cast<MCFixupKind>(FirstLiteralRelocationKind +
16473471bf0Spatrick                                                    ELF::R_PPC64_PCREL_OPT);
16573471bf0Spatrick   DF->getFixups().push_back(
16673471bf0Spatrick       MCFixup::create(LabelSym->getOffset() - 8, SubExpr2,
16773471bf0Spatrick                       FixupKind, Inst.getLoc()));
16873471bf0Spatrick   emitLabel(CurrentLocation, Inst.getLoc());
16973471bf0Spatrick }
17073471bf0Spatrick 
17173471bf0Spatrick // Emit the label that immediately follows the PLDpc for a link time GOT PC Rel
17273471bf0Spatrick // optimization.
emitGOTToPCRelLabel(const MCInst & Inst)17373471bf0Spatrick void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {
17473471bf0Spatrick   // Get the last operand which contains the symbol.
17573471bf0Spatrick   const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
17673471bf0Spatrick   assert(Operand.isExpr() && "Expecting an MCExpr.");
17773471bf0Spatrick   // Cast the last operand to MCSymbolRefExpr to get the symbol.
17873471bf0Spatrick   const MCExpr *Expr = Operand.getExpr();
17973471bf0Spatrick   const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
18073471bf0Spatrick   assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
18173471bf0Spatrick          "Expecting a symbol of type VK_PPC_PCREL_OPT");
18273471bf0Spatrick   MCSymbol *LabelSym =
18373471bf0Spatrick       getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
18473471bf0Spatrick   emitLabel(LabelSym, Inst.getLoc());
18573471bf0Spatrick }
18673471bf0Spatrick 
18773471bf0Spatrick // This funciton checks if the parameter Inst is part of the setup for a link
18873471bf0Spatrick // time GOT PC Relative optimization. For example in this situation:
18973471bf0Spatrick // <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)>
19073471bf0Spatrick //   <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
19173471bf0Spatrick // <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282>
19273471bf0Spatrick //   <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
19373471bf0Spatrick // The above is a pair of such instructions and this function will not return
194*d415bd75Srobert // std::nullopt for either one of them. In both cases we are looking for the
195*d415bd75Srobert // last operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an
196*d415bd75Srobert // MCExpr and has the flag MCSymbolRefExpr::VK_PPC_PCREL_OPT. After that we just
197*d415bd75Srobert // look at the opcode and in the case of PLDpc we will return true. For the load
19873471bf0Spatrick // (or store) this function will return false indicating it has found the second
19973471bf0Spatrick // instruciton in the pair.
isPartOfGOTToPCRelPair(const MCInst & Inst,const MCSubtargetInfo & STI)200*d415bd75Srobert std::optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,
20173471bf0Spatrick                                                  const MCSubtargetInfo &STI) {
20273471bf0Spatrick   // Need at least two operands.
20373471bf0Spatrick   if (Inst.getNumOperands() < 2)
204*d415bd75Srobert     return std::nullopt;
20573471bf0Spatrick 
20673471bf0Spatrick   unsigned LastOp = Inst.getNumOperands() - 1;
20773471bf0Spatrick   // The last operand needs to be an MCExpr and it needs to have a variant kind
20873471bf0Spatrick   // of VK_PPC_PCREL_OPT. If it does not satisfy these conditions it is not a
209*d415bd75Srobert   // link time GOT PC Rel opt instruction and we can ignore it and return
210*d415bd75Srobert   // std::nullopt.
21173471bf0Spatrick   const MCOperand &Operand = Inst.getOperand(LastOp);
21273471bf0Spatrick   if (!Operand.isExpr())
213*d415bd75Srobert     return std::nullopt;
21473471bf0Spatrick 
21573471bf0Spatrick   // Check for the variant kind VK_PPC_PCREL_OPT in this expression.
21673471bf0Spatrick   const MCExpr *Expr = Operand.getExpr();
21773471bf0Spatrick   const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
21873471bf0Spatrick   if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_PPC_PCREL_OPT)
219*d415bd75Srobert     return std::nullopt;
22073471bf0Spatrick 
22173471bf0Spatrick   return (Inst.getOpcode() == PPC::PLDpc);
22273471bf0Spatrick }
22373471bf0Spatrick 
createPPCELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> MAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)224097a140dSpatrick MCELFStreamer *llvm::createPPCELFStreamer(
225097a140dSpatrick     MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
226097a140dSpatrick     std::unique_ptr<MCObjectWriter> OW,
227097a140dSpatrick     std::unique_ptr<MCCodeEmitter> Emitter) {
228097a140dSpatrick   return new PPCELFStreamer(Context, std::move(MAB), std::move(OW),
229097a140dSpatrick                             std::move(Emitter));
230097a140dSpatrick }
231