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