#include "MCTargetDesc/M68kMCCodeEmitter.h"
#include "MCTargetDesc/M68kBaseInfo.h"
#include "MCTargetDesc/M68kFixupKinds.h"
#include "MCTargetDesc/M68kMCTargetDesc.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/raw_ostream.h"
#include <type_traits>
using namespace llvm;
#define DEBUG_TYPE "m68k-mccodeemitter"
namespace {
class M68kMCCodeEmitter : public MCCodeEmitter {
M68kMCCodeEmitter(const M68kMCCodeEmitter &) = delete;
void operator=(const M68kMCCodeEmitter &) = delete;
const MCInstrInfo &MCII;
MCContext &Ctx;
void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,
APInt &Inst, APInt &Scratch,
const MCSubtargetInfo &STI) const;
void getMachineOpValue(const MCInst &MI, const MCOperand &Op,
unsigned InsertPos, APInt &Value,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
template <unsigned Size>
void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
template <unsigned Size>
void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
public:
M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
: MCII(mcii), Ctx(ctx) {}
~M68kMCCodeEmitter() override {}
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
};
}
#include "M68kGenMCCodeEmitter.inc"
template <unsigned Size> struct select_uint_t {
using type = typename std::conditional<
Size == 8, uint8_t,
typename std::conditional<
Size == 16, uint16_t,
typename std::conditional<Size == 32, uint32_t,
uint64_t>::type>::type>::type;
};
template <typename value_t> static value_t swapWord(value_t Val) {
const unsigned NumWords = sizeof(Val) / 2;
if (NumWords <= 1)
return Val;
Val = support::endian::byte_swap(Val, support::big);
value_t NewVal = 0;
for (unsigned i = 0U; i != NumWords; ++i) {
uint16_t Part = (Val >> (i * 16)) & 0xFFFF;
Part = support::endian::byte_swap(Part, support::big);
NewVal |= (Part << (i * 16));
}
return NewVal;
}
template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {
if (Size % 16) {
return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));
} else {
assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");
return BitPos / 8;
}
}
template <unsigned Size>
void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
unsigned InsertPos, APInt &Value,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
using value_t = typename select_uint_t<Size>::type;
const MCOperand &MCO = MI.getOperand(OpIdx);
if (MCO.isImm()) {
Value |= swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
} else if (MCO.isExpr()) {
const MCExpr *Expr = MCO.getExpr();
int64_t Addr;
if (Expr->evaluateAsAbsolute(Addr)) {
Value |= swapWord<value_t>(static_cast<value_t>(Addr));
return;
}
unsigned InsertByte = getBytePosition<Size>(InsertPos);
Fixups.push_back(MCFixup::create(InsertByte, Expr,
getFixupForSize(Size, false),
MI.getLoc()));
}
}
template <unsigned Size>
void M68kMCCodeEmitter::encodePCRelImm(const MCInst &MI, unsigned OpIdx,
unsigned InsertPos, APInt &Value,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MCO = MI.getOperand(OpIdx);
if (MCO.isImm()) {
using value_t = typename select_uint_t<Size>::type;
Value |= swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
} else if (MCO.isExpr()) {
const MCExpr *Expr = MCO.getExpr();
unsigned InsertByte = getBytePosition<Size>(InsertPos);
if (Size < 16) {
int LabelOffset = 0;
if (InsertPos < 16)
LabelOffset = InsertByte - 2;
else if (InsertByte % 2)
LabelOffset = 1;
if (LabelOffset)
Expr = MCBinaryExpr::createAdd(
Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);
}
Fixups.push_back(MCFixup::create(InsertByte, Expr,
getFixupForSize(Size, true),
MI.getLoc()));
}
}
void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
unsigned InsertPos, APInt &Value,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
if (Op.isReg()) {
unsigned RegNum = Op.getReg();
const auto *RI = Ctx.getRegisterInfo();
Value |= RI->getEncodingValue(RegNum);
if (M68kII::isAddressRegister(RegNum))
Value |= 0b1000;
} else if (Op.isImm()) {
Value |= static_cast<uint64_t>(Op.getImm());
} else if (Op.isExpr()) {
int64_t Addr;
if (!Op.getExpr()->evaluateAsAbsolute(Addr))
report_fatal_error("Unsupported asm expression. Only absolute address "
"can be placed here.");
Value |= static_cast<uint64_t>(Addr);
} else {
llvm_unreachable("Unsupported operand type");
}
}
void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
unsigned Opcode = MI.getOpcode();
LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "("
<< Opcode << ")\n");
APInt EncodedInst(16, 0U);
APInt Scratch(16, 0U);
getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI);
ArrayRef<uint64_t> Data(EncodedInst.getRawData(), EncodedInst.getNumWords());
int64_t InstSize = EncodedInst.getBitWidth();
for (uint64_t Word : Data) {
for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) {
support::endian::write<uint16_t>(OS, static_cast<uint16_t>(Word),
support::big);
Word >>= 16;
}
}
}
MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx) {
return new M68kMCCodeEmitter(MCII, Ctx);
}