10b57cec5SDimitry Andric //===-- AVRInstPrinter.cpp - Convert AVR MCInst to assembly syntax --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This class prints an AVR MCInst to a .s file.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "AVRInstPrinter.h"
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "MCTargetDesc/AVRMCTargetDesc.h"
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
220b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
230b57cec5SDimitry Andric #include "llvm/Support/FormattedStream.h"
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric #include <cstring>
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric namespace llvm {
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric // Include the auto-generated portion of the assembly writer.
320b57cec5SDimitry Andric #define PRINT_ALIAS_INSTR
330b57cec5SDimitry Andric #include "AVRGenAsmWriter.inc"
340b57cec5SDimitry Andric
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)35480093f4SDimitry Andric void AVRInstPrinter::printInst(const MCInst *MI, uint64_t Address,
36480093f4SDimitry Andric StringRef Annot, const MCSubtargetInfo &STI,
37480093f4SDimitry Andric raw_ostream &O) {
380b57cec5SDimitry Andric unsigned Opcode = MI->getOpcode();
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric // First handle load and store instructions with postinc or predec
410b57cec5SDimitry Andric // of the form "ld reg, X+".
420b57cec5SDimitry Andric // TODO: We should be able to rewrite this using TableGen data.
430b57cec5SDimitry Andric switch (Opcode) {
440b57cec5SDimitry Andric case AVR::LDRdPtr:
450b57cec5SDimitry Andric case AVR::LDRdPtrPi:
460b57cec5SDimitry Andric case AVR::LDRdPtrPd:
470b57cec5SDimitry Andric O << "\tld\t";
480b57cec5SDimitry Andric printOperand(MI, 0, O);
490b57cec5SDimitry Andric O << ", ";
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric if (Opcode == AVR::LDRdPtrPd)
520b57cec5SDimitry Andric O << '-';
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric printOperand(MI, 1, O);
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric if (Opcode == AVR::LDRdPtrPi)
570b57cec5SDimitry Andric O << '+';
580b57cec5SDimitry Andric break;
590b57cec5SDimitry Andric case AVR::STPtrRr:
600b57cec5SDimitry Andric O << "\tst\t";
610b57cec5SDimitry Andric printOperand(MI, 0, O);
620b57cec5SDimitry Andric O << ", ";
630b57cec5SDimitry Andric printOperand(MI, 1, O);
640b57cec5SDimitry Andric break;
650b57cec5SDimitry Andric case AVR::STPtrPiRr:
660b57cec5SDimitry Andric case AVR::STPtrPdRr:
670b57cec5SDimitry Andric O << "\tst\t";
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric if (Opcode == AVR::STPtrPdRr)
700b57cec5SDimitry Andric O << '-';
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric printOperand(MI, 1, O);
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric if (Opcode == AVR::STPtrPiRr)
750b57cec5SDimitry Andric O << '+';
760b57cec5SDimitry Andric
770b57cec5SDimitry Andric O << ", ";
780b57cec5SDimitry Andric printOperand(MI, 2, O);
790b57cec5SDimitry Andric break;
800b57cec5SDimitry Andric default:
815ffd83dbSDimitry Andric if (!printAliasInstr(MI, Address, O))
82480093f4SDimitry Andric printInstruction(MI, Address, O);
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric printAnnotation(O, Annot);
850b57cec5SDimitry Andric break;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
getPrettyRegisterName(unsigned RegNum,MCRegisterInfo const & MRI)890b57cec5SDimitry Andric const char *AVRInstPrinter::getPrettyRegisterName(unsigned RegNum,
900b57cec5SDimitry Andric MCRegisterInfo const &MRI) {
910b57cec5SDimitry Andric // GCC prints register pairs by just printing the lower register
920b57cec5SDimitry Andric // If the register contains a subregister, print it instead
930b57cec5SDimitry Andric if (MRI.getNumSubRegIndices() > 0) {
940b57cec5SDimitry Andric unsigned RegLoNum = MRI.getSubReg(RegNum, AVR::sub_lo);
950b57cec5SDimitry Andric RegNum = (RegLoNum != AVR::NoRegister) ? RegLoNum : RegNum;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric return getRegisterName(RegNum);
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)1010b57cec5SDimitry Andric void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
1020b57cec5SDimitry Andric raw_ostream &O) {
103*bdd1243dSDimitry Andric const MCOperandInfo &MOI = this->MII.get(MI->getOpcode()).operands()[OpNo];
1045ffd83dbSDimitry Andric if (MOI.RegClass == AVR::ZREGRegClassID) {
1055ffd83dbSDimitry Andric // Special case for the Z register, which sometimes doesn't have an operand
1065ffd83dbSDimitry Andric // in the MCInst.
1075ffd83dbSDimitry Andric O << "Z";
1085ffd83dbSDimitry Andric return;
1095ffd83dbSDimitry Andric }
1105ffd83dbSDimitry Andric
1115ffd83dbSDimitry Andric if (OpNo >= MI->size()) {
1125ffd83dbSDimitry Andric // Not all operands are correctly disassembled at the moment. This means
1135ffd83dbSDimitry Andric // that some machine instructions won't have all the necessary operands
1145ffd83dbSDimitry Andric // set.
1155ffd83dbSDimitry Andric // To avoid asserting, print <unknown> instead until the necessary support
1165ffd83dbSDimitry Andric // has been implemented.
1175ffd83dbSDimitry Andric O << "<unknown>";
1185ffd83dbSDimitry Andric return;
1195ffd83dbSDimitry Andric }
1205ffd83dbSDimitry Andric
1215ffd83dbSDimitry Andric const MCOperand &Op = MI->getOperand(OpNo);
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric if (Op.isReg()) {
1240b57cec5SDimitry Andric bool isPtrReg = (MOI.RegClass == AVR::PTRREGSRegClassID) ||
1250b57cec5SDimitry Andric (MOI.RegClass == AVR::PTRDISPREGSRegClassID) ||
1260b57cec5SDimitry Andric (MOI.RegClass == AVR::ZREGRegClassID);
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric if (isPtrReg) {
1290b57cec5SDimitry Andric O << getRegisterName(Op.getReg(), AVR::ptr);
1300b57cec5SDimitry Andric } else {
1310b57cec5SDimitry Andric O << getPrettyRegisterName(Op.getReg(), MRI);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric } else if (Op.isImm()) {
1345ffd83dbSDimitry Andric O << formatImm(Op.getImm());
1350b57cec5SDimitry Andric } else {
1360b57cec5SDimitry Andric assert(Op.isExpr() && "Unknown operand kind in printOperand");
1370b57cec5SDimitry Andric O << *Op.getExpr();
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric /// This is used to print an immediate value that ends up
1420b57cec5SDimitry Andric /// being encoded as a pc-relative value.
printPCRelImm(const MCInst * MI,unsigned OpNo,raw_ostream & O)1430b57cec5SDimitry Andric void AVRInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo,
1440b57cec5SDimitry Andric raw_ostream &O) {
1455ffd83dbSDimitry Andric if (OpNo >= MI->size()) {
1465ffd83dbSDimitry Andric // Not all operands are correctly disassembled at the moment. This means
1475ffd83dbSDimitry Andric // that some machine instructions won't have all the necessary operands
1485ffd83dbSDimitry Andric // set.
1495ffd83dbSDimitry Andric // To avoid asserting, print <unknown> instead until the necessary support
1505ffd83dbSDimitry Andric // has been implemented.
1515ffd83dbSDimitry Andric O << "<unknown>";
1525ffd83dbSDimitry Andric return;
1535ffd83dbSDimitry Andric }
1545ffd83dbSDimitry Andric
1550b57cec5SDimitry Andric const MCOperand &Op = MI->getOperand(OpNo);
1560b57cec5SDimitry Andric
1570b57cec5SDimitry Andric if (Op.isImm()) {
1580b57cec5SDimitry Andric int64_t Imm = Op.getImm();
1590b57cec5SDimitry Andric O << '.';
1600b57cec5SDimitry Andric
1610b57cec5SDimitry Andric // Print a position sign if needed.
1620b57cec5SDimitry Andric // Negative values have their sign printed automatically.
1630b57cec5SDimitry Andric if (Imm >= 0)
1640b57cec5SDimitry Andric O << '+';
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andric O << Imm;
1670b57cec5SDimitry Andric } else {
1680b57cec5SDimitry Andric assert(Op.isExpr() && "Unknown pcrel immediate operand");
1690b57cec5SDimitry Andric O << *Op.getExpr();
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric
printMemri(const MCInst * MI,unsigned OpNo,raw_ostream & O)1730b57cec5SDimitry Andric void AVRInstPrinter::printMemri(const MCInst *MI, unsigned OpNo,
1740b57cec5SDimitry Andric raw_ostream &O) {
175349cc55cSDimitry Andric assert(MI->getOperand(OpNo).isReg() &&
176349cc55cSDimitry Andric "Expected a register for the first operand");
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric // Print the register.
1810b57cec5SDimitry Andric printOperand(MI, OpNo, O);
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric // Print the {+,-}offset.
1840b57cec5SDimitry Andric if (OffsetOp.isImm()) {
1850b57cec5SDimitry Andric int64_t Offset = OffsetOp.getImm();
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric if (Offset >= 0)
1880b57cec5SDimitry Andric O << '+';
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andric O << Offset;
1910b57cec5SDimitry Andric } else if (OffsetOp.isExpr()) {
1920b57cec5SDimitry Andric O << *OffsetOp.getExpr();
1930b57cec5SDimitry Andric } else {
1940b57cec5SDimitry Andric llvm_unreachable("unknown type for offset");
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric } // end of namespace llvm
199