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