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
printRemainingVariableOps(const MCInst * MI,unsigned StartIndex,raw_ostream & O,bool SkipFirstSpace,bool SkipImmediates)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
printOpConstantVarOps(const MCInst * MI,unsigned StartIndex,raw_ostream & O)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
recordOpExtInstImport(const MCInst * MI)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
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & OS)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
printOpExtInst(const MCInst * MI,raw_ostream & O)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
printOpDecorate(const MCInst * MI,raw_ostream & O)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
printExpr(const MCExpr * Expr,raw_ostream & O)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
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O,const char * Modifier)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
printStringImm(const MCInst * MI,unsigned OpNo,raw_ostream & O)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
printExtension(const MCInst * MI,unsigned OpNo,raw_ostream & O)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>
printSymbolicOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)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