xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===-- SPIRVInstPrinter.cpp - Output SPIR-V MCInsts as ASM -----*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This class prints a SPIR-V MCInst to a .s file.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include "SPIRVInstPrinter.h"
1481ad6265SDimitry Andric #include "SPIRV.h"
1581ad6265SDimitry Andric #include "SPIRVBaseInfo.h"
16*0fca6ea1SDimitry Andric #include "SPIRVInstrInfo.h"
175f757f3fSDimitry Andric #include "llvm/ADT/APFloat.h"
1881ad6265SDimitry Andric #include "llvm/CodeGen/Register.h"
1981ad6265SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
2081ad6265SDimitry Andric #include "llvm/MC/MCExpr.h"
2181ad6265SDimitry Andric #include "llvm/MC/MCInst.h"
2281ad6265SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
2381ad6265SDimitry Andric #include "llvm/MC/MCSymbol.h"
2481ad6265SDimitry Andric #include "llvm/Support/Casting.h"
2581ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2681ad6265SDimitry Andric #include "llvm/Support/FormattedStream.h"
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric using namespace llvm;
29bdd1243dSDimitry Andric using namespace llvm::SPIRV;
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric #define DEBUG_TYPE "asm-printer"
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric // Include the auto-generated portion of the assembly writer.
3481ad6265SDimitry Andric #include "SPIRVGenAsmWriter.inc"
3581ad6265SDimitry Andric 
3681ad6265SDimitry Andric void SPIRVInstPrinter::printRemainingVariableOps(const MCInst *MI,
3781ad6265SDimitry Andric                                                  unsigned StartIndex,
3881ad6265SDimitry Andric                                                  raw_ostream &O,
3981ad6265SDimitry Andric                                                  bool SkipFirstSpace,
4081ad6265SDimitry Andric                                                  bool SkipImmediates) {
4181ad6265SDimitry Andric   const unsigned NumOps = MI->getNumOperands();
4281ad6265SDimitry Andric   for (unsigned i = StartIndex; i < NumOps; ++i) {
4381ad6265SDimitry Andric     if (!SkipImmediates || !MI->getOperand(i).isImm()) {
4481ad6265SDimitry Andric       if (!SkipFirstSpace || i != StartIndex)
4581ad6265SDimitry Andric         O << ' ';
4681ad6265SDimitry Andric       printOperand(MI, i, O);
4781ad6265SDimitry Andric     }
4881ad6265SDimitry Andric   }
4981ad6265SDimitry Andric }
5081ad6265SDimitry Andric 
5181ad6265SDimitry Andric void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI,
5281ad6265SDimitry Andric                                              unsigned StartIndex,
5381ad6265SDimitry Andric                                              raw_ostream &O) {
54*0fca6ea1SDimitry Andric   unsigned IsBitwidth16 = MI->getFlags() & SPIRV::ASM_PRINTER_WIDTH16;
555f757f3fSDimitry Andric   const unsigned NumVarOps = MI->getNumOperands() - StartIndex;
565f757f3fSDimitry Andric 
575f757f3fSDimitry Andric   assert((NumVarOps == 1 || NumVarOps == 2) &&
585f757f3fSDimitry Andric          "Unsupported number of bits for literal variable");
595f757f3fSDimitry Andric 
6081ad6265SDimitry Andric   O << ' ';
615f757f3fSDimitry Andric 
6281ad6265SDimitry Andric   uint64_t Imm = MI->getOperand(StartIndex).getImm();
635f757f3fSDimitry Andric 
645f757f3fSDimitry Andric   // Handle 64 bit literals.
655f757f3fSDimitry Andric   if (NumVarOps == 2) {
6681ad6265SDimitry Andric     Imm |= (MI->getOperand(StartIndex + 1).getImm() << 32);
6781ad6265SDimitry Andric   }
685f757f3fSDimitry Andric 
695f757f3fSDimitry Andric   // Format and print float values.
70*0fca6ea1SDimitry Andric   if (MI->getOpcode() == SPIRV::OpConstantF && IsBitwidth16 == 0) {
715f757f3fSDimitry Andric     APFloat FP = NumVarOps == 1 ? APFloat(APInt(32, Imm).bitsToFloat())
725f757f3fSDimitry Andric                                 : APFloat(APInt(64, Imm).bitsToDouble());
735f757f3fSDimitry Andric 
745f757f3fSDimitry Andric     // Print infinity and NaN as hex floats.
755f757f3fSDimitry Andric     // TODO: Make sure subnormal numbers are handled correctly as they may also
765f757f3fSDimitry Andric     // require hex float notation.
775f757f3fSDimitry Andric     if (FP.isInfinity()) {
785f757f3fSDimitry Andric       if (FP.isNegative())
795f757f3fSDimitry Andric         O << '-';
805f757f3fSDimitry Andric       O << "0x1p+128";
815f757f3fSDimitry Andric       return;
825f757f3fSDimitry Andric     }
835f757f3fSDimitry Andric     if (FP.isNaN()) {
845f757f3fSDimitry Andric       O << "0x1.8p+128";
855f757f3fSDimitry Andric       return;
865f757f3fSDimitry Andric     }
875f757f3fSDimitry Andric 
885f757f3fSDimitry Andric     // Format val as a decimal floating point or scientific notation (whichever
895f757f3fSDimitry Andric     // is shorter), with enough digits of precision to produce the exact value.
905f757f3fSDimitry Andric     O << format("%.*g", std::numeric_limits<double>::max_digits10,
915f757f3fSDimitry Andric                 FP.convertToDouble());
925f757f3fSDimitry Andric 
935f757f3fSDimitry Andric     return;
945f757f3fSDimitry Andric   }
955f757f3fSDimitry Andric 
965f757f3fSDimitry Andric   // Print integer values directly.
975f757f3fSDimitry Andric   O << Imm;
9881ad6265SDimitry Andric }
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric void SPIRVInstPrinter::recordOpExtInstImport(const MCInst *MI) {
101bdd1243dSDimitry Andric   Register Reg = MI->getOperand(0).getReg();
102bdd1243dSDimitry Andric   auto Name = getSPIRVStringOperand(*MI, 1);
103bdd1243dSDimitry Andric   auto Set = getExtInstSetFromString(Name);
104bdd1243dSDimitry Andric   ExtInstSetIDs.insert({Reg, Set});
10581ad6265SDimitry Andric }
10681ad6265SDimitry Andric 
10781ad6265SDimitry Andric void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
10881ad6265SDimitry Andric                                  StringRef Annot, const MCSubtargetInfo &STI,
10981ad6265SDimitry Andric                                  raw_ostream &OS) {
11081ad6265SDimitry Andric   const unsigned OpCode = MI->getOpcode();
11181ad6265SDimitry Andric   printInstruction(MI, Address, OS);
11281ad6265SDimitry Andric 
11381ad6265SDimitry Andric   if (OpCode == SPIRV::OpDecorate) {
11481ad6265SDimitry Andric     printOpDecorate(MI, OS);
11581ad6265SDimitry Andric   } else if (OpCode == SPIRV::OpExtInstImport) {
11681ad6265SDimitry Andric     recordOpExtInstImport(MI);
11781ad6265SDimitry Andric   } else if (OpCode == SPIRV::OpExtInst) {
11881ad6265SDimitry Andric     printOpExtInst(MI, OS);
11981ad6265SDimitry Andric   } else {
12081ad6265SDimitry Andric     // Print any extra operands for variadic instructions.
121bdd1243dSDimitry Andric     const MCInstrDesc &MCDesc = MII.get(OpCode);
12281ad6265SDimitry Andric     if (MCDesc.isVariadic()) {
12381ad6265SDimitry Andric       const unsigned NumFixedOps = MCDesc.getNumOperands();
12481ad6265SDimitry Andric       const unsigned LastFixedIndex = NumFixedOps - 1;
12581ad6265SDimitry Andric       const int FirstVariableIndex = NumFixedOps;
126bdd1243dSDimitry Andric       if (NumFixedOps > 0 && MCDesc.operands()[LastFixedIndex].OperandType ==
127bdd1243dSDimitry Andric                                  MCOI::OPERAND_UNKNOWN) {
12881ad6265SDimitry Andric         // For instructions where a custom type (not reg or immediate) comes as
12981ad6265SDimitry Andric         // the last operand before the variable_ops. This is usually a StringImm
13081ad6265SDimitry Andric         // operand, but there are a few other cases.
13181ad6265SDimitry Andric         switch (OpCode) {
13281ad6265SDimitry Andric         case SPIRV::OpTypeImage:
13381ad6265SDimitry Andric           OS << ' ';
134bdd1243dSDimitry Andric           printSymbolicOperand<OperandCategory::AccessQualifierOperand>(
135bdd1243dSDimitry Andric               MI, FirstVariableIndex, OS);
13681ad6265SDimitry Andric           break;
13781ad6265SDimitry Andric         case SPIRV::OpVariable:
13881ad6265SDimitry Andric           OS << ' ';
13981ad6265SDimitry Andric           printOperand(MI, FirstVariableIndex, OS);
14081ad6265SDimitry Andric           break;
14181ad6265SDimitry Andric         case SPIRV::OpEntryPoint: {
14281ad6265SDimitry Andric           // Print the interface ID operands, skipping the name's string
14381ad6265SDimitry Andric           // literal.
14481ad6265SDimitry Andric           printRemainingVariableOps(MI, NumFixedOps, OS, false, true);
14581ad6265SDimitry Andric           break;
14681ad6265SDimitry Andric         }
14781ad6265SDimitry Andric         case SPIRV::OpExecutionMode:
14881ad6265SDimitry Andric         case SPIRV::OpExecutionModeId:
14981ad6265SDimitry Andric         case SPIRV::OpLoopMerge: {
15081ad6265SDimitry Andric           // Print any literals after the OPERAND_UNKNOWN argument normally.
15181ad6265SDimitry Andric           printRemainingVariableOps(MI, NumFixedOps, OS);
15281ad6265SDimitry Andric           break;
15381ad6265SDimitry Andric         }
15481ad6265SDimitry Andric         default:
155bdd1243dSDimitry Andric           break; // printStringImm has already been handled.
15681ad6265SDimitry Andric         }
15781ad6265SDimitry Andric       } else {
15881ad6265SDimitry Andric         // For instructions with no fixed ops or a reg/immediate as the final
15981ad6265SDimitry Andric         // fixed operand, we can usually print the rest with "printOperand", but
16081ad6265SDimitry Andric         // check for a few cases with custom types first.
16181ad6265SDimitry Andric         switch (OpCode) {
16281ad6265SDimitry Andric         case SPIRV::OpLoad:
16381ad6265SDimitry Andric         case SPIRV::OpStore:
16481ad6265SDimitry Andric           OS << ' ';
165bdd1243dSDimitry Andric           printSymbolicOperand<OperandCategory::MemoryOperandOperand>(
166bdd1243dSDimitry Andric               MI, FirstVariableIndex, OS);
16781ad6265SDimitry Andric           printRemainingVariableOps(MI, FirstVariableIndex + 1, OS);
16881ad6265SDimitry Andric           break;
16981ad6265SDimitry Andric         case SPIRV::OpImageSampleImplicitLod:
17081ad6265SDimitry Andric         case SPIRV::OpImageSampleDrefImplicitLod:
17181ad6265SDimitry Andric         case SPIRV::OpImageSampleProjImplicitLod:
17281ad6265SDimitry Andric         case SPIRV::OpImageSampleProjDrefImplicitLod:
17381ad6265SDimitry Andric         case SPIRV::OpImageFetch:
17481ad6265SDimitry Andric         case SPIRV::OpImageGather:
17581ad6265SDimitry Andric         case SPIRV::OpImageDrefGather:
17681ad6265SDimitry Andric         case SPIRV::OpImageRead:
17781ad6265SDimitry Andric         case SPIRV::OpImageWrite:
17881ad6265SDimitry Andric         case SPIRV::OpImageSparseSampleImplicitLod:
17981ad6265SDimitry Andric         case SPIRV::OpImageSparseSampleDrefImplicitLod:
18081ad6265SDimitry Andric         case SPIRV::OpImageSparseSampleProjImplicitLod:
18181ad6265SDimitry Andric         case SPIRV::OpImageSparseSampleProjDrefImplicitLod:
18281ad6265SDimitry Andric         case SPIRV::OpImageSparseFetch:
18381ad6265SDimitry Andric         case SPIRV::OpImageSparseGather:
18481ad6265SDimitry Andric         case SPIRV::OpImageSparseDrefGather:
18581ad6265SDimitry Andric         case SPIRV::OpImageSparseRead:
18681ad6265SDimitry Andric         case SPIRV::OpImageSampleFootprintNV:
18781ad6265SDimitry Andric           OS << ' ';
188bdd1243dSDimitry Andric           printSymbolicOperand<OperandCategory::ImageOperandOperand>(
189bdd1243dSDimitry Andric               MI, FirstVariableIndex, OS);
19081ad6265SDimitry Andric           printRemainingVariableOps(MI, NumFixedOps + 1, OS);
19181ad6265SDimitry Andric           break;
19281ad6265SDimitry Andric         case SPIRV::OpCopyMemory:
19381ad6265SDimitry Andric         case SPIRV::OpCopyMemorySized: {
19481ad6265SDimitry Andric           const unsigned NumOps = MI->getNumOperands();
19581ad6265SDimitry Andric           for (unsigned i = NumFixedOps; i < NumOps; ++i) {
19681ad6265SDimitry Andric             OS << ' ';
197bdd1243dSDimitry Andric             printSymbolicOperand<OperandCategory::MemoryOperandOperand>(MI, i,
198bdd1243dSDimitry Andric                                                                         OS);
199bdd1243dSDimitry Andric             if (MI->getOperand(i).getImm() & MemoryOperand::Aligned) {
20081ad6265SDimitry Andric               assert(i + 1 < NumOps && "Missing alignment operand");
20181ad6265SDimitry Andric               OS << ' ';
20281ad6265SDimitry Andric               printOperand(MI, i + 1, OS);
20381ad6265SDimitry Andric               i += 1;
20481ad6265SDimitry Andric             }
20581ad6265SDimitry Andric           }
20681ad6265SDimitry Andric           break;
20781ad6265SDimitry Andric         }
20881ad6265SDimitry Andric         case SPIRV::OpConstantI:
20981ad6265SDimitry Andric         case SPIRV::OpConstantF:
2105f757f3fSDimitry Andric           // The last fixed operand along with any variadic operands that follow
2115f757f3fSDimitry Andric           // are part of the variable value.
2125f757f3fSDimitry Andric           printOpConstantVarOps(MI, NumFixedOps - 1, OS);
21381ad6265SDimitry Andric           break;
21481ad6265SDimitry Andric         default:
21581ad6265SDimitry Andric           printRemainingVariableOps(MI, NumFixedOps, OS);
21681ad6265SDimitry Andric           break;
21781ad6265SDimitry Andric         }
21881ad6265SDimitry Andric       }
21981ad6265SDimitry Andric     }
22081ad6265SDimitry Andric   }
22181ad6265SDimitry Andric 
22281ad6265SDimitry Andric   printAnnotation(OS, Annot);
22381ad6265SDimitry Andric }
22481ad6265SDimitry Andric 
22581ad6265SDimitry Andric void SPIRVInstPrinter::printOpExtInst(const MCInst *MI, raw_ostream &O) {
226fcaf7f86SDimitry Andric   // The fixed operands have already been printed, so just need to decide what
227fcaf7f86SDimitry Andric   // type of ExtInst operands to print based on the instruction set and number.
228bdd1243dSDimitry Andric   const MCInstrDesc &MCDesc = MII.get(MI->getOpcode());
229fcaf7f86SDimitry Andric   unsigned NumFixedOps = MCDesc.getNumOperands();
230fcaf7f86SDimitry Andric   const auto NumOps = MI->getNumOperands();
231fcaf7f86SDimitry Andric   if (NumOps == NumFixedOps)
232fcaf7f86SDimitry Andric     return;
233fcaf7f86SDimitry Andric 
234fcaf7f86SDimitry Andric   O << ' ';
235fcaf7f86SDimitry Andric 
236fcaf7f86SDimitry Andric   // TODO: implement special printing for OpenCLExtInst::vstor*.
237fcaf7f86SDimitry Andric   printRemainingVariableOps(MI, NumFixedOps, O, true);
23881ad6265SDimitry Andric }
23981ad6265SDimitry Andric 
24081ad6265SDimitry Andric void SPIRVInstPrinter::printOpDecorate(const MCInst *MI, raw_ostream &O) {
24181ad6265SDimitry Andric   // The fixed operands have already been printed, so just need to decide what
24281ad6265SDimitry Andric   // type of decoration operands to print based on the Decoration type.
243bdd1243dSDimitry Andric   const MCInstrDesc &MCDesc = MII.get(MI->getOpcode());
24481ad6265SDimitry Andric   unsigned NumFixedOps = MCDesc.getNumOperands();
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   if (NumFixedOps != MI->getNumOperands()) {
24781ad6265SDimitry Andric     auto DecOp = MI->getOperand(NumFixedOps - 1);
248bdd1243dSDimitry Andric     auto Dec = static_cast<Decoration::Decoration>(DecOp.getImm());
24981ad6265SDimitry Andric 
25081ad6265SDimitry Andric     O << ' ';
25181ad6265SDimitry Andric 
25281ad6265SDimitry Andric     switch (Dec) {
253bdd1243dSDimitry Andric     case Decoration::BuiltIn:
254bdd1243dSDimitry Andric       printSymbolicOperand<OperandCategory::BuiltInOperand>(MI, NumFixedOps, O);
25581ad6265SDimitry Andric       break;
256bdd1243dSDimitry Andric     case Decoration::UniformId:
257bdd1243dSDimitry Andric       printSymbolicOperand<OperandCategory::ScopeOperand>(MI, NumFixedOps, O);
25881ad6265SDimitry Andric       break;
259bdd1243dSDimitry Andric     case Decoration::FuncParamAttr:
260bdd1243dSDimitry Andric       printSymbolicOperand<OperandCategory::FunctionParameterAttributeOperand>(
261bdd1243dSDimitry Andric           MI, NumFixedOps, O);
26281ad6265SDimitry Andric       break;
263bdd1243dSDimitry Andric     case Decoration::FPRoundingMode:
264bdd1243dSDimitry Andric       printSymbolicOperand<OperandCategory::FPRoundingModeOperand>(
265bdd1243dSDimitry Andric           MI, NumFixedOps, O);
26681ad6265SDimitry Andric       break;
267bdd1243dSDimitry Andric     case Decoration::FPFastMathMode:
268bdd1243dSDimitry Andric       printSymbolicOperand<OperandCategory::FPFastMathModeOperand>(
269bdd1243dSDimitry Andric           MI, NumFixedOps, O);
27081ad6265SDimitry Andric       break;
271bdd1243dSDimitry Andric     case Decoration::LinkageAttributes:
272bdd1243dSDimitry Andric     case Decoration::UserSemantic:
27381ad6265SDimitry Andric       printStringImm(MI, NumFixedOps, O);
27481ad6265SDimitry Andric       break;
275*0fca6ea1SDimitry Andric     case Decoration::HostAccessINTEL:
276*0fca6ea1SDimitry Andric       printOperand(MI, NumFixedOps, O);
277*0fca6ea1SDimitry Andric       if (NumFixedOps + 1 < MI->getNumOperands()) {
278*0fca6ea1SDimitry Andric         O << ' ';
279*0fca6ea1SDimitry Andric         printStringImm(MI, NumFixedOps + 1, O);
280*0fca6ea1SDimitry Andric       }
281*0fca6ea1SDimitry Andric       break;
28281ad6265SDimitry Andric     default:
28381ad6265SDimitry Andric       printRemainingVariableOps(MI, NumFixedOps, O, true);
28481ad6265SDimitry Andric       break;
28581ad6265SDimitry Andric     }
28681ad6265SDimitry Andric   }
28781ad6265SDimitry Andric }
28881ad6265SDimitry Andric 
28981ad6265SDimitry Andric static void printExpr(const MCExpr *Expr, raw_ostream &O) {
29081ad6265SDimitry Andric #ifndef NDEBUG
29181ad6265SDimitry Andric   const MCSymbolRefExpr *SRE;
29281ad6265SDimitry Andric 
29381ad6265SDimitry Andric   if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr))
29481ad6265SDimitry Andric     SRE = cast<MCSymbolRefExpr>(BE->getLHS());
29581ad6265SDimitry Andric   else
29681ad6265SDimitry Andric     SRE = cast<MCSymbolRefExpr>(Expr);
29781ad6265SDimitry Andric 
29881ad6265SDimitry Andric   MCSymbolRefExpr::VariantKind Kind = SRE->getKind();
29981ad6265SDimitry Andric 
30081ad6265SDimitry Andric   assert(Kind == MCSymbolRefExpr::VK_None);
30181ad6265SDimitry Andric #endif
30281ad6265SDimitry Andric   O << *Expr;
30381ad6265SDimitry Andric }
30481ad6265SDimitry Andric 
30581ad6265SDimitry Andric void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
30681ad6265SDimitry Andric                                     raw_ostream &O, const char *Modifier) {
30781ad6265SDimitry Andric   assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
30881ad6265SDimitry Andric   if (OpNo < MI->getNumOperands()) {
30981ad6265SDimitry Andric     const MCOperand &Op = MI->getOperand(OpNo);
31081ad6265SDimitry Andric     if (Op.isReg())
31181ad6265SDimitry Andric       O << '%' << (Register::virtReg2Index(Op.getReg()) + 1);
31281ad6265SDimitry Andric     else if (Op.isImm())
31381ad6265SDimitry Andric       O << formatImm((int64_t)Op.getImm());
31481ad6265SDimitry Andric     else if (Op.isDFPImm())
31581ad6265SDimitry Andric       O << formatImm((double)Op.getDFPImm());
31681ad6265SDimitry Andric     else if (Op.isExpr())
31781ad6265SDimitry Andric       printExpr(Op.getExpr(), O);
31881ad6265SDimitry Andric     else
31981ad6265SDimitry Andric       llvm_unreachable("Unexpected operand type");
32081ad6265SDimitry Andric   }
32181ad6265SDimitry Andric }
32281ad6265SDimitry Andric 
32381ad6265SDimitry Andric void SPIRVInstPrinter::printStringImm(const MCInst *MI, unsigned OpNo,
32481ad6265SDimitry Andric                                       raw_ostream &O) {
32581ad6265SDimitry Andric   const unsigned NumOps = MI->getNumOperands();
32681ad6265SDimitry Andric   unsigned StrStartIndex = OpNo;
32781ad6265SDimitry Andric   while (StrStartIndex < NumOps) {
32881ad6265SDimitry Andric     if (MI->getOperand(StrStartIndex).isReg())
32981ad6265SDimitry Andric       break;
33081ad6265SDimitry Andric 
331*0fca6ea1SDimitry Andric     std::string Str = getSPIRVStringOperand(*MI, StrStartIndex);
33281ad6265SDimitry Andric     if (StrStartIndex != OpNo)
33381ad6265SDimitry Andric       O << ' '; // Add a space if we're starting a new string/argument.
33481ad6265SDimitry Andric     O << '"';
33581ad6265SDimitry Andric     for (char c : Str) {
336*0fca6ea1SDimitry Andric       // Escape ", \n characters (might break for complex UTF-8).
337*0fca6ea1SDimitry Andric       if (c == '\n') {
338*0fca6ea1SDimitry Andric         O.write("\\n", 2);
339*0fca6ea1SDimitry Andric       } else {
34081ad6265SDimitry Andric         if (c == '"')
341*0fca6ea1SDimitry Andric           O.write('\\');
34281ad6265SDimitry Andric         O.write(c);
34381ad6265SDimitry Andric       }
344*0fca6ea1SDimitry Andric     }
34581ad6265SDimitry Andric     O << '"';
34681ad6265SDimitry Andric 
34781ad6265SDimitry Andric     unsigned numOpsInString = (Str.size() / 4) + 1;
34881ad6265SDimitry Andric     StrStartIndex += numOpsInString;
34981ad6265SDimitry Andric 
35081ad6265SDimitry Andric     // Check for final Op of "OpDecorate %x %stringImm %linkageAttribute".
35181ad6265SDimitry Andric     if (MI->getOpcode() == SPIRV::OpDecorate &&
35281ad6265SDimitry Andric         MI->getOperand(1).getImm() ==
353bdd1243dSDimitry Andric             static_cast<unsigned>(Decoration::LinkageAttributes)) {
35481ad6265SDimitry Andric       O << ' ';
355bdd1243dSDimitry Andric       printSymbolicOperand<OperandCategory::LinkageTypeOperand>(
356bdd1243dSDimitry Andric           MI, StrStartIndex, O);
35781ad6265SDimitry Andric       break;
35881ad6265SDimitry Andric     }
35981ad6265SDimitry Andric   }
36081ad6265SDimitry Andric }
36181ad6265SDimitry Andric 
362bdd1243dSDimitry Andric void SPIRVInstPrinter::printExtension(const MCInst *MI, unsigned OpNo,
36381ad6265SDimitry Andric                                       raw_ostream &O) {
364bdd1243dSDimitry Andric   auto SetReg = MI->getOperand(2).getReg();
365bdd1243dSDimitry Andric   auto Set = ExtInstSetIDs[SetReg];
366bdd1243dSDimitry Andric   auto Op = MI->getOperand(OpNo).getImm();
367bdd1243dSDimitry Andric   O << getExtInstName(Set, Op);
36881ad6265SDimitry Andric }
36981ad6265SDimitry Andric 
370bdd1243dSDimitry Andric template <OperandCategory::OperandCategory category>
371bdd1243dSDimitry Andric void SPIRVInstPrinter::printSymbolicOperand(const MCInst *MI, unsigned OpNo,
37281ad6265SDimitry Andric                                             raw_ostream &O) {
37381ad6265SDimitry Andric   if (OpNo < MI->getNumOperands()) {
374bdd1243dSDimitry Andric     O << getSymbolicOperandMnemonic(category, MI->getOperand(OpNo).getImm());
37581ad6265SDimitry Andric   }
37681ad6265SDimitry Andric }
377