1 //===-- SPIRVInstPrinter.cpp - Output SPIR-V MCInsts as ASM -----*- C++ -*-===//
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 // This class prints a SPIR-V MCInst to a .s file.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "SPIRVInstPrinter.h"
14 #include "SPIRV.h"
15 #include "SPIRVBaseInfo.h"
16 #include "llvm/CodeGen/Register.h"
17 #include "llvm/MC/MCAsmInfo.h"
18 #include "llvm/MC/MCExpr.h"
19 #include "llvm/MC/MCInst.h"
20 #include "llvm/MC/MCInstrInfo.h"
21 #include "llvm/MC/MCSymbol.h"
22 #include "llvm/Support/Casting.h"
23 #include "llvm/Support/ErrorHandling.h"
24 #include "llvm/Support/FormattedStream.h"
25 
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "asm-printer"
29 
30 // Include the auto-generated portion of the assembly writer.
31 #include "SPIRVGenAsmWriter.inc"
32 
33 void SPIRVInstPrinter::printRemainingVariableOps(const MCInst *MI,
34                                                  unsigned StartIndex,
35                                                  raw_ostream &O,
36                                                  bool SkipFirstSpace,
37                                                  bool SkipImmediates) {
38   const unsigned NumOps = MI->getNumOperands();
39   for (unsigned i = StartIndex; i < NumOps; ++i) {
40     if (!SkipImmediates || !MI->getOperand(i).isImm()) {
41       if (!SkipFirstSpace || i != StartIndex)
42         O << ' ';
43       printOperand(MI, i, O);
44     }
45   }
46 }
47 
48 void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI,
49                                              unsigned StartIndex,
50                                              raw_ostream &O) {
51   O << ' ';
52   if (MI->getNumOperands() - StartIndex == 2) { // Handle 64 bit literals.
53     uint64_t Imm = MI->getOperand(StartIndex).getImm();
54     Imm |= (MI->getOperand(StartIndex + 1).getImm() << 32);
55     O << Imm;
56   } else {
57     printRemainingVariableOps(MI, StartIndex, O, true, false);
58   }
59 }
60 
61 void SPIRVInstPrinter::recordOpExtInstImport(const MCInst *MI) {
62   llvm_unreachable("Unimplemented recordOpExtInstImport");
63 }
64 
65 void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
66                                  StringRef Annot, const MCSubtargetInfo &STI,
67                                  raw_ostream &OS) {
68   const unsigned OpCode = MI->getOpcode();
69   printInstruction(MI, Address, OS);
70 
71   if (OpCode == SPIRV::OpDecorate) {
72     printOpDecorate(MI, OS);
73   } else if (OpCode == SPIRV::OpExtInstImport) {
74     recordOpExtInstImport(MI);
75   } else if (OpCode == SPIRV::OpExtInst) {
76     printOpExtInst(MI, OS);
77   } else {
78     // Print any extra operands for variadic instructions.
79     MCInstrDesc MCDesc = MII.get(OpCode);
80     if (MCDesc.isVariadic()) {
81       const unsigned NumFixedOps = MCDesc.getNumOperands();
82       const unsigned LastFixedIndex = NumFixedOps - 1;
83       const int FirstVariableIndex = NumFixedOps;
84       if (NumFixedOps > 0 &&
85           MCDesc.OpInfo[LastFixedIndex].OperandType == MCOI::OPERAND_UNKNOWN) {
86         // For instructions where a custom type (not reg or immediate) comes as
87         // the last operand before the variable_ops. This is usually a StringImm
88         // operand, but there are a few other cases.
89         switch (OpCode) {
90         case SPIRV::OpTypeImage:
91           OS << ' ';
92           printAccessQualifier(MI, FirstVariableIndex, OS);
93           break;
94         case SPIRV::OpVariable:
95           OS << ' ';
96           printOperand(MI, FirstVariableIndex, OS);
97           break;
98         case SPIRV::OpEntryPoint: {
99           // Print the interface ID operands, skipping the name's string
100           // literal.
101           printRemainingVariableOps(MI, NumFixedOps, OS, false, true);
102           break;
103         }
104         case SPIRV::OpExecutionMode:
105         case SPIRV::OpExecutionModeId:
106         case SPIRV::OpLoopMerge: {
107           // Print any literals after the OPERAND_UNKNOWN argument normally.
108           printRemainingVariableOps(MI, NumFixedOps, OS);
109           break;
110         }
111         default:
112           break; // printStringImm has already been handled
113         }
114       } else {
115         // For instructions with no fixed ops or a reg/immediate as the final
116         // fixed operand, we can usually print the rest with "printOperand", but
117         // check for a few cases with custom types first.
118         switch (OpCode) {
119         case SPIRV::OpLoad:
120         case SPIRV::OpStore:
121           OS << ' ';
122           printMemoryOperand(MI, FirstVariableIndex, OS);
123           printRemainingVariableOps(MI, FirstVariableIndex + 1, OS);
124           break;
125         case SPIRV::OpImageSampleImplicitLod:
126         case SPIRV::OpImageSampleDrefImplicitLod:
127         case SPIRV::OpImageSampleProjImplicitLod:
128         case SPIRV::OpImageSampleProjDrefImplicitLod:
129         case SPIRV::OpImageFetch:
130         case SPIRV::OpImageGather:
131         case SPIRV::OpImageDrefGather:
132         case SPIRV::OpImageRead:
133         case SPIRV::OpImageWrite:
134         case SPIRV::OpImageSparseSampleImplicitLod:
135         case SPIRV::OpImageSparseSampleDrefImplicitLod:
136         case SPIRV::OpImageSparseSampleProjImplicitLod:
137         case SPIRV::OpImageSparseSampleProjDrefImplicitLod:
138         case SPIRV::OpImageSparseFetch:
139         case SPIRV::OpImageSparseGather:
140         case SPIRV::OpImageSparseDrefGather:
141         case SPIRV::OpImageSparseRead:
142         case SPIRV::OpImageSampleFootprintNV:
143           OS << ' ';
144           printImageOperand(MI, FirstVariableIndex, OS);
145           printRemainingVariableOps(MI, NumFixedOps + 1, OS);
146           break;
147         case SPIRV::OpCopyMemory:
148         case SPIRV::OpCopyMemorySized: {
149           const unsigned NumOps = MI->getNumOperands();
150           for (unsigned i = NumFixedOps; i < NumOps; ++i) {
151             OS << ' ';
152             printMemoryOperand(MI, i, OS);
153             if (MI->getOperand(i).getImm() &
154                 static_cast<unsigned>(SPIRV::MemoryOperand::Aligned)) {
155               assert(i + 1 < NumOps && "Missing alignment operand");
156               OS << ' ';
157               printOperand(MI, i + 1, OS);
158               i += 1;
159             }
160           }
161           break;
162         }
163         case SPIRV::OpConstantI:
164         case SPIRV::OpConstantF:
165           printOpConstantVarOps(MI, NumFixedOps, OS);
166           break;
167         default:
168           printRemainingVariableOps(MI, NumFixedOps, OS);
169           break;
170         }
171       }
172     }
173   }
174 
175   printAnnotation(OS, Annot);
176 }
177 
178 void SPIRVInstPrinter::printOpExtInst(const MCInst *MI, raw_ostream &O) {
179   llvm_unreachable("Unimplemented printOpExtInst");
180 }
181 
182 void SPIRVInstPrinter::printOpDecorate(const MCInst *MI, raw_ostream &O) {
183   // The fixed operands have already been printed, so just need to decide what
184   // type of decoration operands to print based on the Decoration type.
185   MCInstrDesc MCDesc = MII.get(MI->getOpcode());
186   unsigned NumFixedOps = MCDesc.getNumOperands();
187 
188   if (NumFixedOps != MI->getNumOperands()) {
189     auto DecOp = MI->getOperand(NumFixedOps - 1);
190     auto Dec = static_cast<SPIRV::Decoration>(DecOp.getImm());
191 
192     O << ' ';
193 
194     switch (Dec) {
195     case SPIRV::Decoration::BuiltIn:
196       printBuiltIn(MI, NumFixedOps, O);
197       break;
198     case SPIRV::Decoration::UniformId:
199       printScope(MI, NumFixedOps, O);
200       break;
201     case SPIRV::Decoration::FuncParamAttr:
202       printFunctionParameterAttribute(MI, NumFixedOps, O);
203       break;
204     case SPIRV::Decoration::FPRoundingMode:
205       printFPRoundingMode(MI, NumFixedOps, O);
206       break;
207     case SPIRV::Decoration::FPFastMathMode:
208       printFPFastMathMode(MI, NumFixedOps, O);
209       break;
210     case SPIRV::Decoration::LinkageAttributes:
211     case SPIRV::Decoration::UserSemantic:
212       printStringImm(MI, NumFixedOps, O);
213       break;
214     default:
215       printRemainingVariableOps(MI, NumFixedOps, O, true);
216       break;
217     }
218   }
219 }
220 
221 static void printExpr(const MCExpr *Expr, raw_ostream &O) {
222 #ifndef NDEBUG
223   const MCSymbolRefExpr *SRE;
224 
225   if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr))
226     SRE = cast<MCSymbolRefExpr>(BE->getLHS());
227   else
228     SRE = cast<MCSymbolRefExpr>(Expr);
229 
230   MCSymbolRefExpr::VariantKind Kind = SRE->getKind();
231 
232   assert(Kind == MCSymbolRefExpr::VK_None);
233 #endif
234   O << *Expr;
235 }
236 
237 void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
238                                     raw_ostream &O, const char *Modifier) {
239   assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
240   if (OpNo < MI->getNumOperands()) {
241     const MCOperand &Op = MI->getOperand(OpNo);
242     if (Op.isReg())
243       O << '%' << (Register::virtReg2Index(Op.getReg()) + 1);
244     else if (Op.isImm())
245       O << formatImm((int64_t)Op.getImm());
246     else if (Op.isDFPImm())
247       O << formatImm((double)Op.getDFPImm());
248     else if (Op.isExpr())
249       printExpr(Op.getExpr(), O);
250     else
251       llvm_unreachable("Unexpected operand type");
252   }
253 }
254 
255 void SPIRVInstPrinter::printStringImm(const MCInst *MI, unsigned OpNo,
256                                       raw_ostream &O) {
257   const unsigned NumOps = MI->getNumOperands();
258   unsigned StrStartIndex = OpNo;
259   while (StrStartIndex < NumOps) {
260     if (MI->getOperand(StrStartIndex).isReg())
261       break;
262 
263     std::string Str = getSPIRVStringOperand(*MI, OpNo);
264     if (StrStartIndex != OpNo)
265       O << ' '; // Add a space if we're starting a new string/argument.
266     O << '"';
267     for (char c : Str) {
268       if (c == '"')
269         O.write('\\'); // Escape " characters (might break for complex UTF-8).
270       O.write(c);
271     }
272     O << '"';
273 
274     unsigned numOpsInString = (Str.size() / 4) + 1;
275     StrStartIndex += numOpsInString;
276 
277     // Check for final Op of "OpDecorate %x %stringImm %linkageAttribute".
278     if (MI->getOpcode() == SPIRV::OpDecorate &&
279         MI->getOperand(1).getImm() ==
280             static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) {
281       O << ' ';
282       printLinkageType(MI, StrStartIndex, O);
283       break;
284     }
285   }
286 }
287 
288 void SPIRVInstPrinter::printExtInst(const MCInst *MI, unsigned OpNo,
289                                     raw_ostream &O) {
290   llvm_unreachable("Unimplemented printExtInst");
291 }
292 
293 void SPIRVInstPrinter::printCapability(const MCInst *MI, unsigned OpNo,
294                                        raw_ostream &O) {
295   if (OpNo < MI->getNumOperands()) {
296     SPIRV::Capability e =
297         static_cast<SPIRV::Capability>(MI->getOperand(OpNo).getImm());
298     O << SPIRV::getCapabilityName(e);
299   }
300 }
301 
302 void SPIRVInstPrinter::printSourceLanguage(const MCInst *MI, unsigned OpNo,
303                                            raw_ostream &O) {
304   if (OpNo < MI->getNumOperands()) {
305     SPIRV::SourceLanguage e =
306         static_cast<SPIRV::SourceLanguage>(MI->getOperand(OpNo).getImm());
307     O << SPIRV::getSourceLanguageName(e);
308   }
309 }
310 
311 void SPIRVInstPrinter::printExecutionModel(const MCInst *MI, unsigned OpNo,
312                                            raw_ostream &O) {
313   if (OpNo < MI->getNumOperands()) {
314     SPIRV::ExecutionModel e =
315         static_cast<SPIRV::ExecutionModel>(MI->getOperand(OpNo).getImm());
316     O << SPIRV::getExecutionModelName(e);
317   }
318 }
319 
320 void SPIRVInstPrinter::printAddressingModel(const MCInst *MI, unsigned OpNo,
321                                             raw_ostream &O) {
322   if (OpNo < MI->getNumOperands()) {
323     SPIRV::AddressingModel e =
324         static_cast<SPIRV::AddressingModel>(MI->getOperand(OpNo).getImm());
325     O << SPIRV::getAddressingModelName(e);
326   }
327 }
328 
329 void SPIRVInstPrinter::printMemoryModel(const MCInst *MI, unsigned OpNo,
330                                         raw_ostream &O) {
331   if (OpNo < MI->getNumOperands()) {
332     SPIRV::MemoryModel e =
333         static_cast<SPIRV::MemoryModel>(MI->getOperand(OpNo).getImm());
334     O << SPIRV::getMemoryModelName(e);
335   }
336 }
337 
338 void SPIRVInstPrinter::printExecutionMode(const MCInst *MI, unsigned OpNo,
339                                           raw_ostream &O) {
340   if (OpNo < MI->getNumOperands()) {
341     SPIRV::ExecutionMode e =
342         static_cast<SPIRV::ExecutionMode>(MI->getOperand(OpNo).getImm());
343     O << SPIRV::getExecutionModeName(e);
344   }
345 }
346 
347 void SPIRVInstPrinter::printStorageClass(const MCInst *MI, unsigned OpNo,
348                                          raw_ostream &O) {
349   if (OpNo < MI->getNumOperands()) {
350     SPIRV::StorageClass e =
351         static_cast<SPIRV::StorageClass>(MI->getOperand(OpNo).getImm());
352     O << SPIRV::getStorageClassName(e);
353   }
354 }
355 
356 void SPIRVInstPrinter::printDim(const MCInst *MI, unsigned OpNo,
357                                 raw_ostream &O) {
358   if (OpNo < MI->getNumOperands()) {
359     SPIRV::Dim e = static_cast<SPIRV::Dim>(MI->getOperand(OpNo).getImm());
360     O << SPIRV::getDimName(e);
361   }
362 }
363 
364 void SPIRVInstPrinter::printSamplerAddressingMode(const MCInst *MI,
365                                                   unsigned OpNo,
366                                                   raw_ostream &O) {
367   if (OpNo < MI->getNumOperands()) {
368     SPIRV::SamplerAddressingMode e = static_cast<SPIRV::SamplerAddressingMode>(
369         MI->getOperand(OpNo).getImm());
370     O << SPIRV::getSamplerAddressingModeName(e);
371   }
372 }
373 
374 void SPIRVInstPrinter::printSamplerFilterMode(const MCInst *MI, unsigned OpNo,
375                                               raw_ostream &O) {
376   if (OpNo < MI->getNumOperands()) {
377     SPIRV::SamplerFilterMode e =
378         static_cast<SPIRV::SamplerFilterMode>(MI->getOperand(OpNo).getImm());
379     O << SPIRV::getSamplerFilterModeName(e);
380   }
381 }
382 
383 void SPIRVInstPrinter::printImageFormat(const MCInst *MI, unsigned OpNo,
384                                         raw_ostream &O) {
385   if (OpNo < MI->getNumOperands()) {
386     SPIRV::ImageFormat e =
387         static_cast<SPIRV::ImageFormat>(MI->getOperand(OpNo).getImm());
388     O << SPIRV::getImageFormatName(e);
389   }
390 }
391 
392 void SPIRVInstPrinter::printImageChannelOrder(const MCInst *MI, unsigned OpNo,
393                                               raw_ostream &O) {
394   if (OpNo < MI->getNumOperands()) {
395     SPIRV::ImageChannelOrder e =
396         static_cast<SPIRV::ImageChannelOrder>(MI->getOperand(OpNo).getImm());
397     O << SPIRV::getImageChannelOrderName(e);
398   }
399 }
400 
401 void SPIRVInstPrinter::printImageChannelDataType(const MCInst *MI,
402                                                  unsigned OpNo,
403                                                  raw_ostream &O) {
404   if (OpNo < MI->getNumOperands()) {
405     SPIRV::ImageChannelDataType e =
406         static_cast<SPIRV::ImageChannelDataType>(MI->getOperand(OpNo).getImm());
407     O << SPIRV::getImageChannelDataTypeName(e);
408   }
409 }
410 
411 void SPIRVInstPrinter::printImageOperand(const MCInst *MI, unsigned OpNo,
412                                          raw_ostream &O) {
413   if (OpNo < MI->getNumOperands()) {
414     unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
415     O << SPIRV::getImageOperandName(e);
416   }
417 }
418 
419 void SPIRVInstPrinter::printFPFastMathMode(const MCInst *MI, unsigned OpNo,
420                                            raw_ostream &O) {
421   if (OpNo < MI->getNumOperands()) {
422     unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
423     O << SPIRV::getFPFastMathModeName(e);
424   }
425 }
426 
427 void SPIRVInstPrinter::printFPRoundingMode(const MCInst *MI, unsigned OpNo,
428                                            raw_ostream &O) {
429   if (OpNo < MI->getNumOperands()) {
430     SPIRV::FPRoundingMode e =
431         static_cast<SPIRV::FPRoundingMode>(MI->getOperand(OpNo).getImm());
432     O << SPIRV::getFPRoundingModeName(e);
433   }
434 }
435 
436 void SPIRVInstPrinter::printLinkageType(const MCInst *MI, unsigned OpNo,
437                                         raw_ostream &O) {
438   if (OpNo < MI->getNumOperands()) {
439     SPIRV::LinkageType e =
440         static_cast<SPIRV::LinkageType>(MI->getOperand(OpNo).getImm());
441     O << SPIRV::getLinkageTypeName(e);
442   }
443 }
444 
445 void SPIRVInstPrinter::printAccessQualifier(const MCInst *MI, unsigned OpNo,
446                                             raw_ostream &O) {
447   if (OpNo < MI->getNumOperands()) {
448     SPIRV::AccessQualifier e =
449         static_cast<SPIRV::AccessQualifier>(MI->getOperand(OpNo).getImm());
450     O << SPIRV::getAccessQualifierName(e);
451   }
452 }
453 
454 void SPIRVInstPrinter::printFunctionParameterAttribute(const MCInst *MI,
455                                                        unsigned OpNo,
456                                                        raw_ostream &O) {
457   if (OpNo < MI->getNumOperands()) {
458     SPIRV::FunctionParameterAttribute e =
459         static_cast<SPIRV::FunctionParameterAttribute>(
460             MI->getOperand(OpNo).getImm());
461     O << SPIRV::getFunctionParameterAttributeName(e);
462   }
463 }
464 
465 void SPIRVInstPrinter::printDecoration(const MCInst *MI, unsigned OpNo,
466                                        raw_ostream &O) {
467   if (OpNo < MI->getNumOperands()) {
468     SPIRV::Decoration e =
469         static_cast<SPIRV::Decoration>(MI->getOperand(OpNo).getImm());
470     O << SPIRV::getDecorationName(e);
471   }
472 }
473 
474 void SPIRVInstPrinter::printBuiltIn(const MCInst *MI, unsigned OpNo,
475                                     raw_ostream &O) {
476   if (OpNo < MI->getNumOperands()) {
477     SPIRV::BuiltIn e =
478         static_cast<SPIRV::BuiltIn>(MI->getOperand(OpNo).getImm());
479     O << SPIRV::getBuiltInName(e);
480   }
481 }
482 
483 void SPIRVInstPrinter::printSelectionControl(const MCInst *MI, unsigned OpNo,
484                                              raw_ostream &O) {
485   if (OpNo < MI->getNumOperands()) {
486     unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
487     O << SPIRV::getSelectionControlName(e);
488   }
489 }
490 
491 void SPIRVInstPrinter::printLoopControl(const MCInst *MI, unsigned OpNo,
492                                         raw_ostream &O) {
493   if (OpNo < MI->getNumOperands()) {
494     unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
495     O << SPIRV::getLoopControlName(e);
496   }
497 }
498 
499 void SPIRVInstPrinter::printFunctionControl(const MCInst *MI, unsigned OpNo,
500                                             raw_ostream &O) {
501   if (OpNo < MI->getNumOperands()) {
502     unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
503     O << SPIRV::getFunctionControlName(e);
504   }
505 }
506 
507 void SPIRVInstPrinter::printMemorySemantics(const MCInst *MI, unsigned OpNo,
508                                             raw_ostream &O) {
509   if (OpNo < MI->getNumOperands()) {
510     unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
511     O << SPIRV::getMemorySemanticsName(e);
512   }
513 }
514 
515 void SPIRVInstPrinter::printMemoryOperand(const MCInst *MI, unsigned OpNo,
516                                           raw_ostream &O) {
517   if (OpNo < MI->getNumOperands()) {
518     unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
519     O << SPIRV::getMemoryOperandName(e);
520   }
521 }
522 
523 void SPIRVInstPrinter::printScope(const MCInst *MI, unsigned OpNo,
524                                   raw_ostream &O) {
525   if (OpNo < MI->getNumOperands()) {
526     SPIRV::Scope e = static_cast<SPIRV::Scope>(MI->getOperand(OpNo).getImm());
527     O << SPIRV::getScopeName(e);
528   }
529 }
530 
531 void SPIRVInstPrinter::printGroupOperation(const MCInst *MI, unsigned OpNo,
532                                            raw_ostream &O) {
533   if (OpNo < MI->getNumOperands()) {
534     SPIRV::GroupOperation e =
535         static_cast<SPIRV::GroupOperation>(MI->getOperand(OpNo).getImm());
536     O << SPIRV::getGroupOperationName(e);
537   }
538 }
539 
540 void SPIRVInstPrinter::printKernelEnqueueFlags(const MCInst *MI, unsigned OpNo,
541                                                raw_ostream &O) {
542   if (OpNo < MI->getNumOperands()) {
543     SPIRV::KernelEnqueueFlags e =
544         static_cast<SPIRV::KernelEnqueueFlags>(MI->getOperand(OpNo).getImm());
545     O << SPIRV::getKernelEnqueueFlagsName(e);
546   }
547 }
548 
549 void SPIRVInstPrinter::printKernelProfilingInfo(const MCInst *MI, unsigned OpNo,
550                                                 raw_ostream &O) {
551   if (OpNo < MI->getNumOperands()) {
552     SPIRV::KernelProfilingInfo e =
553         static_cast<SPIRV::KernelProfilingInfo>(MI->getOperand(OpNo).getImm());
554     O << SPIRV::getKernelProfilingInfoName(e);
555   }
556 }
557