diff --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt --- a/llvm/lib/Target/DirectX/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/CMakeLists.txt @@ -4,6 +4,9 @@ tablegen(LLVM DirectXGenSubtargetInfo.inc -gen-subtarget) +set(LLVM_TARGET_DEFINITIONS DXIL.td) +tablegen(LLVM DXILConstants.inc -gen-dxil-enum) + add_public_tablegen_target(DirectXCommonTableGen) add_llvm_target(DirectXCodeGen diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -0,0 +1,78 @@ +//- DXIL.td - Describe DXIL operation -------------------------*- tablegen -*-// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This is a target description file for DXIL operation. +/// +//===----------------------------------------------------------------------===// + +// "The parameter description for a DXIL instruction" +class dxil_param { + int pos = _pos; // position in parameter list + string llvm_type = type; // llvm type name, $o for overload, $r for resource + // type, $cb for legacy cbuffer, $u4 for u4 struct + string name = _name; // short, unique name + string doc = _doc; // the documentation description of this parameter + bit is_const = + _is_const; // whether this argument requires a constant value in the IR + string enum_name = _enum_name; // the name of the enum type if applicable + int max_value = + _max_value; // the maximum value for this parameter if applicable +} + +// "A representation for a DXIL instruction" +class dxil_inst { + string name = _name; // short, unique name + + string dxil_op = ""; // name of DXIL operation + int dxil_opid = 0; // ID of DXIL operation + string dxil_class = ""; // name of the opcode class + string category = ""; // classification for this instruction + string doc = ""; // the documentation description of this instruction + list ops = []; // the operands that this instruction takes + string oload_types = ""; // overload types if applicable + string fn_attr = ""; // attribute shorthands: rn=does not access + // memory,ro=only reads from memory, + bit is_deriv = 0; // whether this is some kind of derivative + bit is_gradient = 0; // whether this requires a gradient calculation + bit is_feedback = 0; // whether this is a sampler feedback op + bit is_wave = 0; // whether this requires in-wave, cross-lane functionality + bit requires_uniform_inputs = 0; // whether this operation requires that all + // of its inputs are uniform across the wave + + string llvm_intrinsic = ""; // The intrinsic which map directly to this dxil + // op. "" means no direct map intrinsic. + list counters = []; // counters for this inst. + +} + +class dxil_op op_params, + string intrinsic = ""> : dxil_inst { + let dxil_op = name; + let dxil_opid = code_id; + let doc = _doc; + let ops = op_params; + let dxil_class = code_class; + let oload_types = _oload_types; + let fn_attr = _fn_attr; + let llvm_intrinsic = intrinsic; +} + +let category = "Unary float", + counters = ["floats"] in def Sin + : dxil_op<"Sin", 13, "Unary", "returns sine(theta) for theta in radians.", + "half;float;", "rn", + [ + dxil_param<0, "$o", "", "operation result">, + dxil_param<1, "i32", "opcode", "DXIL opcode">, + dxil_param<2, "$o", "value", "input value"> + ], + "sin">; diff --git a/llvm/lib/Target/DirectX/DXILConstants.h b/llvm/lib/Target/DirectX/DXILConstants.h --- a/llvm/lib/Target/DirectX/DXILConstants.h +++ b/llvm/lib/Target/DirectX/DXILConstants.h @@ -14,14 +14,8 @@ namespace llvm { namespace DXIL { -// Enumeration for operations specified by DXIL -enum class OpCode : unsigned { - Sin = 13, // returns sine(theta) for theta in radians. -}; -// Groups for DXIL operations with equivalent function templates -enum class OpCodeClass : unsigned { - Unary, -}; + +#include "DXILConstants.inc" } // namespace DXIL } // namespace llvm diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -27,6 +27,7 @@ DFAPacketizerEmitter.cpp DirectiveEmitter.cpp DisassemblerEmitter.cpp + DXILEmitter.cpp ExegesisEmitter.cpp FastISelEmitter.cpp GICombinerEmitter.cpp diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp new file mode 100644 --- /dev/null +++ b/llvm/utils/TableGen/DXILEmitter.cpp @@ -0,0 +1,173 @@ +//===- 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 "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" + +using namespace llvm; + +namespace { + +struct DXILShaderModel { + int Major; + int Minor; +}; +struct DXILParam { + int Pos; // position in parameter list + StringRef Type; // llvm type name, $o for overload, $r for resource + // type, $cb for legacy cbuffer, $u4 for u4 struct + 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) { + Name = R->getValueAsString("name"); + Pos = R->getValueAsInt("pos"); + Type = 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"); + } +}; + +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 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, + 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 + 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 + SmallVector 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->getValueAsString("dxil_class"); + Category = R->getValueAsString("category"); + Doc = R->getValueAsString("doc"); + ListInit *ParamList = R->getValueAsListInit("ops"); + for (unsigned i = 0; i < ParamList->size(); ++i) { + Record *Param = ParamList->getElementAsRecord(i); + Params.emplace_back(DXILParam(Param)); + } + OverloadTypes = R->getValueAsString("oload_types"); + FnAttr = R->getValueAsString("fn_attr"); + } +}; +} // end anonymous namespace + +static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) { + // Name = ID, // Doc + OS << DXILOp.Name << " = " << DXILOp.DXILOpID << ", // " << DXILOp.Doc + << "\n"; +} + +static void emitDXILEnums(std::vector &DXILOps, + raw_ostream &OS) { + // Sort by Category + OpName. + std::sort(DXILOps.begin(), DXILOps.end(), + [](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"; + + StringSet<> ClassSet; + std::vector ClassVec; + StringRef PrevCategory = ""; + for (auto &DXILOp : DXILOps) { + StringRef Category = DXILOp.Category; + if (Category != PrevCategory) { + OS << "\n// " << Category << "\n"; + PrevCategory = Category; + } + emitDXILOpEnum(DXILOp, OS); + if (ClassSet.find(DXILOp.DXILClass) != ClassSet.end()) + continue; + ClassSet.insert(DXILOp.DXILClass); + ClassVec.emplace_back(&DXILOp); + } + + OS << "\n};\n\n"; + + // Sort by Category + ClassName. + std::sort(ClassVec.begin(), ClassVec.end(), + [](DXILOperationData *A, DXILOperationData *B) { + // Group by Category first. + if (A->Category == B->Category) + // Inside same Category, order by ClassName. + return A->DXILClass < B->DXILClass; + else + return A->Category < B->Category; + }); + + OS << "// Groups for DXIL operations with equivalent function templates\n"; + OS << "enum class OpCodeClass : unsigned {\n"; + PrevCategory = ""; + for (DXILOperationData *ClassOp : ClassVec) { + StringRef Category = ClassOp->Category; + if (Category != PrevCategory) { + OS << "\n// " << Category << "\n"; + PrevCategory = Category; + } + StringRef Name = ClassOp->DXILClass; + OS << Name << ",\n"; + } + OS << "\n};\n\n"; +} + +namespace llvm { +// Emit enum declaration for DXIL. +void EmitDXILEnum(RecordKeeper &Records, raw_ostream &OS) { + std::vector Ops = Records.getAllDerivedDefinitions("dxil_op"); + OS << "// Generated code, do not edit.\n"; + OS << "\n"; + std::vector DXILOps; + DXILOps.reserve(Ops.size()); + for (auto *Record : Ops) { + DXILOps.emplace_back(DXILOperationData(Record)); + } + emitDXILEnums(DXILOps, OS); + OS << "\n"; +} + +} // namespace llvm diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -58,6 +58,7 @@ GenAutomata, GenDirectivesEnumDecl, GenDirectivesEnumImpl, + GenDXILEnum, }; namespace llvm { @@ -141,7 +142,8 @@ clEnumValN(GenDirectivesEnumDecl, "gen-directive-decl", "Generate directive related declaration code (header file)"), clEnumValN(GenDirectivesEnumImpl, "gen-directive-impl", - "Generate directive related implementation code"))); + "Generate directive related implementation code"), + clEnumValN(GenDXILEnum, "gen-dxil-enum", "Generate enum for DXIL"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt Class("class", cl::desc("Print Enum list for this class"), @@ -278,6 +280,9 @@ case GenDirectivesEnumImpl: EmitDirectivesImpl(Records, OS); break; + case GenDXILEnum: + EmitDXILEnum(Records, OS); + break; } return false; diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -94,6 +94,7 @@ void EmitAutomata(RecordKeeper &RK, raw_ostream &OS); void EmitDirectivesDecl(RecordKeeper &RK, raw_ostream &OS); void EmitDirectivesImpl(RecordKeeper &RK, raw_ostream &OS); +void EmitDXILEnum(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace