1 //===-- AVRInstPrinter.cpp - Convert AVR MCInst to assembly syntax --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This class prints an AVR MCInst to a .s file. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "AVRInstPrinter.h" 14 15 #include "MCTargetDesc/AVRMCTargetDesc.h" 16 17 #include "llvm/MC/MCExpr.h" 18 #include "llvm/MC/MCInst.h" 19 #include "llvm/MC/MCInstrDesc.h" 20 #include "llvm/MC/MCInstrInfo.h" 21 #include "llvm/MC/MCRegisterInfo.h" 22 #include "llvm/Support/ErrorHandling.h" 23 24 #include <cstring> 25 26 #define DEBUG_TYPE "asm-printer" 27 28 namespace llvm { 29 30 // Include the auto-generated portion of the assembly writer. 31 #define PRINT_ALIAS_INSTR 32 #include "AVRGenAsmWriter.inc" 33 34 void AVRInstPrinter::printInst(const MCInst *MI, uint64_t Address, 35 StringRef Annot, const MCSubtargetInfo &STI, 36 raw_ostream &O) { 37 unsigned Opcode = MI->getOpcode(); 38 39 // First handle load and store instructions with postinc or predec 40 // of the form "ld reg, X+". 41 // TODO: We should be able to rewrite this using TableGen data. 42 switch (Opcode) { 43 case AVR::LDRdPtr: 44 case AVR::LDRdPtrPi: 45 case AVR::LDRdPtrPd: 46 O << "\tld\t"; 47 printOperand(MI, 0, O); 48 O << ", "; 49 50 if (Opcode == AVR::LDRdPtrPd) 51 O << '-'; 52 53 printOperand(MI, 1, O); 54 55 if (Opcode == AVR::LDRdPtrPi) 56 O << '+'; 57 break; 58 case AVR::STPtrRr: 59 O << "\tst\t"; 60 printOperand(MI, 0, O); 61 O << ", "; 62 printOperand(MI, 1, O); 63 break; 64 case AVR::STPtrPiRr: 65 case AVR::STPtrPdRr: 66 O << "\tst\t"; 67 68 if (Opcode == AVR::STPtrPdRr) 69 O << '-'; 70 71 printOperand(MI, 1, O); 72 73 if (Opcode == AVR::STPtrPiRr) 74 O << '+'; 75 76 O << ", "; 77 printOperand(MI, 2, O); 78 break; 79 default: 80 if (!printAliasInstr(MI, Address, O)) 81 printInstruction(MI, Address, O); 82 83 printAnnotation(O, Annot); 84 break; 85 } 86 } 87 88 const char *AVRInstPrinter::getPrettyRegisterName(MCRegister Reg, 89 MCRegisterInfo const &MRI) { 90 // GCC prints register pairs by just printing the lower register 91 // If the register contains a subregister, print it instead 92 if (MRI.getNumSubRegIndices() > 0) { 93 MCRegister RegLo = MRI.getSubReg(Reg, AVR::sub_lo); 94 Reg = (RegLo != AVR::NoRegister) ? RegLo : Reg; 95 } 96 97 return getRegisterName(Reg); 98 } 99 100 void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 101 raw_ostream &O) { 102 const MCOperandInfo &MOI = this->MII.get(MI->getOpcode()).operands()[OpNo]; 103 if (MOI.RegClass == AVR::ZREGRegClassID) { 104 // Special case for the Z register, which sometimes doesn't have an operand 105 // in the MCInst. 106 O << "Z"; 107 return; 108 } 109 110 if (OpNo >= MI->size()) { 111 // Not all operands are correctly disassembled at the moment. This means 112 // that some machine instructions won't have all the necessary operands 113 // set. 114 // To avoid asserting, print <unknown> instead until the necessary support 115 // has been implemented. 116 O << "<unknown>"; 117 return; 118 } 119 120 const MCOperand &Op = MI->getOperand(OpNo); 121 122 if (Op.isReg()) { 123 bool isPtrReg = (MOI.RegClass == AVR::PTRREGSRegClassID) || 124 (MOI.RegClass == AVR::PTRDISPREGSRegClassID) || 125 (MOI.RegClass == AVR::ZREGRegClassID); 126 127 if (isPtrReg) { 128 O << getRegisterName(Op.getReg(), AVR::ptr); 129 } else { 130 O << getPrettyRegisterName(Op.getReg(), MRI); 131 } 132 } else if (Op.isImm()) { 133 O << formatImm(Op.getImm()); 134 } else { 135 assert(Op.isExpr() && "Unknown operand kind in printOperand"); 136 O << *Op.getExpr(); 137 } 138 } 139 140 /// This is used to print an immediate value that ends up 141 /// being encoded as a pc-relative value. 142 void AVRInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo, 143 raw_ostream &O) { 144 if (OpNo >= MI->size()) { 145 // Not all operands are correctly disassembled at the moment. This means 146 // that some machine instructions won't have all the necessary operands 147 // set. 148 // To avoid asserting, print <unknown> instead until the necessary support 149 // has been implemented. 150 O << "<unknown>"; 151 return; 152 } 153 154 const MCOperand &Op = MI->getOperand(OpNo); 155 156 if (Op.isImm()) { 157 int64_t Imm = Op.getImm(); 158 O << '.'; 159 160 // Print a position sign if needed. 161 // Negative values have their sign printed automatically. 162 if (Imm >= 0) 163 O << '+'; 164 165 O << Imm; 166 } else { 167 assert(Op.isExpr() && "Unknown pcrel immediate operand"); 168 O << *Op.getExpr(); 169 } 170 } 171 172 void AVRInstPrinter::printMemri(const MCInst *MI, unsigned OpNo, 173 raw_ostream &O) { 174 assert(MI->getOperand(OpNo).isReg() && 175 "Expected a register for the first operand"); 176 177 const MCOperand &OffsetOp = MI->getOperand(OpNo + 1); 178 179 // Print the register. 180 printOperand(MI, OpNo, O); 181 182 // Print the {+,-}offset. 183 if (OffsetOp.isImm()) { 184 int64_t Offset = OffsetOp.getImm(); 185 186 if (Offset >= 0) 187 O << '+'; 188 189 O << Offset; 190 } else if (OffsetOp.isExpr()) { 191 O << *OffsetOp.getExpr(); 192 } else { 193 llvm_unreachable("unknown type for offset"); 194 } 195 } 196 197 } // end of namespace llvm 198