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 
14435897b4Spython3kgae #include "llvm/ADT/MapVector.h"
15435897b4Spython3kgae #include "llvm/ADT/STLExtras.h"
16435897b4Spython3kgae #include "llvm/ADT/SmallVector.h"
17435897b4Spython3kgae #include "llvm/ADT/StringSet.h"
18435897b4Spython3kgae #include "llvm/TableGen/Error.h"
19435897b4Spython3kgae #include "llvm/TableGen/Record.h"
20435897b4Spython3kgae 
21435897b4Spython3kgae using namespace llvm;
22435897b4Spython3kgae 
23435897b4Spython3kgae namespace {
24435897b4Spython3kgae 
25435897b4Spython3kgae struct DXILShaderModel {
26435897b4Spython3kgae   int Major;
27435897b4Spython3kgae   int Minor;
28435897b4Spython3kgae };
29435897b4Spython3kgae struct DXILParam {
30435897b4Spython3kgae   int Pos;        // position in parameter list
31435897b4Spython3kgae   StringRef Type; // llvm type name, $o for overload, $r for resource
32435897b4Spython3kgae                   // type, $cb for legacy cbuffer, $u4 for u4 struct
33435897b4Spython3kgae   StringRef Name; // short, unique name
34435897b4Spython3kgae   StringRef Doc;  // the documentation description of this parameter
35435897b4Spython3kgae   bool IsConst;   // whether this argument requires a constant value in the IR
36435897b4Spython3kgae   StringRef EnumName; // the name of the enum type if applicable
37435897b4Spython3kgae   int MaxValue;       // the maximum value for this parameter if applicable
38435897b4Spython3kgae   DXILParam(const Record *R) {
39435897b4Spython3kgae     Name = R->getValueAsString("name");
40435897b4Spython3kgae     Pos = R->getValueAsInt("pos");
41435897b4Spython3kgae     Type = R->getValueAsString("llvm_type");
42435897b4Spython3kgae     if (R->getValue("doc"))
43435897b4Spython3kgae       Doc = R->getValueAsString("doc");
44435897b4Spython3kgae     IsConst = R->getValueAsBit("is_const");
45435897b4Spython3kgae     EnumName = R->getValueAsString("enum_name");
46435897b4Spython3kgae     MaxValue = R->getValueAsInt("max_value");
47435897b4Spython3kgae   }
48435897b4Spython3kgae };
49435897b4Spython3kgae 
50435897b4Spython3kgae struct DXILOperationData {
51435897b4Spython3kgae   StringRef Name; // short, unique name
52435897b4Spython3kgae 
53435897b4Spython3kgae   StringRef DXILOp;    // name of DXIL operation
54435897b4Spython3kgae   int DXILOpID;        // ID of DXIL operation
55435897b4Spython3kgae   StringRef DXILClass; // name of the opcode class
56435897b4Spython3kgae   StringRef Category;  // classification for this instruction
57435897b4Spython3kgae   StringRef Doc;       // the documentation description of this instruction
58435897b4Spython3kgae 
59435897b4Spython3kgae   SmallVector<DXILParam> Params; // the operands that this instruction takes
60435897b4Spython3kgae   StringRef OverloadTypes;       // overload types if applicable
61435897b4Spython3kgae   StringRef FnAttr;              // attribute shorthands: rn=does not access
62*264c09b7SXiang Li                                  // memory,ro=only reads from memory
63*264c09b7SXiang Li   StringRef Intrinsic; // The llvm intrinsic map to DXILOp. Default is "" which
64*264c09b7SXiang Li                        // means no map exist
65435897b4Spython3kgae   bool IsDeriv;        // whether this is some kind of derivative
66435897b4Spython3kgae   bool IsGradient;               // whether this requires a gradient calculation
67435897b4Spython3kgae   bool IsFeedback;               // whether this is a sampler feedback op
68435897b4Spython3kgae   bool IsWave; // whether this requires in-wave, cross-lane functionality
69435897b4Spython3kgae   bool RequiresUniformInputs; // whether this operation requires that all
70435897b4Spython3kgae                               // of its inputs are uniform across the wave
71435897b4Spython3kgae   SmallVector<StringRef, 4>
72435897b4Spython3kgae       ShaderStages; // shader stages to which this applies, empty for all.
73435897b4Spython3kgae   DXILShaderModel ShaderModel;           // minimum shader model required
74435897b4Spython3kgae   DXILShaderModel ShaderModelTranslated; // minimum shader model required with
75435897b4Spython3kgae                                          // translation by linker
76435897b4Spython3kgae   SmallVector<StringRef, 4> counters;    // counters for this inst.
77435897b4Spython3kgae   DXILOperationData(const Record *R) {
78435897b4Spython3kgae     Name = R->getValueAsString("name");
79435897b4Spython3kgae     DXILOp = R->getValueAsString("dxil_op");
80435897b4Spython3kgae     DXILOpID = R->getValueAsInt("dxil_opid");
81435897b4Spython3kgae     DXILClass = R->getValueAsDef("op_class")->getValueAsString("name");
82435897b4Spython3kgae     Category = R->getValueAsDef("category")->getValueAsString("name");
83435897b4Spython3kgae 
84*264c09b7SXiang Li     if (R->getValue("llvm_intrinsic")) {
85*264c09b7SXiang Li       auto *IntrinsicDef = R->getValueAsDef("llvm_intrinsic");
86*264c09b7SXiang Li       auto DefName = IntrinsicDef->getName();
87*264c09b7SXiang Li       assert(DefName.startswith("int_") && "invalid intrinsic name");
88*264c09b7SXiang Li       // Remove the int_ from intrinsic name.
89*264c09b7SXiang Li       Intrinsic = DefName.substr(4);
90*264c09b7SXiang Li     }
91*264c09b7SXiang Li 
92435897b4Spython3kgae     Doc = R->getValueAsString("doc");
93*264c09b7SXiang Li 
94435897b4Spython3kgae     ListInit *ParamList = R->getValueAsListInit("ops");
95435897b4Spython3kgae     for (unsigned i = 0; i < ParamList->size(); ++i) {
96435897b4Spython3kgae       Record *Param = ParamList->getElementAsRecord(i);
97435897b4Spython3kgae       Params.emplace_back(DXILParam(Param));
98435897b4Spython3kgae     }
99435897b4Spython3kgae     OverloadTypes = R->getValueAsString("oload_types");
100435897b4Spython3kgae     FnAttr = R->getValueAsString("fn_attr");
101435897b4Spython3kgae   }
102435897b4Spython3kgae };
103435897b4Spython3kgae } // end anonymous namespace
104435897b4Spython3kgae 
105435897b4Spython3kgae static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
106435897b4Spython3kgae   // Name = ID, // Doc
107435897b4Spython3kgae   OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc
108435897b4Spython3kgae      << "\n";
109435897b4Spython3kgae }
110435897b4Spython3kgae 
111435897b4Spython3kgae static std::string buildCategoryStr(StringSet<> &Cetegorys) {
112435897b4Spython3kgae   std::string Str;
113435897b4Spython3kgae   raw_string_ostream OS(Str);
114435897b4Spython3kgae   for (auto &It : Cetegorys) {
115435897b4Spython3kgae     OS << " " << It.getKey();
116435897b4Spython3kgae   }
117435897b4Spython3kgae   return OS.str();
118435897b4Spython3kgae }
119435897b4Spython3kgae 
120435897b4Spython3kgae // Emit enum declaration for DXIL.
121435897b4Spython3kgae static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps,
122435897b4Spython3kgae                           raw_ostream &OS) {
123435897b4Spython3kgae   // Sort by Category + OpName.
124435897b4Spython3kgae   std::sort(DXILOps.begin(), DXILOps.end(),
125435897b4Spython3kgae             [](DXILOperationData &A, DXILOperationData &B) {
126435897b4Spython3kgae               // Group by Category first.
127435897b4Spython3kgae               if (A.Category == B.Category)
128435897b4Spython3kgae                 // Inside same Category, order by OpName.
129435897b4Spython3kgae                 return A.DXILOp < B.DXILOp;
130435897b4Spython3kgae               else
131435897b4Spython3kgae                 return A.Category < B.Category;
132435897b4Spython3kgae             });
133435897b4Spython3kgae 
134435897b4Spython3kgae   OS << "// Enumeration for operations specified by DXIL\n";
135435897b4Spython3kgae   OS << "enum class OpCode : unsigned {\n";
136435897b4Spython3kgae 
137435897b4Spython3kgae   StringMap<StringSet<>> ClassMap;
138435897b4Spython3kgae   StringRef PrevCategory = "";
139435897b4Spython3kgae   for (auto &DXILOp : DXILOps) {
140435897b4Spython3kgae     StringRef Category = DXILOp.Category;
141435897b4Spython3kgae     if (Category != PrevCategory) {
142435897b4Spython3kgae       OS << "\n// " << Category << "\n";
143435897b4Spython3kgae       PrevCategory = Category;
144435897b4Spython3kgae     }
145435897b4Spython3kgae     emitDXILOpEnum(DXILOp, OS);
146435897b4Spython3kgae     auto It = ClassMap.find(DXILOp.DXILClass);
147435897b4Spython3kgae     if (It != ClassMap.end()) {
148435897b4Spython3kgae       It->second.insert(DXILOp.Category);
149435897b4Spython3kgae     } else {
150435897b4Spython3kgae       ClassMap[DXILOp.DXILClass].insert(DXILOp.Category);
151435897b4Spython3kgae     }
152435897b4Spython3kgae   }
153435897b4Spython3kgae 
154435897b4Spython3kgae   OS << "\n};\n\n";
155435897b4Spython3kgae 
156435897b4Spython3kgae   std::vector<std::pair<std::string, std::string>> ClassVec;
157435897b4Spython3kgae   for (auto &It : ClassMap) {
158435897b4Spython3kgae     ClassVec.emplace_back(
159435897b4Spython3kgae         std::make_pair(It.getKey().str(), buildCategoryStr(It.second)));
160435897b4Spython3kgae   }
161435897b4Spython3kgae   // Sort by Category + ClassName.
162435897b4Spython3kgae   std::sort(ClassVec.begin(), ClassVec.end(),
163435897b4Spython3kgae             [](std::pair<std::string, std::string> &A,
164435897b4Spython3kgae                std::pair<std::string, std::string> &B) {
165435897b4Spython3kgae               StringRef ClassA = A.first;
166435897b4Spython3kgae               StringRef CategoryA = A.second;
167435897b4Spython3kgae               StringRef ClassB = B.first;
168435897b4Spython3kgae               StringRef CategoryB = B.second;
169435897b4Spython3kgae               // Group by Category first.
170435897b4Spython3kgae               if (CategoryA == CategoryB)
171435897b4Spython3kgae                 // Inside same Category, order by ClassName.
172435897b4Spython3kgae                 return ClassA < ClassB;
173435897b4Spython3kgae               else
174435897b4Spython3kgae                 return CategoryA < CategoryB;
175435897b4Spython3kgae             });
176435897b4Spython3kgae 
177435897b4Spython3kgae   OS << "// Groups for DXIL operations with equivalent function templates\n";
178435897b4Spython3kgae   OS << "enum class OpCodeClass : unsigned {\n";
179435897b4Spython3kgae   PrevCategory = "";
180435897b4Spython3kgae   for (auto &It : ClassVec) {
181435897b4Spython3kgae 
182435897b4Spython3kgae     StringRef Category = It.second;
183435897b4Spython3kgae     if (Category != PrevCategory) {
184435897b4Spython3kgae       OS << "\n// " << Category << "\n";
185435897b4Spython3kgae       PrevCategory = Category;
186435897b4Spython3kgae     }
187435897b4Spython3kgae     StringRef Name = It.first;
188435897b4Spython3kgae     OS << Name << ",\n";
189435897b4Spython3kgae   }
190435897b4Spython3kgae   OS << "\n};\n\n";
191435897b4Spython3kgae }
192435897b4Spython3kgae 
193*264c09b7SXiang Li // Emit map from llvm intrinsic to DXIL operation.
194*264c09b7SXiang Li static void EmitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps,
195*264c09b7SXiang Li                                  raw_ostream &OS) {
196*264c09b7SXiang Li   OS << "\n";
197*264c09b7SXiang Li   // FIXME: use array instead of SmallDenseMap.
198*264c09b7SXiang Li   OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = "
199*264c09b7SXiang Li         "{\n";
200*264c09b7SXiang Li   for (auto &DXILOp : DXILOps) {
201*264c09b7SXiang Li     if (DXILOp.Intrinsic.empty())
202*264c09b7SXiang Li       continue;
203*264c09b7SXiang Li     // {Intrinsic::sin, DXIL::OpCode::Sin},
204*264c09b7SXiang Li     OS << "  { Intrinsic::" << DXILOp.Intrinsic
205*264c09b7SXiang Li        << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n";
206*264c09b7SXiang Li   }
207*264c09b7SXiang Li   OS << "};\n";
208*264c09b7SXiang Li   OS << "\n";
209*264c09b7SXiang Li }
210*264c09b7SXiang Li 
211435897b4Spython3kgae namespace llvm {
212435897b4Spython3kgae 
213435897b4Spython3kgae void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
214435897b4Spython3kgae   std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op");
215435897b4Spython3kgae   OS << "// Generated code, do not edit.\n";
216435897b4Spython3kgae   OS << "\n";
217435897b4Spython3kgae 
218435897b4Spython3kgae   std::vector<DXILOperationData> DXILOps;
219435897b4Spython3kgae   DXILOps.reserve(Ops.size());
220435897b4Spython3kgae   for (auto *Record : Ops) {
221435897b4Spython3kgae     DXILOps.emplace_back(DXILOperationData(Record));
222435897b4Spython3kgae   }
223435897b4Spython3kgae 
224435897b4Spython3kgae   OS << "#ifdef DXIL_OP_ENUM\n";
225435897b4Spython3kgae   emitDXILEnums(DXILOps, OS);
226435897b4Spython3kgae   OS << "#endif\n\n";
227435897b4Spython3kgae 
228*264c09b7SXiang Li   OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n";
229*264c09b7SXiang Li   EmitDXILIntrinsicMap(DXILOps, OS);
230*264c09b7SXiang Li   OS << "#endif\n\n";
231*264c09b7SXiang Li 
232*264c09b7SXiang Li 
233435897b4Spython3kgae   OS << "\n";
234435897b4Spython3kgae }
235435897b4Spython3kgae 
236435897b4Spython3kgae } // namespace llvm
237