629 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// DXILEmitter uses the descriptions of DXIL operation to construct enum and10// 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/SmallVector.h"18#include "llvm/ADT/StringExtras.h"19#include "llvm/ADT/StringSet.h"20#include "llvm/ADT/StringSwitch.h"21#include "llvm/Support/DXILABI.h"22#include "llvm/Support/VersionTuple.h"23#include "llvm/TableGen/Error.h"24#include "llvm/TableGen/Record.h"25#include "llvm/TableGen/TableGenBackend.h"26 27#include <string>28#include <vector>29 30using namespace llvm;31using namespace llvm::dxil;32 33namespace {34 35struct DXILIntrinsicSelect {36 StringRef Intrinsic;37 SmallVector<const Record *> ArgSelectRecords;38};39 40struct DXILOperationDesc {41 std::string OpName; // name of DXIL operation42 int OpCode; // ID of DXIL operation43 StringRef OpClass; // name of the opcode class44 StringRef Doc; // the documentation description of this instruction45 // Vector of operand type records - return type is at index 046 SmallVector<const Record *> OpTypes;47 SmallVector<const Record *> OverloadRecs;48 SmallVector<const Record *> StageRecs;49 SmallVector<const Record *> AttrRecs;50 SmallVector<DXILIntrinsicSelect> IntrinsicSelects;51 SmallVector<StringRef, 4>52 ShaderStages; // shader stages to which this applies, empty for all.53 int OverloadParamIndex; // Index of parameter with overload type.54 // -1 : no overload types55 SmallVector<StringRef, 4> Counters; // counters for this inst.56 DXILOperationDesc(const Record *);57};58} // end anonymous namespace59 60static StringRef stripIntrinArgSelectTypePrefix(StringRef Type) {61 StringRef Prefix = "IntrinArgSelect_";62 if (!Type.starts_with(Prefix)) {63 PrintFatalError("IntrinArgSelectType definintion must be prefixed with "64 "'IntrinArgSelect_'");65 }66 return Type.substr(Prefix.size());67}68 69/// In-place sort TableGen records of class with a field70/// Version dxil_version71/// in the ascending version order.72static void ascendingSortByVersion(std::vector<const Record *> &Recs) {73 sort(Recs, [](const Record *RecA, const Record *RecB) {74 unsigned RecAMaj =75 RecA->getValueAsDef("dxil_version")->getValueAsInt("Major");76 unsigned RecAMin =77 RecA->getValueAsDef("dxil_version")->getValueAsInt("Minor");78 unsigned RecBMaj =79 RecB->getValueAsDef("dxil_version")->getValueAsInt("Major");80 unsigned RecBMin =81 RecB->getValueAsDef("dxil_version")->getValueAsInt("Minor");82 83 return (VersionTuple(RecAMaj, RecAMin) < VersionTuple(RecBMaj, RecBMin));84 });85}86 87/// Take a `int_{intrinsic_name}` and return just the intrinsic_name part if88/// available. Otherwise return the empty string.89static StringRef GetIntrinsicName(const RecordVal *RV) {90 if (RV && RV->getValue()) {91 if (const DefInit *DI = dyn_cast<DefInit>(RV->getValue())) {92 auto *IntrinsicDef = DI->getDef();93 auto DefName = IntrinsicDef->getName();94 assert(DefName.starts_with("int_") && "invalid intrinsic name");95 // Remove the int_ from intrinsic name.96 return DefName.substr(4);97 }98 }99 return "";100}101 102/// Construct an object using the DXIL Operation records specified103/// in DXIL.td. This serves as the single source of reference of104/// the information extracted from the specified Record R, for105/// C++ code generated by this TableGen backend.106// \param R Object representing TableGen record of a DXIL Operation107DXILOperationDesc::DXILOperationDesc(const Record *R) {108 OpName = R->getNameInitAsString();109 OpCode = R->getValueAsInt("OpCode");110 111 Doc = R->getValueAsString("Doc");112 SmallVector<const Record *> ParamTypeRecs;113 114 ParamTypeRecs.push_back(R->getValueAsDef("result"));115 116 llvm::append_range(ParamTypeRecs, R->getValueAsListOfDefs("arguments"));117 size_t ParamTypeRecsSize = ParamTypeRecs.size();118 // Populate OpTypes with return type and parameter types119 120 // Parameter indices of overloaded parameters.121 // This vector contains overload parameters in the order used to122 // resolve an LLVMMatchType in accordance with convention outlined in123 // the comment before the definition of class LLVMMatchType in124 // llvm/IR/Intrinsics.td125 OverloadParamIndex = -1; // A sigil meaning none.126 for (unsigned I = 0; I < ParamTypeRecsSize; I++) {127 const Record *TR = ParamTypeRecs[I];128 // Track operation parameter indices of any overload types129 if (TR->getValueAsInt("isOverload")) {130 if (OverloadParamIndex != -1) {131 assert(TR == ParamTypeRecs[OverloadParamIndex] &&132 "Specification of multiple differing overload parameter types "133 "is not supported");134 }135 // Keep the earliest parameter index we see, but if it was the return type136 // overwrite it with the first overloaded argument.137 if (OverloadParamIndex <= 0)138 OverloadParamIndex = I;139 }140 OpTypes.emplace_back(TR);141 }142 143 // Get overload records144 std::vector<const Record *> Recs = R->getValueAsListOfDefs("overloads");145 146 // Sort records in ascending order of DXIL version147 ascendingSortByVersion(Recs);148 149 llvm::append_range(OverloadRecs, Recs);150 151 // Get stage records152 Recs = R->getValueAsListOfDefs("stages");153 154 if (Recs.empty()) {155 PrintFatalError(R, Twine("Atleast one specification of valid stage for ") +156 OpName + " is required");157 }158 159 // Sort records in ascending order of DXIL version160 ascendingSortByVersion(Recs);161 162 llvm::append_range(StageRecs, Recs);163 164 // Get attribute records165 Recs = R->getValueAsListOfDefs("attributes");166 167 // Sort records in ascending order of DXIL version168 ascendingSortByVersion(Recs);169 170 llvm::append_range(AttrRecs, Recs);171 172 // Get the operation class173 OpClass = R->getValueAsDef("OpClass")->getName();174 175 if (OpClass.str() == "UnknownOpClass")176 PrintFatalError(R, Twine("Unspecified DXIL OpClass for DXIL operation - ") +177 OpName);178 179 auto IntrinsicSelectRecords = R->getValueAsListOfDefs("intrinsics");180 if (IntrinsicSelectRecords.size()) {181 for (const Record *R : IntrinsicSelectRecords) {182 DXILIntrinsicSelect IntrSelect;183 IntrSelect.Intrinsic = GetIntrinsicName(R->getValue("intrinsic"));184 auto Args = R->getValueAsListOfDefs("arg_selects");185 for (const Record *ArgSelect : Args) {186 IntrSelect.ArgSelectRecords.emplace_back(ArgSelect);187 }188 IntrinsicSelects.emplace_back(std::move(IntrSelect));189 }190 }191}192 193/// Return a string representation of OverloadKind enum that maps to194/// input LLVMType record195/// \param R TableGen def record of class LLVMType196/// \return std::string string representation of OverloadKind197 198static StringRef getOverloadKindStr(const Record *R) {199 // TODO: This is a hack. We need to rework how we're handling the set of200 // overloads to avoid this business with the separate OverloadKind enum.201 return StringSwitch<StringRef>(R->getName())202 .Case("HalfTy", "OverloadKind::HALF")203 .Case("FloatTy", "OverloadKind::FLOAT")204 .Case("DoubleTy", "OverloadKind::DOUBLE")205 .Case("Int1Ty", "OverloadKind::I1")206 .Case("Int8Ty", "OverloadKind::I8")207 .Case("Int16Ty", "OverloadKind::I16")208 .Case("Int32Ty", "OverloadKind::I32")209 .Case("Int64Ty", "OverloadKind::I64")210 .Case("ResRetHalfTy", "OverloadKind::HALF")211 .Case("ResRetFloatTy", "OverloadKind::FLOAT")212 .Case("ResRetDoubleTy", "OverloadKind::DOUBLE")213 .Case("ResRetInt16Ty", "OverloadKind::I16")214 .Case("ResRetInt32Ty", "OverloadKind::I32")215 .Case("ResRetInt64Ty", "OverloadKind::I64")216 .Case("CBufRetHalfTy", "OverloadKind::HALF")217 .Case("CBufRetFloatTy", "OverloadKind::FLOAT")218 .Case("CBufRetDoubleTy", "OverloadKind::DOUBLE")219 .Case("CBufRetInt16Ty", "OverloadKind::I16")220 .Case("CBufRetInt32Ty", "OverloadKind::I32")221 .Case("CBufRetInt64Ty", "OverloadKind::I64");222}223 224/// Return a string representation of valid overload information denoted225// by input records226//227/// \param Recs A vector of records of TableGen Overload records228/// \return std::string string representation of overload mask string229/// predicated by DXIL Version. E.g.,230// {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...}231static std::string getOverloadMaskString(ArrayRef<const Record *> Recs) {232 std::string MaskString = "";233 std::string Prefix = "";234 MaskString.append("{");235 // If no overload information records were specified, assume the operation236 // a) to be supported in DXIL Version 1.0 and later237 // b) has no overload types238 if (Recs.empty()) {239 MaskString.append("{{1, 0}, OverloadKind::UNDEFINED}}");240 } else {241 for (const auto *Rec : Recs) {242 unsigned Major =243 Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");244 unsigned Minor =245 Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");246 MaskString.append(Prefix)247 .append("{{")248 .append(std::to_string(Major))249 .append(", ")250 .append(std::to_string(Minor).append("}, "));251 252 std::string PipePrefix = "";253 auto Tys = Rec->getValueAsListOfDefs("overload_types");254 if (Tys.empty()) {255 MaskString.append("OverloadKind::UNDEFINED");256 }257 for (const auto *Ty : Tys) {258 MaskString.append(PipePrefix).append(getOverloadKindStr(Ty));259 PipePrefix = " | ";260 }261 262 MaskString.append("}");263 Prefix = ", ";264 }265 MaskString.append("}");266 }267 return MaskString;268}269 270/// Return a string representation of valid shader stag information denoted271// by input records272//273/// \param Recs A vector of records of TableGen Stages records274/// \return std::string string representation of stages mask string275/// predicated by DXIL Version. E.g.,276// {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...}277static std::string getStageMaskString(ArrayRef<const Record *> Recs) {278 std::string MaskString = "";279 std::string Prefix = "";280 MaskString.append("{");281 // Atleast one stage information record is expected to be specified.282 if (Recs.empty()) {283 PrintFatalError("Atleast one specification of valid stages for "284 "operation must be specified");285 }286 287 for (const auto *Rec : Recs) {288 unsigned Major = Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");289 unsigned Minor = Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");290 MaskString.append(Prefix)291 .append("{{")292 .append(std::to_string(Major))293 .append(", ")294 .append(std::to_string(Minor).append("}, "));295 296 std::string PipePrefix = "";297 auto Stages = Rec->getValueAsListOfDefs("shader_stages");298 if (Stages.empty()) {299 PrintFatalError("No valid stages for operation specified");300 }301 for (const auto *S : Stages) {302 MaskString.append(PipePrefix).append("ShaderKind::").append(S->getName());303 PipePrefix = " | ";304 }305 306 MaskString.append("}");307 Prefix = ", ";308 }309 MaskString.append("}");310 return MaskString;311}312 313/// Emit a list valid DXIL Version records314static void emitDXILVersions(const RecordKeeper &Records, raw_ostream &OS) {315 OS << "#ifdef DXIL_VERSION\n";316 for (const Record *Version : Records.getAllDerivedDefinitions("Version")) {317 unsigned Major = Version->getValueAsInt("Major");318 unsigned Minor = Version->getValueAsInt("Minor");319 OS << "DXIL_VERSION(";320 OS << std::to_string(Major) << ", " << std::to_string(Minor);321 OS << ")\n";322 }323 OS << "#undef DXIL_VERSION\n";324 OS << "#endif\n\n";325}326 327/// Emit a mapping of DXIL opcode to opname328static void emitDXILOpCodes(ArrayRef<DXILOperationDesc> Ops, raw_ostream &OS) {329 OS << "#ifdef DXIL_OPCODE\n";330 for (const DXILOperationDesc &Op : Ops)331 OS << "DXIL_OPCODE(" << Op.OpCode << ", " << Op.OpName << ")\n";332 OS << "#undef DXIL_OPCODE\n";333 OS << "\n";334 OS << "#endif\n\n";335}336 337/// Emit a list of DXIL op classes338static void emitDXILOpClasses(const RecordKeeper &Records, raw_ostream &OS) {339 OS << "#ifdef DXIL_OPCLASS\n";340 for (const Record *OpClass : Records.getAllDerivedDefinitions("DXILOpClass"))341 OS << "DXIL_OPCLASS(" << OpClass->getName() << ")\n";342 OS << "#undef DXIL_OPCLASS\n";343 OS << "#endif\n\n";344}345 346/// Emit a list of DXIL op parameter types347static void emitDXILOpParamTypes(const RecordKeeper &Records, raw_ostream &OS) {348 OS << "#ifdef DXIL_OP_PARAM_TYPE\n";349 for (const Record *OpParamType :350 Records.getAllDerivedDefinitions("DXILOpParamType"))351 OS << "DXIL_OP_PARAM_TYPE(" << OpParamType->getName() << ")\n";352 OS << "#undef DXIL_OP_PARAM_TYPE\n";353 OS << "#endif\n\n";354}355 356/// Emit a list of DXIL op function attributes357static void emitDXILAttributes(const RecordKeeper &Records, raw_ostream &OS) {358 OS << "#ifdef DXIL_ATTRIBUTE\n";359 for (const Record *Attr : Records.getAllDerivedDefinitions("DXILAttribute"))360 OS << "DXIL_ATTRIBUTE(" << Attr->getName() << ")\n";361 OS << "#undef DXIL_ATTRIBUTE\n";362 OS << "#endif\n\n";363}364 365// Helper function to determine if the given Attr is defined in the vector366// Attrs, by comparing the names367static bool attrIsDefined(std::vector<const Record *> Attrs,368 const Record *Attr) {369 for (auto CurAttr : Attrs)370 if (CurAttr->getName() == Attr->getName())371 return true;372 return false;373}374 375/// Emit a table of bools denoting a DXIL op's function attributes376static void emitDXILOpAttributes(const RecordKeeper &Records,377 ArrayRef<DXILOperationDesc> Ops,378 raw_ostream &OS) {379 // A DXIL op can have multiple function attributes that are specific to a380 // specific DXIL version and higher. AttrRecs models this by grouping the381 // attributes by the versions. So we will output a macro for each version382 // number with a table of bools in the following format:383 //384 // OpName, VersionMajor, VersionMinor, FnAttr1, FnAttr2, ...385 // Eg) Abs, 1, 0, true, false, ...386 OS << "#ifdef DXIL_OP_ATTRIBUTES\n";387 for (const auto &Op : Ops) {388 for (const auto *Rec : Op.AttrRecs) {389 unsigned Major =390 Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");391 unsigned Minor =392 Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");393 OS << "DXIL_OP_ATTRIBUTES(dxil::OpCode::" << Op.OpName << ", ";394 OS << std::to_string(Major) << ", " << std::to_string(Minor);395 // These Attrs are the ones set for above DXIL version396 auto Attrs = Rec->getValueAsListOfDefs("fn_attrs");397 // We will then iteratre through all possible attributes and mark the398 // present ones as 'true' and all the others as 'false' to create the399 // boolean table, eg) true, false, false, false400 for (const Record *Attr :401 Records.getAllDerivedDefinitions("DXILAttribute")) {402 std::string HasAttr = ", false";403 if (attrIsDefined(Attrs, Attr))404 HasAttr = ", true";405 OS << HasAttr;406 }407 OS << ")\n";408 }409 }410 OS << "#undef DXIL_OP_ATTRIBUTES\n";411 OS << "#endif\n\n";412}413 414/// Emit a list of DXIL op function types415static void emitDXILOpFunctionTypes(ArrayRef<DXILOperationDesc> Ops,416 raw_ostream &OS) {417 OS << "#ifndef DXIL_OP_FUNCTION_TYPE\n";418 OS << "#define DXIL_OP_FUNCTION_TYPE(OpCode, RetType, ...)\n";419 OS << "#endif\n";420 for (const DXILOperationDesc &Op : Ops) {421 OS << "DXIL_OP_FUNCTION_TYPE(dxil::OpCode::" << Op.OpName;422 for (const Record *Rec : Op.OpTypes)423 OS << ", dxil::OpParamType::" << Rec->getName();424 // If there are no arguments, we need an empty comma for the varargs425 if (Op.OpTypes.size() == 1)426 OS << ", ";427 OS << ")\n";428 }429 OS << "#undef DXIL_OP_FUNCTION_TYPE\n";430}431 432/// Emit map of DXIL operation to LLVM or DirectX intrinsic433/// \param A vector of DXIL Ops434/// \param Output stream435static void emitDXILIntrinsicMap(ArrayRef<DXILOperationDesc> Ops,436 raw_ostream &OS) {437 438 OS << "#ifdef DXIL_OP_INTRINSIC\n";439 OS << "\n";440 for (const auto &Op : Ops) {441 if (Op.IntrinsicSelects.empty()) {442 continue;443 }444 for (const DXILIntrinsicSelect &MappedIntr : Op.IntrinsicSelects) {445 OS << "DXIL_OP_INTRINSIC(dxil::OpCode::" << Op.OpName446 << ", Intrinsic::" << MappedIntr.Intrinsic << ", ";447 for (const Record *ArgSelect : MappedIntr.ArgSelectRecords) {448 std::string Type =449 ArgSelect->getValueAsDef("type")->getNameInitAsString();450 int Value = ArgSelect->getValueAsInt("value");451 OS << "(IntrinArgSelect{"452 << "IntrinArgSelect::Type::" << stripIntrinArgSelectTypePrefix(Type)453 << "," << Value << "}), ";454 }455 OS << ")\n";456 }457 }458 OS << "\n";459 OS << "#undef DXIL_OP_INTRINSIC\n";460 OS << "#endif\n\n";461}462 463/// Emit the IntrinArgSelect type for DirectX intrinsic to DXIL Op lowering464static void emitDXILIntrinsicArgSelectTypes(const RecordKeeper &Records,465 raw_ostream &OS) {466 OS << "#ifdef DXIL_OP_INTRINSIC_ARG_SELECT_TYPE\n";467 for (const Record *Records :468 Records.getAllDerivedDefinitions("IntrinArgSelectType")) {469 StringRef StrippedName = stripIntrinArgSelectTypePrefix(Records->getName());470 OS << "DXIL_OP_INTRINSIC_ARG_SELECT_TYPE(" << StrippedName << ")\n";471 }472 OS << "#undef DXIL_OP_INTRINSIC_ARG_SELECT_TYPE\n";473 OS << "#endif\n\n";474}475 476/// Emit DXIL operation table477/// \param A vector of DXIL Ops478/// \param Output stream479static void emitDXILOperationTable(ArrayRef<DXILOperationDesc> Ops,480 raw_ostream &OS) {481 // Collect Names.482 SequenceToOffsetTable<std::string> OpClassStrings;483 SequenceToOffsetTable<std::string> OpStrings;484 485 StringSet<> ClassSet;486 for (const auto &Op : Ops) {487 OpStrings.add(Op.OpName);488 489 if (ClassSet.insert(Op.OpClass).second)490 OpClassStrings.add(Op.OpClass.data());491 }492 493 // Layout names.494 OpStrings.layout();495 OpClassStrings.layout();496 497 // Emit access function getOpcodeProperty() that embeds DXIL Operation table498 // with entries of type struct OpcodeProperty.499 OS << "static const OpCodeProperty *getOpCodeProperty(dxil::OpCode Op) "500 "{\n";501 502 OS << " static const OpCodeProperty OpCodeProps[] = {\n";503 std::string Prefix = "";504 for (const auto &Op : Ops) {505 OS << Prefix << " { dxil::OpCode::" << Op.OpName << ", "506 << OpStrings.get(Op.OpName) << ", OpCodeClass::" << Op.OpClass << ", "507 << OpClassStrings.get(Op.OpClass.data()) << ", "508 << getOverloadMaskString(Op.OverloadRecs) << ", "509 << getStageMaskString(Op.StageRecs) << ", " << Op.OverloadParamIndex510 << " }";511 Prefix = ",\n";512 }513 OS << " };\n";514 515 OS << " // FIXME: change search to indexing with\n";516 OS << " // Op once all DXIL operations are added.\n";517 OS << " OpCodeProperty TmpProp;\n";518 OS << " TmpProp.OpCode = Op;\n";519 OS << " const OpCodeProperty *Prop =\n";520 OS << " llvm::lower_bound(OpCodeProps, TmpProp,\n";521 OS << " [](const OpCodeProperty &A, const "522 "OpCodeProperty &B) {\n";523 OS << " return A.OpCode < B.OpCode;\n";524 OS << " });\n";525 OS << " assert(Prop && \"failed to find OpCodeProperty\");\n";526 OS << " return Prop;\n";527 OS << "}\n\n";528 529 // Emit the string tables.530 OS << "static const char *getOpCodeName(dxil::OpCode Op) {\n\n";531 532 OpStrings.emitStringLiteralDef(OS,533 " static const char DXILOpCodeNameTable[]");534 535 OS << " auto *Prop = getOpCodeProperty(Op);\n";536 OS << " unsigned Index = Prop->OpCodeNameOffset;\n";537 OS << " return DXILOpCodeNameTable + Index;\n";538 OS << "}\n\n";539 540 OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) "541 "{\n\n";542 543 OpClassStrings.emitStringLiteralDef(544 OS, " static const char DXILOpCodeClassNameTable[]");545 546 OS << " unsigned Index = Prop.OpCodeClassNameOffset;\n";547 OS << " return DXILOpCodeClassNameTable + Index;\n";548 OS << "}\n\n";549}550 551static void emitDXILOperationTableDataStructs(const RecordKeeper &Records,552 raw_ostream &OS) {553 // Get Shader stage records554 std::vector<const Record *> ShaderKindRecs =555 Records.getAllDerivedDefinitions("DXILShaderStage");556 // Sort records by name557 llvm::sort(ShaderKindRecs, [](const Record *A, const Record *B) {558 return A->getName() < B->getName();559 });560 561 OS << "// Valid shader kinds\n\n";562 // Choose the type of enum ShaderKind based on the number of stages declared.563 // This gives the flexibility to just add add new stage records in DXIL.td, if564 // needed, with no need to change this backend code.565 size_t ShaderKindCount = ShaderKindRecs.size();566 uint64_t ShaderKindTySz = PowerOf2Ceil(ShaderKindRecs.size() + 1);567 OS << "enum ShaderKind : uint" << ShaderKindTySz << "_t {\n";568 const std::string AllStages("all_stages");569 const std::string Removed("removed");570 int ShiftVal = 1;571 for (const auto *R : ShaderKindRecs) {572 auto Name = R->getName();573 if (Name.compare(Removed) == 0) {574 OS << " " << Name575 << " = 0, // Pseudo-stage indicating op not supported in any "576 "stage\n";577 } else if (Name.compare(AllStages) == 0) {578 OS << " " << Name << " = 0x"579 << utohexstr(((1 << ShaderKindCount) - 1), false, 0)580 << ", // Pseudo-stage indicating op is supported in all stages\n";581 } else if (Name.compare(AllStages)) {582 OS << " " << Name << " = 1 << " << std::to_string(ShiftVal++) << ",\n";583 }584 }585 OS << "}; // enum ShaderKind\n\n";586}587 588/// Entry function call that invokes the functionality of this TableGen backend589/// \param Records TableGen records of DXIL Operations defined in DXIL.td590/// \param OS output stream591static void emitDxilOperation(const RecordKeeper &Records, raw_ostream &OS) {592 OS << "// Generated code, do not edit.\n";593 OS << "\n";594 // Get all DXIL Ops property records595 std::vector<DXILOperationDesc> DXILOps;596 for (const Record *R : Records.getAllDerivedDefinitions("DXILOp")) {597 DXILOps.emplace_back(DXILOperationDesc(R));598 }599 // Sort by opcode.600 llvm::sort(DXILOps,601 [](const DXILOperationDesc &A, const DXILOperationDesc &B) {602 return A.OpCode < B.OpCode;603 });604 int PrevOp = -1;605 for (const DXILOperationDesc &Desc : DXILOps) {606 if (Desc.OpCode == PrevOp)607 PrintFatalError(Twine("Duplicate opcode: ") + Twine(Desc.OpCode));608 PrevOp = Desc.OpCode;609 }610 611 emitDXILVersions(Records, OS);612 emitDXILOpCodes(DXILOps, OS);613 emitDXILOpClasses(Records, OS);614 emitDXILOpParamTypes(Records, OS);615 emitDXILAttributes(Records, OS);616 emitDXILOpAttributes(Records, DXILOps, OS);617 emitDXILOpFunctionTypes(DXILOps, OS);618 emitDXILIntrinsicArgSelectTypes(Records, OS);619 emitDXILIntrinsicMap(DXILOps, OS);620 OS << "#ifdef DXIL_OP_OPERATION_TABLE\n\n";621 emitDXILOperationTableDataStructs(Records, OS);622 emitDXILOperationTable(DXILOps, OS);623 OS << "#undef DXIL_OP_OPERATION_TABLE\n";624 OS << "#endif\n\n";625}626 627static TableGen::Emitter::Opt X("gen-dxil-operation", emitDxilOperation,628 "Generate DXIL operation information");629