199 lines
5.4 KiB
C++
199 lines
5.4 KiB
C++
|
//===-- AVRInstPrinter.cpp - Convert AVR MCInst to assembly 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 AVR MCInst to a .s file.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "AVRInstPrinter.h"
|
||
|
|
||
|
#include "MCTargetDesc/AVRMCTargetDesc.h"
|
||
|
|
||
|
#include "llvm/MC/MCExpr.h"
|
||
|
#include "llvm/MC/MCInst.h"
|
||
|
#include "llvm/MC/MCInstrDesc.h"
|
||
|
#include "llvm/MC/MCInstrInfo.h"
|
||
|
#include "llvm/MC/MCRegisterInfo.h"
|
||
|
#include "llvm/Support/ErrorHandling.h"
|
||
|
#include "llvm/Support/FormattedStream.h"
|
||
|
|
||
|
#include <cstring>
|
||
|
|
||
|
#define DEBUG_TYPE "asm-printer"
|
||
|
|
||
|
namespace llvm {
|
||
|
|
||
|
// Include the auto-generated portion of the assembly writer.
|
||
|
#define PRINT_ALIAS_INSTR
|
||
|
#include "AVRGenAsmWriter.inc"
|
||
|
|
||
|
void AVRInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
||
|
StringRef Annot, const MCSubtargetInfo &STI,
|
||
|
raw_ostream &O) {
|
||
|
unsigned Opcode = MI->getOpcode();
|
||
|
|
||
|
// First handle load and store instructions with postinc or predec
|
||
|
// of the form "ld reg, X+".
|
||
|
// TODO: We should be able to rewrite this using TableGen data.
|
||
|
switch (Opcode) {
|
||
|
case AVR::LDRdPtr:
|
||
|
case AVR::LDRdPtrPi:
|
||
|
case AVR::LDRdPtrPd:
|
||
|
O << "\tld\t";
|
||
|
printOperand(MI, 0, O);
|
||
|
O << ", ";
|
||
|
|
||
|
if (Opcode == AVR::LDRdPtrPd)
|
||
|
O << '-';
|
||
|
|
||
|
printOperand(MI, 1, O);
|
||
|
|
||
|
if (Opcode == AVR::LDRdPtrPi)
|
||
|
O << '+';
|
||
|
break;
|
||
|
case AVR::STPtrRr:
|
||
|
O << "\tst\t";
|
||
|
printOperand(MI, 0, O);
|
||
|
O << ", ";
|
||
|
printOperand(MI, 1, O);
|
||
|
break;
|
||
|
case AVR::STPtrPiRr:
|
||
|
case AVR::STPtrPdRr:
|
||
|
O << "\tst\t";
|
||
|
|
||
|
if (Opcode == AVR::STPtrPdRr)
|
||
|
O << '-';
|
||
|
|
||
|
printOperand(MI, 1, O);
|
||
|
|
||
|
if (Opcode == AVR::STPtrPiRr)
|
||
|
O << '+';
|
||
|
|
||
|
O << ", ";
|
||
|
printOperand(MI, 2, O);
|
||
|
break;
|
||
|
default:
|
||
|
if (!printAliasInstr(MI, Address, O))
|
||
|
printInstruction(MI, Address, O);
|
||
|
|
||
|
printAnnotation(O, Annot);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char *AVRInstPrinter::getPrettyRegisterName(unsigned RegNum,
|
||
|
MCRegisterInfo const &MRI) {
|
||
|
// GCC prints register pairs by just printing the lower register
|
||
|
// If the register contains a subregister, print it instead
|
||
|
if (MRI.getNumSubRegIndices() > 0) {
|
||
|
unsigned RegLoNum = MRI.getSubReg(RegNum, AVR::sub_lo);
|
||
|
RegNum = (RegLoNum != AVR::NoRegister) ? RegLoNum : RegNum;
|
||
|
}
|
||
|
|
||
|
return getRegisterName(RegNum);
|
||
|
}
|
||
|
|
||
|
void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &O) {
|
||
|
const MCOperandInfo &MOI = this->MII.get(MI->getOpcode()).OpInfo[OpNo];
|
||
|
if (MOI.RegClass == AVR::ZREGRegClassID) {
|
||
|
// Special case for the Z register, which sometimes doesn't have an operand
|
||
|
// in the MCInst.
|
||
|
O << "Z";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (OpNo >= MI->size()) {
|
||
|
// Not all operands are correctly disassembled at the moment. This means
|
||
|
// that some machine instructions won't have all the necessary operands
|
||
|
// set.
|
||
|
// To avoid asserting, print <unknown> instead until the necessary support
|
||
|
// has been implemented.
|
||
|
O << "<unknown>";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const MCOperand &Op = MI->getOperand(OpNo);
|
||
|
|
||
|
if (Op.isReg()) {
|
||
|
bool isPtrReg = (MOI.RegClass == AVR::PTRREGSRegClassID) ||
|
||
|
(MOI.RegClass == AVR::PTRDISPREGSRegClassID) ||
|
||
|
(MOI.RegClass == AVR::ZREGRegClassID);
|
||
|
|
||
|
if (isPtrReg) {
|
||
|
O << getRegisterName(Op.getReg(), AVR::ptr);
|
||
|
} else {
|
||
|
O << getPrettyRegisterName(Op.getReg(), MRI);
|
||
|
}
|
||
|
} else if (Op.isImm()) {
|
||
|
O << formatImm(Op.getImm());
|
||
|
} else {
|
||
|
assert(Op.isExpr() && "Unknown operand kind in printOperand");
|
||
|
O << *Op.getExpr();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// This is used to print an immediate value that ends up
|
||
|
/// being encoded as a pc-relative value.
|
||
|
void AVRInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &O) {
|
||
|
if (OpNo >= MI->size()) {
|
||
|
// Not all operands are correctly disassembled at the moment. This means
|
||
|
// that some machine instructions won't have all the necessary operands
|
||
|
// set.
|
||
|
// To avoid asserting, print <unknown> instead until the necessary support
|
||
|
// has been implemented.
|
||
|
O << "<unknown>";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const MCOperand &Op = MI->getOperand(OpNo);
|
||
|
|
||
|
if (Op.isImm()) {
|
||
|
int64_t Imm = Op.getImm();
|
||
|
O << '.';
|
||
|
|
||
|
// Print a position sign if needed.
|
||
|
// Negative values have their sign printed automatically.
|
||
|
if (Imm >= 0)
|
||
|
O << '+';
|
||
|
|
||
|
O << Imm;
|
||
|
} else {
|
||
|
assert(Op.isExpr() && "Unknown pcrel immediate operand");
|
||
|
O << *Op.getExpr();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AVRInstPrinter::printMemri(const MCInst *MI, unsigned OpNo,
|
||
|
raw_ostream &O) {
|
||
|
assert(MI->getOperand(OpNo).isReg() && "Expected a register for the first operand");
|
||
|
|
||
|
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
|
||
|
|
||
|
// Print the register.
|
||
|
printOperand(MI, OpNo, O);
|
||
|
|
||
|
// Print the {+,-}offset.
|
||
|
if (OffsetOp.isImm()) {
|
||
|
int64_t Offset = OffsetOp.getImm();
|
||
|
|
||
|
if (Offset >= 0)
|
||
|
O << '+';
|
||
|
|
||
|
O << Offset;
|
||
|
} else if (OffsetOp.isExpr()) {
|
||
|
O << *OffsetOp.getExpr();
|
||
|
} else {
|
||
|
llvm_unreachable("unknown type for offset");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // end of namespace llvm
|
||
|
|