1 //===- XtensaInstPrinter.cpp - Convert Xtensa MCInst to asm syntax --------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 // See https://llvm.org/LICENSE.txt for license information.
7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //
9 //===----------------------------------------------------------------------===//
10 //
11 // This class prints an Xtensa MCInst to a .s file.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "XtensaInstPrinter.h"
16 #include "llvm/CodeGen/MachineOperand.h"
17 #include "llvm/MC/MCExpr.h"
18 #include "llvm/MC/MCInstrInfo.h"
19 #include "llvm/MC/MCRegister.h"
20 #include "llvm/MC/MCSymbol.h"
21 #include "llvm/Support/Casting.h"
22 #include "llvm/Support/raw_ostream.h"
23 
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "asm-printer"
27 
28 #include "XtensaGenAsmWriter.inc"
29 
30 static void printExpr(const MCExpr *Expr, raw_ostream &OS) {
31   int Offset = 0;
32   const MCSymbolRefExpr *SRE;
33 
34   if (!(SRE = cast<MCSymbolRefExpr>(Expr)))
35     assert(false && "Unexpected MCExpr type.");
36 
37   MCSymbolRefExpr::VariantKind Kind = SRE->getKind();
38 
39   switch (Kind) {
40   case MCSymbolRefExpr::VK_None:
41     break;
42   // TODO
43   default:
44     report_fatal_error("Invalid kind!");
45   }
46 
47   OS << SRE->getSymbol();
48 
49   if (Offset) {
50     if (Offset > 0)
51       OS << '+';
52     OS << Offset;
53   }
54 
55   if (Kind != MCSymbolRefExpr::VK_None)
56     OS << ')';
57 }
58 
59 void XtensaInstPrinter::printOperand(const MCOperand &MC, raw_ostream &O) {
60   if (MC.isReg())
61     O << getRegisterName(MC.getReg());
62   else if (MC.isImm())
63     O << MC.getImm();
64   else if (MC.isExpr())
65     printExpr(MC.getExpr(), O);
66   else
67     report_fatal_error("Invalid operand");
68 }
69 
70 void XtensaInstPrinter::printInst(const MCInst *MI, uint64_t Address,
71                                   StringRef Annot, const MCSubtargetInfo &STI,
72                                   raw_ostream &O) {
73   printInstruction(MI, Address, O);
74   printAnnotation(O, Annot);
75 }
76 
77 void XtensaInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) const {
78   O << getRegisterName(Reg);
79 }
80 
81 void XtensaInstPrinter::printOperand(const MCInst *MI, int OpNum,
82                                      raw_ostream &O) {
83   printOperand(MI->getOperand(OpNum), O);
84 }
85 
86 void XtensaInstPrinter::printMemOperand(const MCInst *MI, int OpNum,
87                                         raw_ostream &OS) {
88   OS << getRegisterName(MI->getOperand(OpNum).getReg());
89   OS << ", ";
90   printOperand(MI, OpNum + 1, OS);
91 }
92 
93 void XtensaInstPrinter::printBranchTarget(const MCInst *MI, int OpNum,
94                                           raw_ostream &OS) {
95   const MCOperand &MC = MI->getOperand(OpNum);
96   if (MI->getOperand(OpNum).isImm()) {
97     int64_t Val = MC.getImm() + 4;
98     OS << ". ";
99     if (Val > 0)
100       OS << '+';
101     OS << Val;
102   } else if (MC.isExpr())
103     MC.getExpr()->print(OS, &MAI, true);
104   else
105     llvm_unreachable("Invalid operand");
106 }
107 
108 void XtensaInstPrinter::printJumpTarget(const MCInst *MI, int OpNum,
109                                         raw_ostream &OS) {
110   const MCOperand &MC = MI->getOperand(OpNum);
111   if (MC.isImm()) {
112     int64_t Val = MC.getImm() + 4;
113     OS << ". ";
114     if (Val > 0)
115       OS << '+';
116     OS << Val;
117   } else if (MC.isExpr())
118     MC.getExpr()->print(OS, &MAI, true);
119   else
120     llvm_unreachable("Invalid operand");
121   ;
122 }
123 
124 void XtensaInstPrinter::printCallOperand(const MCInst *MI, int OpNum,
125                                          raw_ostream &OS) {
126   const MCOperand &MC = MI->getOperand(OpNum);
127   if (MC.isImm()) {
128     int64_t Val = MC.getImm() + 4;
129     OS << ". ";
130     if (Val > 0)
131       OS << '+';
132     OS << Val;
133   } else if (MC.isExpr())
134     MC.getExpr()->print(OS, &MAI, true);
135   else
136     llvm_unreachable("Invalid operand");
137 }
138 
139 void XtensaInstPrinter::printL32RTarget(const MCInst *MI, int OpNum,
140                                         raw_ostream &O) {
141   const MCOperand &MC = MI->getOperand(OpNum);
142   if (MC.isImm()) {
143     int64_t Value = MI->getOperand(OpNum).getImm();
144     int64_t InstrOff = Value & 0x3;
145     Value -= InstrOff;
146     assert((Value >= -262144 && Value <= -4) &&
147            "Invalid argument, value must be in ranges [-262144,-4]");
148     Value += ((InstrOff + 0x3) & 0x4) - InstrOff;
149     O << ". ";
150     O << Value;
151   } else if (MC.isExpr())
152     MC.getExpr()->print(O, &MAI, true);
153   else
154     llvm_unreachable("Invalid operand");
155 }
156 
157 void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum,
158                                              raw_ostream &O) {
159   if (MI->getOperand(OpNum).isImm()) {
160     int64_t Value = MI->getOperand(OpNum).getImm();
161     assert(isInt<8>(Value) &&
162            "Invalid argument, value must be in ranges [-128,127]");
163     O << Value;
164   } else {
165     printOperand(MI, OpNum, O);
166   }
167 }
168 
169 void XtensaInstPrinter::printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum,
170                                                  raw_ostream &O) {
171   if (MI->getOperand(OpNum).isImm()) {
172     int64_t Value = MI->getOperand(OpNum).getImm();
173     assert((isInt<16>(Value) && ((Value & 0xFF) == 0)) &&
174            "Invalid argument, value must be multiples of 256 in range "
175            "[-32768,32512]");
176     O << Value;
177   } else
178     printOperand(MI, OpNum, O);
179 }
180 
181 void XtensaInstPrinter::printImm12_AsmOperand(const MCInst *MI, int OpNum,
182                                               raw_ostream &O) {
183   if (MI->getOperand(OpNum).isImm()) {
184     int64_t Value = MI->getOperand(OpNum).getImm();
185     assert((Value >= -2048 && Value <= 2047) &&
186            "Invalid argument, value must be in ranges [-2048,2047]");
187     O << Value;
188   } else
189     printOperand(MI, OpNum, O);
190 }
191 
192 void XtensaInstPrinter::printImm12m_AsmOperand(const MCInst *MI, int OpNum,
193                                                raw_ostream &O) {
194   if (MI->getOperand(OpNum).isImm()) {
195     int64_t Value = MI->getOperand(OpNum).getImm();
196     assert((Value >= -2048 && Value <= 2047) &&
197            "Invalid argument, value must be in ranges [-2048,2047]");
198     O << Value;
199   } else
200     printOperand(MI, OpNum, O);
201 }
202 
203 void XtensaInstPrinter::printUimm4_AsmOperand(const MCInst *MI, int OpNum,
204                                               raw_ostream &O) {
205   if (MI->getOperand(OpNum).isImm()) {
206     int64_t Value = MI->getOperand(OpNum).getImm();
207     assert((Value >= 0 && Value <= 15) && "Invalid argument");
208     O << Value;
209   } else
210     printOperand(MI, OpNum, O);
211 }
212 
213 void XtensaInstPrinter::printUimm5_AsmOperand(const MCInst *MI, int OpNum,
214                                               raw_ostream &O) {
215   if (MI->getOperand(OpNum).isImm()) {
216     int64_t Value = MI->getOperand(OpNum).getImm();
217     assert((Value >= 0 && Value <= 31) && "Invalid argument");
218     O << Value;
219   } else
220     printOperand(MI, OpNum, O);
221 }
222 
223 void XtensaInstPrinter::printShimm1_31_AsmOperand(const MCInst *MI, int OpNum,
224                                                   raw_ostream &O) {
225   if (MI->getOperand(OpNum).isImm()) {
226     int64_t Value = MI->getOperand(OpNum).getImm();
227     assert((Value >= 1 && Value <= 31) &&
228            "Invalid argument, value must be in range [1,31]");
229     O << Value;
230   } else
231     printOperand(MI, OpNum, O);
232 }
233 
234 void XtensaInstPrinter::printImm1_16_AsmOperand(const MCInst *MI, int OpNum,
235                                                 raw_ostream &O) {
236   if (MI->getOperand(OpNum).isImm()) {
237     int64_t Value = MI->getOperand(OpNum).getImm();
238     assert((Value >= 1 && Value <= 16) &&
239            "Invalid argument, value must be in range [1,16]");
240     O << Value;
241   } else
242     printOperand(MI, OpNum, O);
243 }
244 
245 void XtensaInstPrinter::printOffset8m8_AsmOperand(const MCInst *MI, int OpNum,
246                                                   raw_ostream &O) {
247   if (MI->getOperand(OpNum).isImm()) {
248     int64_t Value = MI->getOperand(OpNum).getImm();
249     assert((Value >= 0 && Value <= 255) &&
250            "Invalid argument, value must be in range [0,255]");
251     O << Value;
252   } else
253     printOperand(MI, OpNum, O);
254 }
255 
256 void XtensaInstPrinter::printOffset8m16_AsmOperand(const MCInst *MI, int OpNum,
257                                                    raw_ostream &O) {
258   if (MI->getOperand(OpNum).isImm()) {
259     int64_t Value = MI->getOperand(OpNum).getImm();
260     assert((Value >= 0 && Value <= 510 && ((Value & 0x1) == 0)) &&
261            "Invalid argument, value must be multiples of two in range [0,510]");
262     O << Value;
263   } else
264     printOperand(MI, OpNum, O);
265 }
266 
267 void XtensaInstPrinter::printOffset8m32_AsmOperand(const MCInst *MI, int OpNum,
268                                                    raw_ostream &O) {
269   if (MI->getOperand(OpNum).isImm()) {
270     int64_t Value = MI->getOperand(OpNum).getImm();
271     assert(
272         (Value >= 0 && Value <= 1020 && ((Value & 0x3) == 0)) &&
273         "Invalid argument, value must be multiples of four in range [0,1020]");
274     O << Value;
275   } else
276     printOperand(MI, OpNum, O);
277 }
278 
279 void XtensaInstPrinter::printOffset4m32_AsmOperand(const MCInst *MI, int OpNum,
280                                                    raw_ostream &O) {
281   if (MI->getOperand(OpNum).isImm()) {
282     int64_t Value = MI->getOperand(OpNum).getImm();
283     assert((Value >= 0 && Value <= 60 && ((Value & 0x3) == 0)) &&
284            "Invalid argument, value must be multiples of four in range [0,60]");
285     O << Value;
286   } else
287     printOperand(MI, OpNum, O);
288 }
289 
290 void XtensaInstPrinter::printB4const_AsmOperand(const MCInst *MI, int OpNum,
291                                                 raw_ostream &O) {
292   if (MI->getOperand(OpNum).isImm()) {
293     int64_t Value = MI->getOperand(OpNum).getImm();
294 
295     switch (Value) {
296     case -1:
297     case 1:
298     case 2:
299     case 3:
300     case 4:
301     case 5:
302     case 6:
303     case 7:
304     case 8:
305     case 10:
306     case 12:
307     case 16:
308     case 32:
309     case 64:
310     case 128:
311     case 256:
312       break;
313     default:
314       assert((0) && "Invalid B4const argument");
315     }
316     O << Value;
317   } else
318     printOperand(MI, OpNum, O);
319 }
320 
321 void XtensaInstPrinter::printB4constu_AsmOperand(const MCInst *MI, int OpNum,
322                                                  raw_ostream &O) {
323   if (MI->getOperand(OpNum).isImm()) {
324     int64_t Value = MI->getOperand(OpNum).getImm();
325 
326     switch (Value) {
327     case 32768:
328     case 65536:
329     case 2:
330     case 3:
331     case 4:
332     case 5:
333     case 6:
334     case 7:
335     case 8:
336     case 10:
337     case 12:
338     case 16:
339     case 32:
340     case 64:
341     case 128:
342     case 256:
343       break;
344     default:
345       assert((0) && "Invalid B4constu argument");
346     }
347     O << Value;
348   } else
349     printOperand(MI, OpNum, O);
350 }
351