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
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)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
getPrettyRegisterName(unsigned RegNum,MCRegisterInfo const & MRI)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
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)101 void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
102 raw_ostream &O) {
103 const MCOperandInfo &MOI = this->MII.get(MI->getOpcode()).operands()[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.
printPCRelImm(const MCInst * MI,unsigned OpNo,raw_ostream & O)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
printMemri(const MCInst * MI,unsigned OpNo,raw_ostream & O)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