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