xref: /llvm-project/llvm/utils/TableGen/DXILEmitter.cpp (revision 94da6bfb27dcff68bebd0d1ce1a61346c231ed64)
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