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 14*0d2dde20SXiang Li #include "SequenceToOffsetTable.h" 15435897b4Spython3kgae #include "llvm/ADT/STLExtras.h" 16435897b4Spython3kgae #include "llvm/ADT/SmallVector.h" 17435897b4Spython3kgae #include "llvm/ADT/StringSet.h" 18*0d2dde20SXiang Li #include "llvm/ADT/StringSwitch.h" 19435897b4Spython3kgae #include "llvm/TableGen/Error.h" 20435897b4Spython3kgae #include "llvm/TableGen/Record.h" 21435897b4Spython3kgae 22435897b4Spython3kgae using namespace llvm; 23435897b4Spython3kgae 24435897b4Spython3kgae namespace { 25435897b4Spython3kgae 26435897b4Spython3kgae struct DXILShaderModel { 27435897b4Spython3kgae int Major; 28435897b4Spython3kgae int Minor; 29435897b4Spython3kgae }; 30435897b4Spython3kgae struct DXILParam { 31435897b4Spython3kgae int Pos; // position in parameter list 32435897b4Spython3kgae StringRef Type; // llvm type name, $o for overload, $r for resource 33435897b4Spython3kgae // type, $cb for legacy cbuffer, $u4 for u4 struct 34435897b4Spython3kgae StringRef Name; // short, unique name 35435897b4Spython3kgae StringRef Doc; // the documentation description of this parameter 36435897b4Spython3kgae bool IsConst; // whether this argument requires a constant value in the IR 37435897b4Spython3kgae StringRef EnumName; // the name of the enum type if applicable 38435897b4Spython3kgae int MaxValue; // the maximum value for this parameter if applicable 39435897b4Spython3kgae DXILParam(const Record *R) { 40435897b4Spython3kgae Name = R->getValueAsString("name"); 41435897b4Spython3kgae Pos = R->getValueAsInt("pos"); 42435897b4Spython3kgae Type = R->getValueAsString("llvm_type"); 43435897b4Spython3kgae if (R->getValue("doc")) 44435897b4Spython3kgae Doc = R->getValueAsString("doc"); 45435897b4Spython3kgae IsConst = R->getValueAsBit("is_const"); 46435897b4Spython3kgae EnumName = R->getValueAsString("enum_name"); 47435897b4Spython3kgae MaxValue = R->getValueAsInt("max_value"); 48435897b4Spython3kgae } 49435897b4Spython3kgae }; 50435897b4Spython3kgae 51435897b4Spython3kgae struct DXILOperationData { 52435897b4Spython3kgae StringRef Name; // short, unique name 53435897b4Spython3kgae 54435897b4Spython3kgae StringRef DXILOp; // name of DXIL operation 55435897b4Spython3kgae int DXILOpID; // ID of DXIL operation 56435897b4Spython3kgae StringRef DXILClass; // name of the opcode class 57435897b4Spython3kgae StringRef Category; // classification for this instruction 58435897b4Spython3kgae StringRef Doc; // the documentation description of this instruction 59435897b4Spython3kgae 60435897b4Spython3kgae SmallVector<DXILParam> Params; // the operands that this instruction takes 61435897b4Spython3kgae StringRef OverloadTypes; // overload types if applicable 62435897b4Spython3kgae StringRef FnAttr; // attribute shorthands: rn=does not access 63264c09b7SXiang Li // memory,ro=only reads from memory 64264c09b7SXiang Li StringRef Intrinsic; // The llvm intrinsic map to DXILOp. Default is "" which 65264c09b7SXiang Li // means no map exist 66435897b4Spython3kgae bool IsDeriv; // whether this is some kind of derivative 67435897b4Spython3kgae bool IsGradient; // whether this requires a gradient calculation 68435897b4Spython3kgae bool IsFeedback; // whether this is a sampler feedback op 69435897b4Spython3kgae bool IsWave; // whether this requires in-wave, cross-lane functionality 70435897b4Spython3kgae bool RequiresUniformInputs; // whether this operation requires that all 71435897b4Spython3kgae // of its inputs are uniform across the wave 72435897b4Spython3kgae SmallVector<StringRef, 4> 73435897b4Spython3kgae ShaderStages; // shader stages to which this applies, empty for all. 74435897b4Spython3kgae DXILShaderModel ShaderModel; // minimum shader model required 75435897b4Spython3kgae DXILShaderModel ShaderModelTranslated; // minimum shader model required with 76435897b4Spython3kgae // translation by linker 77435897b4Spython3kgae SmallVector<StringRef, 4> counters; // counters for this inst. 78435897b4Spython3kgae DXILOperationData(const Record *R) { 79435897b4Spython3kgae Name = R->getValueAsString("name"); 80435897b4Spython3kgae DXILOp = R->getValueAsString("dxil_op"); 81435897b4Spython3kgae DXILOpID = R->getValueAsInt("dxil_opid"); 82435897b4Spython3kgae DXILClass = R->getValueAsDef("op_class")->getValueAsString("name"); 83435897b4Spython3kgae Category = R->getValueAsDef("category")->getValueAsString("name"); 84435897b4Spython3kgae 85264c09b7SXiang Li if (R->getValue("llvm_intrinsic")) { 86264c09b7SXiang Li auto *IntrinsicDef = R->getValueAsDef("llvm_intrinsic"); 87264c09b7SXiang Li auto DefName = IntrinsicDef->getName(); 88264c09b7SXiang Li assert(DefName.startswith("int_") && "invalid intrinsic name"); 89264c09b7SXiang Li // Remove the int_ from intrinsic name. 90264c09b7SXiang Li Intrinsic = DefName.substr(4); 91264c09b7SXiang Li } 92264c09b7SXiang Li 93435897b4Spython3kgae Doc = R->getValueAsString("doc"); 94264c09b7SXiang Li 95435897b4Spython3kgae ListInit *ParamList = R->getValueAsListInit("ops"); 96435897b4Spython3kgae for (unsigned i = 0; i < ParamList->size(); ++i) { 97435897b4Spython3kgae Record *Param = ParamList->getElementAsRecord(i); 98435897b4Spython3kgae Params.emplace_back(DXILParam(Param)); 99435897b4Spython3kgae } 100435897b4Spython3kgae OverloadTypes = R->getValueAsString("oload_types"); 101435897b4Spython3kgae FnAttr = R->getValueAsString("fn_attr"); 102435897b4Spython3kgae } 103435897b4Spython3kgae }; 104435897b4Spython3kgae } // end anonymous namespace 105435897b4Spython3kgae 106435897b4Spython3kgae static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) { 107435897b4Spython3kgae // Name = ID, // Doc 108435897b4Spython3kgae OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc 109435897b4Spython3kgae << "\n"; 110435897b4Spython3kgae } 111435897b4Spython3kgae 112435897b4Spython3kgae static std::string buildCategoryStr(StringSet<> &Cetegorys) { 113435897b4Spython3kgae std::string Str; 114435897b4Spython3kgae raw_string_ostream OS(Str); 115435897b4Spython3kgae for (auto &It : Cetegorys) { 116435897b4Spython3kgae OS << " " << It.getKey(); 117435897b4Spython3kgae } 118435897b4Spython3kgae return OS.str(); 119435897b4Spython3kgae } 120435897b4Spython3kgae 121435897b4Spython3kgae // Emit enum declaration for DXIL. 122435897b4Spython3kgae static void emitDXILEnums(std::vector<DXILOperationData> &DXILOps, 123435897b4Spython3kgae raw_ostream &OS) { 124435897b4Spython3kgae // Sort by Category + OpName. 125435897b4Spython3kgae std::sort(DXILOps.begin(), DXILOps.end(), 126435897b4Spython3kgae [](DXILOperationData &A, DXILOperationData &B) { 127435897b4Spython3kgae // Group by Category first. 128435897b4Spython3kgae if (A.Category == B.Category) 129435897b4Spython3kgae // Inside same Category, order by OpName. 130435897b4Spython3kgae return A.DXILOp < B.DXILOp; 131435897b4Spython3kgae else 132435897b4Spython3kgae return A.Category < B.Category; 133435897b4Spython3kgae }); 134435897b4Spython3kgae 135435897b4Spython3kgae OS << "// Enumeration for operations specified by DXIL\n"; 136435897b4Spython3kgae OS << "enum class OpCode : unsigned {\n"; 137435897b4Spython3kgae 138435897b4Spython3kgae StringMap<StringSet<>> ClassMap; 139435897b4Spython3kgae StringRef PrevCategory = ""; 140435897b4Spython3kgae for (auto &DXILOp : DXILOps) { 141435897b4Spython3kgae StringRef Category = DXILOp.Category; 142435897b4Spython3kgae if (Category != PrevCategory) { 143435897b4Spython3kgae OS << "\n// " << Category << "\n"; 144435897b4Spython3kgae PrevCategory = Category; 145435897b4Spython3kgae } 146435897b4Spython3kgae emitDXILOpEnum(DXILOp, OS); 147435897b4Spython3kgae auto It = ClassMap.find(DXILOp.DXILClass); 148435897b4Spython3kgae if (It != ClassMap.end()) { 149435897b4Spython3kgae It->second.insert(DXILOp.Category); 150435897b4Spython3kgae } else { 151435897b4Spython3kgae ClassMap[DXILOp.DXILClass].insert(DXILOp.Category); 152435897b4Spython3kgae } 153435897b4Spython3kgae } 154435897b4Spython3kgae 155435897b4Spython3kgae OS << "\n};\n\n"; 156435897b4Spython3kgae 157435897b4Spython3kgae std::vector<std::pair<std::string, std::string>> ClassVec; 158435897b4Spython3kgae for (auto &It : ClassMap) { 159435897b4Spython3kgae ClassVec.emplace_back( 160435897b4Spython3kgae std::make_pair(It.getKey().str(), buildCategoryStr(It.second))); 161435897b4Spython3kgae } 162435897b4Spython3kgae // Sort by Category + ClassName. 163435897b4Spython3kgae std::sort(ClassVec.begin(), ClassVec.end(), 164435897b4Spython3kgae [](std::pair<std::string, std::string> &A, 165435897b4Spython3kgae std::pair<std::string, std::string> &B) { 166435897b4Spython3kgae StringRef ClassA = A.first; 167435897b4Spython3kgae StringRef CategoryA = A.second; 168435897b4Spython3kgae StringRef ClassB = B.first; 169435897b4Spython3kgae StringRef CategoryB = B.second; 170435897b4Spython3kgae // Group by Category first. 171435897b4Spython3kgae if (CategoryA == CategoryB) 172435897b4Spython3kgae // Inside same Category, order by ClassName. 173435897b4Spython3kgae return ClassA < ClassB; 174435897b4Spython3kgae else 175435897b4Spython3kgae return CategoryA < CategoryB; 176435897b4Spython3kgae }); 177435897b4Spython3kgae 178435897b4Spython3kgae OS << "// Groups for DXIL operations with equivalent function templates\n"; 179435897b4Spython3kgae OS << "enum class OpCodeClass : unsigned {\n"; 180435897b4Spython3kgae PrevCategory = ""; 181435897b4Spython3kgae for (auto &It : ClassVec) { 182435897b4Spython3kgae 183435897b4Spython3kgae StringRef Category = It.second; 184435897b4Spython3kgae if (Category != PrevCategory) { 185435897b4Spython3kgae OS << "\n// " << Category << "\n"; 186435897b4Spython3kgae PrevCategory = Category; 187435897b4Spython3kgae } 188435897b4Spython3kgae StringRef Name = It.first; 189435897b4Spython3kgae OS << Name << ",\n"; 190435897b4Spython3kgae } 191435897b4Spython3kgae OS << "\n};\n\n"; 192435897b4Spython3kgae } 193435897b4Spython3kgae 194264c09b7SXiang Li // Emit map from llvm intrinsic to DXIL operation. 195*0d2dde20SXiang Li static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps, 196264c09b7SXiang Li raw_ostream &OS) { 197264c09b7SXiang Li OS << "\n"; 198264c09b7SXiang Li // FIXME: use array instead of SmallDenseMap. 199264c09b7SXiang Li OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = " 200264c09b7SXiang Li "{\n"; 201264c09b7SXiang Li for (auto &DXILOp : DXILOps) { 202264c09b7SXiang Li if (DXILOp.Intrinsic.empty()) 203264c09b7SXiang Li continue; 204264c09b7SXiang Li // {Intrinsic::sin, DXIL::OpCode::Sin}, 205264c09b7SXiang Li OS << " { Intrinsic::" << DXILOp.Intrinsic 206264c09b7SXiang Li << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n"; 207264c09b7SXiang Li } 208264c09b7SXiang Li OS << "};\n"; 209264c09b7SXiang Li OS << "\n"; 210264c09b7SXiang Li } 211264c09b7SXiang Li 212*0d2dde20SXiang Li static std::string emitDXILOperationFnAttr(StringRef FnAttr) { 213*0d2dde20SXiang Li return StringSwitch<std::string>(FnAttr) 214*0d2dde20SXiang Li .Case("rn", "Attribute::ReadNone") 215*0d2dde20SXiang Li .Case("ro", "Attribute::ReadOnly") 216*0d2dde20SXiang Li .Default("Attribute::None"); 217*0d2dde20SXiang Li } 218*0d2dde20SXiang Li 219*0d2dde20SXiang Li static std::string getOverloadKind(StringRef Overload) { 220*0d2dde20SXiang Li return StringSwitch<std::string>(Overload) 221*0d2dde20SXiang Li .Case("half", "OverloadKind::HALF") 222*0d2dde20SXiang Li .Case("float", "OverloadKind::FLOAT") 223*0d2dde20SXiang Li .Case("double", "OverloadKind::DOUBLE") 224*0d2dde20SXiang Li .Case("i1", "OverloadKind::I1") 225*0d2dde20SXiang Li .Case("i16", "OverloadKind::I16") 226*0d2dde20SXiang Li .Case("i32", "OverloadKind::I32") 227*0d2dde20SXiang Li .Case("i64", "OverloadKind::I64") 228*0d2dde20SXiang Li .Case("udt", "OverloadKind::UserDefineType") 229*0d2dde20SXiang Li .Case("obj", "OverloadKind::ObjectType") 230*0d2dde20SXiang Li .Default("OverloadKind::VOID"); 231*0d2dde20SXiang Li } 232*0d2dde20SXiang Li 233*0d2dde20SXiang Li static std::string getDXILOperationOverload(StringRef Overloads) { 234*0d2dde20SXiang Li SmallVector<StringRef> OverloadStrs; 235*0d2dde20SXiang Li Overloads.split(OverloadStrs, ';', /*MaxSplit*/ -1, /*KeepEmpty*/ false); 236*0d2dde20SXiang Li // Format is: OverloadKind::FLOAT | OverloadKind::HALF 237*0d2dde20SXiang Li assert(!OverloadStrs.empty() && "Invalid overloads"); 238*0d2dde20SXiang Li auto It = OverloadStrs.begin(); 239*0d2dde20SXiang Li std::string Result; 240*0d2dde20SXiang Li raw_string_ostream OS(Result); 241*0d2dde20SXiang Li OS << getOverloadKind(*It); 242*0d2dde20SXiang Li for (++It; It != OverloadStrs.end(); ++It) { 243*0d2dde20SXiang Li OS << " | " << getOverloadKind(*It); 244*0d2dde20SXiang Li } 245*0d2dde20SXiang Li return OS.str(); 246*0d2dde20SXiang Li } 247*0d2dde20SXiang Li 248*0d2dde20SXiang Li static std::string lowerFirstLetter(StringRef Name) { 249*0d2dde20SXiang Li if (Name.empty()) 250*0d2dde20SXiang Li return ""; 251*0d2dde20SXiang Li 252*0d2dde20SXiang Li std::string LowerName = Name.str(); 253*0d2dde20SXiang Li LowerName[0] = llvm::toLower(Name[0]); 254*0d2dde20SXiang Li return LowerName; 255*0d2dde20SXiang Li } 256*0d2dde20SXiang Li 257*0d2dde20SXiang Li static std::string getDXILOpClassName(StringRef DXILOpClass) { 258*0d2dde20SXiang Li // Lower first letter expect for special case. 259*0d2dde20SXiang Li return StringSwitch<std::string>(DXILOpClass) 260*0d2dde20SXiang Li .Case("CBufferLoad", "cbufferLoad") 261*0d2dde20SXiang Li .Case("CBufferLoadLegacy", "cbufferLoadLegacy") 262*0d2dde20SXiang Li .Case("GSInstanceID", "gsInstanceID") 263*0d2dde20SXiang Li .Default(lowerFirstLetter(DXILOpClass)); 264*0d2dde20SXiang Li } 265*0d2dde20SXiang Li 266*0d2dde20SXiang Li static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps, 267*0d2dde20SXiang Li raw_ostream &OS) { 268*0d2dde20SXiang Li // Sort by DXILOpID. 269*0d2dde20SXiang Li std::sort(DXILOps.begin(), DXILOps.end(), 270*0d2dde20SXiang Li [](DXILOperationData &A, DXILOperationData &B) { 271*0d2dde20SXiang Li return A.DXILOpID < B.DXILOpID; 272*0d2dde20SXiang Li }); 273*0d2dde20SXiang Li 274*0d2dde20SXiang Li // Collect Names. 275*0d2dde20SXiang Li SequenceToOffsetTable<std::string> OpClassStrings; 276*0d2dde20SXiang Li SequenceToOffsetTable<std::string> OpStrings; 277*0d2dde20SXiang Li 278*0d2dde20SXiang Li StringSet<> ClassSet; 279*0d2dde20SXiang Li for (auto &DXILOp : DXILOps) { 280*0d2dde20SXiang Li OpStrings.add(DXILOp.DXILOp.str()); 281*0d2dde20SXiang Li 282*0d2dde20SXiang Li if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end()) 283*0d2dde20SXiang Li continue; 284*0d2dde20SXiang Li ClassSet.insert(DXILOp.DXILClass); 285*0d2dde20SXiang Li OpClassStrings.add(getDXILOpClassName(DXILOp.DXILClass)); 286*0d2dde20SXiang Li } 287*0d2dde20SXiang Li 288*0d2dde20SXiang Li // Layout names. 289*0d2dde20SXiang Li OpStrings.layout(); 290*0d2dde20SXiang Li OpClassStrings.layout(); 291*0d2dde20SXiang Li 292*0d2dde20SXiang Li // Emit the DXIL operation table. 293*0d2dde20SXiang Li //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary, 294*0d2dde20SXiang Li // OpCodeClassNameIndex, 295*0d2dde20SXiang Li // OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone}, 296*0d2dde20SXiang Li OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) " 297*0d2dde20SXiang Li "{\n"; 298*0d2dde20SXiang Li 299*0d2dde20SXiang Li OS << " static const OpCodeProperty OpCodeProps[] = {\n"; 300*0d2dde20SXiang Li for (auto &DXILOp : DXILOps) { 301*0d2dde20SXiang Li OS << " { DXIL::OpCode::" << DXILOp.DXILOp << ", " 302*0d2dde20SXiang Li << OpStrings.get(DXILOp.DXILOp.str()) 303*0d2dde20SXiang Li << ", OpCodeClass::" << DXILOp.DXILClass << ", " 304*0d2dde20SXiang Li << OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", " 305*0d2dde20SXiang Li << getDXILOperationOverload(DXILOp.OverloadTypes) << ", " 306*0d2dde20SXiang Li << emitDXILOperationFnAttr(DXILOp.FnAttr) << " },\n"; 307*0d2dde20SXiang Li } 308*0d2dde20SXiang Li OS << " };\n"; 309*0d2dde20SXiang Li 310*0d2dde20SXiang Li OS << " // FIXME: change search to indexing with\n"; 311*0d2dde20SXiang Li OS << " // DXILOp once all DXIL op is added.\n"; 312*0d2dde20SXiang Li OS << " OpCodeProperty TmpProp;\n"; 313*0d2dde20SXiang Li OS << " TmpProp.OpCode = DXILOp;\n"; 314*0d2dde20SXiang Li OS << " const OpCodeProperty *Prop =\n"; 315*0d2dde20SXiang Li OS << " llvm::lower_bound(OpCodeProps, TmpProp,\n"; 316*0d2dde20SXiang Li OS << " [](const OpCodeProperty &A, const " 317*0d2dde20SXiang Li "OpCodeProperty &B) {\n"; 318*0d2dde20SXiang Li OS << " return A.OpCode < B.OpCode;\n"; 319*0d2dde20SXiang Li OS << " });\n"; 320*0d2dde20SXiang Li OS << " assert(Prop && \"fail to find OpCodeProperty\");\n"; 321*0d2dde20SXiang Li OS << " return Prop;\n"; 322*0d2dde20SXiang Li OS << "}\n\n"; 323*0d2dde20SXiang Li 324*0d2dde20SXiang Li // Emit the string tables. 325*0d2dde20SXiang Li OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n"; 326*0d2dde20SXiang Li 327*0d2dde20SXiang Li OpStrings.emitStringLiteralDef(OS, 328*0d2dde20SXiang Li " static const char DXILOpCodeNameTable[]"); 329*0d2dde20SXiang Li 330*0d2dde20SXiang Li OS << " auto *Prop = getOpCodeProperty(DXILOp);\n"; 331*0d2dde20SXiang Li OS << " unsigned Index = Prop->OpCodeNameOffset;\n"; 332*0d2dde20SXiang Li OS << " return DXILOpCodeNameTable + Index;\n"; 333*0d2dde20SXiang Li OS << "}\n\n"; 334*0d2dde20SXiang Li 335*0d2dde20SXiang Li OS << "static const char *getOpCodeClassName(const OpCodeProperty &Prop) " 336*0d2dde20SXiang Li "{\n\n"; 337*0d2dde20SXiang Li 338*0d2dde20SXiang Li OpClassStrings.emitStringLiteralDef( 339*0d2dde20SXiang Li OS, " static const char DXILOpCodeClassNameTable[]"); 340*0d2dde20SXiang Li 341*0d2dde20SXiang Li OS << " unsigned Index = Prop.OpCodeClassNameOffset;\n"; 342*0d2dde20SXiang Li OS << " return DXILOpCodeClassNameTable + Index;\n"; 343*0d2dde20SXiang Li OS << "}\n "; 344*0d2dde20SXiang Li } 345*0d2dde20SXiang Li 346435897b4Spython3kgae namespace llvm { 347435897b4Spython3kgae 348435897b4Spython3kgae void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) { 349435897b4Spython3kgae std::vector<Record *> Ops = Records.getAllDerivedDefinitions("dxil_op"); 350435897b4Spython3kgae OS << "// Generated code, do not edit.\n"; 351435897b4Spython3kgae OS << "\n"; 352435897b4Spython3kgae 353435897b4Spython3kgae std::vector<DXILOperationData> DXILOps; 354435897b4Spython3kgae DXILOps.reserve(Ops.size()); 355435897b4Spython3kgae for (auto *Record : Ops) { 356435897b4Spython3kgae DXILOps.emplace_back(DXILOperationData(Record)); 357435897b4Spython3kgae } 358435897b4Spython3kgae 359435897b4Spython3kgae OS << "#ifdef DXIL_OP_ENUM\n"; 360435897b4Spython3kgae emitDXILEnums(DXILOps, OS); 361435897b4Spython3kgae OS << "#endif\n\n"; 362435897b4Spython3kgae 363264c09b7SXiang Li OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n"; 364*0d2dde20SXiang Li emitDXILIntrinsicMap(DXILOps, OS); 365264c09b7SXiang Li OS << "#endif\n\n"; 366264c09b7SXiang Li 367*0d2dde20SXiang Li OS << "#ifdef DXIL_OP_OPERATION_TABLE\n"; 368*0d2dde20SXiang Li emitDXILOperationTable(DXILOps, OS); 369*0d2dde20SXiang Li OS << "#endif\n\n"; 370264c09b7SXiang Li 371435897b4Spython3kgae OS << "\n"; 372435897b4Spython3kgae } 373435897b4Spython3kgae 374435897b4Spython3kgae } // namespace llvm 375