[Frontend] Remove unused includes (NFC) (#116927)
[llvm-project.git] / llvm / utils / TableGen / DXILEmitter.cpp
blobe74fc00015b4045cfac8373046487a541b4b9908
1 //===- DXILEmitter.cpp - DXIL operation Emitter ---------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // DXILEmitter uses the descriptions of DXIL operation to construct enum and
10 // helper functions for DXIL operation.
12 //===----------------------------------------------------------------------===//
14 #include "Basic/SequenceToOffsetTable.h"
15 #include "Common/CodeGenTarget.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/StringSet.h"
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/Support/DXILABI.h"
22 #include "llvm/Support/VersionTuple.h"
23 #include "llvm/TableGen/Error.h"
24 #include "llvm/TableGen/Record.h"
25 #include "llvm/TableGen/TableGenBackend.h"
27 #include <string>
28 #include <vector>
30 using namespace llvm;
31 using namespace llvm::dxil;
33 namespace {
35 struct DXILOperationDesc {
36 std::string OpName; // name of DXIL operation
37 int OpCode; // ID of DXIL operation
38 StringRef OpClass; // name of the opcode class
39 StringRef Doc; // the documentation description of this instruction
40 // Vector of operand type records - return type is at index 0
41 SmallVector<const Record *> OpTypes;
42 SmallVector<const Record *> OverloadRecs;
43 SmallVector<const Record *> StageRecs;
44 SmallVector<const Record *> AttrRecs;
45 StringRef Intrinsic; // The llvm intrinsic map to OpName. Default is "" which
46 // means no map exists
47 SmallVector<StringRef, 4>
48 ShaderStages; // shader stages to which this applies, empty for all.
49 int OverloadParamIndex; // Index of parameter with overload type.
50 // -1 : no overload types
51 SmallVector<StringRef, 4> Counters; // counters for this inst.
52 DXILOperationDesc(const Record *);
54 } // end anonymous namespace
56 /// In-place sort TableGen records of class with a field
57 /// Version dxil_version
58 /// in the ascending version order.
59 static void ascendingSortByVersion(std::vector<const Record *> &Recs) {
60 sort(Recs, [](const Record *RecA, const Record *RecB) {
61 unsigned RecAMaj =
62 RecA->getValueAsDef("dxil_version")->getValueAsInt("Major");
63 unsigned RecAMin =
64 RecA->getValueAsDef("dxil_version")->getValueAsInt("Minor");
65 unsigned RecBMaj =
66 RecB->getValueAsDef("dxil_version")->getValueAsInt("Major");
67 unsigned RecBMin =
68 RecB->getValueAsDef("dxil_version")->getValueAsInt("Minor");
70 return (VersionTuple(RecAMaj, RecAMin) < VersionTuple(RecBMaj, RecBMin));
71 });
74 /// Construct an object using the DXIL Operation records specified
75 /// in DXIL.td. This serves as the single source of reference of
76 /// the information extracted from the specified Record R, for
77 /// C++ code generated by this TableGen backend.
78 // \param R Object representing TableGen record of a DXIL Operation
79 DXILOperationDesc::DXILOperationDesc(const Record *R) {
80 OpName = R->getNameInitAsString();
81 OpCode = R->getValueAsInt("OpCode");
83 Doc = R->getValueAsString("Doc");
84 SmallVector<const Record *> ParamTypeRecs;
86 ParamTypeRecs.push_back(R->getValueAsDef("result"));
88 for (const Record *ArgTy : R->getValueAsListOfDefs("arguments")) {
89 ParamTypeRecs.push_back(ArgTy);
91 size_t ParamTypeRecsSize = ParamTypeRecs.size();
92 // Populate OpTypes with return type and parameter types
94 // Parameter indices of overloaded parameters.
95 // This vector contains overload parameters in the order used to
96 // resolve an LLVMMatchType in accordance with convention outlined in
97 // the comment before the definition of class LLVMMatchType in
98 // llvm/IR/Intrinsics.td
99 OverloadParamIndex = -1; // A sigil meaning none.
100 for (unsigned I = 0; I < ParamTypeRecsSize; I++) {
101 const Record *TR = ParamTypeRecs[I];
102 // Track operation parameter indices of any overload types
103 if (TR->getValueAsInt("isOverload")) {
104 if (OverloadParamIndex != -1) {
105 assert(TR == ParamTypeRecs[OverloadParamIndex] &&
106 "Specification of multiple differing overload parameter types "
107 "is not supported");
109 // Keep the earliest parameter index we see, but if it was the return type
110 // overwrite it with the first overloaded argument.
111 if (OverloadParamIndex <= 0)
112 OverloadParamIndex = I;
114 OpTypes.emplace_back(TR);
117 // Get overload records
118 std::vector<const Record *> Recs = R->getValueAsListOfDefs("overloads");
120 // Sort records in ascending order of DXIL version
121 ascendingSortByVersion(Recs);
123 for (const Record *CR : Recs) {
124 OverloadRecs.push_back(CR);
127 // Get stage records
128 Recs = R->getValueAsListOfDefs("stages");
130 if (Recs.empty()) {
131 PrintFatalError(R, Twine("Atleast one specification of valid stage for ") +
132 OpName + " is required");
135 // Sort records in ascending order of DXIL version
136 ascendingSortByVersion(Recs);
138 for (const Record *CR : Recs) {
139 StageRecs.push_back(CR);
142 // Get attribute records
143 Recs = R->getValueAsListOfDefs("attributes");
145 // Sort records in ascending order of DXIL version
146 ascendingSortByVersion(Recs);
148 for (const Record *CR : Recs) {
149 AttrRecs.push_back(CR);
152 // Get the operation class
153 OpClass = R->getValueAsDef("OpClass")->getName();
155 if (!OpClass.str().compare("UnknownOpClass")) {
156 PrintFatalError(R, Twine("Unspecified DXIL OpClass for DXIL operation - ") +
157 OpName);
160 const RecordVal *RV = R->getValue("LLVMIntrinsic");
161 if (RV && RV->getValue()) {
162 if (const DefInit *DI = dyn_cast<DefInit>(RV->getValue())) {
163 auto *IntrinsicDef = DI->getDef();
164 auto DefName = IntrinsicDef->getName();
165 assert(DefName.starts_with("int_") && "invalid intrinsic name");
166 // Remove the int_ from intrinsic name.
167 Intrinsic = DefName.substr(4);
172 /// Return a string representation of OverloadKind enum that maps to
173 /// input LLVMType record
174 /// \param R TableGen def record of class LLVMType
175 /// \return std::string string representation of OverloadKind
177 static StringRef getOverloadKindStr(const Record *R) {
178 // TODO: This is a hack. We need to rework how we're handling the set of
179 // overloads to avoid this business with the separate OverloadKind enum.
180 return StringSwitch<StringRef>(R->getName())
181 .Case("HalfTy", "OverloadKind::HALF")
182 .Case("FloatTy", "OverloadKind::FLOAT")
183 .Case("DoubleTy", "OverloadKind::DOUBLE")
184 .Case("Int1Ty", "OverloadKind::I1")
185 .Case("Int8Ty", "OverloadKind::I8")
186 .Case("Int16Ty", "OverloadKind::I16")
187 .Case("Int32Ty", "OverloadKind::I32")
188 .Case("Int64Ty", "OverloadKind::I64")
189 .Case("ResRetHalfTy", "OverloadKind::HALF")
190 .Case("ResRetFloatTy", "OverloadKind::FLOAT")
191 .Case("ResRetInt16Ty", "OverloadKind::I16")
192 .Case("ResRetInt32Ty", "OverloadKind::I32");
195 /// Return a string representation of valid overload information denoted
196 // by input records
198 /// \param Recs A vector of records of TableGen Overload records
199 /// \return std::string string representation of overload mask string
200 /// predicated by DXIL Version. E.g.,
201 // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...}
202 static std::string getOverloadMaskString(ArrayRef<const Record *> Recs) {
203 std::string MaskString = "";
204 std::string Prefix = "";
205 MaskString.append("{");
206 // If no overload information records were specified, assume the operation
207 // a) to be supported in DXIL Version 1.0 and later
208 // b) has no overload types
209 if (Recs.empty()) {
210 MaskString.append("{{1, 0}, OverloadKind::UNDEFINED}}");
211 } else {
212 for (const auto *Rec : Recs) {
213 unsigned Major =
214 Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");
215 unsigned Minor =
216 Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");
217 MaskString.append(Prefix)
218 .append("{{")
219 .append(std::to_string(Major))
220 .append(", ")
221 .append(std::to_string(Minor).append("}, "));
223 std::string PipePrefix = "";
224 auto Tys = Rec->getValueAsListOfDefs("overload_types");
225 if (Tys.empty()) {
226 MaskString.append("OverloadKind::UNDEFINED");
228 for (const auto *Ty : Tys) {
229 MaskString.append(PipePrefix).append(getOverloadKindStr(Ty));
230 PipePrefix = " | ";
233 MaskString.append("}");
234 Prefix = ", ";
236 MaskString.append("}");
238 return MaskString;
241 /// Return a string representation of valid shader stag information denoted
242 // by input records
244 /// \param Recs A vector of records of TableGen Stages records
245 /// \return std::string string representation of stages mask string
246 /// predicated by DXIL Version. E.g.,
247 // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...}
248 static std::string getStageMaskString(ArrayRef<const Record *> Recs) {
249 std::string MaskString = "";
250 std::string Prefix = "";
251 MaskString.append("{");
252 // Atleast one stage information record is expected to be specified.
253 if (Recs.empty()) {
254 PrintFatalError("Atleast one specification of valid stages for "
255 "operation must be specified");
258 for (const auto *Rec : Recs) {
259 unsigned Major = Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");
260 unsigned Minor = Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");
261 MaskString.append(Prefix)
262 .append("{{")
263 .append(std::to_string(Major))
264 .append(", ")
265 .append(std::to_string(Minor).append("}, "));
267 std::string PipePrefix = "";
268 auto Stages = Rec->getValueAsListOfDefs("shader_stages");
269 if (Stages.empty()) {
270 PrintFatalError("No valid stages for operation specified");
272 for (const auto *S : Stages) {
273 MaskString.append(PipePrefix).append("ShaderKind::").append(S->getName());
274 PipePrefix = " | ";
277 MaskString.append("}");
278 Prefix = ", ";
280 MaskString.append("}");
281 return MaskString;
284 /// Return a string representation of valid attribute information denoted
285 // by input records
287 /// \param Recs A vector of records of TableGen Attribute records
288 /// \return std::string string representation of stages mask string
289 /// predicated by DXIL Version. E.g.,
290 // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...}
291 static std::string getAttributeMaskString(ArrayRef<const Record *> Recs) {
292 std::string MaskString = "";
293 std::string Prefix = "";
294 MaskString.append("{");
296 for (const auto *Rec : Recs) {
297 unsigned Major = Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");
298 unsigned Minor = Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");
299 MaskString.append(Prefix)
300 .append("{{")
301 .append(std::to_string(Major))
302 .append(", ")
303 .append(std::to_string(Minor).append("}, "));
305 std::string PipePrefix = "";
306 auto Attrs = Rec->getValueAsListOfDefs("op_attrs");
307 if (Attrs.empty()) {
308 MaskString.append("Attribute::None");
309 } else {
310 for (const auto *Attr : Attrs) {
311 MaskString.append(PipePrefix)
312 .append("Attribute::")
313 .append(Attr->getName());
314 PipePrefix = " | ";
318 MaskString.append("}");
319 Prefix = ", ";
321 MaskString.append("}");
322 return MaskString;
325 /// Emit a mapping of DXIL opcode to opname
326 static void emitDXILOpCodes(ArrayRef<DXILOperationDesc> Ops, raw_ostream &OS) {
327 OS << "#ifdef DXIL_OPCODE\n";
328 for (const DXILOperationDesc &Op : Ops)
329 OS << "DXIL_OPCODE(" << Op.OpCode << ", " << Op.OpName << ")\n";
330 OS << "#undef DXIL_OPCODE\n";
331 OS << "\n";
332 OS << "#endif\n\n";
335 /// Emit a list of DXIL op classes
336 static void emitDXILOpClasses(const RecordKeeper &Records, raw_ostream &OS) {
337 OS << "#ifdef DXIL_OPCLASS\n";
338 for (const Record *OpClass : Records.getAllDerivedDefinitions("DXILOpClass"))
339 OS << "DXIL_OPCLASS(" << OpClass->getName() << ")\n";
340 OS << "#undef DXIL_OPCLASS\n";
341 OS << "#endif\n\n";
344 /// Emit a list of DXIL op parameter types
345 static void emitDXILOpParamTypes(const RecordKeeper &Records, raw_ostream &OS) {
346 OS << "#ifdef DXIL_OP_PARAM_TYPE\n";
347 for (const Record *OpParamType :
348 Records.getAllDerivedDefinitions("DXILOpParamType"))
349 OS << "DXIL_OP_PARAM_TYPE(" << OpParamType->getName() << ")\n";
350 OS << "#undef DXIL_OP_PARAM_TYPE\n";
351 OS << "#endif\n\n";
354 /// Emit a list of DXIL op function types
355 static void emitDXILOpFunctionTypes(ArrayRef<DXILOperationDesc> Ops,
356 raw_ostream &OS) {
357 OS << "#ifndef DXIL_OP_FUNCTION_TYPE\n";
358 OS << "#define DXIL_OP_FUNCTION_TYPE(OpCode, RetType, ...)\n";
359 OS << "#endif\n";
360 for (const DXILOperationDesc &Op : Ops) {
361 OS << "DXIL_OP_FUNCTION_TYPE(dxil::OpCode::" << Op.OpName;
362 for (const Record *Rec : Op.OpTypes)
363 OS << ", dxil::OpParamType::" << Rec->getName();
364 // If there are no arguments, we need an empty comma for the varargs
365 if (Op.OpTypes.size() == 1)
366 OS << ", ";
367 OS << ")\n";
369 OS << "#undef DXIL_OP_FUNCTION_TYPE\n";
372 /// Emit map of DXIL operation to LLVM or DirectX intrinsic
373 /// \param A vector of DXIL Ops
374 /// \param Output stream
375 static void emitDXILIntrinsicMap(ArrayRef<DXILOperationDesc> Ops,
376 raw_ostream &OS) {
377 OS << "#ifdef DXIL_OP_INTRINSIC\n";
378 OS << "\n";
379 for (const auto &Op : Ops) {
380 if (Op.Intrinsic.empty())
381 continue;
382 OS << "DXIL_OP_INTRINSIC(dxil::OpCode::" << Op.OpName
383 << ", Intrinsic::" << Op.Intrinsic << ")\n";
385 OS << "\n";
386 OS << "#undef DXIL_OP_INTRINSIC\n";
387 OS << "#endif\n\n";
390 /// Emit DXIL operation table
391 /// \param A vector of DXIL Ops
392 /// \param Output stream
393 static void emitDXILOperationTable(ArrayRef<DXILOperationDesc> Ops,
394 raw_ostream &OS) {
395 // Collect Names.
396 SequenceToOffsetTable<std::string> OpClassStrings;
397 SequenceToOffsetTable<std::string> OpStrings;
399 StringSet<> ClassSet;
400 for (const auto &Op : Ops) {
401 OpStrings.add(Op.OpName);
403 if (ClassSet.insert(Op.OpClass).second)
404 OpClassStrings.add(Op.OpClass.data());
407 // Layout names.
408 OpStrings.layout();
409 OpClassStrings.layout();
411 // Emit access function getOpcodeProperty() that embeds DXIL Operation table
412 // with entries of type struct OpcodeProperty.
413 OS << "static const OpCodeProperty *getOpCodeProperty(dxil::OpCode Op) "
414 "{\n";
416 OS << " static const OpCodeProperty OpCodeProps[] = {\n";
417 std::string Prefix = "";
418 for (const auto &Op : Ops) {
419 OS << Prefix << " { dxil::OpCode::" << Op.OpName << ", "
420 << OpStrings.get(Op.OpName) << ", OpCodeClass::" << Op.OpClass << ", "
421 << OpClassStrings.get(Op.OpClass.data()) << ", "
422 << getOverloadMaskString(Op.OverloadRecs) << ", "
423 << getStageMaskString(Op.StageRecs) << ", "
424 << getAttributeMaskString(Op.AttrRecs) << ", " << Op.OverloadParamIndex
425 << " }";
426 Prefix = ",\n";
428 OS << " };\n";
430 OS << " // FIXME: change search to indexing with\n";
431 OS << " // Op once all DXIL operations are added.\n";
432 OS << " OpCodeProperty TmpProp;\n";
433 OS << " TmpProp.OpCode = Op;\n";
434 OS << " const OpCodeProperty *Prop =\n";
435 OS << " llvm::lower_bound(OpCodeProps, TmpProp,\n";
436 OS << " [](const OpCodeProperty &A, const "
437 "OpCodeProperty &B) {\n";
438 OS << " return A.OpCode < B.OpCode;\n";
439 OS << " });\n";
440 OS << " assert(Prop && \"failed to find OpCodeProperty\");\n";
441 OS << " return Prop;\n";
442 OS << "}\n\n";
444 // Emit the string tables.
445 OS << "static const char *getOpCodeName(dxil::OpCode Op) {\n\n";
447 OpStrings.emitStringLiteralDef(OS,
448 " static const char DXILOpCodeNameTable[]");
450 OS << " auto *Prop = getOpCodeProperty(Op);\n";
451 OS << " unsigned Index = Prop->OpCodeNameOffset;\n";
452 OS << " return DXILOpCodeNameTable + Index;\n";
453 OS << "}\n\n";
455 OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) "
456 "{\n\n";
458 OpClassStrings.emitStringLiteralDef(
459 OS, " static const char DXILOpCodeClassNameTable[]");
461 OS << " unsigned Index = Prop.OpCodeClassNameOffset;\n";
462 OS << " return DXILOpCodeClassNameTable + Index;\n";
463 OS << "}\n\n";
466 static void emitDXILOperationTableDataStructs(const RecordKeeper &Records,
467 raw_ostream &OS) {
468 // Get Shader stage records
469 std::vector<const Record *> ShaderKindRecs =
470 Records.getAllDerivedDefinitions("DXILShaderStage");
471 // Sort records by name
472 llvm::sort(ShaderKindRecs, [](const Record *A, const Record *B) {
473 return A->getName() < B->getName();
476 OS << "// Valid shader kinds\n\n";
477 // Choose the type of enum ShaderKind based on the number of stages declared.
478 // This gives the flexibility to just add add new stage records in DXIL.td, if
479 // needed, with no need to change this backend code.
480 size_t ShaderKindCount = ShaderKindRecs.size();
481 uint64_t ShaderKindTySz = PowerOf2Ceil(ShaderKindRecs.size() + 1);
482 OS << "enum ShaderKind : uint" << ShaderKindTySz << "_t {\n";
483 const std::string AllStages("all_stages");
484 const std::string Removed("removed");
485 int ShiftVal = 1;
486 for (const auto *R : ShaderKindRecs) {
487 auto Name = R->getName();
488 if (Name.compare(Removed) == 0) {
489 OS << " " << Name
490 << " = 0, // Pseudo-stage indicating op not supported in any "
491 "stage\n";
492 } else if (Name.compare(AllStages) == 0) {
493 OS << " " << Name << " = 0x"
494 << utohexstr(((1 << ShaderKindCount) - 1), false, 0)
495 << ", // Pseudo-stage indicating op is supported in all stages\n";
496 } else if (Name.compare(AllStages)) {
497 OS << " " << Name << " = 1 << " << std::to_string(ShiftVal++) << ",\n";
500 OS << "}; // enum ShaderKind\n\n";
503 /// Entry function call that invokes the functionality of this TableGen backend
504 /// \param Records TableGen records of DXIL Operations defined in DXIL.td
505 /// \param OS output stream
506 static void emitDxilOperation(const RecordKeeper &Records, raw_ostream &OS) {
507 OS << "// Generated code, do not edit.\n";
508 OS << "\n";
509 // Get all DXIL Ops property records
510 std::vector<DXILOperationDesc> DXILOps;
511 for (const Record *R : Records.getAllDerivedDefinitions("DXILOp")) {
512 DXILOps.emplace_back(DXILOperationDesc(R));
514 // Sort by opcode.
515 llvm::sort(DXILOps,
516 [](const DXILOperationDesc &A, const DXILOperationDesc &B) {
517 return A.OpCode < B.OpCode;
519 int PrevOp = -1;
520 for (const DXILOperationDesc &Desc : DXILOps) {
521 if (Desc.OpCode == PrevOp)
522 PrintFatalError(Twine("Duplicate opcode: ") + Twine(Desc.OpCode));
523 PrevOp = Desc.OpCode;
526 emitDXILOpCodes(DXILOps, OS);
527 emitDXILOpClasses(Records, OS);
528 emitDXILOpParamTypes(Records, OS);
529 emitDXILOpFunctionTypes(DXILOps, OS);
530 emitDXILIntrinsicMap(DXILOps, OS);
531 OS << "#ifdef DXIL_OP_OPERATION_TABLE\n\n";
532 emitDXILOperationTableDataStructs(Records, OS);
533 emitDXILOperationTable(DXILOps, OS);
534 OS << "#undef DXIL_OP_OPERATION_TABLE\n";
535 OS << "#endif\n\n";
538 static TableGen::Emitter::Opt X("gen-dxil-operation", emitDxilOperation,
539 "Generate DXIL operation information");