xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/DXILEmitter.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1*81ad6265SDimitry Andric //===- DXILEmitter.cpp - DXIL operation Emitter ---------------------------===//
2*81ad6265SDimitry Andric //
3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*81ad6265SDimitry Andric //
7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
8*81ad6265SDimitry Andric //
9*81ad6265SDimitry Andric // DXILEmitter uses the descriptions of DXIL operation to construct enum and
10*81ad6265SDimitry Andric // helper functions for DXIL operation.
11*81ad6265SDimitry Andric //
12*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
13*81ad6265SDimitry Andric 
14*81ad6265SDimitry Andric #include "SequenceToOffsetTable.h"
15*81ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
16*81ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
17*81ad6265SDimitry Andric #include "llvm/ADT/StringSet.h"
18*81ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h"
19*81ad6265SDimitry Andric #include "llvm/TableGen/Error.h"
20*81ad6265SDimitry Andric #include "llvm/TableGen/Record.h"
21*81ad6265SDimitry Andric 
22*81ad6265SDimitry Andric using namespace llvm;
23*81ad6265SDimitry Andric 
24*81ad6265SDimitry Andric namespace {
25*81ad6265SDimitry Andric 
26*81ad6265SDimitry Andric struct DXILShaderModel {
27*81ad6265SDimitry Andric   int Major;
28*81ad6265SDimitry Andric   int Minor;
29*81ad6265SDimitry Andric };
30*81ad6265SDimitry Andric struct DXILParam {
31*81ad6265SDimitry Andric   int Pos;        // position in parameter list
32*81ad6265SDimitry Andric   StringRef Type; // llvm type name, $o for overload, $r for resource
33*81ad6265SDimitry Andric                   // type, $cb for legacy cbuffer, $u4 for u4 struct
34*81ad6265SDimitry Andric   StringRef Name; // short, unique name
35*81ad6265SDimitry Andric   StringRef Doc;  // the documentation description of this parameter
36*81ad6265SDimitry Andric   bool IsConst;   // whether this argument requires a constant value in the IR
37*81ad6265SDimitry Andric   StringRef EnumName; // the name of the enum type if applicable
38*81ad6265SDimitry Andric   int MaxValue;       // the maximum value for this parameter if applicable
39*81ad6265SDimitry Andric   DXILParam(const Record *R) {
40*81ad6265SDimitry Andric     Name = R->getValueAsString("name");
41*81ad6265SDimitry Andric     Pos = R->getValueAsInt("pos");
42*81ad6265SDimitry Andric     Type = R->getValueAsString("llvm_type");
43*81ad6265SDimitry Andric     if (R->getValue("doc"))
44*81ad6265SDimitry Andric       Doc = R->getValueAsString("doc");
45*81ad6265SDimitry Andric     IsConst = R->getValueAsBit("is_const");
46*81ad6265SDimitry Andric     EnumName = R->getValueAsString("enum_name");
47*81ad6265SDimitry Andric     MaxValue = R->getValueAsInt("max_value");
48*81ad6265SDimitry Andric   }
49*81ad6265SDimitry Andric };
50*81ad6265SDimitry Andric 
51*81ad6265SDimitry Andric struct DXILOperationData {
52*81ad6265SDimitry Andric   StringRef Name; // short, unique name
53*81ad6265SDimitry Andric 
54*81ad6265SDimitry Andric   StringRef DXILOp;    // name of DXIL operation
55*81ad6265SDimitry Andric   int DXILOpID;        // ID of DXIL operation
56*81ad6265SDimitry Andric   StringRef DXILClass; // name of the opcode class
57*81ad6265SDimitry Andric   StringRef Category;  // classification for this instruction
58*81ad6265SDimitry Andric   StringRef Doc;       // the documentation description of this instruction
59*81ad6265SDimitry Andric 
60*81ad6265SDimitry Andric   SmallVector<DXILParam> Params; // the operands that this instruction takes
61*81ad6265SDimitry Andric   StringRef OverloadTypes;       // overload types if applicable
62*81ad6265SDimitry Andric   StringRef FnAttr;              // attribute shorthands: rn=does not access
63*81ad6265SDimitry Andric                                  // memory,ro=only reads from memory
64*81ad6265SDimitry Andric   StringRef Intrinsic; // The llvm intrinsic map to DXILOp. Default is "" which
65*81ad6265SDimitry Andric                        // means no map exist
66*81ad6265SDimitry Andric   bool IsDeriv;        // whether this is some kind of derivative
67*81ad6265SDimitry Andric   bool IsGradient;               // whether this requires a gradient calculation
68*81ad6265SDimitry Andric   bool IsFeedback;               // whether this is a sampler feedback op
69*81ad6265SDimitry Andric   bool IsWave; // whether this requires in-wave, cross-lane functionality
70*81ad6265SDimitry Andric   bool RequiresUniformInputs; // whether this operation requires that all
71*81ad6265SDimitry Andric                               // of its inputs are uniform across the wave
72*81ad6265SDimitry Andric   SmallVector<StringRef, 4>
73*81ad6265SDimitry Andric       ShaderStages; // shader stages to which this applies, empty for all.
74*81ad6265SDimitry Andric   DXILShaderModel ShaderModel;           // minimum shader model required
75*81ad6265SDimitry Andric   DXILShaderModel ShaderModelTranslated; // minimum shader model required with
76*81ad6265SDimitry Andric                                          // translation by linker
77*81ad6265SDimitry Andric   SmallVector<StringRef, 4> counters;    // counters for this inst.
78*81ad6265SDimitry Andric   DXILOperationData(const Record *R) {
79*81ad6265SDimitry Andric     Name = R->getValueAsString("name");
80*81ad6265SDimitry Andric     DXILOp = R->getValueAsString("dxil_op");
81*81ad6265SDimitry Andric     DXILOpID = R->getValueAsInt("dxil_opid");
82*81ad6265SDimitry Andric     DXILClass = R->getValueAsDef("op_class")->getValueAsString("name");
83*81ad6265SDimitry Andric     Category = R->getValueAsDef("category")->getValueAsString("name");
84*81ad6265SDimitry Andric 
85*81ad6265SDimitry Andric     if (R->getValue("llvm_intrinsic")) {
86*81ad6265SDimitry Andric       auto *IntrinsicDef = R->getValueAsDef("llvm_intrinsic");
87*81ad6265SDimitry Andric       auto DefName = IntrinsicDef->getName();
88*81ad6265SDimitry Andric       assert(DefName.startswith("int_") && "invalid intrinsic name");
89*81ad6265SDimitry Andric       // Remove the int_ from intrinsic name.
90*81ad6265SDimitry Andric       Intrinsic = DefName.substr(4);
91*81ad6265SDimitry Andric     }
92*81ad6265SDimitry Andric 
93*81ad6265SDimitry Andric     Doc = R->getValueAsString("doc");
94*81ad6265SDimitry Andric 
95*81ad6265SDimitry Andric     ListInit *ParamList = R->getValueAsListInit("ops");
96*81ad6265SDimitry Andric     for (unsigned i = 0; i < ParamList->size(); ++i) {
97*81ad6265SDimitry Andric       Record *Param = ParamList->getElementAsRecord(i);
98*81ad6265SDimitry Andric       Params.emplace_back(DXILParam(Param));
99*81ad6265SDimitry Andric     }
100*81ad6265SDimitry Andric     OverloadTypes = R->getValueAsString("oload_types");
101*81ad6265SDimitry Andric     FnAttr = R->getValueAsString("fn_attr");
102*81ad6265SDimitry Andric   }
103*81ad6265SDimitry Andric };
104*81ad6265SDimitry Andric } // end anonymous namespace
105*81ad6265SDimitry Andric 
106*81ad6265SDimitry Andric static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
107*81ad6265SDimitry Andric   // Name = ID, // Doc
108*81ad6265SDimitry Andric   OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc
109*81ad6265SDimitry Andric      << "\n";
110*81ad6265SDimitry Andric }
111*81ad6265SDimitry Andric 
112*81ad6265SDimitry Andric static std::string buildCategoryStr(StringSet<> &Cetegorys) {
113*81ad6265SDimitry Andric   std::string Str;
114*81ad6265SDimitry Andric   raw_string_ostream OS(Str);
115*81ad6265SDimitry Andric   for (auto &It : Cetegorys) {
116*81ad6265SDimitry Andric     OS << " " << It.getKey();
117*81ad6265SDimitry Andric   }
118*81ad6265SDimitry Andric   return OS.str();
119*81ad6265SDimitry Andric }
120*81ad6265SDimitry Andric 
121*81ad6265SDimitry Andric // Emit enum declaration for DXIL.
122*81ad6265SDimitry Andric static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps,
123*81ad6265SDimitry Andric                           raw_ostream &OS) {
124*81ad6265SDimitry Andric   // Sort by Category + OpName.
125*81ad6265SDimitry Andric   std::sort(DXILOps.begin(), DXILOps.end(),
126*81ad6265SDimitry Andric             [](DXILOperationData &A, DXILOperationData &B) {
127*81ad6265SDimitry Andric               // Group by Category first.
128*81ad6265SDimitry Andric               if (A.Category == B.Category)
129*81ad6265SDimitry Andric                 // Inside same Category, order by OpName.
130*81ad6265SDimitry Andric                 return A.DXILOp < B.DXILOp;
131*81ad6265SDimitry Andric               else
132*81ad6265SDimitry Andric                 return A.Category < B.Category;
133*81ad6265SDimitry Andric             });
134*81ad6265SDimitry Andric 
135*81ad6265SDimitry Andric   OS << "// Enumeration for operations specified by DXIL\n";
136*81ad6265SDimitry Andric   OS << "enum class OpCode : unsigned {\n";
137*81ad6265SDimitry Andric 
138*81ad6265SDimitry Andric   StringMap<StringSet<>> ClassMap;
139*81ad6265SDimitry Andric   StringRef PrevCategory = "";
140*81ad6265SDimitry Andric   for (auto &DXILOp : DXILOps) {
141*81ad6265SDimitry Andric     StringRef Category = DXILOp.Category;
142*81ad6265SDimitry Andric     if (Category != PrevCategory) {
143*81ad6265SDimitry Andric       OS << "\n// " << Category << "\n";
144*81ad6265SDimitry Andric       PrevCategory = Category;
145*81ad6265SDimitry Andric     }
146*81ad6265SDimitry Andric     emitDXILOpEnum(DXILOp, OS);
147*81ad6265SDimitry Andric     auto It = ClassMap.find(DXILOp.DXILClass);
148*81ad6265SDimitry Andric     if (It != ClassMap.end()) {
149*81ad6265SDimitry Andric       It->second.insert(DXILOp.Category);
150*81ad6265SDimitry Andric     } else {
151*81ad6265SDimitry Andric       ClassMap[DXILOp.DXILClass].insert(DXILOp.Category);
152*81ad6265SDimitry Andric     }
153*81ad6265SDimitry Andric   }
154*81ad6265SDimitry Andric 
155*81ad6265SDimitry Andric   OS << "\n};\n\n";
156*81ad6265SDimitry Andric 
157*81ad6265SDimitry Andric   std::vector<std::pair<std::string, std::string>> ClassVec;
158*81ad6265SDimitry Andric   for (auto &It : ClassMap) {
159*81ad6265SDimitry Andric     ClassVec.emplace_back(
160*81ad6265SDimitry Andric         std::make_pair(It.getKey().str(), buildCategoryStr(It.second)));
161*81ad6265SDimitry Andric   }
162*81ad6265SDimitry Andric   // Sort by Category + ClassName.
163*81ad6265SDimitry Andric   std::sort(ClassVec.begin(), ClassVec.end(),
164*81ad6265SDimitry Andric             [](std::pair<std::string, std::string> &A,
165*81ad6265SDimitry Andric                std::pair<std::string, std::string> &B) {
166*81ad6265SDimitry Andric               StringRef ClassA = A.first;
167*81ad6265SDimitry Andric               StringRef CategoryA = A.second;
168*81ad6265SDimitry Andric               StringRef ClassB = B.first;
169*81ad6265SDimitry Andric               StringRef CategoryB = B.second;
170*81ad6265SDimitry Andric               // Group by Category first.
171*81ad6265SDimitry Andric               if (CategoryA == CategoryB)
172*81ad6265SDimitry Andric                 // Inside same Category, order by ClassName.
173*81ad6265SDimitry Andric                 return ClassA < ClassB;
174*81ad6265SDimitry Andric               else
175*81ad6265SDimitry Andric                 return CategoryA < CategoryB;
176*81ad6265SDimitry Andric             });
177*81ad6265SDimitry Andric 
178*81ad6265SDimitry Andric   OS << "// Groups for DXIL operations with equivalent function templates\n";
179*81ad6265SDimitry Andric   OS << "enum class OpCodeClass : unsigned {\n";
180*81ad6265SDimitry Andric   PrevCategory = "";
181*81ad6265SDimitry Andric   for (auto &It : ClassVec) {
182*81ad6265SDimitry Andric 
183*81ad6265SDimitry Andric     StringRef Category = It.second;
184*81ad6265SDimitry Andric     if (Category != PrevCategory) {
185*81ad6265SDimitry Andric       OS << "\n// " << Category << "\n";
186*81ad6265SDimitry Andric       PrevCategory = Category;
187*81ad6265SDimitry Andric     }
188*81ad6265SDimitry Andric     StringRef Name = It.first;
189*81ad6265SDimitry Andric     OS << Name << ",\n";
190*81ad6265SDimitry Andric   }
191*81ad6265SDimitry Andric   OS << "\n};\n\n";
192*81ad6265SDimitry Andric }
193*81ad6265SDimitry Andric 
194*81ad6265SDimitry Andric // Emit map from llvm intrinsic to DXIL operation.
195*81ad6265SDimitry Andric static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps,
196*81ad6265SDimitry Andric                                  raw_ostream &OS) {
197*81ad6265SDimitry Andric   OS << "\n";
198*81ad6265SDimitry Andric   // FIXME: use array instead of SmallDenseMap.
199*81ad6265SDimitry Andric   OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = "
200*81ad6265SDimitry Andric         "{\n";
201*81ad6265SDimitry Andric   for (auto &DXILOp : DXILOps) {
202*81ad6265SDimitry Andric     if (DXILOp.Intrinsic.empty())
203*81ad6265SDimitry Andric       continue;
204*81ad6265SDimitry Andric     // {Intrinsic::sin, DXIL::OpCode::Sin},
205*81ad6265SDimitry Andric     OS << "  { Intrinsic::" << DXILOp.Intrinsic
206*81ad6265SDimitry Andric        << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n";
207*81ad6265SDimitry Andric   }
208*81ad6265SDimitry Andric   OS << "};\n";
209*81ad6265SDimitry Andric   OS << "\n";
210*81ad6265SDimitry Andric }
211*81ad6265SDimitry Andric 
212*81ad6265SDimitry Andric static std::string emitDXILOperationFnAttr(StringRef FnAttr) {
213*81ad6265SDimitry Andric   return StringSwitch<std::string>(FnAttr)
214*81ad6265SDimitry Andric       .Case("rn", "Attribute::ReadNone")
215*81ad6265SDimitry Andric       .Case("ro", "Attribute::ReadOnly")
216*81ad6265SDimitry Andric       .Default("Attribute::None");
217*81ad6265SDimitry Andric }
218*81ad6265SDimitry Andric 
219*81ad6265SDimitry Andric static std::string getOverloadKind(StringRef Overload) {
220*81ad6265SDimitry Andric   return StringSwitch<std::string>(Overload)
221*81ad6265SDimitry Andric       .Case("half", "OverloadKind::HALF")
222*81ad6265SDimitry Andric       .Case("float", "OverloadKind::FLOAT")
223*81ad6265SDimitry Andric       .Case("double", "OverloadKind::DOUBLE")
224*81ad6265SDimitry Andric       .Case("i1", "OverloadKind::I1")
225*81ad6265SDimitry Andric       .Case("i16", "OverloadKind::I16")
226*81ad6265SDimitry Andric       .Case("i32", "OverloadKind::I32")
227*81ad6265SDimitry Andric       .Case("i64", "OverloadKind::I64")
228*81ad6265SDimitry Andric       .Case("udt", "OverloadKind::UserDefineType")
229*81ad6265SDimitry Andric       .Case("obj", "OverloadKind::ObjectType")
230*81ad6265SDimitry Andric       .Default("OverloadKind::VOID");
231*81ad6265SDimitry Andric }
232*81ad6265SDimitry Andric 
233*81ad6265SDimitry Andric static std::string getDXILOperationOverload(StringRef Overloads) {
234*81ad6265SDimitry Andric   SmallVector<StringRef> OverloadStrs;
235*81ad6265SDimitry Andric   Overloads.split(OverloadStrs, ';', /*MaxSplit*/ -1, /*KeepEmpty*/ false);
236*81ad6265SDimitry Andric   // Format is: OverloadKind::FLOAT | OverloadKind::HALF
237*81ad6265SDimitry Andric   assert(!OverloadStrs.empty() && "Invalid overloads");
238*81ad6265SDimitry Andric   auto It = OverloadStrs.begin();
239*81ad6265SDimitry Andric   std::string Result;
240*81ad6265SDimitry Andric   raw_string_ostream OS(Result);
241*81ad6265SDimitry Andric   OS << getOverloadKind(*It);
242*81ad6265SDimitry Andric   for (++It; It != OverloadStrs.end(); ++It) {
243*81ad6265SDimitry Andric     OS << " | " << getOverloadKind(*It);
244*81ad6265SDimitry Andric   }
245*81ad6265SDimitry Andric   return OS.str();
246*81ad6265SDimitry Andric }
247*81ad6265SDimitry Andric 
248*81ad6265SDimitry Andric static std::string lowerFirstLetter(StringRef Name) {
249*81ad6265SDimitry Andric   if (Name.empty())
250*81ad6265SDimitry Andric     return "";
251*81ad6265SDimitry Andric 
252*81ad6265SDimitry Andric   std::string LowerName = Name.str();
253*81ad6265SDimitry Andric   LowerName[0] = llvm::toLower(Name[0]);
254*81ad6265SDimitry Andric   return LowerName;
255*81ad6265SDimitry Andric }
256*81ad6265SDimitry Andric 
257*81ad6265SDimitry Andric static std::string getDXILOpClassName(StringRef DXILOpClass) {
258*81ad6265SDimitry Andric   // Lower first letter expect for special case.
259*81ad6265SDimitry Andric   return StringSwitch<std::string>(DXILOpClass)
260*81ad6265SDimitry Andric       .Case("CBufferLoad", "cbufferLoad")
261*81ad6265SDimitry Andric       .Case("CBufferLoadLegacy", "cbufferLoadLegacy")
262*81ad6265SDimitry Andric       .Case("GSInstanceID", "gsInstanceID")
263*81ad6265SDimitry Andric       .Default(lowerFirstLetter(DXILOpClass));
264*81ad6265SDimitry Andric }
265*81ad6265SDimitry Andric 
266*81ad6265SDimitry Andric static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
267*81ad6265SDimitry Andric                                    raw_ostream &OS) {
268*81ad6265SDimitry Andric   // Sort by DXILOpID.
269*81ad6265SDimitry Andric   std::sort(DXILOps.begin(), DXILOps.end(),
270*81ad6265SDimitry Andric             [](DXILOperationData &A, DXILOperationData &B) {
271*81ad6265SDimitry Andric               return A.DXILOpID < B.DXILOpID;
272*81ad6265SDimitry Andric             });
273*81ad6265SDimitry Andric 
274*81ad6265SDimitry Andric   // Collect Names.
275*81ad6265SDimitry Andric   SequenceToOffsetTable<std::string> OpClassStrings;
276*81ad6265SDimitry Andric   SequenceToOffsetTable<std::string> OpStrings;
277*81ad6265SDimitry Andric 
278*81ad6265SDimitry Andric   StringSet<> ClassSet;
279*81ad6265SDimitry Andric   for (auto &DXILOp : DXILOps) {
280*81ad6265SDimitry Andric     OpStrings.add(DXILOp.DXILOp.str());
281*81ad6265SDimitry Andric 
282*81ad6265SDimitry Andric     if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end())
283*81ad6265SDimitry Andric       continue;
284*81ad6265SDimitry Andric     ClassSet.insert(DXILOp.DXILClass);
285*81ad6265SDimitry Andric     OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass));
286*81ad6265SDimitry Andric   }
287*81ad6265SDimitry Andric 
288*81ad6265SDimitry Andric   // Layout names.
289*81ad6265SDimitry Andric   OpStrings.layout();
290*81ad6265SDimitry Andric   OpClassStrings.layout();
291*81ad6265SDimitry Andric 
292*81ad6265SDimitry Andric   // Emit the DXIL operation table.
293*81ad6265SDimitry Andric   //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary,
294*81ad6265SDimitry Andric   // OpCodeClassNameIndex,
295*81ad6265SDimitry Andric   // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone},
296*81ad6265SDimitry Andric   OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) "
297*81ad6265SDimitry Andric         "{\n";
298*81ad6265SDimitry Andric 
299*81ad6265SDimitry Andric   OS << "  static const OpCodeProperty OpCodeProps[] = {\n";
300*81ad6265SDimitry Andric   for (auto &DXILOp : DXILOps) {
301*81ad6265SDimitry Andric     OS << "  { DXIL::OpCode::" << DXILOp.DXILOp << ", "
302*81ad6265SDimitry Andric        << OpStrings.get(DXILOp.DXILOp.str())
303*81ad6265SDimitry Andric        << ", OpCodeClass::" << DXILOp.DXILClass << ", "
304*81ad6265SDimitry Andric        << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", "
305*81ad6265SDimitry Andric        << getDXILOperationOverload(DXILOp.OverloadTypes) << ", "
306*81ad6265SDimitry Andric        << emitDXILOperationFnAttr(DXILOp.FnAttr) << " },\n";
307*81ad6265SDimitry Andric   }
308*81ad6265SDimitry Andric   OS << "  };\n";
309*81ad6265SDimitry Andric 
310*81ad6265SDimitry Andric   OS << "  // FIXME: change search to indexing with\n";
311*81ad6265SDimitry Andric   OS << "  // DXILOp once all DXIL op is added.\n";
312*81ad6265SDimitry Andric   OS << "  OpCodeProperty TmpProp;\n";
313*81ad6265SDimitry Andric   OS << "  TmpProp.OpCode = DXILOp;\n";
314*81ad6265SDimitry Andric   OS << "  const OpCodeProperty *Prop =\n";
315*81ad6265SDimitry Andric   OS << "      llvm::lower_bound(OpCodeProps, TmpProp,\n";
316*81ad6265SDimitry Andric   OS << "                        [](const OpCodeProperty &A, const "
317*81ad6265SDimitry Andric         "OpCodeProperty &B) {\n";
318*81ad6265SDimitry Andric   OS << "                          return A.OpCode < B.OpCode;\n";
319*81ad6265SDimitry Andric   OS << "                        });\n";
320*81ad6265SDimitry Andric   OS << "  assert(Prop && \"fail to find OpCodeProperty\");\n";
321*81ad6265SDimitry Andric   OS << "  return Prop;\n";
322*81ad6265SDimitry Andric   OS << "}\n\n";
323*81ad6265SDimitry Andric 
324*81ad6265SDimitry Andric   // Emit the string tables.
325*81ad6265SDimitry Andric   OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n";
326*81ad6265SDimitry Andric 
327*81ad6265SDimitry Andric   OpStrings.emitStringLiteralDef(OS,
328*81ad6265SDimitry Andric                                  "  static const char DXILOpCodeNameTable[]");
329*81ad6265SDimitry Andric 
330*81ad6265SDimitry Andric   OS << "  auto *Prop = getOpCodeProperty(DXILOp);\n";
331*81ad6265SDimitry Andric   OS << "  unsigned Index = Prop->OpCodeNameOffset;\n";
332*81ad6265SDimitry Andric   OS << "  return DXILOpCodeNameTable + Index;\n";
333*81ad6265SDimitry Andric   OS << "}\n\n";
334*81ad6265SDimitry Andric 
335*81ad6265SDimitry Andric   OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) "
336*81ad6265SDimitry Andric         "{\n\n";
337*81ad6265SDimitry Andric 
338*81ad6265SDimitry Andric   OpClassStrings.emitStringLiteralDef(
339*81ad6265SDimitry Andric       OS, "  static const char DXILOpCodeClassNameTable[]");
340*81ad6265SDimitry Andric 
341*81ad6265SDimitry Andric   OS << "  unsigned Index = Prop.OpCodeClassNameOffset;\n";
342*81ad6265SDimitry Andric   OS << "  return DXILOpCodeClassNameTable + Index;\n";
343*81ad6265SDimitry Andric   OS << "}\n ";
344*81ad6265SDimitry Andric }
345*81ad6265SDimitry Andric 
346*81ad6265SDimitry Andric namespace llvm {
347*81ad6265SDimitry Andric 
348*81ad6265SDimitry Andric void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
349*81ad6265SDimitry Andric   std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op");
350*81ad6265SDimitry Andric   OS << "// Generated code, do not edit.\n";
351*81ad6265SDimitry Andric   OS << "\n";
352*81ad6265SDimitry Andric 
353*81ad6265SDimitry Andric   std::vector<DXILOperationData> DXILOps;
354*81ad6265SDimitry Andric   DXILOps.reserve(Ops.size());
355*81ad6265SDimitry Andric   for (auto *Record : Ops) {
356*81ad6265SDimitry Andric     DXILOps.emplace_back(DXILOperationData(Record));
357*81ad6265SDimitry Andric   }
358*81ad6265SDimitry Andric 
359*81ad6265SDimitry Andric   OS << "#ifdef DXIL_OP_ENUM\n";
360*81ad6265SDimitry Andric   emitDXILEnums(DXILOps, OS);
361*81ad6265SDimitry Andric   OS << "#endif\n\n";
362*81ad6265SDimitry Andric 
363*81ad6265SDimitry Andric   OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n";
364*81ad6265SDimitry Andric   emitDXILIntrinsicMap(DXILOps, OS);
365*81ad6265SDimitry Andric   OS << "#endif\n\n";
366*81ad6265SDimitry Andric 
367*81ad6265SDimitry Andric   OS << "#ifdef DXIL_OP_OPERATION_TABLE\n";
368*81ad6265SDimitry Andric   emitDXILOperationTable(DXILOps, OS);
369*81ad6265SDimitry Andric   OS << "#endif\n\n";
370*81ad6265SDimitry Andric 
371*81ad6265SDimitry Andric   OS << "\n";
372*81ad6265SDimitry Andric }
373*81ad6265SDimitry Andric 
374*81ad6265SDimitry Andric } // namespace llvm
375