| //===-- XtensaMCCodeEmitter.cpp - Convert Xtensa Code to Machine Code -----===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the XtensaMCCodeEmitter class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "MCTargetDesc/XtensaFixupKinds.h" |
| #include "MCTargetDesc/XtensaMCExpr.h" |
| #include "MCTargetDesc/XtensaMCTargetDesc.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" |
| |
| #define GET_INSTRMAP_INFO |
| #include "XtensaGenInstrInfo.inc" |
| #undef GET_INSTRMAP_INFO |
| |
| using namespace llvm; |
| |
| #define DEBUG_TYPE "mccodeemitter" |
| |
| namespace { |
| class XtensaMCCodeEmitter : public MCCodeEmitter { |
| const MCInstrInfo &MCII; |
| MCContext &Ctx; |
| bool IsLittleEndian; |
| |
| public: |
| XtensaMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx, bool isLE) |
| : MCII(mcii), Ctx(ctx), IsLittleEndian(isLE) {} |
| |
| ~XtensaMCCodeEmitter() {} |
| |
| // OVerride MCCodeEmitter. |
| void encodeInstruction(const MCInst &MI, raw_ostream &OS, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const override; |
| |
| private: |
| // Automatically generated by TableGen. |
| uint64_t getBinaryCodeForInstr(const MCInst &MI, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| // Called by the TableGen code to get the binary encoding of operand |
| // MO in MI. Fixups is the list of fixups against MI. |
| uint32_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getJumpTargetEncoding(const MCInst &MI, unsigned int OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getBranchTargetEncoding(const MCInst &MI, unsigned int OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getCallEncoding(const MCInst &MI, unsigned int OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getL32RTargetEncoding(const MCInst &MI, unsigned OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getMemRegEncoding(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getImm8OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getImm8_sh8OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getImm12OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getUimm4OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getUimm5OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getImm1_16OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getB4constOpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| |
| uint32_t getB4constuOpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const; |
| }; |
| } // namespace |
| |
| MCCodeEmitter *llvm::createXtensaMCCodeEmitter(const MCInstrInfo &MCII, |
| MCContext &Ctx) { |
| return new XtensaMCCodeEmitter(MCII, Ctx, true); |
| } |
| |
| void XtensaMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); |
| unsigned Size = MCII.get(MI.getOpcode()).getSize(); |
| |
| if (IsLittleEndian) { |
| // Little-endian insertion of Size bytes. |
| unsigned ShiftValue = 0; |
| for (unsigned I = 0; I != Size; ++I) { |
| OS << uint8_t(Bits >> ShiftValue); |
| ShiftValue += 8; |
| } |
| } else { |
| // TODO Big-endian insertion of Size bytes. |
| report_fatal_error("Big-endian mode currently is not supported!"); |
| } |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| if (MO.isReg()) |
| return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); |
| if (MO.isImm()) { |
| uint32_t Res = static_cast<uint32_t>(MO.getImm()); |
| return Res; |
| } |
| |
| report_fatal_error("Unhandled expression!"); |
| return 0; |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getJumpTargetEncoding(const MCInst &MI, unsigned int OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNum); |
| |
| if (MO.isImm()) |
| return MO.getImm(); |
| |
| const MCExpr *Expr = MO.getExpr(); |
| Fixups.push_back(MCFixup::create( |
| 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_jump_18), MI.getLoc())); |
| return 0; |
| } |
| |
| uint32_t XtensaMCCodeEmitter::getBranchTargetEncoding( |
| const MCInst &MI, unsigned int OpNum, SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNum); |
| if (MO.isImm()) |
| return static_cast<uint32_t>(MO.getImm()); |
| |
| const MCExpr *Expr = MO.getExpr(); |
| switch (MI.getOpcode()) { |
| case Xtensa::BEQZ: |
| case Xtensa::BGEZ: |
| case Xtensa::BLTZ: |
| case Xtensa::BNEZ: |
| Fixups.push_back(MCFixup::create( |
| 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_branch_12), MI.getLoc())); |
| return 0; |
| default: |
| Fixups.push_back(MCFixup::create( |
| 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_branch_8), MI.getLoc())); |
| return 0; |
| } |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getCallEncoding(const MCInst &MI, unsigned int OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNum); |
| if (MO.isImm()) { |
| int32_t Res = MO.getImm(); |
| if (Res & 0x3) { |
| llvm_unreachable("Unexpected operand value!"); |
| } |
| Res >>= 2; |
| return Res; |
| } |
| |
| assert((MO.isExpr()) && "Unexpected operand value!"); |
| const MCExpr *Expr = MO.getExpr(); |
| Fixups.push_back(MCFixup::create( |
| 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_call_18), MI.getLoc())); |
| return 0; |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getL32RTargetEncoding(const MCInst &MI, unsigned OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNum); |
| if (MO.isImm()) { |
| int32_t Res = MO.getImm(); |
| // We don't check first 2 bits, because in these bits we could store first 2 |
| // bits of instruction address |
| Res >>= 2; |
| return Res; |
| } |
| |
| assert((MO.isExpr()) && "Unexpected operand value!"); |
| |
| Fixups.push_back(MCFixup::create( |
| 0, MO.getExpr(), MCFixupKind(Xtensa::fixup_xtensa_l32r_16), MI.getLoc())); |
| return 0; |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| assert(MI.getOperand(OpNo + 1).isImm()); |
| |
| uint32_t Res = static_cast<uint32_t>(MI.getOperand(OpNo + 1).getImm()); |
| |
| switch (MI.getOpcode()) { |
| case Xtensa::S16I: |
| case Xtensa::L16SI: |
| case Xtensa::L16UI: |
| if (Res & 0x1) { |
| report_fatal_error("Unexpected operand value!"); |
| } |
| Res >>= 1; |
| break; |
| case Xtensa::S32I: |
| case Xtensa::L32I: |
| if (Res & 0x3) { |
| report_fatal_error("Unexpected operand value!"); |
| } |
| Res >>= 2; |
| break; |
| } |
| |
| assert((isUInt<8>(Res)) && "Unexpected operand value!"); |
| |
| uint32_t OffBits = Res << 4; |
| uint32_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); |
| |
| return ((OffBits & 0xFF0) | RegBits); |
| } |
| |
| uint32_t XtensaMCCodeEmitter::getImm8OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| int32_t Res = MO.getImm(); |
| |
| assert(((Res >= -128) && (Res <= 127)) && "Unexpected operand value!"); |
| |
| return (Res & 0xff); |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getImm8_sh8OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| int32_t Res = MO.getImm(); |
| |
| assert(((Res >= -32768) && (Res <= 32512) && ((Res & 0xff) == 0)) && |
| "Unexpected operand value!"); |
| |
| return (Res & 0xffff); |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getImm12OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| int32_t Res = MO.getImm(); |
| |
| assert(((Res >= -2048) && (Res <= 2047)) && "Unexpected operand value!"); |
| |
| return (Res & 0xfff); |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getUimm4OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| uint32_t Res = static_cast<uint32_t>(MO.getImm()); |
| |
| assert((Res <= 15) && "Unexpected operand value!"); |
| |
| return Res & 0xf; |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getUimm5OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| uint32_t Res = static_cast<uint32_t>(MO.getImm()); |
| |
| assert((Res <= 31) && "Unexpected operand value!"); |
| |
| return (Res & 0x1f); |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| uint32_t Res = static_cast<uint32_t>(MO.getImm()); |
| |
| assert(((Res >= 1) && (Res <= 31)) && "Unexpected operand value!"); |
| |
| return ((32 - Res) & 0x1f); |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getImm1_16OpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| uint32_t Res = static_cast<uint32_t>(MO.getImm()); |
| |
| assert(((Res >= 1) && (Res <= 16)) && "Unexpected operand value!"); |
| |
| return (Res - 1); |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getB4constOpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| uint32_t Res = static_cast<uint32_t>(MO.getImm()); |
| |
| switch (Res) { |
| case 0xffffffff: |
| Res = 0; |
| break; |
| case 1: |
| case 2: |
| case 3: |
| case 4: |
| case 5: |
| case 6: |
| case 7: |
| case 8: |
| break; |
| case 10: |
| Res = 9; |
| break; |
| case 12: |
| Res = 10; |
| break; |
| case 16: |
| Res = 11; |
| break; |
| case 32: |
| Res = 12; |
| break; |
| case 64: |
| Res = 13; |
| break; |
| case 128: |
| Res = 14; |
| break; |
| case 256: |
| Res = 15; |
| break; |
| default: |
| llvm_unreachable("Unexpected operand value!"); |
| } |
| |
| return Res; |
| } |
| |
| uint32_t |
| XtensaMCCodeEmitter::getB4constuOpValue(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixups, |
| const MCSubtargetInfo &STI) const { |
| const MCOperand &MO = MI.getOperand(OpNo); |
| uint32_t Res = static_cast<uint32_t>(MO.getImm()); |
| |
| switch (Res) { |
| case 32768: |
| Res = 0; |
| break; |
| case 65536: |
| Res = 1; |
| break; |
| case 2: |
| case 3: |
| case 4: |
| case 5: |
| case 6: |
| case 7: |
| case 8: |
| break; |
| case 10: |
| Res = 9; |
| break; |
| case 12: |
| Res = 10; |
| break; |
| case 16: |
| Res = 11; |
| break; |
| case 32: |
| Res = 12; |
| break; |
| case 64: |
| Res = 13; |
| break; |
| case 128: |
| Res = 14; |
| break; |
| case 256: |
| Res = 15; |
| break; |
| default: |
| llvm_unreachable("Unexpected operand value!"); |
| } |
| |
| return Res; |
| } |
| #include "XtensaGenMCCodeEmitter.inc" |