Implement basic support of the several simple Xtensa Options with 1-4 instructions for each option. The Sign Extend Option (SEXT). The NSA Option. The Minimum/Maximum Integer 32-bit Option and Loop Option. Fixed address operands, added OPERAND_PCREL to operands descriptions.
451 lines
14 KiB
C++
451 lines
14 KiB
C++
//===- XtensaInstPrinter.cpp - Convert Xtensa MCInst to asm syntax --------===//
|
|
//
|
|
// 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 class prints an Xtensa MCInst to a .s file.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "XtensaInstPrinter.h"
|
|
#include "MCTargetDesc/XtensaMCExpr.h"
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
#include "llvm/MC/MCRegister.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
|
|
#include "XtensaGenAsmWriter.inc"
|
|
|
|
static void printExpr(const MCExpr *Expr, raw_ostream &OS) {
|
|
int Offset = 0;
|
|
const MCSymbolRefExpr *SRE;
|
|
|
|
if (!(SRE = cast<MCSymbolRefExpr>(Expr)))
|
|
assert(false && "Unexpected MCExpr type.");
|
|
|
|
auto Spec = XtensaMCExpr::Specifier(SRE->getKind());
|
|
switch (Spec) {
|
|
case XtensaMCExpr::VK_None:
|
|
break;
|
|
// TODO
|
|
default:
|
|
report_fatal_error("Invalid kind!");
|
|
}
|
|
|
|
OS << SRE->getSymbol();
|
|
|
|
if (Offset) {
|
|
if (Offset > 0)
|
|
OS << '+';
|
|
OS << Offset;
|
|
}
|
|
|
|
if (Spec != XtensaMCExpr::VK_None)
|
|
OS << ')';
|
|
}
|
|
|
|
void XtensaInstPrinter::printOperand(const MCOperand &MC, raw_ostream &O) {
|
|
if (MC.isReg())
|
|
O << getRegisterName(MC.getReg());
|
|
else if (MC.isImm())
|
|
O << MC.getImm();
|
|
else if (MC.isExpr())
|
|
printExpr(MC.getExpr(), O);
|
|
else
|
|
report_fatal_error("Invalid operand");
|
|
}
|
|
|
|
void XtensaInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
|
StringRef Annot, const MCSubtargetInfo &STI,
|
|
raw_ostream &O) {
|
|
printInstruction(MI, Address, O);
|
|
printAnnotation(O, Annot);
|
|
}
|
|
|
|
void XtensaInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) {
|
|
O << getRegisterName(Reg);
|
|
}
|
|
|
|
void XtensaInstPrinter::printOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
printOperand(MI->getOperand(OpNum), O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printMemOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &OS) {
|
|
OS << getRegisterName(MI->getOperand(OpNum).getReg());
|
|
OS << ", ";
|
|
printOperand(MI, OpNum + 1, OS);
|
|
}
|
|
|
|
void XtensaInstPrinter::printBranchTarget(const MCInst *MI, uint64_t Address,
|
|
int OpNum, raw_ostream &O) {
|
|
const MCOperand &MC = MI->getOperand(OpNum);
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Val = MC.getImm() + 4;
|
|
printPCRelImm(Address, Val, O);
|
|
} else if (MC.isExpr())
|
|
MC.getExpr()->print(O, &MAI);
|
|
else
|
|
llvm_unreachable("Invalid operand");
|
|
}
|
|
|
|
void XtensaInstPrinter::printLoopTarget(const MCInst *MI, uint64_t Address,
|
|
int OpNum, raw_ostream &O) {
|
|
const MCOperand &MC = MI->getOperand(OpNum);
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Val = MC.getImm() + 4;
|
|
printPCRelImm(Address, Val, O);
|
|
} else if (MC.isExpr())
|
|
MC.getExpr()->print(O, &MAI, true);
|
|
else
|
|
llvm_unreachable("Invalid operand");
|
|
}
|
|
|
|
void XtensaInstPrinter::printJumpTarget(const MCInst *MI, uint64_t Address,
|
|
int OpNum, raw_ostream &O) {
|
|
const MCOperand &MC = MI->getOperand(OpNum);
|
|
if (MC.isImm()) {
|
|
int64_t Val = MC.getImm() + 4;
|
|
printPCRelImm(Address, Val, O);
|
|
} else if (MC.isExpr())
|
|
MC.getExpr()->print(O, &MAI);
|
|
else
|
|
llvm_unreachable("Invalid operand");
|
|
;
|
|
}
|
|
|
|
void XtensaInstPrinter::printCallOperand(const MCInst *MI, uint64_t Address,
|
|
int OpNum, raw_ostream &O) {
|
|
const MCOperand &MC = MI->getOperand(OpNum);
|
|
if (MC.isImm()) {
|
|
int64_t Val = MC.getImm() + 4;
|
|
if (PrintBranchImmAsAddress) {
|
|
uint64_t Target = Address;
|
|
Target &= ~0x3;
|
|
Target += Val & (~0x3);
|
|
O << formatHex(Target);
|
|
} else {
|
|
O << ". ";
|
|
if (Val > 0)
|
|
O << '+';
|
|
O << Val;
|
|
}
|
|
} else if (MC.isExpr())
|
|
MC.getExpr()->print(O, &MAI);
|
|
else
|
|
llvm_unreachable("Invalid operand");
|
|
}
|
|
|
|
void XtensaInstPrinter::printL32RTarget(const MCInst *MI, uint64_t Address,
|
|
int OpNum, raw_ostream &O) {
|
|
const MCOperand &MC = MI->getOperand(OpNum);
|
|
if (MC.isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
if (PrintBranchImmAsAddress) {
|
|
uint64_t Target = (Address + 0x3) & (~0x3);
|
|
Value &= ~0x3;
|
|
Target += Value;
|
|
O << formatHex(Target);
|
|
} else {
|
|
int64_t InstrOff = Value & 0x3;
|
|
Value -= InstrOff;
|
|
assert((Value >= -262144 && Value <= -4) &&
|
|
"Invalid argument, value must be in ranges [-262144,-4]");
|
|
Value += ((InstrOff + 0x3) & 0x4) - InstrOff;
|
|
printPCRelImm(Address, Value, O);
|
|
}
|
|
} else if (MC.isExpr())
|
|
MC.getExpr()->print(O, &MAI);
|
|
else
|
|
llvm_unreachable("Invalid operand");
|
|
}
|
|
|
|
void XtensaInstPrinter::printPCRelImm(uint64_t Address, int64_t Offset,
|
|
raw_ostream &O) {
|
|
if (PrintBranchImmAsAddress) {
|
|
uint64_t Target = Address + Offset;
|
|
Target &= 0xffffffff;
|
|
O << formatHex(Target);
|
|
} else {
|
|
O << ". ";
|
|
if (Offset > 0)
|
|
O << '+';
|
|
O << Offset;
|
|
}
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert(isInt<8>(Value) &&
|
|
"Invalid argument, value must be in ranges [-128,127]");
|
|
O << Value;
|
|
} else {
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((isInt<16>(Value) && ((Value & 0xFF) == 0)) &&
|
|
"Invalid argument, value must be multiples of 256 in range "
|
|
"[-32768,32512]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm12_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= -2048 && Value <= 2047) &&
|
|
"Invalid argument, value must be in ranges [-2048,2047]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm12m_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= -2048 && Value <= 2047) &&
|
|
"Invalid argument, value must be in ranges [-2048,2047]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printUimm4_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 0 && Value <= 15) && "Invalid argument");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printUimm5_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 0 && Value <= 31) && "Invalid argument");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printShimm1_31_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 1 && Value <= 31) &&
|
|
"Invalid argument, value must be in range [1,31]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm1_16_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 1 && Value <= 16) &&
|
|
"Invalid argument, value must be in range [1,16]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm1n_15_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= -1 && (Value != 0) && Value <= 15) &&
|
|
"Invalid argument, value must be in ranges <-1,-1> or <1,15>");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm32n_95_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= -32 && Value <= 95) &&
|
|
"Invalid argument, value must be in ranges <-32,95>");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm8n_7_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= -8 && Value <= 7) &&
|
|
"Invalid argument, value must be in ranges <-8,7>");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm64n_4n_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= -64 && Value <= -4) & ((Value & 0x3) == 0) &&
|
|
"Invalid argument, value must be in ranges <-64,-4>");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printOffset8m8_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 0 && Value <= 255) &&
|
|
"Invalid argument, value must be in range [0,255]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printOffset8m16_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 0 && Value <= 510 && ((Value & 0x1) == 0)) &&
|
|
"Invalid argument, value must be multiples of two in range [0,510]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printOffset8m32_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert(
|
|
(Value >= 0 && Value <= 1020 && ((Value & 0x3) == 0)) &&
|
|
"Invalid argument, value must be multiples of four in range [0,1020]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printOffset4m32_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 0 && Value <= 60 && ((Value & 0x3) == 0)) &&
|
|
"Invalid argument, value must be multiples of four in range [0,60]");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printEntry_Imm12_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 0 && Value <= 32760) &&
|
|
"Invalid argument, value must be multiples of eight in range "
|
|
"<0,32760>");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printB4const_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
|
|
switch (Value) {
|
|
case -1:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 10:
|
|
case 12:
|
|
case 16:
|
|
case 32:
|
|
case 64:
|
|
case 128:
|
|
case 256:
|
|
break;
|
|
default:
|
|
assert((0) && "Invalid B4const argument");
|
|
}
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printB4constu_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
|
|
switch (Value) {
|
|
case 32768:
|
|
case 65536:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 10:
|
|
case 12:
|
|
case 16:
|
|
case 32:
|
|
case 64:
|
|
case 128:
|
|
case 256:
|
|
break;
|
|
default:
|
|
assert((0) && "Invalid B4constu argument");
|
|
}
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
void XtensaInstPrinter::printImm7_22_AsmOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
if (MI->getOperand(OpNum).isImm()) {
|
|
int64_t Value = MI->getOperand(OpNum).getImm();
|
|
assert((Value >= 7 && Value <= 22) &&
|
|
"Invalid argument, value must be in range <7,22>");
|
|
O << Value;
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|