xref: /freebsd/contrib/llvm-project/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===-- NVPTXInstPrinter.cpp - PTX assembly instruction printing ----------===//
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 // Print MCInst instructions to .ptx format.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "MCTargetDesc/NVPTXInstPrinter.h"
14 #include "MCTargetDesc/NVPTXBaseInfo.h"
15 #include "NVPTX.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/MC/MCInstrInfo.h"
19 #include "llvm/MC/MCSubtargetInfo.h"
20 #include "llvm/MC/MCSymbol.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/FormattedStream.h"
23 #include <cctype>
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "asm-printer"
27 
28 #include "NVPTXGenAsmWriter.inc"
29 
NVPTXInstPrinter(const MCAsmInfo & MAI,const MCInstrInfo & MII,const MCRegisterInfo & MRI)30 NVPTXInstPrinter::NVPTXInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
31                                    const MCRegisterInfo &MRI)
32     : MCInstPrinter(MAI, MII, MRI) {}
33 
printRegName(raw_ostream & OS,MCRegister Reg) const34 void NVPTXInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const {
35   // Decode the virtual register
36   // Must be kept in sync with NVPTXAsmPrinter::encodeVirtualRegister
37   unsigned RCId = (Reg.id() >> 28);
38   switch (RCId) {
39   default: report_fatal_error("Bad virtual register encoding");
40   case 0:
41     // This is actually a physical register, so defer to the autogenerated
42     // register printer
43     OS << getRegisterName(Reg);
44     return;
45   case 1:
46     OS << "%p";
47     break;
48   case 2:
49     OS << "%rs";
50     break;
51   case 3:
52     OS << "%r";
53     break;
54   case 4:
55     OS << "%rd";
56     break;
57   case 5:
58     OS << "%f";
59     break;
60   case 6:
61     OS << "%fd";
62     break;
63   case 7:
64     OS << "%rq";
65     break;
66   }
67 
68   unsigned VReg = Reg.id() & 0x0FFFFFFF;
69   OS << VReg;
70 }
71 
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & OS)72 void NVPTXInstPrinter::printInst(const MCInst *MI, uint64_t Address,
73                                  StringRef Annot, const MCSubtargetInfo &STI,
74                                  raw_ostream &OS) {
75   printInstruction(MI, Address, OS);
76 
77   // Next always print the annotation.
78   printAnnotation(OS, Annot);
79 }
80 
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)81 void NVPTXInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
82                                     raw_ostream &O) {
83   const MCOperand &Op = MI->getOperand(OpNo);
84   if (Op.isReg()) {
85     unsigned Reg = Op.getReg();
86     printRegName(O, Reg);
87   } else if (Op.isImm()) {
88     markup(O, Markup::Immediate) << formatImm(Op.getImm());
89   } else {
90     assert(Op.isExpr() && "Unknown operand kind in printOperand");
91     Op.getExpr()->print(O, &MAI);
92   }
93 }
94 
printCvtMode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)95 void NVPTXInstPrinter::printCvtMode(const MCInst *MI, int OpNum, raw_ostream &O,
96                                     const char *Modifier) {
97   const MCOperand &MO = MI->getOperand(OpNum);
98   int64_t Imm = MO.getImm();
99 
100   if (strcmp(Modifier, "ftz") == 0) {
101     // FTZ flag
102     if (Imm & NVPTX::PTXCvtMode::FTZ_FLAG)
103       O << ".ftz";
104   } else if (strcmp(Modifier, "sat") == 0) {
105     // SAT flag
106     if (Imm & NVPTX::PTXCvtMode::SAT_FLAG)
107       O << ".sat";
108   } else if (strcmp(Modifier, "relu") == 0) {
109     // RELU flag
110     if (Imm & NVPTX::PTXCvtMode::RELU_FLAG)
111       O << ".relu";
112   } else if (strcmp(Modifier, "base") == 0) {
113     // Default operand
114     switch (Imm & NVPTX::PTXCvtMode::BASE_MASK) {
115     default:
116       return;
117     case NVPTX::PTXCvtMode::NONE:
118       break;
119     case NVPTX::PTXCvtMode::RNI:
120       O << ".rni";
121       break;
122     case NVPTX::PTXCvtMode::RZI:
123       O << ".rzi";
124       break;
125     case NVPTX::PTXCvtMode::RMI:
126       O << ".rmi";
127       break;
128     case NVPTX::PTXCvtMode::RPI:
129       O << ".rpi";
130       break;
131     case NVPTX::PTXCvtMode::RN:
132       O << ".rn";
133       break;
134     case NVPTX::PTXCvtMode::RZ:
135       O << ".rz";
136       break;
137     case NVPTX::PTXCvtMode::RM:
138       O << ".rm";
139       break;
140     case NVPTX::PTXCvtMode::RP:
141       O << ".rp";
142       break;
143     case NVPTX::PTXCvtMode::RNA:
144       O << ".rna";
145       break;
146     }
147   } else {
148     llvm_unreachable("Invalid conversion modifier");
149   }
150 }
151 
printCmpMode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)152 void NVPTXInstPrinter::printCmpMode(const MCInst *MI, int OpNum, raw_ostream &O,
153                                     const char *Modifier) {
154   const MCOperand &MO = MI->getOperand(OpNum);
155   int64_t Imm = MO.getImm();
156 
157   if (strcmp(Modifier, "ftz") == 0) {
158     // FTZ flag
159     if (Imm & NVPTX::PTXCmpMode::FTZ_FLAG)
160       O << ".ftz";
161   } else if (strcmp(Modifier, "base") == 0) {
162     switch (Imm & NVPTX::PTXCmpMode::BASE_MASK) {
163     default:
164       return;
165     case NVPTX::PTXCmpMode::EQ:
166       O << ".eq";
167       break;
168     case NVPTX::PTXCmpMode::NE:
169       O << ".ne";
170       break;
171     case NVPTX::PTXCmpMode::LT:
172       O << ".lt";
173       break;
174     case NVPTX::PTXCmpMode::LE:
175       O << ".le";
176       break;
177     case NVPTX::PTXCmpMode::GT:
178       O << ".gt";
179       break;
180     case NVPTX::PTXCmpMode::GE:
181       O << ".ge";
182       break;
183     case NVPTX::PTXCmpMode::LO:
184       O << ".lo";
185       break;
186     case NVPTX::PTXCmpMode::LS:
187       O << ".ls";
188       break;
189     case NVPTX::PTXCmpMode::HI:
190       O << ".hi";
191       break;
192     case NVPTX::PTXCmpMode::HS:
193       O << ".hs";
194       break;
195     case NVPTX::PTXCmpMode::EQU:
196       O << ".equ";
197       break;
198     case NVPTX::PTXCmpMode::NEU:
199       O << ".neu";
200       break;
201     case NVPTX::PTXCmpMode::LTU:
202       O << ".ltu";
203       break;
204     case NVPTX::PTXCmpMode::LEU:
205       O << ".leu";
206       break;
207     case NVPTX::PTXCmpMode::GTU:
208       O << ".gtu";
209       break;
210     case NVPTX::PTXCmpMode::GEU:
211       O << ".geu";
212       break;
213     case NVPTX::PTXCmpMode::NUM:
214       O << ".num";
215       break;
216     case NVPTX::PTXCmpMode::NotANumber:
217       O << ".nan";
218       break;
219     }
220   } else {
221     llvm_unreachable("Empty Modifier");
222   }
223 }
224 
printLdStCode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)225 void NVPTXInstPrinter::printLdStCode(const MCInst *MI, int OpNum,
226                                      raw_ostream &O, const char *Modifier) {
227   if (Modifier) {
228     const MCOperand &MO = MI->getOperand(OpNum);
229     int Imm = (int) MO.getImm();
230     if (!strcmp(Modifier, "volatile")) {
231       if (Imm)
232         O << ".volatile";
233     } else if (!strcmp(Modifier, "addsp")) {
234       switch (Imm) {
235       case NVPTX::PTXLdStInstCode::GLOBAL:
236         O << ".global";
237         break;
238       case NVPTX::PTXLdStInstCode::SHARED:
239         O << ".shared";
240         break;
241       case NVPTX::PTXLdStInstCode::LOCAL:
242         O << ".local";
243         break;
244       case NVPTX::PTXLdStInstCode::PARAM:
245         O << ".param";
246         break;
247       case NVPTX::PTXLdStInstCode::CONSTANT:
248         O << ".const";
249         break;
250       case NVPTX::PTXLdStInstCode::GENERIC:
251         break;
252       default:
253         llvm_unreachable("Wrong Address Space");
254       }
255     } else if (!strcmp(Modifier, "sign")) {
256       if (Imm == NVPTX::PTXLdStInstCode::Signed)
257         O << "s";
258       else if (Imm == NVPTX::PTXLdStInstCode::Unsigned)
259         O << "u";
260       else if (Imm == NVPTX::PTXLdStInstCode::Untyped)
261         O << "b";
262       else if (Imm == NVPTX::PTXLdStInstCode::Float)
263         O << "f";
264       else
265         llvm_unreachable("Unknown register type");
266     } else if (!strcmp(Modifier, "vec")) {
267       if (Imm == NVPTX::PTXLdStInstCode::V2)
268         O << ".v2";
269       else if (Imm == NVPTX::PTXLdStInstCode::V4)
270         O << ".v4";
271     } else
272       llvm_unreachable("Unknown Modifier");
273   } else
274     llvm_unreachable("Empty Modifier");
275 }
276 
printMmaCode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)277 void NVPTXInstPrinter::printMmaCode(const MCInst *MI, int OpNum, raw_ostream &O,
278                                     const char *Modifier) {
279   const MCOperand &MO = MI->getOperand(OpNum);
280   int Imm = (int)MO.getImm();
281   if (Modifier == nullptr || strcmp(Modifier, "version") == 0) {
282     O << Imm; // Just print out PTX version
283   } else if (strcmp(Modifier, "aligned") == 0) {
284     // PTX63 requires '.aligned' in the name of the instruction.
285     if (Imm >= 63)
286       O << ".aligned";
287   } else
288     llvm_unreachable("Unknown Modifier");
289 }
290 
printMemOperand(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)291 void NVPTXInstPrinter::printMemOperand(const MCInst *MI, int OpNum,
292                                        raw_ostream &O, const char *Modifier) {
293   printOperand(MI, OpNum, O);
294 
295   if (Modifier && !strcmp(Modifier, "add")) {
296     O << ", ";
297     printOperand(MI, OpNum + 1, O);
298   } else {
299     if (MI->getOperand(OpNum + 1).isImm() &&
300         MI->getOperand(OpNum + 1).getImm() == 0)
301       return; // don't print ',0' or '+0'
302     O << "+";
303     printOperand(MI, OpNum + 1, O);
304   }
305 }
306 
printProtoIdent(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)307 void NVPTXInstPrinter::printProtoIdent(const MCInst *MI, int OpNum,
308                                        raw_ostream &O, const char *Modifier) {
309   const MCOperand &Op = MI->getOperand(OpNum);
310   assert(Op.isExpr() && "Call prototype is not an MCExpr?");
311   const MCExpr *Expr = Op.getExpr();
312   const MCSymbol &Sym = cast<MCSymbolRefExpr>(Expr)->getSymbol();
313   O << Sym.getName();
314 }
315 
printPrmtMode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)316 void NVPTXInstPrinter::printPrmtMode(const MCInst *MI, int OpNum,
317                                      raw_ostream &O, const char *Modifier) {
318   const MCOperand &MO = MI->getOperand(OpNum);
319   int64_t Imm = MO.getImm();
320 
321   switch (Imm) {
322   default:
323     return;
324   case NVPTX::PTXPrmtMode::NONE:
325     break;
326   case NVPTX::PTXPrmtMode::F4E:
327     O << ".f4e";
328     break;
329   case NVPTX::PTXPrmtMode::B4E:
330     O << ".b4e";
331     break;
332   case NVPTX::PTXPrmtMode::RC8:
333     O << ".rc8";
334     break;
335   case NVPTX::PTXPrmtMode::ECL:
336     O << ".ecl";
337     break;
338   case NVPTX::PTXPrmtMode::ECR:
339     O << ".ecr";
340     break;
341   case NVPTX::PTXPrmtMode::RC16:
342     O << ".rc16";
343     break;
344   }
345 }
346