aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp452
1 files changed, 156 insertions, 296 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp b/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
index 9227bd6c3a78..6b093623a106 100644
--- a/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
+++ b/contrib/llvm-project/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
@@ -27,6 +27,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/raw_ostream.h"
+#include <type_traits>
using namespace llvm;
@@ -39,31 +40,30 @@ class M68kMCCodeEmitter : public MCCodeEmitter {
const MCInstrInfo &MCII;
MCContext &Ctx;
-public:
- M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
- : MCII(mcii), Ctx(ctx) {}
+ void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,
+ APInt &Inst, APInt &Scratch,
+ const MCSubtargetInfo &STI) const;
- ~M68kMCCodeEmitter() override {}
+ void getMachineOpValue(const MCInst &MI, const MCOperand &Op,
+ unsigned InsertPos, APInt &Value,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
- // TableGen'erated function
- const uint8_t *getGenInstrBeads(const MCInst &MI) const {
- return M68k::getMCInstrBeads(MI.getOpcode());
- }
+ template <unsigned Size>
+ void encodeRelocImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
+ APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
- unsigned encodeBits(unsigned ThisByte, uint8_t Bead, const MCInst &MI,
- const MCInstrDesc &Desc, uint64_t &Buffer,
- unsigned Offset, SmallVectorImpl<MCFixup> &Fixups,
+ template <unsigned Size>
+ void encodePCRelImm(const MCInst &MI, unsigned OpIdx, unsigned InsertPos,
+ APInt &Value, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
- unsigned encodeReg(unsigned ThisByte, uint8_t Bead, const MCInst &MI,
- const MCInstrDesc &Desc, uint64_t &Buffer, unsigned Offset,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &STI) const;
+public:
+ M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
+ : MCII(mcii), Ctx(ctx) {}
- unsigned encodeImm(unsigned ThisByte, uint8_t Bead, const MCInst &MI,
- const MCInstrDesc &Desc, uint64_t &Buffer, unsigned Offset,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &STI) const;
+ ~M68kMCCodeEmitter() override {}
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
@@ -72,316 +72,176 @@ public:
} // end anonymous namespace
-unsigned M68kMCCodeEmitter::encodeBits(unsigned ThisByte, uint8_t Bead,
- const MCInst &MI,
- const MCInstrDesc &Desc,
- uint64_t &Buffer, unsigned Offset,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &STI) const {
- unsigned Num = 0;
- switch (Bead & 0xF) {
- case M68kBeads::Bits1:
- Num = 1;
- break;
- case M68kBeads::Bits2:
- Num = 2;
- break;
- case M68kBeads::Bits3:
- Num = 3;
- break;
- case M68kBeads::Bits4:
- Num = 4;
- break;
- }
- unsigned char Val = (Bead & 0xF0) >> 4;
-
- LLVM_DEBUG(dbgs() << "\tEncodeBits"
- << " Num: " << Num << " Val: 0x");
- LLVM_DEBUG(dbgs().write_hex(Val) << "\n");
+#include "M68kGenMCCodeEmitter.inc"
- Buffer |= (Val << Offset);
-
- return Num;
-}
+// Select the proper unsigned integer type from a bit size.
+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;
+};
-unsigned M68kMCCodeEmitter::encodeReg(unsigned ThisByte, uint8_t Bead,
- const MCInst &MI, const MCInstrDesc &Desc,
- uint64_t &Buffer, unsigned Offset,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &STI) const {
- bool DA, Reg;
- switch (Bead & 0xF) {
- default:
- llvm_unreachable("Unrecognized Bead code for register type");
- case M68kBeads::DAReg:
- Reg = true;
- DA = true;
- break;
- case M68kBeads::DA:
- Reg = false;
- DA = true;
- break;
- case M68kBeads::DReg:
- case M68kBeads::Reg:
- Reg = true;
- DA = false;
- break;
+// On a LE host:
+// MSB LSB MSB LSB
+// | 0x12 0x34 | 0xAB 0xCD | -> | 0xAB 0xCD | 0x12 0x34 |
+// (On a BE host nothing changes)
+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;
+}
- unsigned Op = (Bead & 0x70) >> 4;
- bool Alt = (Bead & 0x80);
- LLVM_DEBUG(dbgs() << "\tEncodeReg"
- << " Op: " << Op << ", DA: " << DA << ", Reg: " << Reg
- << ", Alt: " << Alt << "\n");
-
- auto MIOpIdx = M68k::getLogicalOperandIdx(MI.getOpcode(), Op);
- bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL;
-
- MCOperand MCO;
- if (M68kII::hasMultiMIOperands(MI.getOpcode(), Op)) {
- if (IsPCRel) {
- assert(Alt &&
- "PCRel addresses use Alt bead register encoding by default");
- MCO = MI.getOperand(MIOpIdx + M68k::PCRelIndex);
- } else {
- MCO = MI.getOperand(MIOpIdx + (Alt ? M68k::MemIndex : M68k::MemBase));
- }
+// Figure out which byte we're at in big endian mode.
+template <unsigned Size> static unsigned getBytePosition(unsigned BitPos) {
+ if (Size % 16) {
+ return static_cast<unsigned>(BitPos / 8 + ((BitPos & 0b1111) < 8 ? 1 : -1));
} else {
- assert(!Alt && "You cannot use Alt register with a simple operand");
- MCO = MI.getOperand(MIOpIdx);
+ assert(!(BitPos & 0b1111) && "Not aligned to word boundary?");
+ return BitPos / 8;
}
-
- unsigned RegNum = MCO.getReg();
- auto RI = Ctx.getRegisterInfo();
-
- unsigned Written = 0;
- if (Reg) {
- uint32_t Val = RI->getEncodingValue(RegNum);
- Buffer |= (Val & 7) << Offset;
- Offset += 3;
- Written += 3;
- }
-
- if (DA) {
- Buffer |= (uint64_t)M68kII::isAddressRegister(RegNum) << Offset;
- Written++;
- }
-
- return Written;
-}
-
-static unsigned EmitConstant(uint64_t Val, unsigned Size, unsigned Pad,
- uint64_t &Buffer, unsigned Offset) {
- assert(Size + Offset <= 64 && isUIntN(Size, Val) && "Value does not fit");
-
- // Writing Value in host's endianness
- Buffer |= (Val & ((1ULL << Size) - 1)) << Offset;
- return Size + Pad;
}
-unsigned M68kMCCodeEmitter::encodeImm(unsigned ThisByte, uint8_t Bead,
- const MCInst &MI, const MCInstrDesc &Desc,
- uint64_t &Buffer, unsigned Offset,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &STI) const {
- unsigned ThisWord = ThisByte / 2;
- unsigned Size = 0;
- unsigned Pad = 0;
- unsigned FixOffset = 0;
- int64_t Addendum = 0;
- bool NoExpr = false;
-
- unsigned Type = Bead & 0xF;
- unsigned Op = (Bead & 0x70) >> 4;
- bool Alt = (Bead & 0x80);
-
- auto MIOpIdx = M68k::getLogicalOperandIdx(MI.getOpcode(), Op);
- bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL;
-
- // The PC value upon instruction reading of a short jump will point to the
- // next instruction, thus we need to compensate 2 bytes, which is the diff
- // between the patch point and the PC.
- if (IsPCRel && ThisWord == 0)
- Addendum -= 2;
-
- switch (Type) {
- // ??? what happens if it is not byte aligned
- // ??? is it even possible
- case M68kBeads::Disp8:
- Size = 8;
- Pad = 0;
- FixOffset = ThisByte + 1;
- Addendum += 1;
- break;
- case M68kBeads::Imm8:
- Size = 8;
- Pad = 8;
- FixOffset = ThisByte;
- break;
- case M68kBeads::Imm16:
- Size = 16;
- Pad = 0;
- FixOffset = ThisByte;
- break;
- case M68kBeads::Imm32:
- Size = 32;
- Pad = 0;
- FixOffset = ThisByte;
- break;
- case M68kBeads::Imm3:
- Size = 3;
- Pad = 0;
- NoExpr = true;
- break;
- }
-
- LLVM_DEBUG(dbgs() << "\tEncodeImm"
- << " Op: " << Op << ", Size: " << Size << ", Alt: " << Alt
- << "\n");
-
- MCOperand MCO;
- if (M68kII::hasMultiMIOperands(MI.getOpcode(), Op)) {
-
- if (IsPCRel) {
- assert(!Alt && "You cannot use ALT operand with PCRel");
- MCO = MI.getOperand(MIOpIdx + M68k::PCRelDisp);
- } else {
- MCO = MI.getOperand(MIOpIdx + (Alt ? M68k::MemOuter : M68k::MemDisp));
+// We need special handlings for relocatable & pc-relative operands that are
+// larger than a word.
+// A M68k instruction is aligned by word (16 bits). That means, 32-bit
+// (& 64-bit) immediate values are separated into hi & lo words and placed
+// at lower & higher addresses, respectively. For immediate values that can
+// be easily expressed in TG, we explicitly rotate the word ordering like
+// this:
+// ```
+// (ascend (slice "$imm", 31, 16), (slice "$imm", 15, 0))
+// ```
+// For operands that call into encoder functions, we need to use the `swapWord`
+// function to assure the correct word ordering on LE host. Note that
+// M68kMCCodeEmitter does massage _byte_ ordering of the final encoded
+// instruction but it assumes everything aligns on word boundaries. So things
+// will go wrong if we don't take care of the _word_ ordering here.
+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();
+
+ // Absolute address
+ int64_t Addr;
+ if (Expr->evaluateAsAbsolute(Addr)) {
+ Value |= swapWord<value_t>(static_cast<value_t>(Addr));
+ return;
}
- if (MCO.isExpr()) {
- assert(!NoExpr && "Cannot use expression here");
- const MCExpr *Expr = MCO.getExpr();
+ // Relocatable address
+ unsigned InsertByte = getBytePosition<Size>(InsertPos);
+ Fixups.push_back(MCFixup::create(InsertByte, Expr,
+ getFixupForSize(Size, /*IsPCRel=*/false),
+ MI.getLoc()));
+ }
+}
- // This only makes sense for PCRel instructions since PC points to the
- // extension word and Disp8 for example is right justified and requires
- // correction. E.g. R_68K_PC32 is calculated as S + A - P, P for Disp8
- // will be EXTENSION_WORD + 1 thus we need to have A equal to 1 to
- // compensate.
- // TODO count extension words
- if (IsPCRel && Addendum != 0) {
+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);
+
+ // Special handlings for sizes smaller than a word.
+ if (Size < 16) {
+ int LabelOffset = 0;
+ if (InsertPos < 16)
+ // If the patch point is at the first word, PC is pointing at the
+ // next word.
+ LabelOffset = InsertByte - 2;
+ else if (InsertByte % 2)
+ // Otherwise the PC is pointing at the first byte of this word.
+ // So we need to consider the offset between PC and the fixup byte.
+ LabelOffset = 1;
+
+ if (LabelOffset)
Expr = MCBinaryExpr::createAdd(
- Expr, MCConstantExpr::create(Addendum, Ctx), Ctx);
- }
-
- Fixups.push_back(MCFixup::create(
- FixOffset, Expr, getFixupForSize(Size, IsPCRel), MI.getLoc()));
- // Write zeros
- return EmitConstant(0, Size, Pad, Buffer, Offset);
+ Expr, MCConstantExpr::create(LabelOffset, Ctx), Ctx);
}
- } else {
- MCO = MI.getOperand(MIOpIdx);
- if (MCO.isExpr()) {
- assert(!NoExpr && "Cannot use expression here");
- const MCExpr *Expr = MCO.getExpr();
-
- if (Addendum != 0) {
- Expr = MCBinaryExpr::createAdd(
- Expr, MCConstantExpr::create(Addendum, Ctx), Ctx);
- }
-
- Fixups.push_back(MCFixup::create(
- FixOffset, Expr, getFixupForSize(Size, IsPCRel), MI.getLoc()));
- // Write zeros
- return EmitConstant(0, Size, Pad, Buffer, Offset);
- }
+ Fixups.push_back(MCFixup::create(InsertByte, Expr,
+ getFixupForSize(Size, /*IsPCRel=*/true),
+ MI.getLoc()));
}
+}
- int64_t I = MCO.getImm();
-
- // Store 8 as 0, thus making range 1-8
- if (Type == M68kBeads::Imm3 && Alt) {
- assert(I && "Cannot encode Alt Imm3 zero value");
- I %= 8;
+void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
+ unsigned InsertPos, APInt &Value,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ // Register
+ if (Op.isReg()) {
+ unsigned RegNum = Op.getReg();
+ const auto *RI = Ctx.getRegisterInfo();
+ Value |= RI->getEncodingValue(RegNum);
+ // Setup the D/A bit
+ if (M68kII::isAddressRegister(RegNum))
+ Value |= 0b1000;
+ } else if (Op.isImm()) {
+ // Immediate
+ Value |= static_cast<uint64_t>(Op.getImm());
+ } else if (Op.isExpr()) {
+ // Absolute address
+ 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 {
- assert(isIntN(Size, I));
+ llvm_unreachable("Unsupported operand type");
}
-
- uint64_t Imm = I;
-
- // 32 bit Imm requires HI16 first then LO16
- if (Size == 32) {
- Offset += EmitConstant((Imm >> 16) & 0xFFFF, 16, Pad, Buffer, Offset);
- EmitConstant(Imm & 0xFFFF, 16, Pad, Buffer, Offset);
- return Size;
- }
-
- return EmitConstant(Imm & ((1ULL << Size) - 1), Size, Pad, Buffer, Offset);
}
-#include "M68kGenMCCodeBeads.inc"
-
void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
unsigned Opcode = MI.getOpcode();
- const MCInstrDesc &Desc = MCII.get(Opcode);
LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "("
<< Opcode << ")\n");
- const uint8_t *Beads = getGenInstrBeads(MI);
- if (!Beads || !*Beads) {
- llvm_unreachable("*** Instruction does not have Beads defined");
- }
-
- uint64_t Buffer = 0;
- unsigned Offset = 0;
- unsigned ThisByte = 0;
-
- for (uint8_t Bead = *Beads; Bead; Bead = *++Beads) {
- // Check for control beads
- if (!(Bead & 0xF)) {
- switch (Bead >> 4) {
- case M68kBeads::Ignore:
- continue;
- }
- }
-
- switch (Bead & 0xF) {
- default:
- llvm_unreachable("Unknown Bead code");
- break;
- case M68kBeads::Bits1:
- case M68kBeads::Bits2:
- case M68kBeads::Bits3:
- case M68kBeads::Bits4:
- Offset +=
- encodeBits(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI);
- break;
- case M68kBeads::DAReg:
- case M68kBeads::DA:
- case M68kBeads::DReg:
- case M68kBeads::Reg:
- Offset +=
- encodeReg(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI);
- break;
- case M68kBeads::Disp8:
- case M68kBeads::Imm8:
- case M68kBeads::Imm16:
- case M68kBeads::Imm32:
- case M68kBeads::Imm3:
- Offset +=
- encodeImm(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI);
- break;
- }
-
- // Since M68k is Big Endian we need to rotate each instruction word
- while (Offset / 16) {
- support::endian::write<uint16_t>(OS, Buffer, support::big);
- Buffer >>= 16;
- Offset -= 16;
- ThisByte += 2;
+ // Try using the new method first.
+ 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;
}
}
-
- assert(Offset == 0 && "M68k Instructions are % 2 bytes");
- assert((ThisByte && !(ThisByte % 2)) && "M68k Instructions are % 2 bytes");
}
MCCodeEmitter *llvm::createM68kMCCodeEmitter(const MCInstrInfo &MCII,
- const MCRegisterInfo &MRI,
MCContext &Ctx) {
return new M68kMCCodeEmitter(MCII, Ctx);
}