#include "MCTargetDesc/PPCFixupKinds.h"
#include "PPCInstrInfo.h"
#include "PPCMCCodeEmitter.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
using namespace llvm;
#define DEBUG_TYPE "mccodeemitter"
STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
MCCodeEmitter *llvm::createPPCMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx) {
return new PPCMCCodeEmitter(MCII, Ctx);
}
unsigned PPCMCCodeEmitter::
getDirectBrEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups, STI);
const PPCInstrInfo *InstrInfo = static_cast<const PPCInstrInfo *>(&MCII);
unsigned Opcode = MI.getOpcode();
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(InstrInfo->isNoTOCCallInstr(Opcode)
? (MCFixupKind)PPC::fixup_ppc_br24_notoc
: (MCFixupKind)PPC::fixup_ppc_br24)));
return 0;
}
unsigned PPCMCCodeEmitter::getCondBrEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_brcond14));
return 0;
}
unsigned PPCMCCodeEmitter::
getAbsDirectBrEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_br24abs));
return 0;
}
unsigned PPCMCCodeEmitter::
getAbsCondBrEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_brcond14abs));
return 0;
}
unsigned
PPCMCCodeEmitter::getVSRpEvenEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
assert(MI.getOperand(OpNo).isReg() && "Operand should be a register");
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI)
<< 1;
return RegBits;
}
unsigned PPCMCCodeEmitter::getImm16Encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(IsLittleEndian? 0 : 2, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_half16));
return 0;
}
uint64_t PPCMCCodeEmitter::getImm34Encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI,
MCFixupKind Fixup) const {
const MCOperand &MO = MI.getOperand(OpNo);
assert(!MO.isReg() && "Not expecting a register for this operand.");
if (MO.isImm())
return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(0, MO.getExpr(), Fixup));
return 0;
}
uint64_t
PPCMCCodeEmitter::getImm34EncodingNoPCRel(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
return getImm34Encoding(MI, OpNo, Fixups, STI,
(MCFixupKind)PPC::fixup_ppc_imm34);
}
uint64_t
PPCMCCodeEmitter::getImm34EncodingPCRel(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
return getImm34Encoding(MI, OpNo, Fixups, STI,
(MCFixupKind)PPC::fixup_ppc_pcrel34);
}
unsigned PPCMCCodeEmitter::getMemRIEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
assert(MI.getOperand(OpNo+1).isReg());
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI) << 16;
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isImm())
return (getMachineOpValue(MI, MO, Fixups, STI) & 0xFFFF) | RegBits;
Fixups.push_back(MCFixup::create(IsLittleEndian? 0 : 2, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_half16));
return RegBits;
}
unsigned PPCMCCodeEmitter::getMemRIXEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
assert(MI.getOperand(OpNo+1).isReg());
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI) << 14;
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isImm())
return ((getMachineOpValue(MI, MO, Fixups, STI) >> 2) & 0x3FFF) | RegBits;
Fixups.push_back(MCFixup::create(IsLittleEndian? 0 : 2, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_half16ds));
return RegBits;
}
unsigned PPCMCCodeEmitter::getMemRIX16Encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
assert(MI.getOperand(OpNo+1).isReg());
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI) << 12;
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isImm()) {
assert(!(MO.getImm() % 16) &&
"Expecting an immediate that is a multiple of 16");
return ((getMachineOpValue(MI, MO, Fixups, STI) >> 4) & 0xFFF) | RegBits;
}
Fixups.push_back(MCFixup::create(IsLittleEndian ? 0 : 2, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_half16dq));
return RegBits;
}
unsigned
PPCMCCodeEmitter::getMemRIHashEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &RegMO = MI.getOperand(OpNo + 1);
const MCOperand &MO = MI.getOperand(OpNo);
assert(RegMO.isReg() && "Base address must be a register.");
assert(MO.isImm() && "Expecting an immediate operand.");
assert(!(MO.getImm() % 8) && "Expecting offset to be 8 byte aligned.");
unsigned RegBits = getMachineOpValue(MI, RegMO, Fixups, STI) << 6;
unsigned DX = (MO.getImm() >> 3) & 0x3F;
return RegBits | DX;
}
uint64_t
PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
assert(MI.getOperand(OpNo + 1).isImm() && "Expecting an immediate.");
uint64_t RegBits =
getMachineOpValue(MI, MI.getOperand(OpNo + 1), Fixups, STI) << 34;
assert(RegBits == 0 && "Operand must be 0.");
const MCOperand &MO = MI.getOperand(OpNo);
if (!MO.isExpr())
return ((getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL) | RegBits;
const MCExpr *Expr = MO.getExpr();
switch (Expr->getKind()) {
default:
llvm_unreachable("Unsupported MCExpr for getMemRI34PCRelEncoding.");
case MCExpr::SymbolRef: {
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr);
(void)SRE;
assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL ||
SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL ||
SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL ||
SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TLSLD_PCREL ||
SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL) &&
"VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL or "
"VK_PPC_GOT_TLSGD_PCREL or VK_PPC_GOT_TLSLD_PCREL or "
"VK_PPC_GOT_TPREL_PCREL.");
Fixups.push_back(
MCFixup::create(0, Expr,
static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34)));
return 0;
}
case MCExpr::Binary: {
const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
assert(BE->getOpcode() == MCBinaryExpr::Add &&
"Binary expression opcode must be an add.");
const MCExpr *LHS = BE->getLHS();
const MCExpr *RHS = BE->getRHS();
if (LHS->getKind() != MCExpr::SymbolRef)
std::swap(LHS, RHS);
if (LHS->getKind() != MCExpr::SymbolRef ||
RHS->getKind() != MCExpr::Constant)
llvm_unreachable("Expecting to have one constant and one relocation.");
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(LHS);
(void)SRE;
assert(isInt<34>(cast<MCConstantExpr>(RHS)->getValue()) &&
"Value must fit in 34 bits.");
assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL ||
SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) &&
"VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL");
Fixups.push_back(
MCFixup::create(0, Expr,
static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34)));
return 0;
}
}
}
uint64_t
PPCMCCodeEmitter::getMemRI34Encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
assert(MI.getOperand(OpNo + 1).isReg() && "Expecting a register.");
uint64_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo + 1), Fixups, STI)
<< 34;
const MCOperand &MO = MI.getOperand(OpNo);
return ((getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL) | RegBits;
}
unsigned PPCMCCodeEmitter::getSPE8DisEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI)
const {
assert(MI.getOperand(OpNo+1).isReg());
uint32_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI) << 5;
const MCOperand &MO = MI.getOperand(OpNo);
assert(MO.isImm());
uint32_t Imm = getMachineOpValue(MI, MO, Fixups, STI) >> 3;
return reverseBits(Imm | RegBits) >> 22;
}
unsigned PPCMCCodeEmitter::getSPE4DisEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI)
const {
assert(MI.getOperand(OpNo+1).isReg());
uint32_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI) << 5;
const MCOperand &MO = MI.getOperand(OpNo);
assert(MO.isImm());
uint32_t Imm = getMachineOpValue(MI, MO, Fixups, STI) >> 2;
return reverseBits(Imm | RegBits) >> 22;
}
unsigned PPCMCCodeEmitter::getSPE2DisEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI)
const {
assert(MI.getOperand(OpNo+1).isReg());
uint32_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI) << 5;
const MCOperand &MO = MI.getOperand(OpNo);
assert(MO.isImm());
uint32_t Imm = getMachineOpValue(MI, MO, Fixups, STI) >> 1;
return reverseBits(Imm | RegBits) >> 22;
}
unsigned PPCMCCodeEmitter::getTLSRegEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg()) return getMachineOpValue(MI, MO, Fixups, STI);
const MCExpr *Expr = MO.getExpr();
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr);
bool IsPCRel = SRE->getKind() == MCSymbolRefExpr::VK_PPC_TLS_PCREL;
Fixups.push_back(MCFixup::create(IsPCRel ? 1 : 0, Expr,
(MCFixupKind)PPC::fixup_ppc_nofixup));
const Triple &TT = STI.getTargetTriple();
bool isPPC64 = TT.isPPC64();
return CTX.getRegisterInfo()->getEncodingValue(isPPC64 ? PPC::X13 : PPC::R2);
}
unsigned PPCMCCodeEmitter::getTLSCallEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo+1);
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_nofixup));
return getDirectBrEncoding(MI, OpNo, Fixups, STI);
}
unsigned PPCMCCodeEmitter::
get_crbitm_encoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
assert((MI.getOpcode() == PPC::MTOCRF || MI.getOpcode() == PPC::MTOCRF8 ||
MI.getOpcode() == PPC::MFOCRF || MI.getOpcode() == PPC::MFOCRF8) &&
(MO.getReg() >= PPC::CR0 && MO.getReg() <= PPC::CR7));
return 0x80 >> CTX.getRegisterInfo()->getEncodingValue(MO.getReg());
}
static unsigned getOpIdxForMO(const MCInst &MI, const MCOperand &MO) {
for (unsigned i = 0; i < MI.getNumOperands(); i++) {
const MCOperand &Op = MI.getOperand(i);
if (&Op == &MO)
return i;
}
llvm_unreachable("This operand is not part of this instruction");
return ~0U; }
uint64_t PPCMCCodeEmitter::
getMachineOpValue(const MCInst &MI, const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
if (MO.isReg()) {
assert((MI.getOpcode() != PPC::MTOCRF && MI.getOpcode() != PPC::MTOCRF8 &&
MI.getOpcode() != PPC::MFOCRF && MI.getOpcode() != PPC::MFOCRF8) ||
MO.getReg() < PPC::CR0 || MO.getReg() > PPC::CR7);
unsigned OpNo = getOpIdxForMO(MI, MO);
unsigned Reg =
PPCInstrInfo::getRegNumForOperand(MCII.get(MI.getOpcode()),
MO.getReg(), OpNo);
return CTX.getRegisterInfo()->getEncodingValue(Reg);
}
assert(MO.isImm() &&
"Relocation required in an instruction that we cannot encode!");
return MO.getImm();
}
void PPCMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
unsigned Size = getInstSizeInBytes(MI);
support::endianness E = IsLittleEndian ? support::little : support::big;
switch (Size) {
case 0:
break;
case 4:
support::endian::write<uint32_t>(OS, Bits, E);
break;
case 8:
support::endian::write<uint32_t>(OS, Bits >> 32, E);
support::endian::write<uint32_t>(OS, Bits, E);
break;
default:
llvm_unreachable("Invalid instruction size");
}
++MCNumEmitted; }
unsigned PPCMCCodeEmitter::getInstSizeInBytes(const MCInst &MI) const {
unsigned Opcode = MI.getOpcode();
const MCInstrDesc &Desc = MCII.get(Opcode);
return Desc.getSize();
}
bool PPCMCCodeEmitter::isPrefixedInstruction(const MCInst &MI) const {
unsigned Opcode = MI.getOpcode();
const PPCInstrInfo *InstrInfo = static_cast<const PPCInstrInfo*>(&MCII);
return InstrInfo->isPrefixed(Opcode);
}
#include "PPCGenMCCodeEmitter.inc"