xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AVR/MCTargetDesc/AVRInstPrinter.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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