#include "MCTargetDesc/M68kBaseInfo.h"
#include "MCTargetDesc/M68kFixupKinds.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCMachObjectWriter.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
class M68kAsmBackend : public MCAsmBackend {
public:
M68kAsmBackend(const Target &T) : MCAsmBackend(support::big) {}
unsigned getNumFixupKinds() const override { return 0; }
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
uint64_t Value, bool IsResolved,
const MCSubtargetInfo *STI) const override {
unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());
assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");
assert(isIntN(Size * 8 + 1, Value) &&
"Value does not fit in the Fixup field");
for (unsigned i = 0; i != Size; ++i)
Data[Fixup.getOffset() + i] = uint8_t(Value >> ((Size - i - 1) * 8));
}
bool mayNeedRelaxation(const MCInst &Inst,
const MCSubtargetInfo &STI) const override;
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override;
void relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const override;
unsigned getMinimumNopSize() const override { return 2; }
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
};
}
static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) {
unsigned Op = Inst.getOpcode();
switch (Op) {
default:
return Op;
case M68k::BRA8:
return M68k::BRA16;
case M68k::Bcc8:
return M68k::Bcc16;
case M68k::Bls8:
return M68k::Bls16;
case M68k::Blt8:
return M68k::Blt16;
case M68k::Beq8:
return M68k::Beq16;
case M68k::Bmi8:
return M68k::Bmi16;
case M68k::Bne8:
return M68k::Bne16;
case M68k::Bge8:
return M68k::Bge16;
case M68k::Bcs8:
return M68k::Bcs16;
case M68k::Bpl8:
return M68k::Bpl16;
case M68k::Bgt8:
return M68k::Bgt16;
case M68k::Bhi8:
return M68k::Bhi16;
case M68k::Bvc8:
return M68k::Bvc16;
case M68k::Ble8:
return M68k::Ble16;
case M68k::Bvs8:
return M68k::Bvs16;
}
}
static unsigned getRelaxedOpcodeArith(const MCInst &Inst) {
unsigned Op = Inst.getOpcode();
return Op;
}
static unsigned getRelaxedOpcode(const MCInst &Inst) {
unsigned R = getRelaxedOpcodeArith(Inst);
if (R != Inst.getOpcode())
return R;
return getRelaxedOpcodeBranch(Inst);
}
bool M68kAsmBackend::mayNeedRelaxation(const MCInst &Inst,
const MCSubtargetInfo &STI) const {
if (getRelaxedOpcodeBranch(Inst) != Inst.getOpcode())
return true;
if (getRelaxedOpcodeArith(Inst) == Inst.getOpcode())
return false;
unsigned RelaxableOp = Inst.getNumOperands() - 1;
if (Inst.getOperand(RelaxableOp).isExpr())
return true;
return false;
}
bool M68kAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const {
if (!isInt<16>(Value)) {
llvm_unreachable("Cannot relax the instruction, value does not fit");
}
return Value == 0 || !isInt<8>(Value);
}
void M68kAsmBackend::relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const {
unsigned RelaxedOp = getRelaxedOpcode(Inst);
if (RelaxedOp == Inst.getOpcode()) {
SmallString<256> Tmp;
raw_svector_ostream OS(Tmp);
Inst.dump_pretty(OS);
OS << "\n";
report_fatal_error("unexpected instruction to relax: " + OS.str());
}
Inst.setOpcode(RelaxedOp);
}
bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
if (Count % 2 != 0)
return false;
uint64_t NumNops = Count / 2;
for (uint64_t i = 0; i != NumNops; ++i) {
OS << "\x4E\x71";
}
return true;
}
namespace {
class M68kELFAsmBackend : public M68kAsmBackend {
public:
uint8_t OSABI;
M68kELFAsmBackend(const Target &T, uint8_t OSABI)
: M68kAsmBackend(T), OSABI(OSABI) {}
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override {
return createM68kELFObjectWriter(OSABI);
}
};
}
MCAsmBackend *llvm::createM68kAsmBackend(const Target &T,
const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options) {
const Triple &TheTriple = STI.getTargetTriple();
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
return new M68kELFAsmBackend(T, OSABI);
}