//===-- 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 #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 instead until the necessary support // has been implemented. O << ""; 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 instead until the necessary support // has been implemented. O << ""; 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