Path: blob/main/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp
35294 views
//===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This is a custom MCELFStreamer for PowerPC.9//10// The purpose of the custom ELF streamer is to allow us to intercept11// instructions as they are being emitted and align all 8 byte instructions12// to a 64 byte boundary if required (by adding a 4 byte nop). This is important13// because 8 byte instructions are not allowed to cross 64 byte boundaries14// and by aliging anything that is within 4 bytes of the boundary we can15// guarantee that the 8 byte instructions do not cross that boundary.16//17//===----------------------------------------------------------------------===//1819#include "PPCELFStreamer.h"20#include "PPCFixupKinds.h"21#include "PPCMCCodeEmitter.h"22#include "PPCMCTargetDesc.h"23#include "llvm/BinaryFormat/ELF.h"24#include "llvm/MC/MCAsmBackend.h"25#include "llvm/MC/MCAssembler.h"26#include "llvm/MC/MCCodeEmitter.h"27#include "llvm/MC/MCContext.h"28#include "llvm/MC/MCInst.h"29#include "llvm/MC/MCInstrDesc.h"30#include "llvm/MC/MCObjectWriter.h"31#include "llvm/MC/MCSymbolELF.h"32#include "llvm/Support/Casting.h"33#include "llvm/Support/SourceMgr.h"3435using namespace llvm;3637PPCELFStreamer::PPCELFStreamer(MCContext &Context,38std::unique_ptr<MCAsmBackend> MAB,39std::unique_ptr<MCObjectWriter> OW,40std::unique_ptr<MCCodeEmitter> Emitter)41: MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(Emitter)),42LastLabel(nullptr) {}4344void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst,45const MCSubtargetInfo &STI) {46// Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is47// before the boundary and the remaining 4-bytes are after the boundary). In48// order to achieve this, a nop is added prior to any such boundary-crossing49// prefixed instruction. Align to 64 bytes if possible but add a maximum of 450// bytes when trying to do that. If alignment requires adding more than 451// bytes then the instruction won't be aligned. When emitting a code alignment52// a new fragment is created for this alignment. This fragment will contain53// all of the nops required as part of the alignment operation. In the cases54// when no nops are added then The fragment is still created but it remains55// empty.56emitCodeAlignment(Align(64), &STI, 4);5758// Emit the instruction.59// Since the previous emit created a new fragment then adding this instruction60// also forces the addition of a new fragment. Inst is now the first61// instruction in that new fragment.62MCELFStreamer::emitInstruction(Inst, STI);6364// The above instruction is forced to start a new fragment because it65// comes after a code alignment fragment. Get that new fragment.66MCFragment *InstructionFragment = getCurrentFragment();67SMLoc InstLoc = Inst.getLoc();68// Check if there was a last label emitted.69if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() &&70InstLoc.isValid()) {71const SourceMgr *SourceManager = getContext().getSourceManager();72unsigned InstLine = SourceManager->FindLineNumber(InstLoc);73unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc);74// If the Label and the Instruction are on the same line then move the75// label to the top of the fragment containing the aligned instruction that76// was just added.77if (InstLine == LabelLine) {78LastLabel->setFragment(InstructionFragment);79LastLabel->setOffset(0);80}81}82}8384void PPCELFStreamer::emitInstruction(const MCInst &Inst,85const MCSubtargetInfo &STI) {86PPCMCCodeEmitter *Emitter =87static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr());8889// If the instruction is a part of the GOT to PC-Rel link time optimization90// instruction pair, return a value, otherwise return std::nullopt. A true91// returned value means the instruction is the PLDpc and a false value means92// it is the user instruction.93std::optional<bool> IsPartOfGOTToPCRelPair =94isPartOfGOTToPCRelPair(Inst, STI);9596// User of the GOT-indirect address.97// For example, the load that will get the relocation as follows:98// .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)99// lwa 3, 4(3)100if (IsPartOfGOTToPCRelPair && !*IsPartOfGOTToPCRelPair)101emitGOTToPCRelReloc(Inst);102103// Special handling is only for prefixed instructions.104if (!Emitter->isPrefixedInstruction(Inst)) {105MCELFStreamer::emitInstruction(Inst, STI);106return;107}108emitPrefixedInstruction(Inst, STI);109110// Producer of the GOT-indirect address.111// For example, the prefixed load from the got that will get the label as112// follows:113// pld 3, vec@got@pcrel(0), 1114// .Lpcrel1:115if (IsPartOfGOTToPCRelPair && *IsPartOfGOTToPCRelPair)116emitGOTToPCRelLabel(Inst);117}118119void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {120LastLabel = Symbol;121LastLabelLoc = Loc;122MCELFStreamer::emitLabel(Symbol);123}124125// This linker time GOT PC Relative optimization relocation will look like this:126// pld <reg> symbol@got@pcrel127// <Label###>:128// .reloc Label###-8,R_PPC64_PCREL_OPT,.-(Label###-8)129// load <loadedreg>, 0(<reg>)130// The reason we place the label after the PLDpc instruction is that there131// may be an alignment nop before it since prefixed instructions must not132// cross a 64-byte boundary (please see133// PPCELFStreamer::emitPrefixedInstruction()). When referring to the134// label, we subtract the width of a prefixed instruction (8 bytes) to ensure135// we refer to the PLDpc.136void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {137// Get the last operand which contains the symbol.138const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);139assert(Operand.isExpr() && "Expecting an MCExpr.");140// Cast the last operand to MCSymbolRefExpr to get the symbol.141const MCExpr *Expr = Operand.getExpr();142const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);143assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&144"Expecting a symbol of type VK_PPC_PCREL_OPT");145MCSymbol *LabelSym =146getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());147const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext());148const MCExpr *Eight = MCConstantExpr::create(8, getContext());149// SubExpr is just Label###-8150const MCExpr *SubExpr =151MCBinaryExpr::createSub(LabelExpr, Eight, getContext());152MCSymbol *CurrentLocation = getContext().createTempSymbol();153const MCExpr *CurrentLocationExpr =154MCSymbolRefExpr::create(CurrentLocation, getContext());155// SubExpr2 is .-(Label###-8)156const MCExpr *SubExpr2 =157MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, getContext());158159MCDataFragment *DF = static_cast<MCDataFragment *>(LabelSym->getFragment());160assert(DF && "Expecting a valid data fragment.");161MCFixupKind FixupKind = static_cast<MCFixupKind>(FirstLiteralRelocationKind +162ELF::R_PPC64_PCREL_OPT);163DF->getFixups().push_back(164MCFixup::create(LabelSym->getOffset() - 8, SubExpr2,165FixupKind, Inst.getLoc()));166emitLabel(CurrentLocation, Inst.getLoc());167}168169// Emit the label that immediately follows the PLDpc for a link time GOT PC Rel170// optimization.171void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {172// Get the last operand which contains the symbol.173const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);174assert(Operand.isExpr() && "Expecting an MCExpr.");175// Cast the last operand to MCSymbolRefExpr to get the symbol.176const MCExpr *Expr = Operand.getExpr();177const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);178assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&179"Expecting a symbol of type VK_PPC_PCREL_OPT");180MCSymbol *LabelSym =181getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());182emitLabel(LabelSym, Inst.getLoc());183}184185// This function checks if the parameter Inst is part of the setup for a link186// time GOT PC Relative optimization. For example in this situation:187// <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)>188// <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>>189// <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282>190// <MCOperand Expr:(.Lpcrel@<<invalid>>)>>191// The above is a pair of such instructions and this function will not return192// std::nullopt for either one of them. In both cases we are looking for the193// last operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an194// MCExpr and has the flag MCSymbolRefExpr::VK_PPC_PCREL_OPT. After that we just195// look at the opcode and in the case of PLDpc we will return true. For the load196// (or store) this function will return false indicating it has found the second197// instruciton in the pair.198std::optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,199const MCSubtargetInfo &STI) {200// Need at least two operands.201if (Inst.getNumOperands() < 2)202return std::nullopt;203204unsigned LastOp = Inst.getNumOperands() - 1;205// The last operand needs to be an MCExpr and it needs to have a variant kind206// of VK_PPC_PCREL_OPT. If it does not satisfy these conditions it is not a207// link time GOT PC Rel opt instruction and we can ignore it and return208// std::nullopt.209const MCOperand &Operand = Inst.getOperand(LastOp);210if (!Operand.isExpr())211return std::nullopt;212213// Check for the variant kind VK_PPC_PCREL_OPT in this expression.214const MCExpr *Expr = Operand.getExpr();215const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);216if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_PPC_PCREL_OPT)217return std::nullopt;218219return (Inst.getOpcode() == PPC::PLDpc);220}221222MCELFStreamer *llvm::createPPCELFStreamer(223MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,224std::unique_ptr<MCObjectWriter> OW,225std::unique_ptr<MCCodeEmitter> Emitter) {226return new PPCELFStreamer(Context, std::move(MAB), std::move(OW),227std::move(Emitter));228}229230231