brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.1 KiB · 132d5a4 Raw
226 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This is a custom MCELFStreamer for PowerPC.10//11// The purpose of the custom ELF streamer is to allow us to intercept12// instructions as they are being emitted and align all 8 byte instructions13// to a 64 byte boundary if required (by adding a 4 byte nop). This is important14// because 8 byte instructions are not allowed to cross 64 byte boundaries15// and by aliging anything that is within 4 bytes of the boundary we can16// 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 is46  // before the boundary and the remaining 4-bytes are after the boundary). In47  // order to achieve this, a nop is added prior to any such boundary-crossing48  // prefixed instruction. Align to 64 bytes if possible but add a maximum of 449  // bytes when trying to do that. If alignment requires adding more than 450  // bytes then the instruction won't be aligned. When emitting a code alignment51  // a new fragment is created for this alignment. This fragment will contain52  // all of the nops required as part of the alignment operation. In the cases53  // when no nops are added then The fragment is still created but it remains54  // empty.55  emitCodeAlignment(Align(64), &STI, 4);56 57  // Emit the instruction.58  // Since the previous emit created a new fragment then adding this instruction59  // also forces the addition of a new fragment. Inst is now the first60  // instruction in that new fragment.61  MCELFStreamer::emitInstruction(Inst, STI);62 63  // The above instruction is forced to start a new fragment because it64  // 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->isDefined() && 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 the74    // label to the top of the fragment containing the aligned instruction that75    // 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 optimization89  // instruction pair, return a value, otherwise return std::nullopt. A true90  // returned value means the instruction is the PLDpc and a false value means91  // 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 as111  // follows:112  //  pld 3, vec@got@pcrel(0), 1113  // .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@pcrel126// <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 there130// may be an alignment nop before it since prefixed instructions must not131// cross a 64-byte boundary (please see132// PPCELFStreamer::emitPrefixedInstruction()). When referring to the133// label, we subtract the width of a prefixed instruction (8 bytes) to ensure134// 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(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###-8149  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  MCFragment *F = LabelSym->getFragment();159  F->addFixup(160      MCFixup::create(LabelSym->getOffset() - 8, SubExpr2,161                      FirstLiteralRelocationKind + ELF::R_PPC64_PCREL_OPT));162  emitLabel(CurrentLocation, Inst.getLoc());163}164 165// Emit the label that immediately follows the PLDpc for a link time GOT PC Rel166// optimization.167void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {168  // Get the last operand which contains the symbol.169  const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);170  assert(Operand.isExpr() && "Expecting an MCExpr.");171  // Cast the last operand to MCSymbolRefExpr to get the symbol.172  const MCExpr *Expr = Operand.getExpr();173  const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);174  assert(getSpecifier(SymExpr) == PPC::S_PCREL_OPT &&175         "Expecting a symbol of type VK_PCREL_OPT");176  MCSymbol *LabelSym =177      getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());178  emitLabel(LabelSym, Inst.getLoc());179}180 181// This function checks if the parameter Inst is part of the setup for a link182// time GOT PC Relative optimization. For example in this situation:183// <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)>184//   <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>>185// <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282>186//   <MCOperand Expr:(.Lpcrel@<<invalid>>)>>187// The above is a pair of such instructions and this function will not return188// std::nullopt for either one of them. In both cases we are looking for the189// last operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an190// MCExpr and has the flag PPC::S_PCREL_OPT. After that we just191// look at the opcode and in the case of PLDpc we will return true. For the load192// (or store) this function will return false indicating it has found the second193// instruciton in the pair.194std::optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,195                                                 const MCSubtargetInfo &STI) {196  // Need at least two operands.197  if (Inst.getNumOperands() < 2)198    return std::nullopt;199 200  unsigned LastOp = Inst.getNumOperands() - 1;201  // The last operand needs to be an MCExpr and it needs to have a variant kind202  // of VK_PCREL_OPT. If it does not satisfy these conditions it is not a203  // link time GOT PC Rel opt instruction and we can ignore it and return204  // std::nullopt.205  const MCOperand &Operand = Inst.getOperand(LastOp);206  if (!Operand.isExpr())207    return std::nullopt;208 209  // Check for the variant kind VK_PCREL_OPT in this expression.210  const MCExpr *Expr = Operand.getExpr();211  const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);212  if (!SymExpr || getSpecifier(SymExpr) != PPC::S_PCREL_OPT)213    return std::nullopt;214 215  return (Inst.getOpcode() == PPC::PLDpc);216}217 218MCStreamer *219llvm::createPPCELFStreamer(const Triple &T, MCContext &C,220                           std::unique_ptr<MCAsmBackend> &&MAB,221                           std::unique_ptr<MCObjectWriter> &&OW,222                           std::unique_ptr<MCCodeEmitter> &&Emitter) {223  return new PPCELFStreamer(C, std::move(MAB), std::move(OW),224                            std::move(Emitter));225}226