xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/DXILEmitter.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
181ad6265SDimitry Andric //===- DXILEmitter.cpp - DXIL operation Emitter ---------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // DXILEmitter uses the descriptions of DXIL operation to construct enum and
1081ad6265SDimitry Andric // helper functions for DXIL operation.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "SequenceToOffsetTable.h"
1581ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
1681ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
1781ad6265SDimitry Andric #include "llvm/ADT/StringSet.h"
1881ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h"
19*972a253aSDimitry Andric #include "llvm/Support/DXILOperationCommon.h"
2081ad6265SDimitry Andric #include "llvm/TableGen/Error.h"
2181ad6265SDimitry Andric #include "llvm/TableGen/Record.h"
2281ad6265SDimitry Andric 
2381ad6265SDimitry Andric using namespace llvm;
24*972a253aSDimitry Andric using namespace llvm::DXIL;
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric namespace {
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric struct DXILShaderModel {
2981ad6265SDimitry Andric   int Major;
3081ad6265SDimitry Andric   int Minor;
3181ad6265SDimitry Andric };
32*972a253aSDimitry Andric 
3381ad6265SDimitry Andric struct DXILParam {
3481ad6265SDimitry Andric   int Pos; // position in parameter list
35*972a253aSDimitry Andric   ParameterKind Kind;
3681ad6265SDimitry Andric   StringRef Name; // short, unique name
3781ad6265SDimitry Andric   StringRef Doc;  // the documentation description of this parameter
3881ad6265SDimitry Andric   bool IsConst;   // whether this argument requires a constant value in the IR
3981ad6265SDimitry Andric   StringRef EnumName; // the name of the enum type if applicable
4081ad6265SDimitry Andric   int MaxValue;       // the maximum value for this parameter if applicable
41*972a253aSDimitry Andric   DXILParam(const Record *R);
4281ad6265SDimitry Andric };
4381ad6265SDimitry Andric 
4481ad6265SDimitry Andric struct DXILOperationData {
4581ad6265SDimitry Andric   StringRef Name; // short, unique name
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric   StringRef DXILOp;    // name of DXIL operation
4881ad6265SDimitry Andric   int DXILOpID;        // ID of DXIL operation
4981ad6265SDimitry Andric   StringRef DXILClass; // name of the opcode class
5081ad6265SDimitry Andric   StringRef Category;  // classification for this instruction
5181ad6265SDimitry Andric   StringRef Doc;       // the documentation description of this instruction
5281ad6265SDimitry Andric 
5381ad6265SDimitry Andric   SmallVector<DXILParam> Params; // the operands that this instruction takes
5481ad6265SDimitry Andric   StringRef OverloadTypes;       // overload types if applicable
5581ad6265SDimitry Andric   StringRef FnAttr;              // attribute shorthands: rn=does not access
5681ad6265SDimitry Andric                                  // memory,ro=only reads from memory
5781ad6265SDimitry Andric   StringRef Intrinsic; // The llvm intrinsic map to DXILOp. Default is "" which
5881ad6265SDimitry Andric                        // means no map exist
5981ad6265SDimitry Andric   bool IsDeriv;        // whether this is some kind of derivative
6081ad6265SDimitry Andric   bool IsGradient;               // whether this requires a gradient calculation
6181ad6265SDimitry Andric   bool IsFeedback;               // whether this is a sampler feedback op
6281ad6265SDimitry Andric   bool IsWave; // whether this requires in-wave, cross-lane functionality
6381ad6265SDimitry Andric   bool RequiresUniformInputs; // whether this operation requires that all
6481ad6265SDimitry Andric                               // of its inputs are uniform across the wave
6581ad6265SDimitry Andric   SmallVector<StringRef, 4>
6681ad6265SDimitry Andric       ShaderStages; // shader stages to which this applies, empty for all.
6781ad6265SDimitry Andric   DXILShaderModel ShaderModel;           // minimum shader model required
6881ad6265SDimitry Andric   DXILShaderModel ShaderModelTranslated; // minimum shader model required with
6981ad6265SDimitry Andric                                          // translation by linker
70*972a253aSDimitry Andric   int OverloadParamIndex; // parameter index which control the overload.
71*972a253aSDimitry Andric                           // When < 0, should be only 1 overload type.
7281ad6265SDimitry Andric   SmallVector<StringRef, 4> counters; // counters for this inst.
7381ad6265SDimitry Andric   DXILOperationData(const Record *R) {
7481ad6265SDimitry Andric     Name = R->getValueAsString("name");
7581ad6265SDimitry Andric     DXILOp = R->getValueAsString("dxil_op");
7681ad6265SDimitry Andric     DXILOpID = R->getValueAsInt("dxil_opid");
7781ad6265SDimitry Andric     DXILClass = R->getValueAsDef("op_class")->getValueAsString("name");
7881ad6265SDimitry Andric     Category = R->getValueAsDef("category")->getValueAsString("name");
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric     if (R->getValue("llvm_intrinsic")) {
8181ad6265SDimitry Andric       auto *IntrinsicDef = R->getValueAsDef("llvm_intrinsic");
8281ad6265SDimitry Andric       auto DefName = IntrinsicDef->getName();
8381ad6265SDimitry Andric       assert(DefName.startswith("int_") && "invalid intrinsic name");
8481ad6265SDimitry Andric       // Remove the int_ from intrinsic name.
8581ad6265SDimitry Andric       Intrinsic = DefName.substr(4);
8681ad6265SDimitry Andric     }
8781ad6265SDimitry Andric 
8881ad6265SDimitry Andric     Doc = R->getValueAsString("doc");
8981ad6265SDimitry Andric 
9081ad6265SDimitry Andric     ListInit *ParamList = R->getValueAsListInit("ops");
91*972a253aSDimitry Andric     OverloadParamIndex = -1;
92*972a253aSDimitry Andric     for (unsigned I = 0; I < ParamList->size(); ++I) {
93*972a253aSDimitry Andric       Record *Param = ParamList->getElementAsRecord(I);
9481ad6265SDimitry Andric       Params.emplace_back(DXILParam(Param));
95*972a253aSDimitry Andric       auto &CurParam = Params.back();
96*972a253aSDimitry Andric       if (CurParam.Kind >= ParameterKind::OVERLOAD)
97*972a253aSDimitry Andric         OverloadParamIndex = I;
9881ad6265SDimitry Andric     }
9981ad6265SDimitry Andric     OverloadTypes = R->getValueAsString("oload_types");
10081ad6265SDimitry Andric     FnAttr = R->getValueAsString("fn_attr");
10181ad6265SDimitry Andric   }
10281ad6265SDimitry Andric };
10381ad6265SDimitry Andric } // end anonymous namespace
10481ad6265SDimitry Andric 
105*972a253aSDimitry Andric DXILParam::DXILParam(const Record *R) {
106*972a253aSDimitry Andric   Name = R->getValueAsString("name");
107*972a253aSDimitry Andric   Pos = R->getValueAsInt("pos");
108*972a253aSDimitry Andric   Kind = parameterTypeNameToKind(R->getValueAsString("llvm_type"));
109*972a253aSDimitry Andric   if (R->getValue("doc"))
110*972a253aSDimitry Andric     Doc = R->getValueAsString("doc");
111*972a253aSDimitry Andric   IsConst = R->getValueAsBit("is_const");
112*972a253aSDimitry Andric   EnumName = R->getValueAsString("enum_name");
113*972a253aSDimitry Andric   MaxValue = R->getValueAsInt("max_value");
114*972a253aSDimitry Andric }
115*972a253aSDimitry Andric 
116*972a253aSDimitry Andric static std::string parameterKindToString(ParameterKind Kind) {
117*972a253aSDimitry Andric   switch (Kind) {
118*972a253aSDimitry Andric   case ParameterKind::INVALID:
119*972a253aSDimitry Andric     return "INVALID";
120*972a253aSDimitry Andric   case ParameterKind::VOID:
121*972a253aSDimitry Andric     return "VOID";
122*972a253aSDimitry Andric   case ParameterKind::HALF:
123*972a253aSDimitry Andric     return "HALF";
124*972a253aSDimitry Andric   case ParameterKind::FLOAT:
125*972a253aSDimitry Andric     return "FLOAT";
126*972a253aSDimitry Andric   case ParameterKind::DOUBLE:
127*972a253aSDimitry Andric     return "DOUBLE";
128*972a253aSDimitry Andric   case ParameterKind::I1:
129*972a253aSDimitry Andric     return "I1";
130*972a253aSDimitry Andric   case ParameterKind::I8:
131*972a253aSDimitry Andric     return "I8";
132*972a253aSDimitry Andric   case ParameterKind::I16:
133*972a253aSDimitry Andric     return "I16";
134*972a253aSDimitry Andric   case ParameterKind::I32:
135*972a253aSDimitry Andric     return "I32";
136*972a253aSDimitry Andric   case ParameterKind::I64:
137*972a253aSDimitry Andric     return "I64";
138*972a253aSDimitry Andric   case ParameterKind::OVERLOAD:
139*972a253aSDimitry Andric     return "OVERLOAD";
140*972a253aSDimitry Andric   case ParameterKind::CBUFFER_RET:
141*972a253aSDimitry Andric     return "CBUFFER_RET";
142*972a253aSDimitry Andric   case ParameterKind::RESOURCE_RET:
143*972a253aSDimitry Andric     return "RESOURCE_RET";
144*972a253aSDimitry Andric   case ParameterKind::DXIL_HANDLE:
145*972a253aSDimitry Andric     return "DXIL_HANDLE";
146*972a253aSDimitry Andric   }
147*972a253aSDimitry Andric   llvm_unreachable("Unknown llvm::DXIL::ParameterKind enum");
148*972a253aSDimitry Andric }
149*972a253aSDimitry Andric 
15081ad6265SDimitry Andric static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
15181ad6265SDimitry Andric   // Name = ID, // Doc
15281ad6265SDimitry Andric   OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc
15381ad6265SDimitry Andric      << "\n";
15481ad6265SDimitry Andric }
15581ad6265SDimitry Andric 
15681ad6265SDimitry Andric static std::string buildCategoryStr(StringSet<> &Cetegorys) {
15781ad6265SDimitry Andric   std::string Str;
15881ad6265SDimitry Andric   raw_string_ostream OS(Str);
15981ad6265SDimitry Andric   for (auto &It : Cetegorys) {
16081ad6265SDimitry Andric     OS << " " << It.getKey();
16181ad6265SDimitry Andric   }
16281ad6265SDimitry Andric   return OS.str();
16381ad6265SDimitry Andric }
16481ad6265SDimitry Andric 
16581ad6265SDimitry Andric // Emit enum declaration for DXIL.
16681ad6265SDimitry Andric static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps,
16781ad6265SDimitry Andric                           raw_ostream &OS) {
16881ad6265SDimitry Andric   // Sort by Category + OpName.
169fcaf7f86SDimitry Andric   llvm::sort(DXILOps, [](DXILOperationData &A, DXILOperationData &B) {
17081ad6265SDimitry Andric     // Group by Category first.
17181ad6265SDimitry Andric     if (A.Category == B.Category)
17281ad6265SDimitry Andric       // Inside same Category, order by OpName.
17381ad6265SDimitry Andric       return A.DXILOp < B.DXILOp;
17481ad6265SDimitry Andric     else
17581ad6265SDimitry Andric       return A.Category < B.Category;
17681ad6265SDimitry Andric   });
17781ad6265SDimitry Andric 
17881ad6265SDimitry Andric   OS << "// Enumeration for operations specified by DXIL\n";
17981ad6265SDimitry Andric   OS << "enum class OpCode : unsigned {\n";
18081ad6265SDimitry Andric 
18181ad6265SDimitry Andric   StringMap<StringSet<>> ClassMap;
18281ad6265SDimitry Andric   StringRef PrevCategory = "";
18381ad6265SDimitry Andric   for (auto &DXILOp : DXILOps) {
18481ad6265SDimitry Andric     StringRef Category = DXILOp.Category;
18581ad6265SDimitry Andric     if (Category != PrevCategory) {
18681ad6265SDimitry Andric       OS << "\n// " << Category << "\n";
18781ad6265SDimitry Andric       PrevCategory = Category;
18881ad6265SDimitry Andric     }
18981ad6265SDimitry Andric     emitDXILOpEnum(DXILOp, OS);
19081ad6265SDimitry Andric     auto It = ClassMap.find(DXILOp.DXILClass);
19181ad6265SDimitry Andric     if (It != ClassMap.end()) {
19281ad6265SDimitry Andric       It->second.insert(DXILOp.Category);
19381ad6265SDimitry Andric     } else {
19481ad6265SDimitry Andric       ClassMap[DXILOp.DXILClass].insert(DXILOp.Category);
19581ad6265SDimitry Andric     }
19681ad6265SDimitry Andric   }
19781ad6265SDimitry Andric 
19881ad6265SDimitry Andric   OS << "\n};\n\n";
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric   std::vector<std::pair<std::string, std::string>> ClassVec;
20181ad6265SDimitry Andric   for (auto &It : ClassMap) {
20281ad6265SDimitry Andric     ClassVec.emplace_back(
20381ad6265SDimitry Andric         std::make_pair(It.getKey().str(), buildCategoryStr(It.second)));
20481ad6265SDimitry Andric   }
20581ad6265SDimitry Andric   // Sort by Category + ClassName.
206fcaf7f86SDimitry Andric   llvm::sort(ClassVec, [](std::pair<std::string, std::string> &A,
20781ad6265SDimitry Andric                           std::pair<std::string, std::string> &B) {
20881ad6265SDimitry Andric     StringRef ClassA = A.first;
20981ad6265SDimitry Andric     StringRef CategoryA = A.second;
21081ad6265SDimitry Andric     StringRef ClassB = B.first;
21181ad6265SDimitry Andric     StringRef CategoryB = B.second;
21281ad6265SDimitry Andric     // Group by Category first.
21381ad6265SDimitry Andric     if (CategoryA == CategoryB)
21481ad6265SDimitry Andric       // Inside same Category, order by ClassName.
21581ad6265SDimitry Andric       return ClassA < ClassB;
21681ad6265SDimitry Andric     else
21781ad6265SDimitry Andric       return CategoryA < CategoryB;
21881ad6265SDimitry Andric   });
21981ad6265SDimitry Andric 
22081ad6265SDimitry Andric   OS << "// Groups for DXIL operations with equivalent function templates\n";
22181ad6265SDimitry Andric   OS << "enum class OpCodeClass : unsigned {\n";
22281ad6265SDimitry Andric   PrevCategory = "";
22381ad6265SDimitry Andric   for (auto &It : ClassVec) {
22481ad6265SDimitry Andric 
22581ad6265SDimitry Andric     StringRef Category = It.second;
22681ad6265SDimitry Andric     if (Category != PrevCategory) {
22781ad6265SDimitry Andric       OS << "\n// " << Category << "\n";
22881ad6265SDimitry Andric       PrevCategory = Category;
22981ad6265SDimitry Andric     }
23081ad6265SDimitry Andric     StringRef Name = It.first;
23181ad6265SDimitry Andric     OS << Name << ",\n";
23281ad6265SDimitry Andric   }
23381ad6265SDimitry Andric   OS << "\n};\n\n";
23481ad6265SDimitry Andric }
23581ad6265SDimitry Andric 
23681ad6265SDimitry Andric // Emit map from llvm intrinsic to DXIL operation.
23781ad6265SDimitry Andric static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps,
23881ad6265SDimitry Andric                                  raw_ostream &OS) {
23981ad6265SDimitry Andric   OS << "\n";
24081ad6265SDimitry Andric   // FIXME: use array instead of SmallDenseMap.
24181ad6265SDimitry Andric   OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = "
24281ad6265SDimitry Andric         "{\n";
24381ad6265SDimitry Andric   for (auto &DXILOp : DXILOps) {
24481ad6265SDimitry Andric     if (DXILOp.Intrinsic.empty())
24581ad6265SDimitry Andric       continue;
24681ad6265SDimitry Andric     // {Intrinsic::sin, DXIL::OpCode::Sin},
24781ad6265SDimitry Andric     OS << "  { Intrinsic::" << DXILOp.Intrinsic
24881ad6265SDimitry Andric        << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n";
24981ad6265SDimitry Andric   }
25081ad6265SDimitry Andric   OS << "};\n";
25181ad6265SDimitry Andric   OS << "\n";
25281ad6265SDimitry Andric }
25381ad6265SDimitry Andric 
25481ad6265SDimitry Andric static std::string emitDXILOperationFnAttr(StringRef FnAttr) {
25581ad6265SDimitry Andric   return StringSwitch<std::string>(FnAttr)
25681ad6265SDimitry Andric       .Case("rn", "Attribute::ReadNone")
25781ad6265SDimitry Andric       .Case("ro", "Attribute::ReadOnly")
25881ad6265SDimitry Andric       .Default("Attribute::None");
25981ad6265SDimitry Andric }
26081ad6265SDimitry Andric 
26181ad6265SDimitry Andric static std::string getOverloadKind(StringRef Overload) {
26281ad6265SDimitry Andric   return StringSwitch<std::string>(Overload)
26381ad6265SDimitry Andric       .Case("half", "OverloadKind::HALF")
26481ad6265SDimitry Andric       .Case("float", "OverloadKind::FLOAT")
26581ad6265SDimitry Andric       .Case("double", "OverloadKind::DOUBLE")
26681ad6265SDimitry Andric       .Case("i1", "OverloadKind::I1")
26781ad6265SDimitry Andric       .Case("i16", "OverloadKind::I16")
26881ad6265SDimitry Andric       .Case("i32", "OverloadKind::I32")
26981ad6265SDimitry Andric       .Case("i64", "OverloadKind::I64")
27081ad6265SDimitry Andric       .Case("udt", "OverloadKind::UserDefineType")
27181ad6265SDimitry Andric       .Case("obj", "OverloadKind::ObjectType")
27281ad6265SDimitry Andric       .Default("OverloadKind::VOID");
27381ad6265SDimitry Andric }
27481ad6265SDimitry Andric 
27581ad6265SDimitry Andric static std::string getDXILOperationOverload(StringRef Overloads) {
27681ad6265SDimitry Andric   SmallVector<StringRef> OverloadStrs;
27781ad6265SDimitry Andric   Overloads.split(OverloadStrs, ';', /*MaxSplit*/ -1, /*KeepEmpty*/ false);
27881ad6265SDimitry Andric   // Format is: OverloadKind::FLOAT | OverloadKind::HALF
27981ad6265SDimitry Andric   assert(!OverloadStrs.empty() && "Invalid overloads");
28081ad6265SDimitry Andric   auto It = OverloadStrs.begin();
28181ad6265SDimitry Andric   std::string Result;
28281ad6265SDimitry Andric   raw_string_ostream OS(Result);
28381ad6265SDimitry Andric   OS << getOverloadKind(*It);
28481ad6265SDimitry Andric   for (++It; It != OverloadStrs.end(); ++It) {
28581ad6265SDimitry Andric     OS << " | " << getOverloadKind(*It);
28681ad6265SDimitry Andric   }
28781ad6265SDimitry Andric   return OS.str();
28881ad6265SDimitry Andric }
28981ad6265SDimitry Andric 
29081ad6265SDimitry Andric static std::string lowerFirstLetter(StringRef Name) {
29181ad6265SDimitry Andric   if (Name.empty())
29281ad6265SDimitry Andric     return "";
29381ad6265SDimitry Andric 
29481ad6265SDimitry Andric   std::string LowerName = Name.str();
29581ad6265SDimitry Andric   LowerName[0] = llvm::toLower(Name[0]);
29681ad6265SDimitry Andric   return LowerName;
29781ad6265SDimitry Andric }
29881ad6265SDimitry Andric 
29981ad6265SDimitry Andric static std::string getDXILOpClassName(StringRef DXILOpClass) {
30081ad6265SDimitry Andric   // Lower first letter expect for special case.
30181ad6265SDimitry Andric   return StringSwitch<std::string>(DXILOpClass)
30281ad6265SDimitry Andric       .Case("CBufferLoad", "cbufferLoad")
30381ad6265SDimitry Andric       .Case("CBufferLoadLegacy", "cbufferLoadLegacy")
30481ad6265SDimitry Andric       .Case("GSInstanceID", "gsInstanceID")
30581ad6265SDimitry Andric       .Default(lowerFirstLetter(DXILOpClass));
30681ad6265SDimitry Andric }
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
30981ad6265SDimitry Andric                                    raw_ostream &OS) {
31081ad6265SDimitry Andric   // Sort by DXILOpID.
311fcaf7f86SDimitry Andric   llvm::sort(DXILOps, [](DXILOperationData &A, DXILOperationData &B) {
31281ad6265SDimitry Andric     return A.DXILOpID < B.DXILOpID;
31381ad6265SDimitry Andric   });
31481ad6265SDimitry Andric 
31581ad6265SDimitry Andric   // Collect Names.
31681ad6265SDimitry Andric   SequenceToOffsetTable<std::string> OpClassStrings;
31781ad6265SDimitry Andric   SequenceToOffsetTable<std::string> OpStrings;
318*972a253aSDimitry Andric   SequenceToOffsetTable<SmallVector<ParameterKind>> Parameters;
31981ad6265SDimitry Andric 
320*972a253aSDimitry Andric   StringMap<SmallVector<ParameterKind>> ParameterMap;
32181ad6265SDimitry Andric   StringSet<> ClassSet;
32281ad6265SDimitry Andric   for (auto &DXILOp : DXILOps) {
32381ad6265SDimitry Andric     OpStrings.add(DXILOp.DXILOp.str());
32481ad6265SDimitry Andric 
32581ad6265SDimitry Andric     if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end())
32681ad6265SDimitry Andric       continue;
32781ad6265SDimitry Andric     ClassSet.insert(DXILOp.DXILClass);
32881ad6265SDimitry Andric     OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass));
329*972a253aSDimitry Andric     SmallVector<ParameterKind> ParamKindVec;
330*972a253aSDimitry Andric     for (auto &Param : DXILOp.Params) {
331*972a253aSDimitry Andric       ParamKindVec.emplace_back(Param.Kind);
332*972a253aSDimitry Andric     }
333*972a253aSDimitry Andric     ParameterMap[DXILOp.DXILClass] = ParamKindVec;
334*972a253aSDimitry Andric     Parameters.add(ParamKindVec);
33581ad6265SDimitry Andric   }
33681ad6265SDimitry Andric 
33781ad6265SDimitry Andric   // Layout names.
33881ad6265SDimitry Andric   OpStrings.layout();
33981ad6265SDimitry Andric   OpClassStrings.layout();
340*972a253aSDimitry Andric   Parameters.layout();
34181ad6265SDimitry Andric 
34281ad6265SDimitry Andric   // Emit the DXIL operation table.
34381ad6265SDimitry Andric   //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary,
34481ad6265SDimitry Andric   // OpCodeClassNameIndex,
345*972a253aSDimitry Andric   // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone, 0,
346*972a253aSDimitry Andric   // 3, ParameterTableOffset},
34781ad6265SDimitry Andric   OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) "
34881ad6265SDimitry Andric         "{\n";
34981ad6265SDimitry Andric 
35081ad6265SDimitry Andric   OS << "  static const OpCodeProperty OpCodeProps[] = {\n";
35181ad6265SDimitry Andric   for (auto &DXILOp : DXILOps) {
35281ad6265SDimitry Andric     OS << "  { DXIL::OpCode::" << DXILOp.DXILOp << ", "
35381ad6265SDimitry Andric        << OpStrings.get(DXILOp.DXILOp.str())
35481ad6265SDimitry Andric        << ", OpCodeClass::" << DXILOp.DXILClass << ", "
35581ad6265SDimitry Andric        << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", "
35681ad6265SDimitry Andric        << getDXILOperationOverload(DXILOp.OverloadTypes) << ", "
357*972a253aSDimitry Andric        << emitDXILOperationFnAttr(DXILOp.FnAttr) << ", "
358*972a253aSDimitry Andric        << DXILOp.OverloadParamIndex << ", " << DXILOp.Params.size() << ", "
359*972a253aSDimitry Andric        << Parameters.get(ParameterMap[DXILOp.DXILClass]) << " },\n";
36081ad6265SDimitry Andric   }
36181ad6265SDimitry Andric   OS << "  };\n";
36281ad6265SDimitry Andric 
36381ad6265SDimitry Andric   OS << "  // FIXME: change search to indexing with\n";
36481ad6265SDimitry Andric   OS << "  // DXILOp once all DXIL op is added.\n";
36581ad6265SDimitry Andric   OS << "  OpCodeProperty TmpProp;\n";
36681ad6265SDimitry Andric   OS << "  TmpProp.OpCode = DXILOp;\n";
36781ad6265SDimitry Andric   OS << "  const OpCodeProperty *Prop =\n";
36881ad6265SDimitry Andric   OS << "      llvm::lower_bound(OpCodeProps, TmpProp,\n";
36981ad6265SDimitry Andric   OS << "                        [](const OpCodeProperty &A, const "
37081ad6265SDimitry Andric         "OpCodeProperty &B) {\n";
37181ad6265SDimitry Andric   OS << "                          return A.OpCode < B.OpCode;\n";
37281ad6265SDimitry Andric   OS << "                        });\n";
37381ad6265SDimitry Andric   OS << "  assert(Prop && \"fail to find OpCodeProperty\");\n";
37481ad6265SDimitry Andric   OS << "  return Prop;\n";
37581ad6265SDimitry Andric   OS << "}\n\n";
37681ad6265SDimitry Andric 
37781ad6265SDimitry Andric   // Emit the string tables.
37881ad6265SDimitry Andric   OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n";
37981ad6265SDimitry Andric 
38081ad6265SDimitry Andric   OpStrings.emitStringLiteralDef(OS,
38181ad6265SDimitry Andric                                  "  static const char DXILOpCodeNameTable[]");
38281ad6265SDimitry Andric 
38381ad6265SDimitry Andric   OS << "  auto *Prop = getOpCodeProperty(DXILOp);\n";
38481ad6265SDimitry Andric   OS << "  unsigned Index = Prop->OpCodeNameOffset;\n";
38581ad6265SDimitry Andric   OS << "  return DXILOpCodeNameTable + Index;\n";
38681ad6265SDimitry Andric   OS << "}\n\n";
38781ad6265SDimitry Andric 
38881ad6265SDimitry Andric   OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) "
38981ad6265SDimitry Andric         "{\n\n";
39081ad6265SDimitry Andric 
39181ad6265SDimitry Andric   OpClassStrings.emitStringLiteralDef(
39281ad6265SDimitry Andric       OS, "  static const char DXILOpCodeClassNameTable[]");
39381ad6265SDimitry Andric 
39481ad6265SDimitry Andric   OS << "  unsigned Index = Prop.OpCodeClassNameOffset;\n";
39581ad6265SDimitry Andric   OS << "  return DXILOpCodeClassNameTable + Index;\n";
39681ad6265SDimitry Andric   OS << "}\n ";
397*972a253aSDimitry Andric 
398*972a253aSDimitry Andric   OS << "static const ParameterKind *getOpCodeParameterKind(const "
399*972a253aSDimitry Andric         "OpCodeProperty &Prop) "
400*972a253aSDimitry Andric         "{\n\n";
401*972a253aSDimitry Andric   OS << "  static const ParameterKind DXILOpParameterKindTable[] = {\n";
402*972a253aSDimitry Andric   Parameters.emit(
403*972a253aSDimitry Andric       OS,
404*972a253aSDimitry Andric       [](raw_ostream &ParamOS, ParameterKind Kind) {
405*972a253aSDimitry Andric         ParamOS << "ParameterKind::" << parameterKindToString(Kind);
406*972a253aSDimitry Andric       },
407*972a253aSDimitry Andric       "ParameterKind::INVALID");
408*972a253aSDimitry Andric   OS << "  };\n\n";
409*972a253aSDimitry Andric   OS << "  unsigned Index = Prop.ParameterTableOffset;\n";
410*972a253aSDimitry Andric   OS << "  return DXILOpParameterKindTable + Index;\n";
411*972a253aSDimitry Andric   OS << "}\n ";
41281ad6265SDimitry Andric }
41381ad6265SDimitry Andric 
41481ad6265SDimitry Andric namespace llvm {
41581ad6265SDimitry Andric 
41681ad6265SDimitry Andric void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
41781ad6265SDimitry Andric   std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op");
41881ad6265SDimitry Andric   OS << "// Generated code, do not edit.\n";
41981ad6265SDimitry Andric   OS << "\n";
42081ad6265SDimitry Andric 
42181ad6265SDimitry Andric   std::vector<DXILOperationData> DXILOps;
42281ad6265SDimitry Andric   DXILOps.reserve(Ops.size());
42381ad6265SDimitry Andric   for (auto *Record : Ops) {
42481ad6265SDimitry Andric     DXILOps.emplace_back(DXILOperationData(Record));
42581ad6265SDimitry Andric   }
42681ad6265SDimitry Andric 
42781ad6265SDimitry Andric   OS << "#ifdef DXIL_OP_ENUM\n";
42881ad6265SDimitry Andric   emitDXILEnums(DXILOps, OS);
42981ad6265SDimitry Andric   OS << "#endif\n\n";
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric   OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n";
43281ad6265SDimitry Andric   emitDXILIntrinsicMap(DXILOps, OS);
43381ad6265SDimitry Andric   OS << "#endif\n\n";
43481ad6265SDimitry Andric 
43581ad6265SDimitry Andric   OS << "#ifdef DXIL_OP_OPERATION_TABLE\n";
43681ad6265SDimitry Andric   emitDXILOperationTable(DXILOps, OS);
43781ad6265SDimitry Andric   OS << "#endif\n\n";
43881ad6265SDimitry Andric 
43981ad6265SDimitry Andric   OS << "\n";
44081ad6265SDimitry Andric }
44181ad6265SDimitry Andric 
44281ad6265SDimitry Andric } // namespace llvm
443