1 //===- DXILEmitter.cpp - DXIL operation Emitter ---------------------------===// 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 // DXILEmitter uses the descriptions of DXIL operation to construct enum and 10 // helper functions for DXIL operation. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "Basic/SequenceToOffsetTable.h" 15 #include "Common/CodeGenTarget.h" 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/SmallSet.h" 18 #include "llvm/ADT/SmallVector.h" 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/ADT/StringSet.h" 21 #include "llvm/CodeGenTypes/MachineValueType.h" 22 #include "llvm/Support/DXILABI.h" 23 #include "llvm/Support/VersionTuple.h" 24 #include "llvm/TableGen/Error.h" 25 #include "llvm/TableGen/Record.h" 26 #include "llvm/TableGen/TableGenBackend.h" 27 28 #include <string> 29 #include <vector> 30 31 using namespace llvm; 32 using namespace llvm::dxil; 33 34 namespace { 35 36 struct DXILOperationDesc { 37 std::string OpName; // name of DXIL operation 38 int OpCode; // ID of DXIL operation 39 StringRef OpClass; // name of the opcode class 40 StringRef Doc; // the documentation description of this instruction 41 // Vector of operand type records - return type is at index 0 42 SmallVector<Record *> OpTypes; 43 SmallVector<Record *> OverloadRecs; 44 SmallVector<Record *> StageRecs; 45 SmallVector<Record *> AttrRecs; 46 StringRef Intrinsic; // The llvm intrinsic map to OpName. Default is "" which 47 // means no map exists 48 SmallVector<StringRef, 4> 49 ShaderStages; // shader stages to which this applies, empty for all. 50 int OverloadParamIndex; // Index of parameter with overload type. 51 // -1 : no overload types 52 SmallVector<StringRef, 4> counters; // counters for this inst. 53 DXILOperationDesc(const Record *); 54 }; 55 } // end anonymous namespace 56 57 /// Return dxil::ParameterKind corresponding to input LLVMType record 58 /// 59 /// \param R TableGen def record of class LLVMType 60 /// \return ParameterKind As defined in llvm/Support/DXILABI.h 61 62 static ParameterKind getParameterKind(const Record *R) { 63 auto VTRec = R->getValueAsDef("VT"); 64 switch (getValueType(VTRec)) { 65 case MVT::isVoid: 66 return ParameterKind::Void; 67 case MVT::f16: 68 return ParameterKind::Half; 69 case MVT::f32: 70 return ParameterKind::Float; 71 case MVT::f64: 72 return ParameterKind::Double; 73 case MVT::i1: 74 return ParameterKind::I1; 75 case MVT::i8: 76 return ParameterKind::I8; 77 case MVT::i16: 78 return ParameterKind::I16; 79 case MVT::i32: 80 return ParameterKind::I32; 81 case MVT::fAny: 82 case MVT::iAny: 83 case MVT::Any: 84 return ParameterKind::Overload; 85 default: 86 llvm_unreachable( 87 "Support for specified parameter type not yet implemented"); 88 } 89 } 90 91 /// In-place sort TableGen records of class with a field 92 /// Version dxil_version 93 /// in the ascending version order. 94 static void AscendingSortByVersion(std::vector<Record *> &Recs) { 95 std::sort(Recs.begin(), Recs.end(), [](Record *RecA, Record *RecB) { 96 unsigned RecAMaj = 97 RecA->getValueAsDef("dxil_version")->getValueAsInt("Major"); 98 unsigned RecAMin = 99 RecA->getValueAsDef("dxil_version")->getValueAsInt("Minor"); 100 unsigned RecBMaj = 101 RecB->getValueAsDef("dxil_version")->getValueAsInt("Major"); 102 unsigned RecBMin = 103 RecB->getValueAsDef("dxil_version")->getValueAsInt("Minor"); 104 105 return (VersionTuple(RecAMaj, RecAMin) < VersionTuple(RecBMaj, RecBMin)); 106 }); 107 } 108 109 /// Construct an object using the DXIL Operation records specified 110 /// in DXIL.td. This serves as the single source of reference of 111 /// the information extracted from the specified Record R, for 112 /// C++ code generated by this TableGen backend. 113 // \param R Object representing TableGen record of a DXIL Operation 114 DXILOperationDesc::DXILOperationDesc(const Record *R) { 115 OpName = R->getNameInitAsString(); 116 OpCode = R->getValueAsInt("OpCode"); 117 118 Doc = R->getValueAsString("Doc"); 119 SmallVector<Record *> ParamTypeRecs; 120 121 ParamTypeRecs.push_back(R->getValueAsDef("result")); 122 123 std::vector<Record *> ArgTys = R->getValueAsListOfDefs("arguments"); 124 for (auto Ty : ArgTys) { 125 ParamTypeRecs.push_back(Ty); 126 } 127 size_t ParamTypeRecsSize = ParamTypeRecs.size(); 128 // Populate OpTypes with return type and parameter types 129 130 // Parameter indices of overloaded parameters. 131 // This vector contains overload parameters in the order used to 132 // resolve an LLVMMatchType in accordance with convention outlined in 133 // the comment before the definition of class LLVMMatchType in 134 // llvm/IR/Intrinsics.td 135 SmallVector<int> OverloadParamIndices; 136 for (unsigned i = 0; i < ParamTypeRecsSize; i++) { 137 auto TR = ParamTypeRecs[i]; 138 // Track operation parameter indices of any overload types 139 auto isAny = TR->getValueAsInt("isAny"); 140 if (isAny == 1) { 141 // All overload types in a DXIL Op are required to be of the same type. 142 if (!OverloadParamIndices.empty()) { 143 [[maybe_unused]] bool knownType = true; 144 // Ensure that the same overload type registered earlier is being used 145 for (auto Idx : OverloadParamIndices) { 146 if (TR != ParamTypeRecs[Idx]) { 147 knownType = false; 148 break; 149 } 150 } 151 assert(knownType && "Specification of multiple differing overload " 152 "parameter types not yet supported"); 153 } else { 154 OverloadParamIndices.push_back(i); 155 } 156 } 157 // Populate OpTypes array according to the type specification 158 if (TR->isAnonymous()) { 159 // Check prior overload types exist 160 assert(!OverloadParamIndices.empty() && 161 "No prior overloaded parameter found to match."); 162 // Get the parameter index of anonymous type, TR, references 163 auto OLParamIndex = TR->getValueAsInt("Number"); 164 // Resolve and insert the type to that at OLParamIndex 165 OpTypes.emplace_back(ParamTypeRecs[OLParamIndex]); 166 } else { 167 // A non-anonymous type. Just record it in OpTypes 168 OpTypes.emplace_back(TR); 169 } 170 } 171 172 // Set the index of the overload parameter, if any. 173 OverloadParamIndex = -1; // default; indicating none 174 if (!OverloadParamIndices.empty()) { 175 assert(OverloadParamIndices.size() == 1 && 176 "Multiple overload type specification not supported"); 177 OverloadParamIndex = OverloadParamIndices[0]; 178 } 179 180 // Get overload records 181 std::vector<Record *> Recs = R->getValueAsListOfDefs("overloads"); 182 183 // Sort records in ascending order of DXIL version 184 AscendingSortByVersion(Recs); 185 186 for (Record *CR : Recs) { 187 OverloadRecs.push_back(CR); 188 } 189 190 // Get stage records 191 Recs = R->getValueAsListOfDefs("stages"); 192 193 if (Recs.empty()) { 194 PrintFatalError(R, Twine("Atleast one specification of valid stage for ") + 195 OpName + " is required"); 196 } 197 198 // Sort records in ascending order of DXIL version 199 AscendingSortByVersion(Recs); 200 201 for (Record *CR : Recs) { 202 StageRecs.push_back(CR); 203 } 204 205 // Get attribute records 206 Recs = R->getValueAsListOfDefs("attributes"); 207 208 // Sort records in ascending order of DXIL version 209 AscendingSortByVersion(Recs); 210 211 for (Record *CR : Recs) { 212 AttrRecs.push_back(CR); 213 } 214 215 // Get the operation class 216 OpClass = R->getValueAsDef("OpClass")->getName(); 217 218 if (!OpClass.str().compare("UnknownOpClass")) { 219 PrintFatalError(R, Twine("Unspecified DXIL OpClass for DXIL operation - ") + 220 OpName); 221 } 222 223 const RecordVal *RV = R->getValue("LLVMIntrinsic"); 224 if (RV && RV->getValue()) { 225 if (DefInit *DI = dyn_cast<DefInit>(RV->getValue())) { 226 auto *IntrinsicDef = DI->getDef(); 227 auto DefName = IntrinsicDef->getName(); 228 assert(DefName.starts_with("int_") && "invalid intrinsic name"); 229 // Remove the int_ from intrinsic name. 230 Intrinsic = DefName.substr(4); 231 } 232 } 233 } 234 235 /// Return a string representation of ParameterKind enum 236 /// \param Kind Parameter Kind enum value 237 /// \return std::string string representation of input Kind 238 static std::string getParameterKindStr(ParameterKind Kind) { 239 switch (Kind) { 240 case ParameterKind::Invalid: 241 return "Invalid"; 242 case ParameterKind::Void: 243 return "Void"; 244 case ParameterKind::Half: 245 return "Half"; 246 case ParameterKind::Float: 247 return "Float"; 248 case ParameterKind::Double: 249 return "Double"; 250 case ParameterKind::I1: 251 return "I1"; 252 case ParameterKind::I8: 253 return "I8"; 254 case ParameterKind::I16: 255 return "I16"; 256 case ParameterKind::I32: 257 return "I32"; 258 case ParameterKind::I64: 259 return "I64"; 260 case ParameterKind::Overload: 261 return "Overload"; 262 case ParameterKind::CBufferRet: 263 return "CBufferRet"; 264 case ParameterKind::ResourceRet: 265 return "ResourceRet"; 266 case ParameterKind::DXILHandle: 267 return "DXILHandle"; 268 } 269 llvm_unreachable("Unknown llvm::dxil::ParameterKind enum"); 270 } 271 272 /// Return a string representation of OverloadKind enum that maps to 273 /// input LLVMType record 274 /// \param R TableGen def record of class LLVMType 275 /// \return std::string string representation of OverloadKind 276 277 static std::string getOverloadKindStr(const Record *R) { 278 Record *VTRec = R->getValueAsDef("VT"); 279 switch (getValueType(VTRec)) { 280 case MVT::f16: 281 return "OverloadKind::HALF"; 282 case MVT::f32: 283 return "OverloadKind::FLOAT"; 284 case MVT::f64: 285 return "OverloadKind::DOUBLE"; 286 case MVT::i1: 287 return "OverloadKind::I1"; 288 case MVT::i8: 289 return "OverloadKind::I8"; 290 case MVT::i16: 291 return "OverloadKind::I16"; 292 case MVT::i32: 293 return "OverloadKind::I32"; 294 case MVT::i64: 295 return "OverloadKind::I64"; 296 default: 297 llvm_unreachable("Support for specified fixed type option for overload " 298 "type not supported"); 299 } 300 } 301 302 /// Return a string representation of valid overload information denoted 303 // by input records 304 // 305 /// \param Recs A vector of records of TableGen Overload records 306 /// \return std::string string representation of overload mask string 307 /// predicated by DXIL Version. E.g., 308 // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...} 309 static std::string getOverloadMaskString(const SmallVector<Record *> Recs) { 310 std::string MaskString = ""; 311 std::string Prefix = ""; 312 MaskString.append("{"); 313 // If no overload information records were specified, assume the operation 314 // a) to be supported in DXIL Version 1.0 and later 315 // b) has no overload types 316 if (Recs.empty()) { 317 MaskString.append("{{1, 0}, OverloadKind::UNDEFINED}}"); 318 } else { 319 for (auto Rec : Recs) { 320 unsigned Major = 321 Rec->getValueAsDef("dxil_version")->getValueAsInt("Major"); 322 unsigned Minor = 323 Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor"); 324 MaskString.append(Prefix) 325 .append("{{") 326 .append(std::to_string(Major)) 327 .append(", ") 328 .append(std::to_string(Minor).append("}, ")); 329 330 std::string PipePrefix = ""; 331 auto Tys = Rec->getValueAsListOfDefs("overload_types"); 332 if (Tys.empty()) { 333 MaskString.append("OverloadKind::UNDEFINED"); 334 } 335 for (const auto *Ty : Tys) { 336 MaskString.append(PipePrefix).append(getOverloadKindStr(Ty)); 337 PipePrefix = " | "; 338 } 339 340 MaskString.append("}"); 341 Prefix = ", "; 342 } 343 MaskString.append("}"); 344 } 345 return MaskString; 346 } 347 348 /// Return a string representation of valid shader stag information denoted 349 // by input records 350 // 351 /// \param Recs A vector of records of TableGen Stages records 352 /// \return std::string string representation of stages mask string 353 /// predicated by DXIL Version. E.g., 354 // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...} 355 static std::string getStageMaskString(const SmallVector<Record *> Recs) { 356 std::string MaskString = ""; 357 std::string Prefix = ""; 358 MaskString.append("{"); 359 // Atleast one stage information record is expected to be specified. 360 if (Recs.empty()) { 361 PrintFatalError("Atleast one specification of valid stages for " 362 "operation must be specified"); 363 } 364 365 for (auto Rec : Recs) { 366 unsigned Major = Rec->getValueAsDef("dxil_version")->getValueAsInt("Major"); 367 unsigned Minor = Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor"); 368 MaskString.append(Prefix) 369 .append("{{") 370 .append(std::to_string(Major)) 371 .append(", ") 372 .append(std::to_string(Minor).append("}, ")); 373 374 std::string PipePrefix = ""; 375 auto Stages = Rec->getValueAsListOfDefs("shader_stages"); 376 if (Stages.empty()) { 377 PrintFatalError("No valid stages for operation specified"); 378 } 379 for (const auto *S : Stages) { 380 MaskString.append(PipePrefix).append("ShaderKind::").append(S->getName()); 381 PipePrefix = " | "; 382 } 383 384 MaskString.append("}"); 385 Prefix = ", "; 386 } 387 MaskString.append("}"); 388 return MaskString; 389 } 390 391 /// Return a string representation of valid attribute information denoted 392 // by input records 393 // 394 /// \param Recs A vector of records of TableGen Attribute records 395 /// \return std::string string representation of stages mask string 396 /// predicated by DXIL Version. E.g., 397 // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...} 398 static std::string getAttributeMaskString(const SmallVector<Record *> Recs) { 399 std::string MaskString = ""; 400 std::string Prefix = ""; 401 MaskString.append("{"); 402 403 for (auto Rec : Recs) { 404 unsigned Major = Rec->getValueAsDef("dxil_version")->getValueAsInt("Major"); 405 unsigned Minor = Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor"); 406 MaskString.append(Prefix) 407 .append("{{") 408 .append(std::to_string(Major)) 409 .append(", ") 410 .append(std::to_string(Minor).append("}, ")); 411 412 std::string PipePrefix = ""; 413 auto Attrs = Rec->getValueAsListOfDefs("op_attrs"); 414 if (Attrs.empty()) { 415 MaskString.append("Attribute::None"); 416 } else { 417 for (const auto *Attr : Attrs) { 418 MaskString.append(PipePrefix) 419 .append("Attribute::") 420 .append(Attr->getName()); 421 PipePrefix = " | "; 422 } 423 } 424 425 MaskString.append("}"); 426 Prefix = ", "; 427 } 428 MaskString.append("}"); 429 return MaskString; 430 } 431 432 /// Emit Enums of DXIL Ops 433 /// \param A vector of DXIL Ops 434 /// \param Output stream 435 static void emitDXILEnums(std::vector<DXILOperationDesc> &Ops, 436 raw_ostream &OS) { 437 OS << "#ifdef DXIL_OP_ENUM\n\n"; 438 OS << "// Enumeration for operations specified by DXIL\n"; 439 OS << "enum class OpCode : unsigned {\n"; 440 441 for (auto &Op : Ops) { 442 // Name = ID, // Doc 443 OS << Op.OpName << " = " << Op.OpCode << ", // " << Op.Doc << "\n"; 444 } 445 446 OS << "\n};\n\n"; 447 448 OS << "// Groups for DXIL operations with equivalent function templates\n"; 449 OS << "enum class OpCodeClass : unsigned {\n"; 450 // Build an OpClass set to print 451 SmallSet<StringRef, 2> OpClassSet; 452 for (auto &Op : Ops) { 453 OpClassSet.insert(Op.OpClass); 454 } 455 for (auto &C : OpClassSet) { 456 OS << C << ",\n"; 457 } 458 OS << "\n};\n\n"; 459 OS << "#undef DXIL_OP_ENUM\n"; 460 OS << "#endif\n\n"; 461 } 462 463 /// Emit map of DXIL operation to LLVM or DirectX intrinsic 464 /// \param A vector of DXIL Ops 465 /// \param Output stream 466 static void emitDXILIntrinsicMap(std::vector<DXILOperationDesc> &Ops, 467 raw_ostream &OS) { 468 OS << "#ifdef DXIL_OP_INTRINSIC\n"; 469 OS << "\n"; 470 for (const auto &Op : Ops) { 471 if (Op.Intrinsic.empty()) 472 continue; 473 OS << "DXIL_OP_INTRINSIC(dxil::OpCode::" << Op.OpName 474 << ", Intrinsic::" << Op.Intrinsic << ")\n"; 475 } 476 OS << "\n"; 477 OS << "#undef DXIL_OP_INTRINSIC\n"; 478 OS << "#endif\n\n"; 479 } 480 481 /// Emit DXIL operation table 482 /// \param A vector of DXIL Ops 483 /// \param Output stream 484 static void emitDXILOperationTable(std::vector<DXILOperationDesc> &Ops, 485 raw_ostream &OS) { 486 // Collect Names. 487 SequenceToOffsetTable<std::string> OpClassStrings; 488 SequenceToOffsetTable<std::string> OpStrings; 489 SequenceToOffsetTable<SmallVector<ParameterKind>> Parameters; 490 491 StringMap<SmallVector<ParameterKind>> ParameterMap; 492 StringSet<> ClassSet; 493 for (auto &Op : Ops) { 494 OpStrings.add(Op.OpName); 495 496 if (ClassSet.contains(Op.OpClass)) 497 continue; 498 ClassSet.insert(Op.OpClass); 499 OpClassStrings.add(Op.OpClass.data()); 500 SmallVector<ParameterKind> ParamKindVec; 501 // ParamKindVec is a vector of parameters. Skip return type at index 0 502 for (unsigned i = 1; i < Op.OpTypes.size(); i++) { 503 ParamKindVec.emplace_back(getParameterKind(Op.OpTypes[i])); 504 } 505 ParameterMap[Op.OpClass] = ParamKindVec; 506 Parameters.add(ParamKindVec); 507 } 508 509 // Layout names. 510 OpStrings.layout(); 511 OpClassStrings.layout(); 512 Parameters.layout(); 513 514 // Emit access function getOpcodeProperty() that embeds DXIL Operation table 515 // with entries of type struct OpcodeProperty. 516 OS << "static const OpCodeProperty *getOpCodeProperty(dxil::OpCode Op) " 517 "{\n"; 518 519 OS << " static const OpCodeProperty OpCodeProps[] = {\n"; 520 std::string Prefix = ""; 521 for (auto &Op : Ops) { 522 // Consider Op.OverloadParamIndex as the overload parameter index, by 523 // default 524 auto OLParamIdx = Op.OverloadParamIndex; 525 // If no overload parameter index is set, treat first parameter type as 526 // overload type - unless the Op has no parameters, in which case treat the 527 // return type - as overload parameter to emit the appropriate overload kind 528 // enum. 529 if (OLParamIdx < 0) { 530 OLParamIdx = (Op.OpTypes.size() > 1) ? 1 : 0; 531 } 532 OS << Prefix << " { dxil::OpCode::" << Op.OpName << ", " 533 << OpStrings.get(Op.OpName) << ", OpCodeClass::" << Op.OpClass << ", " 534 << OpClassStrings.get(Op.OpClass.data()) << ", " 535 << getOverloadMaskString(Op.OverloadRecs) << ", " 536 << getStageMaskString(Op.StageRecs) << ", " 537 << getAttributeMaskString(Op.AttrRecs) << ", " << Op.OverloadParamIndex 538 << ", " << Op.OpTypes.size() - 1 << ", " 539 << Parameters.get(ParameterMap[Op.OpClass]) << " }"; 540 Prefix = ",\n"; 541 } 542 OS << " };\n"; 543 544 OS << " // FIXME: change search to indexing with\n"; 545 OS << " // Op once all DXIL operations are added.\n"; 546 OS << " OpCodeProperty TmpProp;\n"; 547 OS << " TmpProp.OpCode = Op;\n"; 548 OS << " const OpCodeProperty *Prop =\n"; 549 OS << " llvm::lower_bound(OpCodeProps, TmpProp,\n"; 550 OS << " [](const OpCodeProperty &A, const " 551 "OpCodeProperty &B) {\n"; 552 OS << " return A.OpCode < B.OpCode;\n"; 553 OS << " });\n"; 554 OS << " assert(Prop && \"failed to find OpCodeProperty\");\n"; 555 OS << " return Prop;\n"; 556 OS << "}\n\n"; 557 558 // Emit the string tables. 559 OS << "static const char *getOpCodeName(dxil::OpCode Op) {\n\n"; 560 561 OpStrings.emitStringLiteralDef(OS, 562 " static const char DXILOpCodeNameTable[]"); 563 564 OS << " auto *Prop = getOpCodeProperty(Op);\n"; 565 OS << " unsigned Index = Prop->OpCodeNameOffset;\n"; 566 OS << " return DXILOpCodeNameTable + Index;\n"; 567 OS << "}\n\n"; 568 569 OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) " 570 "{\n\n"; 571 572 OpClassStrings.emitStringLiteralDef( 573 OS, " static const char DXILOpCodeClassNameTable[]"); 574 575 OS << " unsigned Index = Prop.OpCodeClassNameOffset;\n"; 576 OS << " return DXILOpCodeClassNameTable + Index;\n"; 577 OS << "}\n "; 578 579 OS << "static const ParameterKind *getOpCodeParameterKind(const " 580 "OpCodeProperty &Prop) " 581 "{\n\n"; 582 OS << " static const ParameterKind DXILOpParameterKindTable[] = {\n"; 583 Parameters.emit( 584 OS, 585 [](raw_ostream &ParamOS, ParameterKind Kind) { 586 ParamOS << "ParameterKind::" << getParameterKindStr(Kind); 587 }, 588 "ParameterKind::Invalid"); 589 OS << " };\n\n"; 590 OS << " unsigned Index = Prop.ParameterTableOffset;\n"; 591 OS << " return DXILOpParameterKindTable + Index;\n"; 592 OS << "}\n\n"; 593 } 594 595 static void emitDXILOperationTableDataStructs(RecordKeeper &Records, 596 raw_ostream &OS) { 597 // Get Shader stage records 598 std::vector<Record *> ShaderKindRecs = 599 Records.getAllDerivedDefinitions("DXILShaderStage"); 600 // Sort records by name 601 llvm::sort(ShaderKindRecs, 602 [](Record *A, Record *B) { return A->getName() < B->getName(); }); 603 604 OS << "// Valid shader kinds\n\n"; 605 // Choose the type of enum ShaderKind based on the number of stages declared. 606 // This gives the flexibility to just add add new stage records in DXIL.td, if 607 // needed, with no need to change this backend code. 608 size_t ShaderKindCount = ShaderKindRecs.size(); 609 uint64_t ShaderKindTySz = PowerOf2Ceil(ShaderKindRecs.size() + 1); 610 OS << "enum ShaderKind : uint" << ShaderKindTySz << "_t {\n"; 611 const std::string allStages("all_stages"); 612 const std::string removed("removed"); 613 int shiftVal = 1; 614 for (auto R : ShaderKindRecs) { 615 auto Name = R->getName(); 616 if (Name.compare(removed) == 0) { 617 OS << " " << Name 618 << " = 0, // Pseudo-stage indicating op not supported in any " 619 "stage\n"; 620 } else if (Name.compare(allStages) == 0) { 621 OS << " " << Name << " = 0x" 622 << utohexstr(((1 << ShaderKindCount) - 1), false, 0) 623 << ", // Pseudo-stage indicating op is supported in all stages\n"; 624 } else if (Name.compare(allStages)) { 625 OS << " " << Name << " = 1 << " << std::to_string(shiftVal++) << ",\n"; 626 } 627 } 628 OS << "}; // enum ShaderKind\n\n"; 629 } 630 631 /// Entry function call that invokes the functionality of this TableGen backend 632 /// \param Records TableGen records of DXIL Operations defined in DXIL.td 633 /// \param OS output stream 634 static void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) { 635 OS << "// Generated code, do not edit.\n"; 636 OS << "\n"; 637 // Get all DXIL Ops property records 638 std::vector<Record *> OpIntrProps = 639 Records.getAllDerivedDefinitions("DXILOp"); 640 std::vector<DXILOperationDesc> DXILOps; 641 for (auto *Record : OpIntrProps) { 642 DXILOps.emplace_back(DXILOperationDesc(Record)); 643 } 644 // Sort by opcode. 645 llvm::sort(DXILOps, [](DXILOperationDesc &A, DXILOperationDesc &B) { 646 return A.OpCode < B.OpCode; 647 }); 648 int PrevOp = -1; 649 for (DXILOperationDesc &Desc : DXILOps) { 650 if (Desc.OpCode == PrevOp) 651 PrintFatalError(Twine("Duplicate opcode: ") + Twine(Desc.OpCode)); 652 PrevOp = Desc.OpCode; 653 } 654 655 emitDXILEnums(DXILOps, OS); 656 emitDXILIntrinsicMap(DXILOps, OS); 657 OS << "#ifdef DXIL_OP_OPERATION_TABLE\n\n"; 658 emitDXILOperationTableDataStructs(Records, OS); 659 emitDXILOperationTable(DXILOps, OS); 660 OS << "#undef DXIL_OP_OPERATION_TABLE\n"; 661 OS << "#endif\n\n"; 662 } 663 664 static TableGen::Emitter::Opt X("gen-dxil-operation", EmitDXILOperation, 665 "Generate DXIL operation information"); 666