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 
140d2dde20SXiang Li #include "SequenceToOffsetTable.h"
15435897b4Spython3kgae #include "llvm/ADT/STLExtras.h"
16435897b4Spython3kgae #include "llvm/ADT/SmallVector.h"
17435897b4Spython3kgae #include "llvm/ADT/StringSet.h"
180d2dde20SXiang Li #include "llvm/ADT/StringSwitch.h"
1957006b14SXiang Li #include "llvm/Support/DXILOperationCommon.h"
20435897b4Spython3kgae #include "llvm/TableGen/Error.h"
21435897b4Spython3kgae #include "llvm/TableGen/Record.h"
22435897b4Spython3kgae 
23435897b4Spython3kgae using namespace llvm;
2457006b14SXiang Li using namespace llvm::DXIL;
25435897b4Spython3kgae 
26435897b4Spython3kgae namespace {
27435897b4Spython3kgae 
28435897b4Spython3kgae struct DXILShaderModel {
29435897b4Spython3kgae   int Major;
30435897b4Spython3kgae   int Minor;
31435897b4Spython3kgae };
3257006b14SXiang Li 
33435897b4Spython3kgae struct DXILParam {
34435897b4Spython3kgae   int Pos; // position in parameter list
3557006b14SXiang Li   ParameterKind Kind;
36435897b4Spython3kgae   StringRef Name; // short, unique name
37435897b4Spython3kgae   StringRef Doc;  // the documentation description of this parameter
38435897b4Spython3kgae   bool IsConst;   // whether this argument requires a constant value in the IR
39435897b4Spython3kgae   StringRef EnumName; // the name of the enum type if applicable
40435897b4Spython3kgae   int MaxValue;       // the maximum value for this parameter if applicable
4157006b14SXiang Li   DXILParam(const Record *R);
42435897b4Spython3kgae };
43435897b4Spython3kgae 
44435897b4Spython3kgae struct DXILOperationData {
45435897b4Spython3kgae   StringRef Name; // short, unique name
46435897b4Spython3kgae 
47435897b4Spython3kgae   StringRef DXILOp;    // name of DXIL operation
48435897b4Spython3kgae   int DXILOpID;        // ID of DXIL operation
49435897b4Spython3kgae   StringRef DXILClass; // name of the opcode class
50435897b4Spython3kgae   StringRef Category;  // classification for this instruction
51435897b4Spython3kgae   StringRef Doc;       // the documentation description of this instruction
52435897b4Spython3kgae 
53435897b4Spython3kgae   SmallVector<DXILParam> Params; // the operands that this instruction takes
54435897b4Spython3kgae   StringRef OverloadTypes;       // overload types if applicable
55435897b4Spython3kgae   StringRef FnAttr;              // attribute shorthands: rn=does not access
56264c09b7SXiang Li                                  // memory,ro=only reads from memory
57264c09b7SXiang Li   StringRef Intrinsic; // The llvm intrinsic map to DXILOp. Default is "" which
58264c09b7SXiang Li                        // means no map exist
59435897b4Spython3kgae   bool IsDeriv;        // whether this is some kind of derivative
60435897b4Spython3kgae   bool IsGradient;               // whether this requires a gradient calculation
61435897b4Spython3kgae   bool IsFeedback;               // whether this is a sampler feedback op
62435897b4Spython3kgae   bool IsWave; // whether this requires in-wave, cross-lane functionality
63435897b4Spython3kgae   bool RequiresUniformInputs; // whether this operation requires that all
64435897b4Spython3kgae                               // of its inputs are uniform across the wave
65435897b4Spython3kgae   SmallVector<StringRef, 4>
66435897b4Spython3kgae       ShaderStages; // shader stages to which this applies, empty for all.
67435897b4Spython3kgae   DXILShaderModel ShaderModel;           // minimum shader model required
68435897b4Spython3kgae   DXILShaderModel ShaderModelTranslated; // minimum shader model required with
69435897b4Spython3kgae                                          // translation by linker
7057006b14SXiang Li   int OverloadParamIndex; // parameter index which control the overload.
7157006b14SXiang Li                           // When < 0, should be only 1 overload type.
72435897b4Spython3kgae   SmallVector<StringRef, 4> counters; // counters for this inst.
DXILOperationData__anon4696d6560111::DXILOperationData73435897b4Spython3kgae   DXILOperationData(const Record *R) {
74435897b4Spython3kgae     Name = R->getValueAsString("name");
75435897b4Spython3kgae     DXILOp = R->getValueAsString("dxil_op");
76435897b4Spython3kgae     DXILOpID = R->getValueAsInt("dxil_opid");
77435897b4Spython3kgae     DXILClass = R->getValueAsDef("op_class")->getValueAsString("name");
78435897b4Spython3kgae     Category = R->getValueAsDef("category")->getValueAsString("name");
79435897b4Spython3kgae 
80264c09b7SXiang Li     if (R->getValue("llvm_intrinsic")) {
81264c09b7SXiang Li       auto *IntrinsicDef = R->getValueAsDef("llvm_intrinsic");
82264c09b7SXiang Li       auto DefName = IntrinsicDef->getName();
83264c09b7SXiang Li       assert(DefName.startswith("int_") && "invalid intrinsic name");
84264c09b7SXiang Li       // Remove the int_ from intrinsic name.
85264c09b7SXiang Li       Intrinsic = DefName.substr(4);
86264c09b7SXiang Li     }
87264c09b7SXiang Li 
88435897b4Spython3kgae     Doc = R->getValueAsString("doc");
89264c09b7SXiang Li 
90435897b4Spython3kgae     ListInit *ParamList = R->getValueAsListInit("ops");
9157006b14SXiang Li     OverloadParamIndex = -1;
9257006b14SXiang Li     for (unsigned I = 0; I < ParamList->size(); ++I) {
9357006b14SXiang Li       Record *Param = ParamList->getElementAsRecord(I);
94435897b4Spython3kgae       Params.emplace_back(DXILParam(Param));
9557006b14SXiang Li       auto &CurParam = Params.back();
9657006b14SXiang Li       if (CurParam.Kind >= ParameterKind::OVERLOAD)
9757006b14SXiang Li         OverloadParamIndex = I;
98435897b4Spython3kgae     }
99435897b4Spython3kgae     OverloadTypes = R->getValueAsString("oload_types");
100435897b4Spython3kgae     FnAttr = R->getValueAsString("fn_attr");
101435897b4Spython3kgae   }
102435897b4Spython3kgae };
103435897b4Spython3kgae } // end anonymous namespace
104435897b4Spython3kgae 
DXILParam(const Record * R)10557006b14SXiang Li DXILParam::DXILParam(const Record *R) {
10657006b14SXiang Li   Name = R->getValueAsString("name");
10757006b14SXiang Li   Pos = R->getValueAsInt("pos");
10857006b14SXiang Li   Kind = parameterTypeNameToKind(R->getValueAsString("llvm_type"));
10957006b14SXiang Li   if (R->getValue("doc"))
11057006b14SXiang Li     Doc = R->getValueAsString("doc");
11157006b14SXiang Li   IsConst = R->getValueAsBit("is_const");
11257006b14SXiang Li   EnumName = R->getValueAsString("enum_name");
11357006b14SXiang Li   MaxValue = R->getValueAsInt("max_value");
11457006b14SXiang Li }
11557006b14SXiang Li 
parameterKindToString(ParameterKind Kind)11657006b14SXiang Li static std::string parameterKindToString(ParameterKind Kind) {
11757006b14SXiang Li   switch (Kind) {
11857006b14SXiang Li   case ParameterKind::INVALID:
11957006b14SXiang Li     return "INVALID";
12057006b14SXiang Li   case ParameterKind::VOID:
12157006b14SXiang Li     return "VOID";
12257006b14SXiang Li   case ParameterKind::HALF:
12357006b14SXiang Li     return "HALF";
12457006b14SXiang Li   case ParameterKind::FLOAT:
12557006b14SXiang Li     return "FLOAT";
12657006b14SXiang Li   case ParameterKind::DOUBLE:
12757006b14SXiang Li     return "DOUBLE";
12857006b14SXiang Li   case ParameterKind::I1:
12957006b14SXiang Li     return "I1";
13057006b14SXiang Li   case ParameterKind::I8:
13157006b14SXiang Li     return "I8";
13257006b14SXiang Li   case ParameterKind::I16:
13357006b14SXiang Li     return "I16";
13457006b14SXiang Li   case ParameterKind::I32:
13557006b14SXiang Li     return "I32";
13657006b14SXiang Li   case ParameterKind::I64:
13757006b14SXiang Li     return "I64";
13857006b14SXiang Li   case ParameterKind::OVERLOAD:
13957006b14SXiang Li     return "OVERLOAD";
14057006b14SXiang Li   case ParameterKind::CBUFFER_RET:
14157006b14SXiang Li     return "CBUFFER_RET";
14257006b14SXiang Li   case ParameterKind::RESOURCE_RET:
14357006b14SXiang Li     return "RESOURCE_RET";
14457006b14SXiang Li   case ParameterKind::DXIL_HANDLE:
14557006b14SXiang Li     return "DXIL_HANDLE";
14657006b14SXiang Li   }
147*da2ed951SSimon Pilgrim   llvm_unreachable("Unknown llvm::DXIL::ParameterKind enum");
14857006b14SXiang Li }
14957006b14SXiang Li 
emitDXILOpEnum(DXILOperationData & DXILOp,raw_ostream & OS)150435897b4Spython3kgae static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
151435897b4Spython3kgae   // Name = ID, // Doc
152435897b4Spython3kgae   OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc
153435897b4Spython3kgae      << "\n";
154435897b4Spython3kgae }
155435897b4Spython3kgae 
buildCategoryStr(StringSet<> & Cetegorys)156435897b4Spython3kgae static std::string buildCategoryStr(StringSet<> &Cetegorys) {
157435897b4Spython3kgae   std::string Str;
158435897b4Spython3kgae   raw_string_ostream OS(Str);
159435897b4Spython3kgae   for (auto &It : Cetegorys) {
160435897b4Spython3kgae     OS << " " << It.getKey();
161435897b4Spython3kgae   }
162435897b4Spython3kgae   return OS.str();
163435897b4Spython3kgae }
164435897b4Spython3kgae 
165435897b4Spython3kgae // Emit enum declaration for DXIL.
emitDXILEnums(std::vector<DXILOperationData> & DXILOps,raw_ostream & OS)166435897b4Spython3kgae static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps,
167435897b4Spython3kgae                           raw_ostream &OS) {
168435897b4Spython3kgae   // Sort by Category + OpName.
169aba43035SDmitri Gribenko   llvm::sort(DXILOps, [](DXILOperationData &A, DXILOperationData &B) {
170435897b4Spython3kgae     // Group by Category first.
171435897b4Spython3kgae     if (A.Category == B.Category)
172435897b4Spython3kgae       // Inside same Category, order by OpName.
173435897b4Spython3kgae       return A.DXILOp < B.DXILOp;
174435897b4Spython3kgae     else
175435897b4Spython3kgae       return A.Category < B.Category;
176435897b4Spython3kgae   });
177435897b4Spython3kgae 
178435897b4Spython3kgae   OS << "// Enumeration for operations specified by DXIL\n";
179435897b4Spython3kgae   OS << "enum class OpCode : unsigned {\n";
180435897b4Spython3kgae 
181435897b4Spython3kgae   StringMap<StringSet<>> ClassMap;
182435897b4Spython3kgae   StringRef PrevCategory = "";
183435897b4Spython3kgae   for (auto &DXILOp : DXILOps) {
184435897b4Spython3kgae     StringRef Category = DXILOp.Category;
185435897b4Spython3kgae     if (Category != PrevCategory) {
186435897b4Spython3kgae       OS << "\n// " << Category << "\n";
187435897b4Spython3kgae       PrevCategory = Category;
188435897b4Spython3kgae     }
189435897b4Spython3kgae     emitDXILOpEnum(DXILOp, OS);
190435897b4Spython3kgae     auto It = ClassMap.find(DXILOp.DXILClass);
191435897b4Spython3kgae     if (It != ClassMap.end()) {
192435897b4Spython3kgae       It->second.insert(DXILOp.Category);
193435897b4Spython3kgae     } else {
194435897b4Spython3kgae       ClassMap[DXILOp.DXILClass].insert(DXILOp.Category);
195435897b4Spython3kgae     }
196435897b4Spython3kgae   }
197435897b4Spython3kgae 
198435897b4Spython3kgae   OS << "\n};\n\n";
199435897b4Spython3kgae 
200435897b4Spython3kgae   std::vector<std::pair<std::string, std::string>> ClassVec;
201435897b4Spython3kgae   for (auto &It : ClassMap) {
202435897b4Spython3kgae     ClassVec.emplace_back(
203435897b4Spython3kgae         std::make_pair(It.getKey().str(), buildCategoryStr(It.second)));
204435897b4Spython3kgae   }
205435897b4Spython3kgae   // Sort by Category + ClassName.
206aba43035SDmitri Gribenko   llvm::sort(ClassVec, [](std::pair<std::string, std::string> &A,
207435897b4Spython3kgae                           std::pair<std::string, std::string> &B) {
208435897b4Spython3kgae     StringRef ClassA = A.first;
209435897b4Spython3kgae     StringRef CategoryA = A.second;
210435897b4Spython3kgae     StringRef ClassB = B.first;
211435897b4Spython3kgae     StringRef CategoryB = B.second;
212435897b4Spython3kgae     // Group by Category first.
213435897b4Spython3kgae     if (CategoryA == CategoryB)
214435897b4Spython3kgae       // Inside same Category, order by ClassName.
215435897b4Spython3kgae       return ClassA < ClassB;
216435897b4Spython3kgae     else
217435897b4Spython3kgae       return CategoryA < CategoryB;
218435897b4Spython3kgae   });
219435897b4Spython3kgae 
220435897b4Spython3kgae   OS << "// Groups for DXIL operations with equivalent function templates\n";
221435897b4Spython3kgae   OS << "enum class OpCodeClass : unsigned {\n";
222435897b4Spython3kgae   PrevCategory = "";
223435897b4Spython3kgae   for (auto &It : ClassVec) {
224435897b4Spython3kgae 
225435897b4Spython3kgae     StringRef Category = It.second;
226435897b4Spython3kgae     if (Category != PrevCategory) {
227435897b4Spython3kgae       OS << "\n// " << Category << "\n";
228435897b4Spython3kgae       PrevCategory = Category;
229435897b4Spython3kgae     }
230435897b4Spython3kgae     StringRef Name = It.first;
231435897b4Spython3kgae     OS << Name << ",\n";
232435897b4Spython3kgae   }
233435897b4Spython3kgae   OS << "\n};\n\n";
234435897b4Spython3kgae }
235435897b4Spython3kgae 
236264c09b7SXiang Li // Emit map from llvm intrinsic to DXIL operation.
emitDXILIntrinsicMap(std::vector<DXILOperationData> & DXILOps,raw_ostream & OS)2370d2dde20SXiang Li static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps,
238264c09b7SXiang Li                                  raw_ostream &OS) {
239264c09b7SXiang Li   OS << "\n";
240264c09b7SXiang Li   // FIXME: use array instead of SmallDenseMap.
241264c09b7SXiang Li   OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = "
242264c09b7SXiang Li         "{\n";
243264c09b7SXiang Li   for (auto &DXILOp : DXILOps) {
244264c09b7SXiang Li     if (DXILOp.Intrinsic.empty())
245264c09b7SXiang Li       continue;
246264c09b7SXiang Li     // {Intrinsic::sin, DXIL::OpCode::Sin},
247264c09b7SXiang Li     OS << "  { Intrinsic::" << DXILOp.Intrinsic
248264c09b7SXiang Li        << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n";
249264c09b7SXiang Li   }
250264c09b7SXiang Li   OS << "};\n";
251264c09b7SXiang Li   OS << "\n";
252264c09b7SXiang Li }
253264c09b7SXiang Li 
emitDXILOperationFnAttr(StringRef FnAttr)2540d2dde20SXiang Li static std::string emitDXILOperationFnAttr(StringRef FnAttr) {
2550d2dde20SXiang Li   return StringSwitch<std::string>(FnAttr)
2560d2dde20SXiang Li       .Case("rn", "Attribute::ReadNone")
2570d2dde20SXiang Li       .Case("ro", "Attribute::ReadOnly")
2580d2dde20SXiang Li       .Default("Attribute::None");
2590d2dde20SXiang Li }
2600d2dde20SXiang Li 
getOverloadKind(StringRef Overload)2610d2dde20SXiang Li static std::string getOverloadKind(StringRef Overload) {
2620d2dde20SXiang Li   return StringSwitch<std::string>(Overload)
2630d2dde20SXiang Li       .Case("half", "OverloadKind::HALF")
2640d2dde20SXiang Li       .Case("float", "OverloadKind::FLOAT")
2650d2dde20SXiang Li       .Case("double", "OverloadKind::DOUBLE")
2660d2dde20SXiang Li       .Case("i1", "OverloadKind::I1")
2670d2dde20SXiang Li       .Case("i16", "OverloadKind::I16")
2680d2dde20SXiang Li       .Case("i32", "OverloadKind::I32")
2690d2dde20SXiang Li       .Case("i64", "OverloadKind::I64")
2700d2dde20SXiang Li       .Case("udt", "OverloadKind::UserDefineType")
2710d2dde20SXiang Li       .Case("obj", "OverloadKind::ObjectType")
2720d2dde20SXiang Li       .Default("OverloadKind::VOID");
2730d2dde20SXiang Li }
2740d2dde20SXiang Li 
getDXILOperationOverload(StringRef Overloads)2750d2dde20SXiang Li static std::string getDXILOperationOverload(StringRef Overloads) {
2760d2dde20SXiang Li   SmallVector<StringRef> OverloadStrs;
2770d2dde20SXiang Li   Overloads.split(OverloadStrs, ';', /*MaxSplit*/ -1, /*KeepEmpty*/ false);
2780d2dde20SXiang Li   // Format is: OverloadKind::FLOAT | OverloadKind::HALF
2790d2dde20SXiang Li   assert(!OverloadStrs.empty() && "Invalid overloads");
2800d2dde20SXiang Li   auto It = OverloadStrs.begin();
2810d2dde20SXiang Li   std::string Result;
2820d2dde20SXiang Li   raw_string_ostream OS(Result);
2830d2dde20SXiang Li   OS << getOverloadKind(*It);
2840d2dde20SXiang Li   for (++It; It != OverloadStrs.end(); ++It) {
2850d2dde20SXiang Li     OS << " | " << getOverloadKind(*It);
2860d2dde20SXiang Li   }
2870d2dde20SXiang Li   return OS.str();
2880d2dde20SXiang Li }
2890d2dde20SXiang Li 
lowerFirstLetter(StringRef Name)2900d2dde20SXiang Li static std::string lowerFirstLetter(StringRef Name) {
2910d2dde20SXiang Li   if (Name.empty())
2920d2dde20SXiang Li     return "";
2930d2dde20SXiang Li 
2940d2dde20SXiang Li   std::string LowerName = Name.str();
2950d2dde20SXiang Li   LowerName[0] = llvm::toLower(Name[0]);
2960d2dde20SXiang Li   return LowerName;
2970d2dde20SXiang Li }
2980d2dde20SXiang Li 
getDXILOpClassName(StringRef DXILOpClass)2990d2dde20SXiang Li static std::string getDXILOpClassName(StringRef DXILOpClass) {
3000d2dde20SXiang Li   // Lower first letter expect for special case.
3010d2dde20SXiang Li   return StringSwitch<std::string>(DXILOpClass)
3020d2dde20SXiang Li       .Case("CBufferLoad", "cbufferLoad")
3030d2dde20SXiang Li       .Case("CBufferLoadLegacy", "cbufferLoadLegacy")
3040d2dde20SXiang Li       .Case("GSInstanceID", "gsInstanceID")
3050d2dde20SXiang Li       .Default(lowerFirstLetter(DXILOpClass));
3060d2dde20SXiang Li }
3070d2dde20SXiang Li 
emitDXILOperationTable(std::vector<DXILOperationData> & DXILOps,raw_ostream & OS)3080d2dde20SXiang Li static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
3090d2dde20SXiang Li                                    raw_ostream &OS) {
3100d2dde20SXiang Li   // Sort by DXILOpID.
311aba43035SDmitri Gribenko   llvm::sort(DXILOps, [](DXILOperationData &A, DXILOperationData &B) {
3120d2dde20SXiang Li     return A.DXILOpID < B.DXILOpID;
3130d2dde20SXiang Li   });
3140d2dde20SXiang Li 
3150d2dde20SXiang Li   // Collect Names.
3160d2dde20SXiang Li   SequenceToOffsetTable<std::string> OpClassStrings;
3170d2dde20SXiang Li   SequenceToOffsetTable<std::string> OpStrings;
31857006b14SXiang Li   SequenceToOffsetTable<SmallVector<ParameterKind>> Parameters;
3190d2dde20SXiang Li 
32057006b14SXiang Li   StringMap<SmallVector<ParameterKind>> ParameterMap;
3210d2dde20SXiang Li   StringSet<> ClassSet;
3220d2dde20SXiang Li   for (auto &DXILOp : DXILOps) {
3230d2dde20SXiang Li     OpStrings.add(DXILOp.DXILOp.str());
3240d2dde20SXiang Li 
3250d2dde20SXiang Li     if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end())
3260d2dde20SXiang Li       continue;
3270d2dde20SXiang Li     ClassSet.insert(DXILOp.DXILClass);
3280d2dde20SXiang Li     OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass));
32957006b14SXiang Li     SmallVector<ParameterKind> ParamKindVec;
33057006b14SXiang Li     for (auto &Param : DXILOp.Params) {
33157006b14SXiang Li       ParamKindVec.emplace_back(Param.Kind);
33257006b14SXiang Li     }
33357006b14SXiang Li     ParameterMap[DXILOp.DXILClass] = ParamKindVec;
33457006b14SXiang Li     Parameters.add(ParamKindVec);
3350d2dde20SXiang Li   }
3360d2dde20SXiang Li 
3370d2dde20SXiang Li   // Layout names.
3380d2dde20SXiang Li   OpStrings.layout();
3390d2dde20SXiang Li   OpClassStrings.layout();
34057006b14SXiang Li   Parameters.layout();
3410d2dde20SXiang Li 
3420d2dde20SXiang Li   // Emit the DXIL operation table.
3430d2dde20SXiang Li   //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary,
3440d2dde20SXiang Li   // OpCodeClassNameIndex,
34557006b14SXiang Li   // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone, 0,
34657006b14SXiang Li   // 3, ParameterTableOffset},
3470d2dde20SXiang Li   OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) "
3480d2dde20SXiang Li         "{\n";
3490d2dde20SXiang Li 
3500d2dde20SXiang Li   OS << "  static const OpCodeProperty OpCodeProps[] = {\n";
3510d2dde20SXiang Li   for (auto &DXILOp : DXILOps) {
3520d2dde20SXiang Li     OS << "  { DXIL::OpCode::" << DXILOp.DXILOp << ", "
3530d2dde20SXiang Li        << OpStrings.get(DXILOp.DXILOp.str())
3540d2dde20SXiang Li        << ", OpCodeClass::" << DXILOp.DXILClass << ", "
3550d2dde20SXiang Li        << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", "
3560d2dde20SXiang Li        << getDXILOperationOverload(DXILOp.OverloadTypes) << ", "
35757006b14SXiang Li        << emitDXILOperationFnAttr(DXILOp.FnAttr) << ", "
35857006b14SXiang Li        << DXILOp.OverloadParamIndex << ", " << DXILOp.Params.size() << ", "
35957006b14SXiang Li        << Parameters.get(ParameterMap[DXILOp.DXILClass]) << " },\n";
3600d2dde20SXiang Li   }
3610d2dde20SXiang Li   OS << "  };\n";
3620d2dde20SXiang Li 
3630d2dde20SXiang Li   OS << "  // FIXME: change search to indexing with\n";
3640d2dde20SXiang Li   OS << "  // DXILOp once all DXIL op is added.\n";
3650d2dde20SXiang Li   OS << "  OpCodeProperty TmpProp;\n";
3660d2dde20SXiang Li   OS << "  TmpProp.OpCode = DXILOp;\n";
3670d2dde20SXiang Li   OS << "  const OpCodeProperty *Prop =\n";
3680d2dde20SXiang Li   OS << "      llvm::lower_bound(OpCodeProps, TmpProp,\n";
3690d2dde20SXiang Li   OS << "                        [](const OpCodeProperty &A, const "
3700d2dde20SXiang Li         "OpCodeProperty &B) {\n";
3710d2dde20SXiang Li   OS << "                          return A.OpCode < B.OpCode;\n";
3720d2dde20SXiang Li   OS << "                        });\n";
3730d2dde20SXiang Li   OS << "  assert(Prop && \"fail to find OpCodeProperty\");\n";
3740d2dde20SXiang Li   OS << "  return Prop;\n";
3750d2dde20SXiang Li   OS << "}\n\n";
3760d2dde20SXiang Li 
3770d2dde20SXiang Li   // Emit the string tables.
3780d2dde20SXiang Li   OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n";
3790d2dde20SXiang Li 
3800d2dde20SXiang Li   OpStrings.emitStringLiteralDef(OS,
3810d2dde20SXiang Li                                  "  static const char DXILOpCodeNameTable[]");
3820d2dde20SXiang Li 
3830d2dde20SXiang Li   OS << "  auto *Prop = getOpCodeProperty(DXILOp);\n";
3840d2dde20SXiang Li   OS << "  unsigned Index = Prop->OpCodeNameOffset;\n";
3850d2dde20SXiang Li   OS << "  return DXILOpCodeNameTable + Index;\n";
3860d2dde20SXiang Li   OS << "}\n\n";
3870d2dde20SXiang Li 
3880d2dde20SXiang Li   OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) "
3890d2dde20SXiang Li         "{\n\n";
3900d2dde20SXiang Li 
3910d2dde20SXiang Li   OpClassStrings.emitStringLiteralDef(
3920d2dde20SXiang Li       OS, "  static const char DXILOpCodeClassNameTable[]");
3930d2dde20SXiang Li 
3940d2dde20SXiang Li   OS << "  unsigned Index = Prop.OpCodeClassNameOffset;\n";
3950d2dde20SXiang Li   OS << "  return DXILOpCodeClassNameTable + Index;\n";
3960d2dde20SXiang Li   OS << "}\n ";
39757006b14SXiang Li 
39857006b14SXiang Li   OS << "static const ParameterKind *getOpCodeParameterKind(const "
39957006b14SXiang Li         "OpCodeProperty &Prop) "
40057006b14SXiang Li         "{\n\n";
40157006b14SXiang Li   OS << "  static const ParameterKind DXILOpParameterKindTable[] = {\n";
40257006b14SXiang Li   Parameters.emit(
40357006b14SXiang Li       OS,
40457006b14SXiang Li       [](raw_ostream &ParamOS, ParameterKind Kind) {
40557006b14SXiang Li         ParamOS << "ParameterKind::" << parameterKindToString(Kind);
40657006b14SXiang Li       },
40757006b14SXiang Li       "ParameterKind::INVALID");
40857006b14SXiang Li   OS << "  };\n\n";
40957006b14SXiang Li   OS << "  unsigned Index = Prop.ParameterTableOffset;\n";
41057006b14SXiang Li   OS << "  return DXILOpParameterKindTable + Index;\n";
41157006b14SXiang Li   OS << "}\n ";
4120d2dde20SXiang Li }
4130d2dde20SXiang Li 
414435897b4Spython3kgae namespace llvm {
415435897b4Spython3kgae 
EmitDXILOperation(RecordKeeper & Records,raw_ostream & OS)416435897b4Spython3kgae void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
417435897b4Spython3kgae   std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op");
418435897b4Spython3kgae   OS << "// Generated code, do not edit.\n";
419435897b4Spython3kgae   OS << "\n";
420435897b4Spython3kgae 
421435897b4Spython3kgae   std::vector<DXILOperationData> DXILOps;
422435897b4Spython3kgae   DXILOps.reserve(Ops.size());
423435897b4Spython3kgae   for (auto *Record : Ops) {
424435897b4Spython3kgae     DXILOps.emplace_back(DXILOperationData(Record));
425435897b4Spython3kgae   }
426435897b4Spython3kgae 
427435897b4Spython3kgae   OS << "#ifdef DXIL_OP_ENUM\n";
428435897b4Spython3kgae   emitDXILEnums(DXILOps, OS);
429435897b4Spython3kgae   OS << "#endif\n\n";
430435897b4Spython3kgae 
431264c09b7SXiang Li   OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n";
4320d2dde20SXiang Li   emitDXILIntrinsicMap(DXILOps, OS);
433264c09b7SXiang Li   OS << "#endif\n\n";
434264c09b7SXiang Li 
4350d2dde20SXiang Li   OS << "#ifdef DXIL_OP_OPERATION_TABLE\n";
4360d2dde20SXiang Li   emitDXILOperationTable(DXILOps, OS);
4370d2dde20SXiang Li   OS << "#endif\n\n";
438264c09b7SXiang Li 
439435897b4Spython3kgae   OS << "\n";
440435897b4Spython3kgae }
441435897b4Spython3kgae 
442435897b4Spython3kgae } // namespace llvm
443