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