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 | |
30 | NVPTXInstPrinter::NVPTXInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, |
31 | const MCRegisterInfo &MRI) |
32 | : MCInstPrinter(MAI, MII, MRI) {} |
33 | |
34 | 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(reason: "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 | |
72 | void NVPTXInstPrinter::printInst(const MCInst *MI, uint64_t Address, |
73 | StringRef Annot, const MCSubtargetInfo &STI, |
74 | raw_ostream &OS) { |
75 | printInstruction(MI, Address, O&: OS); |
76 | |
77 | // Next always print the annotation. |
78 | printAnnotation(OS, Annot); |
79 | } |
80 | |
81 | void NVPTXInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, |
82 | raw_ostream &O) { |
83 | const MCOperand &Op = MI->getOperand(i: OpNo); |
84 | if (Op.isReg()) { |
85 | unsigned Reg = Op.getReg(); |
86 | printRegName(OS&: O, Reg); |
87 | } else if (Op.isImm()) { |
88 | markup(OS&: O, M: Markup::Immediate) << formatImm(Value: Op.getImm()); |
89 | } else { |
90 | assert(Op.isExpr() && "Unknown operand kind in printOperand" ); |
91 | Op.getExpr()->print(OS&: O, MAI: &MAI); |
92 | } |
93 | } |
94 | |
95 | void NVPTXInstPrinter::printCvtMode(const MCInst *MI, int OpNum, raw_ostream &O, |
96 | const char *Modifier) { |
97 | const MCOperand &MO = MI->getOperand(i: OpNum); |
98 | int64_t Imm = MO.getImm(); |
99 | |
100 | if (strcmp(s1: Modifier, s2: "ftz" ) == 0) { |
101 | // FTZ flag |
102 | if (Imm & NVPTX::PTXCvtMode::FTZ_FLAG) |
103 | O << ".ftz" ; |
104 | } else if (strcmp(s1: Modifier, s2: "sat" ) == 0) { |
105 | // SAT flag |
106 | if (Imm & NVPTX::PTXCvtMode::SAT_FLAG) |
107 | O << ".sat" ; |
108 | } else if (strcmp(s1: Modifier, s2: "relu" ) == 0) { |
109 | // RELU flag |
110 | if (Imm & NVPTX::PTXCvtMode::RELU_FLAG) |
111 | O << ".relu" ; |
112 | } else if (strcmp(s1: Modifier, s2: "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 | |
152 | void NVPTXInstPrinter::printCmpMode(const MCInst *MI, int OpNum, raw_ostream &O, |
153 | const char *Modifier) { |
154 | const MCOperand &MO = MI->getOperand(i: OpNum); |
155 | int64_t Imm = MO.getImm(); |
156 | |
157 | if (strcmp(s1: Modifier, s2: "ftz" ) == 0) { |
158 | // FTZ flag |
159 | if (Imm & NVPTX::PTXCmpMode::FTZ_FLAG) |
160 | O << ".ftz" ; |
161 | } else if (strcmp(s1: Modifier, s2: "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 | |
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(i: OpNum); |
229 | int Imm = (int) MO.getImm(); |
230 | if (!strcmp(s1: Modifier, s2: "volatile" )) { |
231 | if (Imm) |
232 | O << ".volatile" ; |
233 | } else if (!strcmp(s1: Modifier, s2: "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(s1: Modifier, s2: "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(s1: Modifier, s2: "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 | |
277 | void NVPTXInstPrinter::printMmaCode(const MCInst *MI, int OpNum, raw_ostream &O, |
278 | const char *Modifier) { |
279 | const MCOperand &MO = MI->getOperand(i: OpNum); |
280 | int Imm = (int)MO.getImm(); |
281 | if (Modifier == nullptr || strcmp(s1: Modifier, s2: "version" ) == 0) { |
282 | O << Imm; // Just print out PTX version |
283 | } else if (strcmp(s1: Modifier, s2: "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 | |
291 | void NVPTXInstPrinter::printMemOperand(const MCInst *MI, int OpNum, |
292 | raw_ostream &O, const char *Modifier) { |
293 | printOperand(MI, OpNo: OpNum, O); |
294 | |
295 | if (Modifier && !strcmp(s1: Modifier, s2: "add" )) { |
296 | O << ", " ; |
297 | printOperand(MI, OpNo: OpNum + 1, O); |
298 | } else { |
299 | if (MI->getOperand(i: OpNum + 1).isImm() && |
300 | MI->getOperand(i: OpNum + 1).getImm() == 0) |
301 | return; // don't print ',0' or '+0' |
302 | O << "+" ; |
303 | printOperand(MI, OpNo: OpNum + 1, O); |
304 | } |
305 | } |
306 | |
307 | void NVPTXInstPrinter::printProtoIdent(const MCInst *MI, int OpNum, |
308 | raw_ostream &O, const char *Modifier) { |
309 | const MCOperand &Op = MI->getOperand(i: OpNum); |
310 | assert(Op.isExpr() && "Call prototype is not an MCExpr?" ); |
311 | const MCExpr *Expr = Op.getExpr(); |
312 | const MCSymbol &Sym = cast<MCSymbolRefExpr>(Val: Expr)->getSymbol(); |
313 | O << Sym.getName(); |
314 | } |
315 | |
316 | void NVPTXInstPrinter::printPrmtMode(const MCInst *MI, int OpNum, |
317 | raw_ostream &O, const char *Modifier) { |
318 | const MCOperand &MO = MI->getOperand(i: 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 | |