In preparation for passing the MCSubtargetInfo (STI) through to writeNops so that it can use the STI in operation at the time, we need to record the STI in operation when a MCAlignFragment may write nops as padding. The STI is currently unused, a further patch will pass it through to writeNops. There are many places that can create an MCAlignFragment, in most cases we can find out the STI in operation at the time. In a few places this isn't possible as we are in initialisation or finalisation, or are emitting constant pools. When possible I've tried to find the most appropriate existing fragment to obtain the STI from, when none is available use the per module STI. For constant pools we don't actually need to use EmitCodeAlign as the constant pools are data anyway so falling through into it via an executable NOP is no better than falling through into data padding. This is a prerequisite for D45962 which uses the STI to emit the appropriate NOP for the STI. Which can differ per fragment. Note that involves an interface change to InitSections. It is now called initSections and requires a SubtargetInfo as a parameter. Differential Revision: https://reviews.llvm.org/D45961
230 lines
10 KiB
C++
230 lines
10 KiB
C++
//===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This is a custom MCELFStreamer for PowerPC.
|
|
//
|
|
// The purpose of the custom ELF streamer is to allow us to intercept
|
|
// instructions as they are being emitted and align all 8 byte instructions
|
|
// to a 64 byte boundary if required (by adding a 4 byte nop). This is important
|
|
// because 8 byte instructions are not allowed to cross 64 byte boundaries
|
|
// and by aliging anything that is within 4 bytes of the boundary we can
|
|
// guarantee that the 8 byte instructions do not cross that boundary.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
#include "PPCELFStreamer.h"
|
|
#include "PPCFixupKinds.h"
|
|
#include "PPCInstrInfo.h"
|
|
#include "PPCMCCodeEmitter.h"
|
|
#include "llvm/BinaryFormat/ELF.h"
|
|
#include "llvm/MC/MCAsmBackend.h"
|
|
#include "llvm/MC/MCAssembler.h"
|
|
#include "llvm/MC/MCCodeEmitter.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCInstrDesc.h"
|
|
#include "llvm/MC/MCObjectWriter.h"
|
|
#include "llvm/MC/MCSymbolELF.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
using namespace llvm;
|
|
|
|
PPCELFStreamer::PPCELFStreamer(MCContext &Context,
|
|
std::unique_ptr<MCAsmBackend> MAB,
|
|
std::unique_ptr<MCObjectWriter> OW,
|
|
std::unique_ptr<MCCodeEmitter> Emitter)
|
|
: MCELFStreamer(Context, std::move(MAB), std::move(OW),
|
|
std::move(Emitter)), LastLabel(NULL) {
|
|
}
|
|
|
|
void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst,
|
|
const MCSubtargetInfo &STI) {
|
|
// Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is
|
|
// before the boundary and the remaining 4-bytes are after the boundary). In
|
|
// order to achieve this, a nop is added prior to any such boundary-crossing
|
|
// prefixed instruction. Align to 64 bytes if possible but add a maximum of 4
|
|
// bytes when trying to do that. If alignment requires adding more than 4
|
|
// bytes then the instruction won't be aligned. When emitting a code alignment
|
|
// a new fragment is created for this alignment. This fragment will contain
|
|
// all of the nops required as part of the alignment operation. In the cases
|
|
// when no nops are added then The fragment is still created but it remains
|
|
// empty.
|
|
emitCodeAlignment(64, &STI, 4);
|
|
|
|
// Emit the instruction.
|
|
// Since the previous emit created a new fragment then adding this instruction
|
|
// also forces the addition of a new fragment. Inst is now the first
|
|
// instruction in that new fragment.
|
|
MCELFStreamer::emitInstruction(Inst, STI);
|
|
|
|
// The above instruction is forced to start a new fragment because it
|
|
// comes after a code alignment fragment. Get that new fragment.
|
|
MCFragment *InstructionFragment = getCurrentFragment();
|
|
SMLoc InstLoc = Inst.getLoc();
|
|
// Check if there was a last label emitted.
|
|
if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() &&
|
|
InstLoc.isValid()) {
|
|
const SourceMgr *SourceManager = getContext().getSourceManager();
|
|
unsigned InstLine = SourceManager->FindLineNumber(InstLoc);
|
|
unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc);
|
|
// If the Label and the Instruction are on the same line then move the
|
|
// label to the top of the fragment containing the aligned instruction that
|
|
// was just added.
|
|
if (InstLine == LabelLine) {
|
|
AssignFragment(LastLabel, InstructionFragment);
|
|
LastLabel->setOffset(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PPCELFStreamer::emitInstruction(const MCInst &Inst,
|
|
const MCSubtargetInfo &STI) {
|
|
PPCMCCodeEmitter *Emitter =
|
|
static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr());
|
|
|
|
// If the instruction is a part of the GOT to PC-Rel link time optimization
|
|
// instruction pair, return a value, otherwise return None. A true returned
|
|
// value means the instruction is the PLDpc and a false value means it is
|
|
// the user instruction.
|
|
Optional<bool> IsPartOfGOTToPCRelPair = isPartOfGOTToPCRelPair(Inst, STI);
|
|
|
|
// User of the GOT-indirect address.
|
|
// For example, the load that will get the relocation as follows:
|
|
// .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
|
|
// lwa 3, 4(3)
|
|
if (IsPartOfGOTToPCRelPair.hasValue() && !IsPartOfGOTToPCRelPair.getValue())
|
|
emitGOTToPCRelReloc(Inst);
|
|
|
|
// Special handling is only for prefixed instructions.
|
|
if (!Emitter->isPrefixedInstruction(Inst)) {
|
|
MCELFStreamer::emitInstruction(Inst, STI);
|
|
return;
|
|
}
|
|
emitPrefixedInstruction(Inst, STI);
|
|
|
|
// Producer of the GOT-indirect address.
|
|
// For example, the prefixed load from the got that will get the label as
|
|
// follows:
|
|
// pld 3, vec@got@pcrel(0), 1
|
|
// .Lpcrel1:
|
|
if (IsPartOfGOTToPCRelPair.hasValue() && IsPartOfGOTToPCRelPair.getValue())
|
|
emitGOTToPCRelLabel(Inst);
|
|
}
|
|
|
|
void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
|
|
LastLabel = Symbol;
|
|
LastLabelLoc = Loc;
|
|
MCELFStreamer::emitLabel(Symbol);
|
|
}
|
|
|
|
// This linker time GOT PC Relative optimization relocation will look like this:
|
|
// pld <reg> symbol@got@pcrel
|
|
// <Label###>:
|
|
// .reloc Label###-8,R_PPC64_PCREL_OPT,.-(Label###-8)
|
|
// load <loadedreg>, 0(<reg>)
|
|
// The reason we place the label after the PLDpc instruction is that there
|
|
// may be an alignment nop before it since prefixed instructions must not
|
|
// cross a 64-byte boundary (please see
|
|
// PPCELFStreamer::emitPrefixedInstruction()). When referring to the
|
|
// label, we subtract the width of a prefixed instruction (8 bytes) to ensure
|
|
// we refer to the PLDpc.
|
|
void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {
|
|
// Get the last operand which contains the symbol.
|
|
const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
|
|
assert(Operand.isExpr() && "Expecting an MCExpr.");
|
|
// Cast the last operand to MCSymbolRefExpr to get the symbol.
|
|
const MCExpr *Expr = Operand.getExpr();
|
|
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
|
|
assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
|
|
"Expecting a symbol of type VK_PPC_PCREL_OPT");
|
|
MCSymbol *LabelSym =
|
|
getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
|
|
const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext());
|
|
const MCExpr *Eight = MCConstantExpr::create(8, getContext());
|
|
// SubExpr is just Label###-8
|
|
const MCExpr *SubExpr =
|
|
MCBinaryExpr::createSub(LabelExpr, Eight, getContext());
|
|
MCSymbol *CurrentLocation = getContext().createTempSymbol();
|
|
const MCExpr *CurrentLocationExpr =
|
|
MCSymbolRefExpr::create(CurrentLocation, getContext());
|
|
// SubExpr2 is .-(Label###-8)
|
|
const MCExpr *SubExpr2 =
|
|
MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, getContext());
|
|
|
|
MCDataFragment *DF = static_cast<MCDataFragment *>(LabelSym->getFragment());
|
|
assert(DF && "Expecting a valid data fragment.");
|
|
MCFixupKind FixupKind = static_cast<MCFixupKind>(FirstLiteralRelocationKind +
|
|
ELF::R_PPC64_PCREL_OPT);
|
|
DF->getFixups().push_back(
|
|
MCFixup::create(LabelSym->getOffset() - 8, SubExpr2,
|
|
FixupKind, Inst.getLoc()));
|
|
emitLabel(CurrentLocation, Inst.getLoc());
|
|
}
|
|
|
|
// Emit the label that immediately follows the PLDpc for a link time GOT PC Rel
|
|
// optimization.
|
|
void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {
|
|
// Get the last operand which contains the symbol.
|
|
const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
|
|
assert(Operand.isExpr() && "Expecting an MCExpr.");
|
|
// Cast the last operand to MCSymbolRefExpr to get the symbol.
|
|
const MCExpr *Expr = Operand.getExpr();
|
|
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
|
|
assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT &&
|
|
"Expecting a symbol of type VK_PPC_PCREL_OPT");
|
|
MCSymbol *LabelSym =
|
|
getContext().getOrCreateSymbol(SymExpr->getSymbol().getName());
|
|
emitLabel(LabelSym, Inst.getLoc());
|
|
}
|
|
|
|
// This funciton checks if the parameter Inst is part of the setup for a link
|
|
// time GOT PC Relative optimization. For example in this situation:
|
|
// <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)>
|
|
// <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
|
|
// <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282>
|
|
// <MCOperand Expr:(.Lpcrel@<<invalid>>)>>
|
|
// The above is a pair of such instructions and this function will not return
|
|
// None for either one of them. In both cases we are looking for the last
|
|
// operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an MCExpr
|
|
// and has the flag MCSymbolRefExpr::VK_PPC_PCREL_OPT. After that we just look
|
|
// at the opcode and in the case of PLDpc we will return true. For the load
|
|
// (or store) this function will return false indicating it has found the second
|
|
// instruciton in the pair.
|
|
Optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,
|
|
const MCSubtargetInfo &STI) {
|
|
// Need at least two operands.
|
|
if (Inst.getNumOperands() < 2)
|
|
return None;
|
|
|
|
unsigned LastOp = Inst.getNumOperands() - 1;
|
|
// The last operand needs to be an MCExpr and it needs to have a variant kind
|
|
// of VK_PPC_PCREL_OPT. If it does not satisfy these conditions it is not a
|
|
// link time GOT PC Rel opt instruction and we can ignore it and return None.
|
|
const MCOperand &Operand = Inst.getOperand(LastOp);
|
|
if (!Operand.isExpr())
|
|
return None;
|
|
|
|
// Check for the variant kind VK_PPC_PCREL_OPT in this expression.
|
|
const MCExpr *Expr = Operand.getExpr();
|
|
const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr);
|
|
if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_PPC_PCREL_OPT)
|
|
return None;
|
|
|
|
return (Inst.getOpcode() == PPC::PLDpc);
|
|
}
|
|
|
|
MCELFStreamer *llvm::createPPCELFStreamer(
|
|
MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
|
|
std::unique_ptr<MCObjectWriter> OW,
|
|
std::unique_ptr<MCCodeEmitter> Emitter) {
|
|
return new PPCELFStreamer(Context, std::move(MAB), std::move(OW),
|
|
std::move(Emitter));
|
|
}
|