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>
24using namespace llvm;
25
26#define DEBUG_TYPE "asm-printer"
27
28#include "NVPTXGenAsmWriter.inc"
29
30NVPTXInstPrinter::NVPTXInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
31 const MCRegisterInfo &MRI)
32 : MCInstPrinter(MAI, MII, MRI) {}
33
34void 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
72void 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
81void 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
95void 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
152void 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
225void 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
277void 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
291void 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
307void 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
316void 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