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