//===-- 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, SmallVectorImpl &CB, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const override; private: // Automatically generated by TableGen. uint64_t getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl &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 &Fixups, const MCSubtargetInfo &STI) const; uint32_t getJumpTargetEncoding(const MCInst &MI, unsigned int OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getBranchTargetEncoding(const MCInst &MI, unsigned int OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getCallEncoding(const MCInst &MI, unsigned int OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getL32RTargetEncoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getMemRegEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getImm8OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getImm8_sh8OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getImm12OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getUimm4OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getUimm5OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getImm1_16OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getB4constOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; uint32_t getB4constuOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &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, SmallVectorImpl &CB, SmallVectorImpl &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) { CB.push_back(char(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 &Fixups, const MCSubtargetInfo &STI) const { if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); if (MO.isImm()) { uint32_t Res = static_cast(MO.getImm()); return Res; } report_fatal_error("Unhandled expression!"); return 0; } uint32_t XtensaMCCodeEmitter::getJumpTargetEncoding(const MCInst &MI, unsigned int OpNum, SmallVectorImpl &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 &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNum); if (MO.isImm()) return static_cast(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 &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 &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 &Fixups, const MCSubtargetInfo &STI) const { assert(MI.getOperand(OpNo + 1).isImm()); uint32_t Res = static_cast(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 &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 &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 &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 &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); uint32_t Res = static_cast(MO.getImm()); assert((Res <= 15) && "Unexpected operand value!"); return Res & 0xf; } uint32_t XtensaMCCodeEmitter::getUimm5OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); uint32_t Res = static_cast(MO.getImm()); assert((Res <= 31) && "Unexpected operand value!"); return (Res & 0x1f); } uint32_t XtensaMCCodeEmitter::getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); uint32_t Res = static_cast(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 &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); uint32_t Res = static_cast(MO.getImm()); assert(((Res >= 1) && (Res <= 16)) && "Unexpected operand value!"); return (Res - 1); } uint32_t XtensaMCCodeEmitter::getB4constOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); uint32_t Res = static_cast(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 &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); uint32_t Res = static_cast(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"