#include "MCTargetDesc/SPIRVMCTargetDesc.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/EndianStream.h"
using namespace llvm;
#define DEBUG_TYPE "spirv-mccodeemitter"
namespace {
class SPIRVMCCodeEmitter : public MCCodeEmitter {
const MCInstrInfo &MCII;
public:
SPIRVMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}
SPIRVMCCodeEmitter(const SPIRVMCCodeEmitter &) = delete;
void operator=(const SPIRVMCCodeEmitter &) = delete;
~SPIRVMCCodeEmitter() override = default;
uint64_t getBinaryCodeForInstr(const MCInst &MI,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
};
}
MCCodeEmitter *llvm::createSPIRVMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx) {
return new SPIRVMCCodeEmitter(MCII);
}
using EndianWriter = support::endian::Writer;
static bool hasType(const MCInst &MI, const MCInstrInfo &MII) {
MCInstrDesc MCDesc = MII.get(MI.getOpcode());
if (MCDesc.getNumDefs() == 1 && MCDesc.getNumOperands() >= 2) {
auto DefOpInfo = MCDesc.opInfo_begin();
auto FirstArgOpInfo = MCDesc.opInfo_begin() + 1;
return (DefOpInfo->RegClass == SPIRV::IDRegClassID ||
DefOpInfo->RegClass == SPIRV::ANYIDRegClassID) &&
FirstArgOpInfo->RegClass == SPIRV::TYPERegClassID;
}
return false;
}
static void emitOperand(const MCOperand &Op, EndianWriter &OSE) {
if (Op.isReg()) {
OSE.write<uint32_t>(Register::virtReg2Index(Op.getReg()) + 1);
} else if (Op.isImm()) {
OSE.write<uint32_t>(Op.getImm());
} else {
llvm_unreachable("Unexpected operand type in VReg");
}
}
static void emitTypedInstrOperands(const MCInst &MI, EndianWriter &OSE) {
unsigned NumOps = MI.getNumOperands();
emitOperand(MI.getOperand(1), OSE);
emitOperand(MI.getOperand(0), OSE);
for (unsigned i = 2; i < NumOps; ++i)
emitOperand(MI.getOperand(i), OSE);
}
static void emitUntypedInstrOperands(const MCInst &MI, EndianWriter &OSE) {
for (const auto &Op : MI)
emitOperand(Op, OSE);
}
void SPIRVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
EndianWriter OSE(OS, support::little);
const uint64_t OpCode = getBinaryCodeForInstr(MI, Fixups, STI);
const uint32_t NumWords = MI.getNumOperands() + 1;
const uint32_t FirstWord = (NumWords << 16) | OpCode;
OSE.write<uint32_t>(FirstWord);
if (hasType(MI, MCII))
emitTypedInstrOperands(MI, OSE);
else
emitUntypedInstrOperands(MI, OSE);
}
#include "SPIRVGenMCCodeEmitter.inc"