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 // TODO: insert {Reg, Set} into ExtInstSetIDs map. 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 // The fixed operands have already been printed, so just need to decide what 180 // type of ExtInst operands to print based on the instruction set and number. 181 MCInstrDesc MCDesc = MII.get(MI->getOpcode()); 182 unsigned NumFixedOps = MCDesc.getNumOperands(); 183 const auto NumOps = MI->getNumOperands(); 184 if (NumOps == NumFixedOps) 185 return; 186 187 O << ' '; 188 189 // TODO: implement special printing for OpenCLExtInst::vstor*. 190 printRemainingVariableOps(MI, NumFixedOps, O, true); 191 } 192 193 void SPIRVInstPrinter::printOpDecorate(const MCInst *MI, raw_ostream &O) { 194 // The fixed operands have already been printed, so just need to decide what 195 // type of decoration operands to print based on the Decoration type. 196 MCInstrDesc MCDesc = MII.get(MI->getOpcode()); 197 unsigned NumFixedOps = MCDesc.getNumOperands(); 198 199 if (NumFixedOps != MI->getNumOperands()) { 200 auto DecOp = MI->getOperand(NumFixedOps - 1); 201 auto Dec = static_cast<SPIRV::Decoration>(DecOp.getImm()); 202 203 O << ' '; 204 205 switch (Dec) { 206 case SPIRV::Decoration::BuiltIn: 207 printBuiltIn(MI, NumFixedOps, O); 208 break; 209 case SPIRV::Decoration::UniformId: 210 printScope(MI, NumFixedOps, O); 211 break; 212 case SPIRV::Decoration::FuncParamAttr: 213 printFunctionParameterAttribute(MI, NumFixedOps, O); 214 break; 215 case SPIRV::Decoration::FPRoundingMode: 216 printFPRoundingMode(MI, NumFixedOps, O); 217 break; 218 case SPIRV::Decoration::FPFastMathMode: 219 printFPFastMathMode(MI, NumFixedOps, O); 220 break; 221 case SPIRV::Decoration::LinkageAttributes: 222 case SPIRV::Decoration::UserSemantic: 223 printStringImm(MI, NumFixedOps, O); 224 break; 225 default: 226 printRemainingVariableOps(MI, NumFixedOps, O, true); 227 break; 228 } 229 } 230 } 231 232 static void printExpr(const MCExpr *Expr, raw_ostream &O) { 233 #ifndef NDEBUG 234 const MCSymbolRefExpr *SRE; 235 236 if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) 237 SRE = cast<MCSymbolRefExpr>(BE->getLHS()); 238 else 239 SRE = cast<MCSymbolRefExpr>(Expr); 240 241 MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); 242 243 assert(Kind == MCSymbolRefExpr::VK_None); 244 #endif 245 O << *Expr; 246 } 247 248 void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 249 raw_ostream &O, const char *Modifier) { 250 assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); 251 if (OpNo < MI->getNumOperands()) { 252 const MCOperand &Op = MI->getOperand(OpNo); 253 if (Op.isReg()) 254 O << '%' << (Register::virtReg2Index(Op.getReg()) + 1); 255 else if (Op.isImm()) 256 O << formatImm((int64_t)Op.getImm()); 257 else if (Op.isDFPImm()) 258 O << formatImm((double)Op.getDFPImm()); 259 else if (Op.isExpr()) 260 printExpr(Op.getExpr(), O); 261 else 262 llvm_unreachable("Unexpected operand type"); 263 } 264 } 265 266 void SPIRVInstPrinter::printStringImm(const MCInst *MI, unsigned OpNo, 267 raw_ostream &O) { 268 const unsigned NumOps = MI->getNumOperands(); 269 unsigned StrStartIndex = OpNo; 270 while (StrStartIndex < NumOps) { 271 if (MI->getOperand(StrStartIndex).isReg()) 272 break; 273 274 std::string Str = getSPIRVStringOperand(*MI, OpNo); 275 if (StrStartIndex != OpNo) 276 O << ' '; // Add a space if we're starting a new string/argument. 277 O << '"'; 278 for (char c : Str) { 279 if (c == '"') 280 O.write('\\'); // Escape " characters (might break for complex UTF-8). 281 O.write(c); 282 } 283 O << '"'; 284 285 unsigned numOpsInString = (Str.size() / 4) + 1; 286 StrStartIndex += numOpsInString; 287 288 // Check for final Op of "OpDecorate %x %stringImm %linkageAttribute". 289 if (MI->getOpcode() == SPIRV::OpDecorate && 290 MI->getOperand(1).getImm() == 291 static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) { 292 O << ' '; 293 printLinkageType(MI, StrStartIndex, O); 294 break; 295 } 296 } 297 } 298 299 void SPIRVInstPrinter::printExtInst(const MCInst *MI, unsigned OpNo, 300 raw_ostream &O) { 301 llvm_unreachable("Unimplemented printExtInst"); 302 } 303 304 void SPIRVInstPrinter::printCapability(const MCInst *MI, unsigned OpNo, 305 raw_ostream &O) { 306 if (OpNo < MI->getNumOperands()) { 307 SPIRV::Capability e = 308 static_cast<SPIRV::Capability>(MI->getOperand(OpNo).getImm()); 309 O << SPIRV::getCapabilityName(e); 310 } 311 } 312 313 void SPIRVInstPrinter::printSourceLanguage(const MCInst *MI, unsigned OpNo, 314 raw_ostream &O) { 315 if (OpNo < MI->getNumOperands()) { 316 SPIRV::SourceLanguage e = 317 static_cast<SPIRV::SourceLanguage>(MI->getOperand(OpNo).getImm()); 318 O << SPIRV::getSourceLanguageName(e); 319 } 320 } 321 322 void SPIRVInstPrinter::printExecutionModel(const MCInst *MI, unsigned OpNo, 323 raw_ostream &O) { 324 if (OpNo < MI->getNumOperands()) { 325 SPIRV::ExecutionModel e = 326 static_cast<SPIRV::ExecutionModel>(MI->getOperand(OpNo).getImm()); 327 O << SPIRV::getExecutionModelName(e); 328 } 329 } 330 331 void SPIRVInstPrinter::printAddressingModel(const MCInst *MI, unsigned OpNo, 332 raw_ostream &O) { 333 if (OpNo < MI->getNumOperands()) { 334 SPIRV::AddressingModel e = 335 static_cast<SPIRV::AddressingModel>(MI->getOperand(OpNo).getImm()); 336 O << SPIRV::getAddressingModelName(e); 337 } 338 } 339 340 void SPIRVInstPrinter::printMemoryModel(const MCInst *MI, unsigned OpNo, 341 raw_ostream &O) { 342 if (OpNo < MI->getNumOperands()) { 343 SPIRV::MemoryModel e = 344 static_cast<SPIRV::MemoryModel>(MI->getOperand(OpNo).getImm()); 345 O << SPIRV::getMemoryModelName(e); 346 } 347 } 348 349 void SPIRVInstPrinter::printExecutionMode(const MCInst *MI, unsigned OpNo, 350 raw_ostream &O) { 351 if (OpNo < MI->getNumOperands()) { 352 SPIRV::ExecutionMode e = 353 static_cast<SPIRV::ExecutionMode>(MI->getOperand(OpNo).getImm()); 354 O << SPIRV::getExecutionModeName(e); 355 } 356 } 357 358 void SPIRVInstPrinter::printStorageClass(const MCInst *MI, unsigned OpNo, 359 raw_ostream &O) { 360 if (OpNo < MI->getNumOperands()) { 361 SPIRV::StorageClass e = 362 static_cast<SPIRV::StorageClass>(MI->getOperand(OpNo).getImm()); 363 O << SPIRV::getStorageClassName(e); 364 } 365 } 366 367 void SPIRVInstPrinter::printDim(const MCInst *MI, unsigned OpNo, 368 raw_ostream &O) { 369 if (OpNo < MI->getNumOperands()) { 370 SPIRV::Dim e = static_cast<SPIRV::Dim>(MI->getOperand(OpNo).getImm()); 371 O << SPIRV::getDimName(e); 372 } 373 } 374 375 void SPIRVInstPrinter::printSamplerAddressingMode(const MCInst *MI, 376 unsigned OpNo, 377 raw_ostream &O) { 378 if (OpNo < MI->getNumOperands()) { 379 SPIRV::SamplerAddressingMode e = static_cast<SPIRV::SamplerAddressingMode>( 380 MI->getOperand(OpNo).getImm()); 381 O << SPIRV::getSamplerAddressingModeName(e); 382 } 383 } 384 385 void SPIRVInstPrinter::printSamplerFilterMode(const MCInst *MI, unsigned OpNo, 386 raw_ostream &O) { 387 if (OpNo < MI->getNumOperands()) { 388 SPIRV::SamplerFilterMode e = 389 static_cast<SPIRV::SamplerFilterMode>(MI->getOperand(OpNo).getImm()); 390 O << SPIRV::getSamplerFilterModeName(e); 391 } 392 } 393 394 void SPIRVInstPrinter::printImageFormat(const MCInst *MI, unsigned OpNo, 395 raw_ostream &O) { 396 if (OpNo < MI->getNumOperands()) { 397 SPIRV::ImageFormat e = 398 static_cast<SPIRV::ImageFormat>(MI->getOperand(OpNo).getImm()); 399 O << SPIRV::getImageFormatName(e); 400 } 401 } 402 403 void SPIRVInstPrinter::printImageChannelOrder(const MCInst *MI, unsigned OpNo, 404 raw_ostream &O) { 405 if (OpNo < MI->getNumOperands()) { 406 SPIRV::ImageChannelOrder e = 407 static_cast<SPIRV::ImageChannelOrder>(MI->getOperand(OpNo).getImm()); 408 O << SPIRV::getImageChannelOrderName(e); 409 } 410 } 411 412 void SPIRVInstPrinter::printImageChannelDataType(const MCInst *MI, 413 unsigned OpNo, 414 raw_ostream &O) { 415 if (OpNo < MI->getNumOperands()) { 416 SPIRV::ImageChannelDataType e = 417 static_cast<SPIRV::ImageChannelDataType>(MI->getOperand(OpNo).getImm()); 418 O << SPIRV::getImageChannelDataTypeName(e); 419 } 420 } 421 422 void SPIRVInstPrinter::printImageOperand(const MCInst *MI, unsigned OpNo, 423 raw_ostream &O) { 424 if (OpNo < MI->getNumOperands()) { 425 unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm()); 426 O << SPIRV::getImageOperandName(e); 427 } 428 } 429 430 void SPIRVInstPrinter::printFPFastMathMode(const MCInst *MI, unsigned OpNo, 431 raw_ostream &O) { 432 if (OpNo < MI->getNumOperands()) { 433 unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm()); 434 O << SPIRV::getFPFastMathModeName(e); 435 } 436 } 437 438 void SPIRVInstPrinter::printFPRoundingMode(const MCInst *MI, unsigned OpNo, 439 raw_ostream &O) { 440 if (OpNo < MI->getNumOperands()) { 441 SPIRV::FPRoundingMode e = 442 static_cast<SPIRV::FPRoundingMode>(MI->getOperand(OpNo).getImm()); 443 O << SPIRV::getFPRoundingModeName(e); 444 } 445 } 446 447 void SPIRVInstPrinter::printLinkageType(const MCInst *MI, unsigned OpNo, 448 raw_ostream &O) { 449 if (OpNo < MI->getNumOperands()) { 450 SPIRV::LinkageType e = 451 static_cast<SPIRV::LinkageType>(MI->getOperand(OpNo).getImm()); 452 O << SPIRV::getLinkageTypeName(e); 453 } 454 } 455 456 void SPIRVInstPrinter::printAccessQualifier(const MCInst *MI, unsigned OpNo, 457 raw_ostream &O) { 458 if (OpNo < MI->getNumOperands()) { 459 SPIRV::AccessQualifier e = 460 static_cast<SPIRV::AccessQualifier>(MI->getOperand(OpNo).getImm()); 461 O << SPIRV::getAccessQualifierName(e); 462 } 463 } 464 465 void SPIRVInstPrinter::printFunctionParameterAttribute(const MCInst *MI, 466 unsigned OpNo, 467 raw_ostream &O) { 468 if (OpNo < MI->getNumOperands()) { 469 SPIRV::FunctionParameterAttribute e = 470 static_cast<SPIRV::FunctionParameterAttribute>( 471 MI->getOperand(OpNo).getImm()); 472 O << SPIRV::getFunctionParameterAttributeName(e); 473 } 474 } 475 476 void SPIRVInstPrinter::printDecoration(const MCInst *MI, unsigned OpNo, 477 raw_ostream &O) { 478 if (OpNo < MI->getNumOperands()) { 479 SPIRV::Decoration e = 480 static_cast<SPIRV::Decoration>(MI->getOperand(OpNo).getImm()); 481 O << SPIRV::getDecorationName(e); 482 } 483 } 484 485 void SPIRVInstPrinter::printBuiltIn(const MCInst *MI, unsigned OpNo, 486 raw_ostream &O) { 487 if (OpNo < MI->getNumOperands()) { 488 SPIRV::BuiltIn e = 489 static_cast<SPIRV::BuiltIn>(MI->getOperand(OpNo).getImm()); 490 O << SPIRV::getBuiltInName(e); 491 } 492 } 493 494 void SPIRVInstPrinter::printSelectionControl(const MCInst *MI, unsigned OpNo, 495 raw_ostream &O) { 496 if (OpNo < MI->getNumOperands()) { 497 unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm()); 498 O << SPIRV::getSelectionControlName(e); 499 } 500 } 501 502 void SPIRVInstPrinter::printLoopControl(const MCInst *MI, unsigned OpNo, 503 raw_ostream &O) { 504 if (OpNo < MI->getNumOperands()) { 505 unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm()); 506 O << SPIRV::getLoopControlName(e); 507 } 508 } 509 510 void SPIRVInstPrinter::printFunctionControl(const MCInst *MI, unsigned OpNo, 511 raw_ostream &O) { 512 if (OpNo < MI->getNumOperands()) { 513 unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm()); 514 O << SPIRV::getFunctionControlName(e); 515 } 516 } 517 518 void SPIRVInstPrinter::printMemorySemantics(const MCInst *MI, unsigned OpNo, 519 raw_ostream &O) { 520 if (OpNo < MI->getNumOperands()) { 521 unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm()); 522 O << SPIRV::getMemorySemanticsName(e); 523 } 524 } 525 526 void SPIRVInstPrinter::printMemoryOperand(const MCInst *MI, unsigned OpNo, 527 raw_ostream &O) { 528 if (OpNo < MI->getNumOperands()) { 529 unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm()); 530 O << SPIRV::getMemoryOperandName(e); 531 } 532 } 533 534 void SPIRVInstPrinter::printScope(const MCInst *MI, unsigned OpNo, 535 raw_ostream &O) { 536 if (OpNo < MI->getNumOperands()) { 537 SPIRV::Scope e = static_cast<SPIRV::Scope>(MI->getOperand(OpNo).getImm()); 538 O << SPIRV::getScopeName(e); 539 } 540 } 541 542 void SPIRVInstPrinter::printGroupOperation(const MCInst *MI, unsigned OpNo, 543 raw_ostream &O) { 544 if (OpNo < MI->getNumOperands()) { 545 SPIRV::GroupOperation e = 546 static_cast<SPIRV::GroupOperation>(MI->getOperand(OpNo).getImm()); 547 O << SPIRV::getGroupOperationName(e); 548 } 549 } 550 551 void SPIRVInstPrinter::printKernelEnqueueFlags(const MCInst *MI, unsigned OpNo, 552 raw_ostream &O) { 553 if (OpNo < MI->getNumOperands()) { 554 SPIRV::KernelEnqueueFlags e = 555 static_cast<SPIRV::KernelEnqueueFlags>(MI->getOperand(OpNo).getImm()); 556 O << SPIRV::getKernelEnqueueFlagsName(e); 557 } 558 } 559 560 void SPIRVInstPrinter::printKernelProfilingInfo(const MCInst *MI, unsigned OpNo, 561 raw_ostream &O) { 562 if (OpNo < MI->getNumOperands()) { 563 SPIRV::KernelProfilingInfo e = 564 static_cast<SPIRV::KernelProfilingInfo>(MI->getOperand(OpNo).getImm()); 565 O << SPIRV::getKernelProfilingInfoName(e); 566 } 567 } 568