1*435897b4Spython3kgae //===- DXILEmitter.cpp - DXIL operation Emitter ---------------------------===//
2*435897b4Spython3kgae //
3*435897b4Spython3kgae // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*435897b4Spython3kgae // See https://llvm.org/LICENSE.txt for license information.
5*435897b4Spython3kgae // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*435897b4Spython3kgae //
7*435897b4Spython3kgae //===----------------------------------------------------------------------===//
8*435897b4Spython3kgae //
9*435897b4Spython3kgae // DXILEmitter uses the descriptions of DXIL operation to construct enum and
10*435897b4Spython3kgae // helper functions for DXIL operation.
11*435897b4Spython3kgae //
12*435897b4Spython3kgae //===----------------------------------------------------------------------===//
13*435897b4Spython3kgae 
14*435897b4Spython3kgae #include "llvm/ADT/MapVector.h"
15*435897b4Spython3kgae #include "llvm/ADT/STLExtras.h"
16*435897b4Spython3kgae #include "llvm/ADT/SmallVector.h"
17*435897b4Spython3kgae #include "llvm/ADT/StringSet.h"
18*435897b4Spython3kgae #include "llvm/TableGen/Error.h"
19*435897b4Spython3kgae #include "llvm/TableGen/Record.h"
20*435897b4Spython3kgae 
21*435897b4Spython3kgae using namespace llvm;
22*435897b4Spython3kgae 
23*435897b4Spython3kgae namespace {
24*435897b4Spython3kgae 
25*435897b4Spython3kgae struct DXILShaderModel {
26*435897b4Spython3kgae   int Major;
27*435897b4Spython3kgae   int Minor;
28*435897b4Spython3kgae };
29*435897b4Spython3kgae struct DXILParam {
30*435897b4Spython3kgae   int Pos;        // position in parameter list
31*435897b4Spython3kgae   StringRef Type; // llvm type name, $o for overload, $r for resource
32*435897b4Spython3kgae                   // type, $cb for legacy cbuffer, $u4 for u4 struct
33*435897b4Spython3kgae   StringRef Name; // short, unique name
34*435897b4Spython3kgae   StringRef Doc;  // the documentation description of this parameter
35*435897b4Spython3kgae   bool IsConst;   // whether this argument requires a constant value in the IR
36*435897b4Spython3kgae   StringRef EnumName; // the name of the enum type if applicable
37*435897b4Spython3kgae   int MaxValue;       // the maximum value for this parameter if applicable
38*435897b4Spython3kgae   DXILParam(const Record *R) {
39*435897b4Spython3kgae     Name = R->getValueAsString("name");
40*435897b4Spython3kgae     Pos = R->getValueAsInt("pos");
41*435897b4Spython3kgae     Type = R->getValueAsString("llvm_type");
42*435897b4Spython3kgae     if (R->getValue("doc"))
43*435897b4Spython3kgae       Doc = R->getValueAsString("doc");
44*435897b4Spython3kgae     IsConst = R->getValueAsBit("is_const");
45*435897b4Spython3kgae     EnumName = R->getValueAsString("enum_name");
46*435897b4Spython3kgae     MaxValue = R->getValueAsInt("max_value");
47*435897b4Spython3kgae   }
48*435897b4Spython3kgae };
49*435897b4Spython3kgae 
50*435897b4Spython3kgae struct DXILOperationData {
51*435897b4Spython3kgae   StringRef Name; // short, unique name
52*435897b4Spython3kgae 
53*435897b4Spython3kgae   StringRef DXILOp;    // name of DXIL operation
54*435897b4Spython3kgae   int DXILOpID;        // ID of DXIL operation
55*435897b4Spython3kgae   StringRef DXILClass; // name of the opcode class
56*435897b4Spython3kgae   StringRef Category;  // classification for this instruction
57*435897b4Spython3kgae   StringRef Doc;       // the documentation description of this instruction
58*435897b4Spython3kgae 
59*435897b4Spython3kgae   SmallVector<DXILParam> Params; // the operands that this instruction takes
60*435897b4Spython3kgae   StringRef OverloadTypes;       // overload types if applicable
61*435897b4Spython3kgae   StringRef FnAttr;              // attribute shorthands: rn=does not access
62*435897b4Spython3kgae                                  // memory,ro=only reads from memory,
63*435897b4Spython3kgae   bool IsDeriv;                  // whether this is some kind of derivative
64*435897b4Spython3kgae   bool IsGradient;               // whether this requires a gradient calculation
65*435897b4Spython3kgae   bool IsFeedback;               // whether this is a sampler feedback op
66*435897b4Spython3kgae   bool IsWave; // whether this requires in-wave, cross-lane functionality
67*435897b4Spython3kgae   bool RequiresUniformInputs; // whether this operation requires that all
68*435897b4Spython3kgae                               // of its inputs are uniform across the wave
69*435897b4Spython3kgae   SmallVector<StringRef, 4>
70*435897b4Spython3kgae       ShaderStages; // shader stages to which this applies, empty for all.
71*435897b4Spython3kgae   DXILShaderModel ShaderModel;           // minimum shader model required
72*435897b4Spython3kgae   DXILShaderModel ShaderModelTranslated; // minimum shader model required with
73*435897b4Spython3kgae                                          // translation by linker
74*435897b4Spython3kgae   SmallVector<StringRef, 4> counters;    // counters for this inst.
75*435897b4Spython3kgae   DXILOperationData(const Record *R) {
76*435897b4Spython3kgae     Name = R->getValueAsString("name");
77*435897b4Spython3kgae     DXILOp = R->getValueAsString("dxil_op");
78*435897b4Spython3kgae     DXILOpID = R->getValueAsInt("dxil_opid");
79*435897b4Spython3kgae     DXILClass = R->getValueAsDef("op_class")->getValueAsString("name");
80*435897b4Spython3kgae     Category = R->getValueAsDef("category")->getValueAsString("name");
81*435897b4Spython3kgae 
82*435897b4Spython3kgae     Doc = R->getValueAsString("doc");
83*435897b4Spython3kgae     ListInit *ParamList = R->getValueAsListInit("ops");
84*435897b4Spython3kgae     for (unsigned i = 0; i < ParamList->size(); ++i) {
85*435897b4Spython3kgae       Record *Param = ParamList->getElementAsRecord(i);
86*435897b4Spython3kgae       Params.emplace_back(DXILParam(Param));
87*435897b4Spython3kgae     }
88*435897b4Spython3kgae     OverloadTypes = R->getValueAsString("oload_types");
89*435897b4Spython3kgae     FnAttr = R->getValueAsString("fn_attr");
90*435897b4Spython3kgae   }
91*435897b4Spython3kgae };
92*435897b4Spython3kgae } // end anonymous namespace
93*435897b4Spython3kgae 
94*435897b4Spython3kgae static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
95*435897b4Spython3kgae   // Name = ID, // Doc
96*435897b4Spython3kgae   OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc
97*435897b4Spython3kgae      << "\n";
98*435897b4Spython3kgae }
99*435897b4Spython3kgae 
100*435897b4Spython3kgae static std::string buildCategoryStr(StringSet<> &Cetegorys) {
101*435897b4Spython3kgae   std::string Str;
102*435897b4Spython3kgae   raw_string_ostream OS(Str);
103*435897b4Spython3kgae   for (auto &It : Cetegorys) {
104*435897b4Spython3kgae     OS << " " << It.getKey();
105*435897b4Spython3kgae   }
106*435897b4Spython3kgae   return OS.str();
107*435897b4Spython3kgae }
108*435897b4Spython3kgae 
109*435897b4Spython3kgae // Emit enum declaration for DXIL.
110*435897b4Spython3kgae static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps,
111*435897b4Spython3kgae                           raw_ostream &OS) {
112*435897b4Spython3kgae   // Sort by Category + OpName.
113*435897b4Spython3kgae   std::sort(DXILOps.begin(), DXILOps.end(),
114*435897b4Spython3kgae             [](DXILOperationData &A, DXILOperationData &B) {
115*435897b4Spython3kgae               // Group by Category first.
116*435897b4Spython3kgae               if (A.Category == B.Category)
117*435897b4Spython3kgae                 // Inside same Category, order by OpName.
118*435897b4Spython3kgae                 return A.DXILOp < B.DXILOp;
119*435897b4Spython3kgae               else
120*435897b4Spython3kgae                 return A.Category < B.Category;
121*435897b4Spython3kgae             });
122*435897b4Spython3kgae 
123*435897b4Spython3kgae   OS << "// Enumeration for operations specified by DXIL\n";
124*435897b4Spython3kgae   OS << "enum class OpCode : unsigned {\n";
125*435897b4Spython3kgae 
126*435897b4Spython3kgae   StringMap<StringSet<>> ClassMap;
127*435897b4Spython3kgae   StringRef PrevCategory = "";
128*435897b4Spython3kgae   for (auto &DXILOp : DXILOps) {
129*435897b4Spython3kgae     StringRef Category = DXILOp.Category;
130*435897b4Spython3kgae     if (Category != PrevCategory) {
131*435897b4Spython3kgae       OS << "\n// " << Category << "\n";
132*435897b4Spython3kgae       PrevCategory = Category;
133*435897b4Spython3kgae     }
134*435897b4Spython3kgae     emitDXILOpEnum(DXILOp, OS);
135*435897b4Spython3kgae     auto It = ClassMap.find(DXILOp.DXILClass);
136*435897b4Spython3kgae     if (It != ClassMap.end()) {
137*435897b4Spython3kgae       It->second.insert(DXILOp.Category);
138*435897b4Spython3kgae     } else {
139*435897b4Spython3kgae       ClassMap[DXILOp.DXILClass].insert(DXILOp.Category);
140*435897b4Spython3kgae     }
141*435897b4Spython3kgae   }
142*435897b4Spython3kgae 
143*435897b4Spython3kgae   OS << "\n};\n\n";
144*435897b4Spython3kgae 
145*435897b4Spython3kgae   std::vector<std::pair<std::string, std::string>> ClassVec;
146*435897b4Spython3kgae   for (auto &It : ClassMap) {
147*435897b4Spython3kgae     ClassVec.emplace_back(
148*435897b4Spython3kgae         std::make_pair(It.getKey().str(), buildCategoryStr(It.second)));
149*435897b4Spython3kgae   }
150*435897b4Spython3kgae   // Sort by Category + ClassName.
151*435897b4Spython3kgae   std::sort(ClassVec.begin(), ClassVec.end(),
152*435897b4Spython3kgae             [](std::pair<std::string, std::string> &A,
153*435897b4Spython3kgae                std::pair<std::string, std::string> &B) {
154*435897b4Spython3kgae               StringRef ClassA = A.first;
155*435897b4Spython3kgae               StringRef CategoryA = A.second;
156*435897b4Spython3kgae               StringRef ClassB = B.first;
157*435897b4Spython3kgae               StringRef CategoryB = B.second;
158*435897b4Spython3kgae               // Group by Category first.
159*435897b4Spython3kgae               if (CategoryA == CategoryB)
160*435897b4Spython3kgae                 // Inside same Category, order by ClassName.
161*435897b4Spython3kgae                 return ClassA < ClassB;
162*435897b4Spython3kgae               else
163*435897b4Spython3kgae                 return CategoryA < CategoryB;
164*435897b4Spython3kgae             });
165*435897b4Spython3kgae 
166*435897b4Spython3kgae   OS << "// Groups for DXIL operations with equivalent function templates\n";
167*435897b4Spython3kgae   OS << "enum class OpCodeClass : unsigned {\n";
168*435897b4Spython3kgae   PrevCategory = "";
169*435897b4Spython3kgae   for (auto &It : ClassVec) {
170*435897b4Spython3kgae 
171*435897b4Spython3kgae     StringRef Category = It.second;
172*435897b4Spython3kgae     if (Category != PrevCategory) {
173*435897b4Spython3kgae       OS << "\n// " << Category << "\n";
174*435897b4Spython3kgae       PrevCategory = Category;
175*435897b4Spython3kgae     }
176*435897b4Spython3kgae     StringRef Name = It.first;
177*435897b4Spython3kgae     OS << Name << ",\n";
178*435897b4Spython3kgae   }
179*435897b4Spython3kgae   OS << "\n};\n\n";
180*435897b4Spython3kgae }
181*435897b4Spython3kgae 
182*435897b4Spython3kgae namespace llvm {
183*435897b4Spython3kgae 
184*435897b4Spython3kgae void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
185*435897b4Spython3kgae   std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op");
186*435897b4Spython3kgae   OS << "// Generated code, do not edit.\n";
187*435897b4Spython3kgae   OS << "\n";
188*435897b4Spython3kgae 
189*435897b4Spython3kgae   std::vector<DXILOperationData> DXILOps;
190*435897b4Spython3kgae   DXILOps.reserve(Ops.size());
191*435897b4Spython3kgae   for (auto *Record : Ops) {
192*435897b4Spython3kgae     DXILOps.emplace_back(DXILOperationData(Record));
193*435897b4Spython3kgae   }
194*435897b4Spython3kgae 
195*435897b4Spython3kgae   OS << "#ifdef DXIL_OP_ENUM\n";
196*435897b4Spython3kgae   emitDXILEnums(DXILOps, OS);
197*435897b4Spython3kgae   OS << "#endif\n\n";
198*435897b4Spython3kgae 
199*435897b4Spython3kgae   OS << "\n";
200*435897b4Spython3kgae }
201*435897b4Spython3kgae 
202*435897b4Spython3kgae } // namespace llvm
203