brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.2 KiB · 9471959 Raw
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