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