123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- //===- DXILEmitter.cpp - DXIL operation Emitter ---------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // DXILEmitter uses the descriptions of DXIL operation to construct enum and
- // helper functions for DXIL operation.
- //
- //===----------------------------------------------------------------------===//
- #include "SequenceToOffsetTable.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringSet.h"
- #include "llvm/ADT/StringSwitch.h"
- #include "llvm/Support/DXILOperationCommon.h"
- #include "llvm/TableGen/Error.h"
- #include "llvm/TableGen/Record.h"
- using namespace llvm;
- using namespace llvm::dxil;
- namespace {
- struct DXILShaderModel {
- int Major;
- int Minor;
- };
- struct DXILParam {
- int Pos; // position in parameter list
- ParameterKind Kind;
- StringRef Name; // short, unique name
- StringRef Doc; // the documentation description of this parameter
- bool IsConst; // whether this argument requires a constant value in the IR
- StringRef EnumName; // the name of the enum type if applicable
- int MaxValue; // the maximum value for this parameter if applicable
- DXILParam(const Record *R);
- };
- struct DXILOperationData {
- StringRef Name; // short, unique name
- StringRef DXILOp; // name of DXIL operation
- int DXILOpID; // ID of DXIL operation
- StringRef DXILClass; // name of the opcode class
- StringRef Category; // classification for this instruction
- StringRef Doc; // the documentation description of this instruction
- SmallVector<DXILParam> Params; // the operands that this instruction takes
- StringRef OverloadTypes; // overload types if applicable
- StringRef FnAttr; // attribute shorthands: rn=does not access
- // memory,ro=only reads from memory
- StringRef Intrinsic; // The llvm intrinsic map to DXILOp. Default is "" which
- // means no map exist
- bool IsDeriv; // whether this is some kind of derivative
- bool IsGradient; // whether this requires a gradient calculation
- bool IsFeedback; // whether this is a sampler feedback op
- bool IsWave; // whether this requires in-wave, cross-lane functionality
- bool RequiresUniformInputs; // whether this operation requires that all
- // of its inputs are uniform across the wave
- SmallVector<StringRef, 4>
- ShaderStages; // shader stages to which this applies, empty for all.
- DXILShaderModel ShaderModel; // minimum shader model required
- DXILShaderModel ShaderModelTranslated; // minimum shader model required with
- // translation by linker
- int OverloadParamIndex; // parameter index which control the overload.
- // When < 0, should be only 1 overload type.
- SmallVector<StringRef, 4> counters; // counters for this inst.
- DXILOperationData(const Record *R) {
- Name = R->getValueAsString("name");
- DXILOp = R->getValueAsString("dxil_op");
- DXILOpID = R->getValueAsInt("dxil_opid");
- DXILClass = R->getValueAsDef("op_class")->getValueAsString("name");
- Category = R->getValueAsDef("category")->getValueAsString("name");
- if (R->getValue("llvm_intrinsic")) {
- auto *IntrinsicDef = R->getValueAsDef("llvm_intrinsic");
- auto DefName = IntrinsicDef->getName();
- assert(DefName.startswith("int_") && "invalid intrinsic name");
- // Remove the int_ from intrinsic name.
- Intrinsic = DefName.substr(4);
- }
- Doc = R->getValueAsString("doc");
- ListInit *ParamList = R->getValueAsListInit("ops");
- OverloadParamIndex = -1;
- for (unsigned I = 0; I < ParamList->size(); ++I) {
- Record *Param = ParamList->getElementAsRecord(I);
- Params.emplace_back(DXILParam(Param));
- auto &CurParam = Params.back();
- if (CurParam.Kind >= ParameterKind::OVERLOAD)
- OverloadParamIndex = I;
- }
- OverloadTypes = R->getValueAsString("oload_types");
- FnAttr = R->getValueAsString("fn_attr");
- }
- };
- } // end anonymous namespace
- DXILParam::DXILParam(const Record *R) {
- Name = R->getValueAsString("name");
- Pos = R->getValueAsInt("pos");
- Kind = parameterTypeNameToKind(R->getValueAsString("llvm_type"));
- if (R->getValue("doc"))
- Doc = R->getValueAsString("doc");
- IsConst = R->getValueAsBit("is_const");
- EnumName = R->getValueAsString("enum_name");
- MaxValue = R->getValueAsInt("max_value");
- }
- static std::string parameterKindToString(ParameterKind Kind) {
- switch (Kind) {
- case ParameterKind::INVALID:
- return "INVALID";
- case ParameterKind::VOID:
- return "VOID";
- case ParameterKind::HALF:
- return "HALF";
- case ParameterKind::FLOAT:
- return "FLOAT";
- case ParameterKind::DOUBLE:
- return "DOUBLE";
- case ParameterKind::I1:
- return "I1";
- case ParameterKind::I8:
- return "I8";
- case ParameterKind::I16:
- return "I16";
- case ParameterKind::I32:
- return "I32";
- case ParameterKind::I64:
- return "I64";
- case ParameterKind::OVERLOAD:
- return "OVERLOAD";
- case ParameterKind::CBUFFER_RET:
- return "CBUFFER_RET";
- case ParameterKind::RESOURCE_RET:
- return "RESOURCE_RET";
- case ParameterKind::DXIL_HANDLE:
- return "DXIL_HANDLE";
- }
- llvm_unreachable("Unknown llvm::dxil::ParameterKind enum");
- }
- static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
- // Name = ID, // Doc
- OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc
- << "\n";
- }
- static std::string buildCategoryStr(StringSet<> &Cetegorys) {
- std::string Str;
- raw_string_ostream OS(Str);
- for (auto &It : Cetegorys) {
- OS << " " << It.getKey();
- }
- return OS.str();
- }
- // Emit enum declaration for DXIL.
- static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps,
- raw_ostream &OS) {
- // Sort by Category + OpName.
- llvm::sort(DXILOps, [](DXILOperationData &A, DXILOperationData &B) {
- // Group by Category first.
- if (A.Category == B.Category)
- // Inside same Category, order by OpName.
- return A.DXILOp < B.DXILOp;
- else
- return A.Category < B.Category;
- });
- OS << "// Enumeration for operations specified by DXIL\n";
- OS << "enum class OpCode : unsigned {\n";
- StringMap<StringSet<>> ClassMap;
- StringRef PrevCategory = "";
- for (auto &DXILOp : DXILOps) {
- StringRef Category = DXILOp.Category;
- if (Category != PrevCategory) {
- OS << "\n// " << Category << "\n";
- PrevCategory = Category;
- }
- emitDXILOpEnum(DXILOp, OS);
- auto It = ClassMap.find(DXILOp.DXILClass);
- if (It != ClassMap.end()) {
- It->second.insert(DXILOp.Category);
- } else {
- ClassMap[DXILOp.DXILClass].insert(DXILOp.Category);
- }
- }
- OS << "\n};\n\n";
- std::vector<std::pair<std::string, std::string>> ClassVec;
- for (auto &It : ClassMap) {
- ClassVec.emplace_back(
- std::make_pair(It.getKey().str(), buildCategoryStr(It.second)));
- }
- // Sort by Category + ClassName.
- llvm::sort(ClassVec, [](std::pair<std::string, std::string> &A,
- std::pair<std::string, std::string> &B) {
- StringRef ClassA = A.first;
- StringRef CategoryA = A.second;
- StringRef ClassB = B.first;
- StringRef CategoryB = B.second;
- // Group by Category first.
- if (CategoryA == CategoryB)
- // Inside same Category, order by ClassName.
- return ClassA < ClassB;
- else
- return CategoryA < CategoryB;
- });
- OS << "// Groups for DXIL operations with equivalent function templates\n";
- OS << "enum class OpCodeClass : unsigned {\n";
- PrevCategory = "";
- for (auto &It : ClassVec) {
- StringRef Category = It.second;
- if (Category != PrevCategory) {
- OS << "\n// " << Category << "\n";
- PrevCategory = Category;
- }
- StringRef Name = It.first;
- OS << Name << ",\n";
- }
- OS << "\n};\n\n";
- }
- // Emit map from llvm intrinsic to DXIL operation.
- static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps,
- raw_ostream &OS) {
- OS << "\n";
- // FIXME: use array instead of SmallDenseMap.
- OS << "static const SmallDenseMap<Intrinsic::ID, dxil::OpCode> LowerMap = "
- "{\n";
- for (auto &DXILOp : DXILOps) {
- if (DXILOp.Intrinsic.empty())
- continue;
- // {Intrinsic::sin, dxil::OpCode::Sin},
- OS << " { Intrinsic::" << DXILOp.Intrinsic
- << ", dxil::OpCode::" << DXILOp.DXILOp << "},\n";
- }
- OS << "};\n";
- OS << "\n";
- }
- static std::string emitDXILOperationFnAttr(StringRef FnAttr) {
- return StringSwitch<std::string>(FnAttr)
- .Case("rn", "Attribute::ReadNone")
- .Case("ro", "Attribute::ReadOnly")
- .Default("Attribute::None");
- }
- static std::string getOverloadKind(StringRef Overload) {
- return StringSwitch<std::string>(Overload)
- .Case("half", "OverloadKind::HALF")
- .Case("float", "OverloadKind::FLOAT")
- .Case("double", "OverloadKind::DOUBLE")
- .Case("i1", "OverloadKind::I1")
- .Case("i16", "OverloadKind::I16")
- .Case("i32", "OverloadKind::I32")
- .Case("i64", "OverloadKind::I64")
- .Case("udt", "OverloadKind::UserDefineType")
- .Case("obj", "OverloadKind::ObjectType")
- .Default("OverloadKind::VOID");
- }
- static std::string getDXILOperationOverload(StringRef Overloads) {
- SmallVector<StringRef> OverloadStrs;
- Overloads.split(OverloadStrs, ';', /*MaxSplit*/ -1, /*KeepEmpty*/ false);
- // Format is: OverloadKind::FLOAT | OverloadKind::HALF
- assert(!OverloadStrs.empty() && "Invalid overloads");
- auto It = OverloadStrs.begin();
- std::string Result;
- raw_string_ostream OS(Result);
- OS << getOverloadKind(*It);
- for (++It; It != OverloadStrs.end(); ++It) {
- OS << " | " << getOverloadKind(*It);
- }
- return OS.str();
- }
- static std::string lowerFirstLetter(StringRef Name) {
- if (Name.empty())
- return "";
- std::string LowerName = Name.str();
- LowerName[0] = llvm::toLower(Name[0]);
- return LowerName;
- }
- static std::string getDXILOpClassName(StringRef DXILOpClass) {
- // Lower first letter expect for special case.
- return StringSwitch<std::string>(DXILOpClass)
- .Case("CBufferLoad", "cbufferLoad")
- .Case("CBufferLoadLegacy", "cbufferLoadLegacy")
- .Case("GSInstanceID", "gsInstanceID")
- .Default(lowerFirstLetter(DXILOpClass));
- }
- static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
- raw_ostream &OS) {
- // Sort by DXILOpID.
- llvm::sort(DXILOps, [](DXILOperationData &A, DXILOperationData &B) {
- return A.DXILOpID < B.DXILOpID;
- });
- // Collect Names.
- SequenceToOffsetTable<std::string> OpClassStrings;
- SequenceToOffsetTable<std::string> OpStrings;
- SequenceToOffsetTable<SmallVector<ParameterKind>> Parameters;
- StringMap<SmallVector<ParameterKind>> ParameterMap;
- StringSet<> ClassSet;
- for (auto &DXILOp : DXILOps) {
- OpStrings.add(DXILOp.DXILOp.str());
- if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end())
- continue;
- ClassSet.insert(DXILOp.DXILClass);
- OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass));
- SmallVector<ParameterKind> ParamKindVec;
- for (auto &Param : DXILOp.Params) {
- ParamKindVec.emplace_back(Param.Kind);
- }
- ParameterMap[DXILOp.DXILClass] = ParamKindVec;
- Parameters.add(ParamKindVec);
- }
- // Layout names.
- OpStrings.layout();
- OpClassStrings.layout();
- Parameters.layout();
- // Emit the DXIL operation table.
- //{dxil::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary,
- // OpCodeClassNameIndex,
- // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone, 0,
- // 3, ParameterTableOffset},
- OS << "static const OpCodeProperty *getOpCodeProperty(dxil::OpCode DXILOp) "
- "{\n";
- OS << " static const OpCodeProperty OpCodeProps[] = {\n";
- for (auto &DXILOp : DXILOps) {
- OS << " { dxil::OpCode::" << DXILOp.DXILOp << ", "
- << OpStrings.get(DXILOp.DXILOp.str())
- << ", OpCodeClass::" << DXILOp.DXILClass << ", "
- << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", "
- << getDXILOperationOverload(DXILOp.OverloadTypes) << ", "
- << emitDXILOperationFnAttr(DXILOp.FnAttr) << ", "
- << DXILOp.OverloadParamIndex << ", " << DXILOp.Params.size() << ", "
- << Parameters.get(ParameterMap[DXILOp.DXILClass]) << " },\n";
- }
- OS << " };\n";
- OS << " // FIXME: change search to indexing with\n";
- OS << " // DXILOp once all DXIL op is added.\n";
- OS << " OpCodeProperty TmpProp;\n";
- OS << " TmpProp.OpCode = DXILOp;\n";
- OS << " const OpCodeProperty *Prop =\n";
- OS << " llvm::lower_bound(OpCodeProps, TmpProp,\n";
- OS << " [](const OpCodeProperty &A, const "
- "OpCodeProperty &B) {\n";
- OS << " return A.OpCode < B.OpCode;\n";
- OS << " });\n";
- OS << " assert(Prop && \"fail to find OpCodeProperty\");\n";
- OS << " return Prop;\n";
- OS << "}\n\n";
- // Emit the string tables.
- OS << "static const char *getOpCodeName(dxil::OpCode DXILOp) {\n\n";
- OpStrings.emitStringLiteralDef(OS,
- " static const char DXILOpCodeNameTable[]");
- OS << " auto *Prop = getOpCodeProperty(DXILOp);\n";
- OS << " unsigned Index = Prop->OpCodeNameOffset;\n";
- OS << " return DXILOpCodeNameTable + Index;\n";
- OS << "}\n\n";
- OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) "
- "{\n\n";
- OpClassStrings.emitStringLiteralDef(
- OS, " static const char DXILOpCodeClassNameTable[]");
- OS << " unsigned Index = Prop.OpCodeClassNameOffset;\n";
- OS << " return DXILOpCodeClassNameTable + Index;\n";
- OS << "}\n ";
- OS << "static const ParameterKind *getOpCodeParameterKind(const "
- "OpCodeProperty &Prop) "
- "{\n\n";
- OS << " static const ParameterKind DXILOpParameterKindTable[] = {\n";
- Parameters.emit(
- OS,
- [](raw_ostream &ParamOS, ParameterKind Kind) {
- ParamOS << "ParameterKind::" << parameterKindToString(Kind);
- },
- "ParameterKind::INVALID");
- OS << " };\n\n";
- OS << " unsigned Index = Prop.ParameterTableOffset;\n";
- OS << " return DXILOpParameterKindTable + Index;\n";
- OS << "}\n ";
- }
- namespace llvm {
- void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
- std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op");
- OS << "// Generated code, do not edit.\n";
- OS << "\n";
- std::vector<DXILOperationData> DXILOps;
- DXILOps.reserve(Ops.size());
- for (auto *Record : Ops) {
- DXILOps.emplace_back(DXILOperationData(Record));
- }
- OS << "#ifdef DXIL_OP_ENUM\n";
- emitDXILEnums(DXILOps, OS);
- OS << "#endif\n\n";
- OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n";
- emitDXILIntrinsicMap(DXILOps, OS);
- OS << "#endif\n\n";
- OS << "#ifdef DXIL_OP_OPERATION_TABLE\n";
- emitDXILOperationTable(DXILOps, OS);
- OS << "#endif\n\n";
- OS << "\n";
- }
- } // namespace llvm
|