diff options
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.cpp | 452 |
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); } |