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