1435897b4Spython3kgae //===- DXILEmitter.cpp - DXIL operation Emitter ---------------------------===//
2435897b4Spython3kgae //
3435897b4Spython3kgae // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4435897b4Spython3kgae // See https://llvm.org/LICENSE.txt for license information.
5435897b4Spython3kgae // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6435897b4Spython3kgae //
7435897b4Spython3kgae //===----------------------------------------------------------------------===//
8435897b4Spython3kgae //
9435897b4Spython3kgae // DXILEmitter uses the descriptions of DXIL operation to construct enum and
10435897b4Spython3kgae // helper functions for DXIL operation.
11435897b4Spython3kgae //
12435897b4Spython3kgae //===----------------------------------------------------------------------===//
13435897b4Spython3kgae 
14*0d2dde20SXiang Li #include "SequenceToOffsetTable.h"
15435897b4Spython3kgae #include "llvm/ADT/STLExtras.h"
16435897b4Spython3kgae #include "llvm/ADT/SmallVector.h"
17435897b4Spython3kgae #include "llvm/ADT/StringSet.h"
18*0d2dde20SXiang Li #include "llvm/ADT/StringSwitch.h"
19435897b4Spython3kgae #include "llvm/TableGen/Error.h"
20435897b4Spython3kgae #include "llvm/TableGen/Record.h"
21435897b4Spython3kgae 
22435897b4Spython3kgae using namespace llvm;
23435897b4Spython3kgae 
24435897b4Spython3kgae namespace {
25435897b4Spython3kgae 
26435897b4Spython3kgae struct DXILShaderModel {
27435897b4Spython3kgae   int Major;
28435897b4Spython3kgae   int Minor;
29435897b4Spython3kgae };
30435897b4Spython3kgae struct DXILParam {
31435897b4Spython3kgae   int Pos;        // position in parameter list
32435897b4Spython3kgae   StringRef Type; // llvm type name, $o for overload, $r for resource
33435897b4Spython3kgae                   // type, $cb for legacy cbuffer, $u4 for u4 struct
34435897b4Spython3kgae   StringRef Name; // short, unique name
35435897b4Spython3kgae   StringRef Doc;  // the documentation description of this parameter
36435897b4Spython3kgae   bool IsConst;   // whether this argument requires a constant value in the IR
37435897b4Spython3kgae   StringRef EnumName; // the name of the enum type if applicable
38435897b4Spython3kgae   int MaxValue;       // the maximum value for this parameter if applicable
39435897b4Spython3kgae   DXILParam(const Record *R) {
40435897b4Spython3kgae     Name = R->getValueAsString("name");
41435897b4Spython3kgae     Pos = R->getValueAsInt("pos");
42435897b4Spython3kgae     Type = R->getValueAsString("llvm_type");
43435897b4Spython3kgae     if (R->getValue("doc"))
44435897b4Spython3kgae       Doc = R->getValueAsString("doc");
45435897b4Spython3kgae     IsConst = R->getValueAsBit("is_const");
46435897b4Spython3kgae     EnumName = R->getValueAsString("enum_name");
47435897b4Spython3kgae     MaxValue = R->getValueAsInt("max_value");
48435897b4Spython3kgae   }
49435897b4Spython3kgae };
50435897b4Spython3kgae 
51435897b4Spython3kgae struct DXILOperationData {
52435897b4Spython3kgae   StringRef Name; // short, unique name
53435897b4Spython3kgae 
54435897b4Spython3kgae   StringRef DXILOp;    // name of DXIL operation
55435897b4Spython3kgae   int DXILOpID;        // ID of DXIL operation
56435897b4Spython3kgae   StringRef DXILClass; // name of the opcode class
57435897b4Spython3kgae   StringRef Category;  // classification for this instruction
58435897b4Spython3kgae   StringRef Doc;       // the documentation description of this instruction
59435897b4Spython3kgae 
60435897b4Spython3kgae   SmallVector<DXILParam> Params; // the operands that this instruction takes
61435897b4Spython3kgae   StringRef OverloadTypes;       // overload types if applicable
62435897b4Spython3kgae   StringRef FnAttr;              // attribute shorthands: rn=does not access
63264c09b7SXiang Li                                  // memory,ro=only reads from memory
64264c09b7SXiang Li   StringRef Intrinsic; // The llvm intrinsic map to DXILOp. Default is "" which
65264c09b7SXiang Li                        // means no map exist
66435897b4Spython3kgae   bool IsDeriv;        // whether this is some kind of derivative
67435897b4Spython3kgae   bool IsGradient;               // whether this requires a gradient calculation
68435897b4Spython3kgae   bool IsFeedback;               // whether this is a sampler feedback op
69435897b4Spython3kgae   bool IsWave; // whether this requires in-wave, cross-lane functionality
70435897b4Spython3kgae   bool RequiresUniformInputs; // whether this operation requires that all
71435897b4Spython3kgae                               // of its inputs are uniform across the wave
72435897b4Spython3kgae   SmallVector<StringRef, 4>
73435897b4Spython3kgae       ShaderStages; // shader stages to which this applies, empty for all.
74435897b4Spython3kgae   DXILShaderModel ShaderModel;           // minimum shader model required
75435897b4Spython3kgae   DXILShaderModel ShaderModelTranslated; // minimum shader model required with
76435897b4Spython3kgae                                          // translation by linker
77435897b4Spython3kgae   SmallVector<StringRef, 4> counters;    // counters for this inst.
78435897b4Spython3kgae   DXILOperationData(const Record *R) {
79435897b4Spython3kgae     Name = R->getValueAsString("name");
80435897b4Spython3kgae     DXILOp = R->getValueAsString("dxil_op");
81435897b4Spython3kgae     DXILOpID = R->getValueAsInt("dxil_opid");
82435897b4Spython3kgae     DXILClass = R->getValueAsDef("op_class")->getValueAsString("name");
83435897b4Spython3kgae     Category = R->getValueAsDef("category")->getValueAsString("name");
84435897b4Spython3kgae 
85264c09b7SXiang Li     if (R->getValue("llvm_intrinsic")) {
86264c09b7SXiang Li       auto *IntrinsicDef = R->getValueAsDef("llvm_intrinsic");
87264c09b7SXiang Li       auto DefName = IntrinsicDef->getName();
88264c09b7SXiang Li       assert(DefName.startswith("int_") && "invalid intrinsic name");
89264c09b7SXiang Li       // Remove the int_ from intrinsic name.
90264c09b7SXiang Li       Intrinsic = DefName.substr(4);
91264c09b7SXiang Li     }
92264c09b7SXiang Li 
93435897b4Spython3kgae     Doc = R->getValueAsString("doc");
94264c09b7SXiang Li 
95435897b4Spython3kgae     ListInit *ParamList = R->getValueAsListInit("ops");
96435897b4Spython3kgae     for (unsigned i = 0; i < ParamList->size(); ++i) {
97435897b4Spython3kgae       Record *Param = ParamList->getElementAsRecord(i);
98435897b4Spython3kgae       Params.emplace_back(DXILParam(Param));
99435897b4Spython3kgae     }
100435897b4Spython3kgae     OverloadTypes = R->getValueAsString("oload_types");
101435897b4Spython3kgae     FnAttr = R->getValueAsString("fn_attr");
102435897b4Spython3kgae   }
103435897b4Spython3kgae };
104435897b4Spython3kgae } // end anonymous namespace
105435897b4Spython3kgae 
106435897b4Spython3kgae static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
107435897b4Spython3kgae   // Name = ID, // Doc
108435897b4Spython3kgae   OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc
109435897b4Spython3kgae      << "\n";
110435897b4Spython3kgae }
111435897b4Spython3kgae 
112435897b4Spython3kgae static std::string buildCategoryStr(StringSet<> &Cetegorys) {
113435897b4Spython3kgae   std::string Str;
114435897b4Spython3kgae   raw_string_ostream OS(Str);
115435897b4Spython3kgae   for (auto &It : Cetegorys) {
116435897b4Spython3kgae     OS << " " << It.getKey();
117435897b4Spython3kgae   }
118435897b4Spython3kgae   return OS.str();
119435897b4Spython3kgae }
120435897b4Spython3kgae 
121435897b4Spython3kgae // Emit enum declaration for DXIL.
122435897b4Spython3kgae static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps,
123435897b4Spython3kgae                           raw_ostream &OS) {
124435897b4Spython3kgae   // Sort by Category + OpName.
125435897b4Spython3kgae   std::sort(DXILOps.begin(), DXILOps.end(),
126435897b4Spython3kgae             [](DXILOperationData &A, DXILOperationData &B) {
127435897b4Spython3kgae               // Group by Category first.
128435897b4Spython3kgae               if (A.Category == B.Category)
129435897b4Spython3kgae                 // Inside same Category, order by OpName.
130435897b4Spython3kgae                 return A.DXILOp < B.DXILOp;
131435897b4Spython3kgae               else
132435897b4Spython3kgae                 return A.Category < B.Category;
133435897b4Spython3kgae             });
134435897b4Spython3kgae 
135435897b4Spython3kgae   OS << "// Enumeration for operations specified by DXIL\n";
136435897b4Spython3kgae   OS << "enum class OpCode : unsigned {\n";
137435897b4Spython3kgae 
138435897b4Spython3kgae   StringMap<StringSet<>> ClassMap;
139435897b4Spython3kgae   StringRef PrevCategory = "";
140435897b4Spython3kgae   for (auto &DXILOp : DXILOps) {
141435897b4Spython3kgae     StringRef Category = DXILOp.Category;
142435897b4Spython3kgae     if (Category != PrevCategory) {
143435897b4Spython3kgae       OS << "\n// " << Category << "\n";
144435897b4Spython3kgae       PrevCategory = Category;
145435897b4Spython3kgae     }
146435897b4Spython3kgae     emitDXILOpEnum(DXILOp, OS);
147435897b4Spython3kgae     auto It = ClassMap.find(DXILOp.DXILClass);
148435897b4Spython3kgae     if (It != ClassMap.end()) {
149435897b4Spython3kgae       It->second.insert(DXILOp.Category);
150435897b4Spython3kgae     } else {
151435897b4Spython3kgae       ClassMap[DXILOp.DXILClass].insert(DXILOp.Category);
152435897b4Spython3kgae     }
153435897b4Spython3kgae   }
154435897b4Spython3kgae 
155435897b4Spython3kgae   OS << "\n};\n\n";
156435897b4Spython3kgae 
157435897b4Spython3kgae   std::vector<std::pair<std::string, std::string>> ClassVec;
158435897b4Spython3kgae   for (auto &It : ClassMap) {
159435897b4Spython3kgae     ClassVec.emplace_back(
160435897b4Spython3kgae         std::make_pair(It.getKey().str(), buildCategoryStr(It.second)));
161435897b4Spython3kgae   }
162435897b4Spython3kgae   // Sort by Category + ClassName.
163435897b4Spython3kgae   std::sort(ClassVec.begin(), ClassVec.end(),
164435897b4Spython3kgae             [](std::pair<std::string, std::string> &A,
165435897b4Spython3kgae                std::pair<std::string, std::string> &B) {
166435897b4Spython3kgae               StringRef ClassA = A.first;
167435897b4Spython3kgae               StringRef CategoryA = A.second;
168435897b4Spython3kgae               StringRef ClassB = B.first;
169435897b4Spython3kgae               StringRef CategoryB = B.second;
170435897b4Spython3kgae               // Group by Category first.
171435897b4Spython3kgae               if (CategoryA == CategoryB)
172435897b4Spython3kgae                 // Inside same Category, order by ClassName.
173435897b4Spython3kgae                 return ClassA < ClassB;
174435897b4Spython3kgae               else
175435897b4Spython3kgae                 return CategoryA < CategoryB;
176435897b4Spython3kgae             });
177435897b4Spython3kgae 
178435897b4Spython3kgae   OS << "// Groups for DXIL operations with equivalent function templates\n";
179435897b4Spython3kgae   OS << "enum class OpCodeClass : unsigned {\n";
180435897b4Spython3kgae   PrevCategory = "";
181435897b4Spython3kgae   for (auto &It : ClassVec) {
182435897b4Spython3kgae 
183435897b4Spython3kgae     StringRef Category = It.second;
184435897b4Spython3kgae     if (Category != PrevCategory) {
185435897b4Spython3kgae       OS << "\n// " << Category << "\n";
186435897b4Spython3kgae       PrevCategory = Category;
187435897b4Spython3kgae     }
188435897b4Spython3kgae     StringRef Name = It.first;
189435897b4Spython3kgae     OS << Name << ",\n";
190435897b4Spython3kgae   }
191435897b4Spython3kgae   OS << "\n};\n\n";
192435897b4Spython3kgae }
193435897b4Spython3kgae 
194264c09b7SXiang Li // Emit map from llvm intrinsic to DXIL operation.
195*0d2dde20SXiang Li static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps,
196264c09b7SXiang Li                                  raw_ostream &OS) {
197264c09b7SXiang Li   OS << "\n";
198264c09b7SXiang Li   // FIXME: use array instead of SmallDenseMap.
199264c09b7SXiang Li   OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = "
200264c09b7SXiang Li         "{\n";
201264c09b7SXiang Li   for (auto &DXILOp : DXILOps) {
202264c09b7SXiang Li     if (DXILOp.Intrinsic.empty())
203264c09b7SXiang Li       continue;
204264c09b7SXiang Li     // {Intrinsic::sin, DXIL::OpCode::Sin},
205264c09b7SXiang Li     OS << "  { Intrinsic::" << DXILOp.Intrinsic
206264c09b7SXiang Li        << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n";
207264c09b7SXiang Li   }
208264c09b7SXiang Li   OS << "};\n";
209264c09b7SXiang Li   OS << "\n";
210264c09b7SXiang Li }
211264c09b7SXiang Li 
212*0d2dde20SXiang Li static std::string emitDXILOperationFnAttr(StringRef FnAttr) {
213*0d2dde20SXiang Li   return StringSwitch<std::string>(FnAttr)
214*0d2dde20SXiang Li       .Case("rn", "Attribute::ReadNone")
215*0d2dde20SXiang Li       .Case("ro", "Attribute::ReadOnly")
216*0d2dde20SXiang Li       .Default("Attribute::None");
217*0d2dde20SXiang Li }
218*0d2dde20SXiang Li 
219*0d2dde20SXiang Li static std::string getOverloadKind(StringRef Overload) {
220*0d2dde20SXiang Li   return StringSwitch<std::string>(Overload)
221*0d2dde20SXiang Li       .Case("half", "OverloadKind::HALF")
222*0d2dde20SXiang Li       .Case("float", "OverloadKind::FLOAT")
223*0d2dde20SXiang Li       .Case("double", "OverloadKind::DOUBLE")
224*0d2dde20SXiang Li       .Case("i1", "OverloadKind::I1")
225*0d2dde20SXiang Li       .Case("i16", "OverloadKind::I16")
226*0d2dde20SXiang Li       .Case("i32", "OverloadKind::I32")
227*0d2dde20SXiang Li       .Case("i64", "OverloadKind::I64")
228*0d2dde20SXiang Li       .Case("udt", "OverloadKind::UserDefineType")
229*0d2dde20SXiang Li       .Case("obj", "OverloadKind::ObjectType")
230*0d2dde20SXiang Li       .Default("OverloadKind::VOID");
231*0d2dde20SXiang Li }
232*0d2dde20SXiang Li 
233*0d2dde20SXiang Li static std::string getDXILOperationOverload(StringRef Overloads) {
234*0d2dde20SXiang Li   SmallVector<StringRef> OverloadStrs;
235*0d2dde20SXiang Li   Overloads.split(OverloadStrs, ';', /*MaxSplit*/ -1, /*KeepEmpty*/ false);
236*0d2dde20SXiang Li   // Format is: OverloadKind::FLOAT | OverloadKind::HALF
237*0d2dde20SXiang Li   assert(!OverloadStrs.empty() && "Invalid overloads");
238*0d2dde20SXiang Li   auto It = OverloadStrs.begin();
239*0d2dde20SXiang Li   std::string Result;
240*0d2dde20SXiang Li   raw_string_ostream OS(Result);
241*0d2dde20SXiang Li   OS << getOverloadKind(*It);
242*0d2dde20SXiang Li   for (++It; It != OverloadStrs.end(); ++It) {
243*0d2dde20SXiang Li     OS << " | " << getOverloadKind(*It);
244*0d2dde20SXiang Li   }
245*0d2dde20SXiang Li   return OS.str();
246*0d2dde20SXiang Li }
247*0d2dde20SXiang Li 
248*0d2dde20SXiang Li static std::string lowerFirstLetter(StringRef Name) {
249*0d2dde20SXiang Li   if (Name.empty())
250*0d2dde20SXiang Li     return "";
251*0d2dde20SXiang Li 
252*0d2dde20SXiang Li   std::string LowerName = Name.str();
253*0d2dde20SXiang Li   LowerName[0] = llvm::toLower(Name[0]);
254*0d2dde20SXiang Li   return LowerName;
255*0d2dde20SXiang Li }
256*0d2dde20SXiang Li 
257*0d2dde20SXiang Li static std::string getDXILOpClassName(StringRef DXILOpClass) {
258*0d2dde20SXiang Li   // Lower first letter expect for special case.
259*0d2dde20SXiang Li   return StringSwitch<std::string>(DXILOpClass)
260*0d2dde20SXiang Li       .Case("CBufferLoad", "cbufferLoad")
261*0d2dde20SXiang Li       .Case("CBufferLoadLegacy", "cbufferLoadLegacy")
262*0d2dde20SXiang Li       .Case("GSInstanceID", "gsInstanceID")
263*0d2dde20SXiang Li       .Default(lowerFirstLetter(DXILOpClass));
264*0d2dde20SXiang Li }
265*0d2dde20SXiang Li 
266*0d2dde20SXiang Li static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
267*0d2dde20SXiang Li                                    raw_ostream &OS) {
268*0d2dde20SXiang Li   // Sort by DXILOpID.
269*0d2dde20SXiang Li   std::sort(DXILOps.begin(), DXILOps.end(),
270*0d2dde20SXiang Li             [](DXILOperationData &A, DXILOperationData &B) {
271*0d2dde20SXiang Li               return A.DXILOpID < B.DXILOpID;
272*0d2dde20SXiang Li             });
273*0d2dde20SXiang Li 
274*0d2dde20SXiang Li   // Collect Names.
275*0d2dde20SXiang Li   SequenceToOffsetTable<std::string> OpClassStrings;
276*0d2dde20SXiang Li   SequenceToOffsetTable<std::string> OpStrings;
277*0d2dde20SXiang Li 
278*0d2dde20SXiang Li   StringSet<> ClassSet;
279*0d2dde20SXiang Li   for (auto &DXILOp : DXILOps) {
280*0d2dde20SXiang Li     OpStrings.add(DXILOp.DXILOp.str());
281*0d2dde20SXiang Li 
282*0d2dde20SXiang Li     if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end())
283*0d2dde20SXiang Li       continue;
284*0d2dde20SXiang Li     ClassSet.insert(DXILOp.DXILClass);
285*0d2dde20SXiang Li     OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass));
286*0d2dde20SXiang Li   }
287*0d2dde20SXiang Li 
288*0d2dde20SXiang Li   // Layout names.
289*0d2dde20SXiang Li   OpStrings.layout();
290*0d2dde20SXiang Li   OpClassStrings.layout();
291*0d2dde20SXiang Li 
292*0d2dde20SXiang Li   // Emit the DXIL operation table.
293*0d2dde20SXiang Li   //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary,
294*0d2dde20SXiang Li   // OpCodeClassNameIndex,
295*0d2dde20SXiang Li   // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone},
296*0d2dde20SXiang Li   OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) "
297*0d2dde20SXiang Li         "{\n";
298*0d2dde20SXiang Li 
299*0d2dde20SXiang Li   OS << "  static const OpCodeProperty OpCodeProps[] = {\n";
300*0d2dde20SXiang Li   for (auto &DXILOp : DXILOps) {
301*0d2dde20SXiang Li     OS << "  { DXIL::OpCode::" << DXILOp.DXILOp << ", "
302*0d2dde20SXiang Li        << OpStrings.get(DXILOp.DXILOp.str())
303*0d2dde20SXiang Li        << ", OpCodeClass::" << DXILOp.DXILClass << ", "
304*0d2dde20SXiang Li        << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", "
305*0d2dde20SXiang Li        << getDXILOperationOverload(DXILOp.OverloadTypes) << ", "
306*0d2dde20SXiang Li        << emitDXILOperationFnAttr(DXILOp.FnAttr) << " },\n";
307*0d2dde20SXiang Li   }
308*0d2dde20SXiang Li   OS << "  };\n";
309*0d2dde20SXiang Li 
310*0d2dde20SXiang Li   OS << "  // FIXME: change search to indexing with\n";
311*0d2dde20SXiang Li   OS << "  // DXILOp once all DXIL op is added.\n";
312*0d2dde20SXiang Li   OS << "  OpCodeProperty TmpProp;\n";
313*0d2dde20SXiang Li   OS << "  TmpProp.OpCode = DXILOp;\n";
314*0d2dde20SXiang Li   OS << "  const OpCodeProperty *Prop =\n";
315*0d2dde20SXiang Li   OS << "      llvm::lower_bound(OpCodeProps, TmpProp,\n";
316*0d2dde20SXiang Li   OS << "                        [](const OpCodeProperty &A, const "
317*0d2dde20SXiang Li         "OpCodeProperty &B) {\n";
318*0d2dde20SXiang Li   OS << "                          return A.OpCode < B.OpCode;\n";
319*0d2dde20SXiang Li   OS << "                        });\n";
320*0d2dde20SXiang Li   OS << "  assert(Prop && \"fail to find OpCodeProperty\");\n";
321*0d2dde20SXiang Li   OS << "  return Prop;\n";
322*0d2dde20SXiang Li   OS << "}\n\n";
323*0d2dde20SXiang Li 
324*0d2dde20SXiang Li   // Emit the string tables.
325*0d2dde20SXiang Li   OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n";
326*0d2dde20SXiang Li 
327*0d2dde20SXiang Li   OpStrings.emitStringLiteralDef(OS,
328*0d2dde20SXiang Li                                  "  static const char DXILOpCodeNameTable[]");
329*0d2dde20SXiang Li 
330*0d2dde20SXiang Li   OS << "  auto *Prop = getOpCodeProperty(DXILOp);\n";
331*0d2dde20SXiang Li   OS << "  unsigned Index = Prop->OpCodeNameOffset;\n";
332*0d2dde20SXiang Li   OS << "  return DXILOpCodeNameTable + Index;\n";
333*0d2dde20SXiang Li   OS << "}\n\n";
334*0d2dde20SXiang Li 
335*0d2dde20SXiang Li   OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) "
336*0d2dde20SXiang Li         "{\n\n";
337*0d2dde20SXiang Li 
338*0d2dde20SXiang Li   OpClassStrings.emitStringLiteralDef(
339*0d2dde20SXiang Li       OS, "  static const char DXILOpCodeClassNameTable[]");
340*0d2dde20SXiang Li 
341*0d2dde20SXiang Li   OS << "  unsigned Index = Prop.OpCodeClassNameOffset;\n";
342*0d2dde20SXiang Li   OS << "  return DXILOpCodeClassNameTable + Index;\n";
343*0d2dde20SXiang Li   OS << "}\n ";
344*0d2dde20SXiang Li }
345*0d2dde20SXiang Li 
346435897b4Spython3kgae namespace llvm {
347435897b4Spython3kgae 
348435897b4Spython3kgae void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
349435897b4Spython3kgae   std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op");
350435897b4Spython3kgae   OS << "// Generated code, do not edit.\n";
351435897b4Spython3kgae   OS << "\n";
352435897b4Spython3kgae 
353435897b4Spython3kgae   std::vector<DXILOperationData> DXILOps;
354435897b4Spython3kgae   DXILOps.reserve(Ops.size());
355435897b4Spython3kgae   for (auto *Record : Ops) {
356435897b4Spython3kgae     DXILOps.emplace_back(DXILOperationData(Record));
357435897b4Spython3kgae   }
358435897b4Spython3kgae 
359435897b4Spython3kgae   OS << "#ifdef DXIL_OP_ENUM\n";
360435897b4Spython3kgae   emitDXILEnums(DXILOps, OS);
361435897b4Spython3kgae   OS << "#endif\n\n";
362435897b4Spython3kgae 
363264c09b7SXiang Li   OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n";
364*0d2dde20SXiang Li   emitDXILIntrinsicMap(DXILOps, OS);
365264c09b7SXiang Li   OS << "#endif\n\n";
366264c09b7SXiang Li 
367*0d2dde20SXiang Li   OS << "#ifdef DXIL_OP_OPERATION_TABLE\n";
368*0d2dde20SXiang Li   emitDXILOperationTable(DXILOps, OS);
369*0d2dde20SXiang Li   OS << "#endif\n\n";
370264c09b7SXiang Li 
371435897b4Spython3kgae   OS << "\n";
372435897b4Spython3kgae }
373435897b4Spython3kgae 
374435897b4Spython3kgae } // namespace llvm
375