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