#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(nullptr) {}
void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst,
const MCSubtargetInfo &STI) {
emitCodeAlignment(64, &STI, 4);
MCELFStreamer::emitInstruction(Inst, STI);
MCFragment *InstructionFragment = getCurrentFragment();
SMLoc InstLoc = Inst.getLoc();
if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() &&
InstLoc.isValid()) {
const SourceMgr *SourceManager = getContext().getSourceManager();
unsigned InstLine = SourceManager->FindLineNumber(InstLoc);
unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc);
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());
Optional<bool> IsPartOfGOTToPCRelPair = isPartOfGOTToPCRelPair(Inst, STI);
if (IsPartOfGOTToPCRelPair && !*IsPartOfGOTToPCRelPair)
emitGOTToPCRelReloc(Inst);
if (!Emitter->isPrefixedInstruction(Inst)) {
MCELFStreamer::emitInstruction(Inst, STI);
return;
}
emitPrefixedInstruction(Inst, STI);
if (IsPartOfGOTToPCRelPair && *IsPartOfGOTToPCRelPair)
emitGOTToPCRelLabel(Inst);
}
void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
LastLabel = Symbol;
LastLabelLoc = Loc;
MCELFStreamer::emitLabel(Symbol);
}
void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {
const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
assert(Operand.isExpr() && "Expecting an MCExpr.");
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());
const MCExpr *SubExpr =
MCBinaryExpr::createSub(LabelExpr, Eight, getContext());
MCSymbol *CurrentLocation = getContext().createTempSymbol();
const MCExpr *CurrentLocationExpr =
MCSymbolRefExpr::create(CurrentLocation, getContext());
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());
}
void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {
const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1);
assert(Operand.isExpr() && "Expecting an MCExpr.");
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());
}
Optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,
const MCSubtargetInfo &STI) {
if (Inst.getNumOperands() < 2)
return None;
unsigned LastOp = Inst.getNumOperands() - 1;
const MCOperand &Operand = Inst.getOperand(LastOp);
if (!Operand.isExpr())
return None;
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));
}