to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
305 lines
11 KiB
C++
305 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 "Lanai.h"
|
|
#include "MCTargetDesc/LanaiMCExpr.h"
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCInst.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, raw_ostream &OS,
|
|
StringRef Annotation,
|
|
const MCSubtargetInfo & /*STI*/) {
|
|
if (!printAlias(MI, OS) && !printAliasInstr(MI, OS))
|
|
printInstruction(MI, 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);
|
|
}
|