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,unsigned RegNo) const34 void NVPTXInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
35   // Decode the virtual register
36   // Must be kept in sync with NVPTXAsmPrinter::encodeVirtualRegister
37   unsigned RCId = (RegNo >> 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(RegNo);
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 << "%h";
65     break;
66   case 8:
67     OS << "%hh";
68     break;
69   }
70 
71   unsigned VReg = RegNo & 0x0FFFFFFF;
72   OS << VReg;
73 }
74 
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & OS)75 void NVPTXInstPrinter::printInst(const MCInst *MI, uint64_t Address,
76                                  StringRef Annot, const MCSubtargetInfo &STI,
77                                  raw_ostream &OS) {
78   printInstruction(MI, Address, OS);
79 
80   // Next always print the annotation.
81   printAnnotation(OS, Annot);
82 }
83 
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)84 void NVPTXInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
85                                     raw_ostream &O) {
86   const MCOperand &Op = MI->getOperand(OpNo);
87   if (Op.isReg()) {
88     unsigned Reg = Op.getReg();
89     printRegName(O, Reg);
90   } else if (Op.isImm()) {
91     O << markup("<imm:") << formatImm(Op.getImm()) << markup(">");
92   } else {
93     assert(Op.isExpr() && "Unknown operand kind in printOperand");
94     Op.getExpr()->print(O, &MAI);
95   }
96 }
97 
printCvtMode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)98 void NVPTXInstPrinter::printCvtMode(const MCInst *MI, int OpNum, raw_ostream &O,
99                                     const char *Modifier) {
100   const MCOperand &MO = MI->getOperand(OpNum);
101   int64_t Imm = MO.getImm();
102 
103   if (strcmp(Modifier, "ftz") == 0) {
104     // FTZ flag
105     if (Imm & NVPTX::PTXCvtMode::FTZ_FLAG)
106       O << ".ftz";
107   } else if (strcmp(Modifier, "sat") == 0) {
108     // SAT flag
109     if (Imm & NVPTX::PTXCvtMode::SAT_FLAG)
110       O << ".sat";
111   } else if (strcmp(Modifier, "base") == 0) {
112     // Default operand
113     switch (Imm & NVPTX::PTXCvtMode::BASE_MASK) {
114     default:
115       return;
116     case NVPTX::PTXCvtMode::NONE:
117       break;
118     case NVPTX::PTXCvtMode::RNI:
119       O << ".rni";
120       break;
121     case NVPTX::PTXCvtMode::RZI:
122       O << ".rzi";
123       break;
124     case NVPTX::PTXCvtMode::RMI:
125       O << ".rmi";
126       break;
127     case NVPTX::PTXCvtMode::RPI:
128       O << ".rpi";
129       break;
130     case NVPTX::PTXCvtMode::RN:
131       O << ".rn";
132       break;
133     case NVPTX::PTXCvtMode::RZ:
134       O << ".rz";
135       break;
136     case NVPTX::PTXCvtMode::RM:
137       O << ".rm";
138       break;
139     case NVPTX::PTXCvtMode::RP:
140       O << ".rp";
141       break;
142     }
143   } else {
144     llvm_unreachable("Invalid conversion modifier");
145   }
146 }
147 
printCmpMode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)148 void NVPTXInstPrinter::printCmpMode(const MCInst *MI, int OpNum, raw_ostream &O,
149                                     const char *Modifier) {
150   const MCOperand &MO = MI->getOperand(OpNum);
151   int64_t Imm = MO.getImm();
152 
153   if (strcmp(Modifier, "ftz") == 0) {
154     // FTZ flag
155     if (Imm & NVPTX::PTXCmpMode::FTZ_FLAG)
156       O << ".ftz";
157   } else if (strcmp(Modifier, "base") == 0) {
158     switch (Imm & NVPTX::PTXCmpMode::BASE_MASK) {
159     default:
160       return;
161     case NVPTX::PTXCmpMode::EQ:
162       O << ".eq";
163       break;
164     case NVPTX::PTXCmpMode::NE:
165       O << ".ne";
166       break;
167     case NVPTX::PTXCmpMode::LT:
168       O << ".lt";
169       break;
170     case NVPTX::PTXCmpMode::LE:
171       O << ".le";
172       break;
173     case NVPTX::PTXCmpMode::GT:
174       O << ".gt";
175       break;
176     case NVPTX::PTXCmpMode::GE:
177       O << ".ge";
178       break;
179     case NVPTX::PTXCmpMode::LO:
180       O << ".lo";
181       break;
182     case NVPTX::PTXCmpMode::LS:
183       O << ".ls";
184       break;
185     case NVPTX::PTXCmpMode::HI:
186       O << ".hi";
187       break;
188     case NVPTX::PTXCmpMode::HS:
189       O << ".hs";
190       break;
191     case NVPTX::PTXCmpMode::EQU:
192       O << ".equ";
193       break;
194     case NVPTX::PTXCmpMode::NEU:
195       O << ".neu";
196       break;
197     case NVPTX::PTXCmpMode::LTU:
198       O << ".ltu";
199       break;
200     case NVPTX::PTXCmpMode::LEU:
201       O << ".leu";
202       break;
203     case NVPTX::PTXCmpMode::GTU:
204       O << ".gtu";
205       break;
206     case NVPTX::PTXCmpMode::GEU:
207       O << ".geu";
208       break;
209     case NVPTX::PTXCmpMode::NUM:
210       O << ".num";
211       break;
212     case NVPTX::PTXCmpMode::NotANumber:
213       O << ".nan";
214       break;
215     }
216   } else {
217     llvm_unreachable("Empty Modifier");
218   }
219 }
220 
printLdStCode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)221 void NVPTXInstPrinter::printLdStCode(const MCInst *MI, int OpNum,
222                                      raw_ostream &O, const char *Modifier) {
223   if (Modifier) {
224     const MCOperand &MO = MI->getOperand(OpNum);
225     int Imm = (int) MO.getImm();
226     if (!strcmp(Modifier, "volatile")) {
227       if (Imm)
228         O << ".volatile";
229     } else if (!strcmp(Modifier, "addsp")) {
230       switch (Imm) {
231       case NVPTX::PTXLdStInstCode::GLOBAL:
232         O << ".global";
233         break;
234       case NVPTX::PTXLdStInstCode::SHARED:
235         O << ".shared";
236         break;
237       case NVPTX::PTXLdStInstCode::LOCAL:
238         O << ".local";
239         break;
240       case NVPTX::PTXLdStInstCode::PARAM:
241         O << ".param";
242         break;
243       case NVPTX::PTXLdStInstCode::CONSTANT:
244         O << ".const";
245         break;
246       case NVPTX::PTXLdStInstCode::GENERIC:
247         break;
248       default:
249         llvm_unreachable("Wrong Address Space");
250       }
251     } else if (!strcmp(Modifier, "sign")) {
252       if (Imm == NVPTX::PTXLdStInstCode::Signed)
253         O << "s";
254       else if (Imm == NVPTX::PTXLdStInstCode::Unsigned)
255         O << "u";
256       else if (Imm == NVPTX::PTXLdStInstCode::Untyped)
257         O << "b";
258       else if (Imm == NVPTX::PTXLdStInstCode::Float)
259         O << "f";
260       else
261         llvm_unreachable("Unknown register type");
262     } else if (!strcmp(Modifier, "vec")) {
263       if (Imm == NVPTX::PTXLdStInstCode::V2)
264         O << ".v2";
265       else if (Imm == NVPTX::PTXLdStInstCode::V4)
266         O << ".v4";
267     } else
268       llvm_unreachable("Unknown Modifier");
269   } else
270     llvm_unreachable("Empty Modifier");
271 }
272 
printMmaCode(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)273 void NVPTXInstPrinter::printMmaCode(const MCInst *MI, int OpNum, raw_ostream &O,
274                                     const char *Modifier) {
275   const MCOperand &MO = MI->getOperand(OpNum);
276   int Imm = (int)MO.getImm();
277   if (Modifier == nullptr || strcmp(Modifier, "version") == 0) {
278     O << Imm; // Just print out PTX version
279   } else if (strcmp(Modifier, "aligned") == 0) {
280     // PTX63 requires '.aligned' in the name of the instruction.
281     if (Imm >= 63)
282       O << ".aligned";
283   } else
284     llvm_unreachable("Unknown Modifier");
285 }
286 
printMemOperand(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)287 void NVPTXInstPrinter::printMemOperand(const MCInst *MI, int OpNum,
288                                        raw_ostream &O, const char *Modifier) {
289   printOperand(MI, OpNum, O);
290 
291   if (Modifier && !strcmp(Modifier, "add")) {
292     O << ", ";
293     printOperand(MI, OpNum + 1, O);
294   } else {
295     if (MI->getOperand(OpNum + 1).isImm() &&
296         MI->getOperand(OpNum + 1).getImm() == 0)
297       return; // don't print ',0' or '+0'
298     O << "+";
299     printOperand(MI, OpNum + 1, O);
300   }
301 }
302 
printProtoIdent(const MCInst * MI,int OpNum,raw_ostream & O,const char * Modifier)303 void NVPTXInstPrinter::printProtoIdent(const MCInst *MI, int OpNum,
304                                        raw_ostream &O, const char *Modifier) {
305   const MCOperand &Op = MI->getOperand(OpNum);
306   assert(Op.isExpr() && "Call prototype is not an MCExpr?");
307   const MCExpr *Expr = Op.getExpr();
308   const MCSymbol &Sym = cast<MCSymbolRefExpr>(Expr)->getSymbol();
309   O << Sym.getName();
310 }
311