309 lines
11 KiB
C++
309 lines
11 KiB
C++
|
//===-- LanaiInstPrinter.cpp - Convert Lanai MCInst to asm syntax ---------===//
|
||
|
//
|
||
|
// 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 Lanai MCInst to a .s file.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "LanaiInstPrinter.h"
|
||
|
#include "LanaiMCExpr.h"
|
||
|
#include "LanaiAluCode.h"
|
||
|
#include "LanaiCondCode.h"
|
||
|
#include "MCTargetDesc/LanaiMCTargetDesc.h"
|
||
|
#include "llvm/MC/MCAsmInfo.h"
|
||
|
#include "llvm/MC/MCExpr.h"
|
||
|
#include "llvm/MC/MCInst.h"
|
||
|
#include "llvm/MC/MCRegisterInfo.h"
|
||
|
#include "llvm/MC/MCSymbol.h"
|
||
|
#include "llvm/Support/ErrorHandling.h"
|
||
|
#include "llvm/Support/FormattedStream.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
#define DEBUG_TYPE "asm-printer"
|
||
|
|
||
|
// Include the auto-generated portion of the assembly writer.
|
||
|
#define PRINT_ALIAS_INSTR
|
||
|
#include "LanaiGenAsmWriter.inc"
|
||
|
|
||
|
void LanaiInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
|
||
|
OS << StringRef(getRegisterName(RegNo)).lower();
|
||
|
}
|
||
|
|
||
|
bool LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
|
||
|
StringRef Alias, unsigned OpNo0,
|
||
|
unsigned OpNo1) {
|
||
|
OS << "\t" << Alias << " ";
|
||
|
printOperand(MI, OpNo0, OS);
|
||
|
OS << ", ";
|
||
|
printOperand(MI, OpNo1, OS);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool usesGivenOffset(const MCInst *MI, int AddOffset) {
|
||
|
unsigned AluCode = MI->getOperand(3).getImm();
|
||
|
return LPAC::encodeLanaiAluCode(AluCode) == LPAC::ADD &&
|
||
|
(MI->getOperand(2).getImm() == AddOffset ||
|
||
|
MI->getOperand(2).getImm() == -AddOffset);
|
||
|
}
|
||
|
|
||
|
static bool isPreIncrementForm(const MCInst *MI, int AddOffset) {
|
||
|
unsigned AluCode = MI->getOperand(3).getImm();
|
||
|
return LPAC::isPreOp(AluCode) && usesGivenOffset(MI, AddOffset);
|
||
|
}
|
||
|
|
||
|
static bool isPostIncrementForm(const MCInst *MI, int AddOffset) {
|
||
|
unsigned AluCode = MI->getOperand(3).getImm();
|
||
|
return LPAC::isPostOp(AluCode) && usesGivenOffset(MI, AddOffset);
|
||
|
}
|
||
|
|
||
|
static StringRef decIncOperator(const MCInst *MI) {
|
||
|
if (MI->getOperand(2).getImm() < 0)
|
||
|
return "--";
|
||
|
return "++";
|
||
|
}
|
||
|
|
||
|
bool LanaiInstPrinter::printMemoryLoadIncrement(const MCInst *MI,
|
||
|
raw_ostream &OS,
|
||
|
StringRef Opcode,
|
||
|
int AddOffset) {
|
||
|
if (isPreIncrementForm(MI, AddOffset)) {
|
||
|
OS << "\t" << Opcode << "\t[" << decIncOperator(MI) << "%"
|
||
|
<< getRegisterName(MI->getOperand(1).getReg()) << "], %"
|
||
|
<< getRegisterName(MI->getOperand(0).getReg());
|
||
|
return true;
|
||
|
}
|
||
|
if (isPostIncrementForm(MI, AddOffset)) {
|
||
|
OS << "\t" << Opcode << "\t[%"
|
||
|
<< getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI)
|
||
|
<< "], %" << getRegisterName(MI->getOperand(0).getReg());
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool LanaiInstPrinter::printMemoryStoreIncrement(const MCInst *MI,
|
||
|
raw_ostream &OS,
|
||
|
StringRef Opcode,
|
||
|
int AddOffset) {
|
||
|
if (isPreIncrementForm(MI, AddOffset)) {
|
||
|
OS << "\t" << Opcode << "\t%" << getRegisterName(MI->getOperand(0).getReg())
|
||
|
<< ", [" << decIncOperator(MI) << "%"
|
||
|
<< getRegisterName(MI->getOperand(1).getReg()) << "]";
|
||
|
return true;
|
||
|
}
|
||
|
if (isPostIncrementForm(MI, AddOffset)) {
|
||
|
OS << "\t" << Opcode << "\t%" << getRegisterName(MI->getOperand(0).getReg())
|
||
|
<< ", [%" << getRegisterName(MI->getOperand(1).getReg())
|
||
|
<< decIncOperator(MI) << "]";
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool LanaiInstPrinter::printAlias(const MCInst *MI, raw_ostream &OS) {
|
||
|
switch (MI->getOpcode()) {
|
||
|
case Lanai::LDW_RI:
|
||
|
// ld 4[*%rN], %rX => ld [++imm], %rX
|
||
|
// ld -4[*%rN], %rX => ld [--imm], %rX
|
||
|
// ld 4[%rN*], %rX => ld [imm++], %rX
|
||
|
// ld -4[%rN*], %rX => ld [imm--], %rX
|
||
|
return printMemoryLoadIncrement(MI, OS, "ld", 4);
|
||
|
case Lanai::LDHs_RI:
|
||
|
return printMemoryLoadIncrement(MI, OS, "ld.h", 2);
|
||
|
case Lanai::LDHz_RI:
|
||
|
return printMemoryLoadIncrement(MI, OS, "uld.h", 2);
|
||
|
case Lanai::LDBs_RI:
|
||
|
return printMemoryLoadIncrement(MI, OS, "ld.b", 1);
|
||
|
case Lanai::LDBz_RI:
|
||
|
return printMemoryLoadIncrement(MI, OS, "uld.b", 1);
|
||
|
case Lanai::SW_RI:
|
||
|
// st %rX, 4[*%rN] => st %rX, [++imm]
|
||
|
// st %rX, -4[*%rN] => st %rX, [--imm]
|
||
|
// st %rX, 4[%rN*] => st %rX, [imm++]
|
||
|
// st %rX, -4[%rN*] => st %rX, [imm--]
|
||
|
return printMemoryStoreIncrement(MI, OS, "st", 4);
|
||
|
case Lanai::STH_RI:
|
||
|
return printMemoryStoreIncrement(MI, OS, "st.h", 2);
|
||
|
case Lanai::STB_RI:
|
||
|
return printMemoryStoreIncrement(MI, OS, "st.b", 1);
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
||
|
StringRef Annotation,
|
||
|
const MCSubtargetInfo & /*STI*/,
|
||
|
raw_ostream &OS) {
|
||
|
if (!printAlias(MI, OS) && !printAliasInstr(MI, Address, OS))
|
||
|
printInstruction(MI, Address, OS);
|
||
|
printAnnotation(OS, Annotation);
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &OS, const char *Modifier) {
|
||
|
assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
|
||
|
const MCOperand &Op = MI->getOperand(OpNo);
|
||
|
if (Op.isReg())
|
||
|
OS << "%" << getRegisterName(Op.getReg());
|
||
|
else if (Op.isImm())
|
||
|
OS << formatHex(Op.getImm());
|
||
|
else {
|
||
|
assert(Op.isExpr() && "Expected an expression");
|
||
|
Op.getExpr()->print(OS, &MAI);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printMemImmOperand(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &OS) {
|
||
|
const MCOperand &Op = MI->getOperand(OpNo);
|
||
|
if (Op.isImm()) {
|
||
|
OS << '[' << formatHex(Op.getImm()) << ']';
|
||
|
} else {
|
||
|
// Symbolic operand will be lowered to immediate value by linker
|
||
|
assert(Op.isExpr() && "Expected an expression");
|
||
|
OS << '[';
|
||
|
Op.getExpr()->print(OS, &MAI);
|
||
|
OS << ']';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printHi16ImmOperand(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &OS) {
|
||
|
const MCOperand &Op = MI->getOperand(OpNo);
|
||
|
if (Op.isImm()) {
|
||
|
OS << formatHex(Op.getImm() << 16);
|
||
|
} else {
|
||
|
// Symbolic operand will be lowered to immediate value by linker
|
||
|
assert(Op.isExpr() && "Expected an expression");
|
||
|
Op.getExpr()->print(OS, &MAI);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printHi16AndImmOperand(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &OS) {
|
||
|
const MCOperand &Op = MI->getOperand(OpNo);
|
||
|
if (Op.isImm()) {
|
||
|
OS << formatHex((Op.getImm() << 16) | 0xffff);
|
||
|
} else {
|
||
|
// Symbolic operand will be lowered to immediate value by linker
|
||
|
assert(Op.isExpr() && "Expected an expression");
|
||
|
Op.getExpr()->print(OS, &MAI);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printLo16AndImmOperand(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &OS) {
|
||
|
const MCOperand &Op = MI->getOperand(OpNo);
|
||
|
if (Op.isImm()) {
|
||
|
OS << formatHex(0xffff0000 | Op.getImm());
|
||
|
} else {
|
||
|
// Symbolic operand will be lowered to immediate value by linker
|
||
|
assert(Op.isExpr() && "Expected an expression");
|
||
|
Op.getExpr()->print(OS, &MAI);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void printMemoryBaseRegister(raw_ostream &OS, const unsigned AluCode,
|
||
|
const MCOperand &RegOp) {
|
||
|
assert(RegOp.isReg() && "Register operand expected");
|
||
|
OS << "[";
|
||
|
if (LPAC::isPreOp(AluCode))
|
||
|
OS << "*";
|
||
|
OS << "%" << LanaiInstPrinter::getRegisterName(RegOp.getReg());
|
||
|
if (LPAC::isPostOp(AluCode))
|
||
|
OS << "*";
|
||
|
OS << "]";
|
||
|
}
|
||
|
|
||
|
template <unsigned SizeInBits>
|
||
|
static void printMemoryImmediateOffset(const MCAsmInfo &MAI,
|
||
|
const MCOperand &OffsetOp,
|
||
|
raw_ostream &OS) {
|
||
|
assert((OffsetOp.isImm() || OffsetOp.isExpr()) && "Immediate expected");
|
||
|
if (OffsetOp.isImm()) {
|
||
|
assert(isInt<SizeInBits>(OffsetOp.getImm()) && "Constant value truncated");
|
||
|
OS << OffsetOp.getImm();
|
||
|
} else
|
||
|
OffsetOp.getExpr()->print(OS, &MAI);
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printMemRiOperand(const MCInst *MI, int OpNo,
|
||
|
raw_ostream &OS,
|
||
|
const char * /*Modifier*/) {
|
||
|
const MCOperand &RegOp = MI->getOperand(OpNo);
|
||
|
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
|
||
|
const MCOperand &AluOp = MI->getOperand(OpNo + 2);
|
||
|
const unsigned AluCode = AluOp.getImm();
|
||
|
|
||
|
// Offset
|
||
|
printMemoryImmediateOffset<16>(MAI, OffsetOp, OS);
|
||
|
|
||
|
// Register
|
||
|
printMemoryBaseRegister(OS, AluCode, RegOp);
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printMemRrOperand(const MCInst *MI, int OpNo,
|
||
|
raw_ostream &OS,
|
||
|
const char * /*Modifier*/) {
|
||
|
const MCOperand &RegOp = MI->getOperand(OpNo);
|
||
|
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
|
||
|
const MCOperand &AluOp = MI->getOperand(OpNo + 2);
|
||
|
const unsigned AluCode = AluOp.getImm();
|
||
|
assert(OffsetOp.isReg() && RegOp.isReg() && "Registers expected.");
|
||
|
|
||
|
// [ Base OP Offset ]
|
||
|
OS << "[";
|
||
|
if (LPAC::isPreOp(AluCode))
|
||
|
OS << "*";
|
||
|
OS << "%" << getRegisterName(RegOp.getReg());
|
||
|
if (LPAC::isPostOp(AluCode))
|
||
|
OS << "*";
|
||
|
OS << " " << LPAC::lanaiAluCodeToString(AluCode) << " ";
|
||
|
OS << "%" << getRegisterName(OffsetOp.getReg());
|
||
|
OS << "]";
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printMemSplsOperand(const MCInst *MI, int OpNo,
|
||
|
raw_ostream &OS,
|
||
|
const char * /*Modifier*/) {
|
||
|
const MCOperand &RegOp = MI->getOperand(OpNo);
|
||
|
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
|
||
|
const MCOperand &AluOp = MI->getOperand(OpNo + 2);
|
||
|
const unsigned AluCode = AluOp.getImm();
|
||
|
|
||
|
// Offset
|
||
|
printMemoryImmediateOffset<10>(MAI, OffsetOp, OS);
|
||
|
|
||
|
// Register
|
||
|
printMemoryBaseRegister(OS, AluCode, RegOp);
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo,
|
||
|
raw_ostream &OS) {
|
||
|
LPCC::CondCode CC =
|
||
|
static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm());
|
||
|
// Handle the undefined value here for printing so we don't abort().
|
||
|
if (CC >= LPCC::UNKNOWN)
|
||
|
OS << "<und>";
|
||
|
else
|
||
|
OS << lanaiCondCodeToString(CC);
|
||
|
}
|
||
|
|
||
|
void LanaiInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &OS) {
|
||
|
LPCC::CondCode CC =
|
||
|
static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm());
|
||
|
// Handle the undefined value here for printing so we don't abort().
|
||
|
if (CC >= LPCC::UNKNOWN)
|
||
|
OS << "<und>";
|
||
|
else if (CC != LPCC::ICC_T)
|
||
|
OS << "." << lanaiCondCodeToString(CC);
|
||
|
}
|