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