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