454 lines
14 KiB
C++
454 lines
14 KiB
C++
//===-- 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<char> &CB,
|
|
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,
|
|
SmallVectorImpl<char> &CB,
|
|
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) {
|
|
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<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"
|