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