diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h index 71a6d15e46a81..cb6324c99ab9d 100644 --- a/llvm/include/llvm/BinaryFormat/DXContainer.h +++ b/llvm/include/llvm/BinaryFormat/DXContainer.h @@ -63,13 +63,51 @@ struct ShaderHash { void swapBytes() { sys::swapByteOrder(Flags); } }; -struct RootSignatureDesc { - uint32_t Size; - uint32_t Flags; +#define ROOT_PARAMETER(Val, Enum) Enum = Val, +enum class RootParameterType : uint8_t { +#include "DXContainerConstants.def" +}; + +ArrayRef> getRootParameterTypes(); + +#define SHADER_VISIBILITY(Val, Enum) Enum = Val, +enum class ShaderVisibilityFlag : uint8_t { +#include "DXContainerConstants.def" +}; + +ArrayRef> getShaderVisibilityFlags(); + +struct RootConstants { + uint32_t ShaderRegister; + uint32_t RegisterSpace; + uint32_t Num32BitValues; void swapBytes() { - sys::swapByteOrder(Size); - sys::swapByteOrder(Flags); + sys::swapByteOrder(ShaderRegister); + sys::swapByteOrder(RegisterSpace); + sys::swapByteOrder(Num32BitValues); + } +}; + +struct RootParameter { + RootParameterType ParameterType; + union { + RootConstants Constants; + }; + ShaderVisibilityFlag ShaderVisibility; + + void swapBytes() { + switch (ParameterType) { + + case RootParameterType::Constants32Bit: + Constants.swapBytes(); + break; + case RootParameterType::DescriptorTable: + case RootParameterType::CBV: + case RootParameterType::SRV: + case RootParameterType::UAV: + break; + } } }; diff --git a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def index 2134c2375f6d3..755322abf8140 100644 --- a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def +++ b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def @@ -55,25 +55,25 @@ SHADER_FEATURE_FLAG(31, 36, NextUnusedBit, "Next reserved shader flag bit (not a #ifdef ROOT_PARAMETER -ROOT_PARAMETER(DescriptorTable) -ROOT_PARAMETER(Constants32Bit) -ROOT_PARAMETER(CBV) -ROOT_PARAMETER(SRV) -ROOT_PARAMETER(UAV) +ROOT_PARAMETER(0, DescriptorTable) +ROOT_PARAMETER(1, Constants32Bit) +ROOT_PARAMETER(2, CBV) +ROOT_PARAMETER(3, SRV) +ROOT_PARAMETER(4, UAV) #undef ROOT_PARAMETER #endif // ROOT_PARAMETER #ifdef SHADER_VISIBILITY -SHADER_VISIBILITY(All) -SHADER_VISIBILITY(Vertex) -SHADER_VISIBILITY(Hull) -SHADER_VISIBILITY(Domain) -SHADER_VISIBILITY(Geometry) -SHADER_VISIBILITY(Pixel) -SHADER_VISIBILITY(Amplification) -SHADER_VISIBILITY(Mesh) +SHADER_VISIBILITY(0, All) +SHADER_VISIBILITY(1, Vertex) +SHADER_VISIBILITY(2, Hull) +SHADER_VISIBILITY(3, Domain) +SHADER_VISIBILITY(4, Geometry) +SHADER_VISIBILITY(5, Pixel) +SHADER_VISIBILITY(6, Amplification) +SHADER_VISIBILITY(7, Mesh) #undef SHADER_VISIBILITY #endif // SHADER_VISIBILITY diff --git a/llvm/include/llvm/MC/DXContainerRootSignature.h b/llvm/include/llvm/MC/DXContainerRootSignature.h index 20b4f5a4285f6..9102137c14b47 100644 --- a/llvm/include/llvm/MC/DXContainerRootSignature.h +++ b/llvm/include/llvm/MC/DXContainerRootSignature.h @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallVector.h" +#include "llvm/BinaryFormat/DXContainer.h" #include #include @@ -16,6 +18,7 @@ class raw_ostream; namespace mcdxbc { struct RootSignatureHeader { uint32_t Flags; + SmallVector Parameters; void swapBytes(); void write(raw_ostream &OS); diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h index 5f7737d2fa41d..e2d9f7266fcb4 100644 --- a/llvm/include/llvm/Object/DXContainer.h +++ b/llvm/include/llvm/Object/DXContainer.h @@ -118,10 +118,15 @@ template struct ViewArray { namespace DirectX { class RootSignature { + + using ParametersArray = ViewArray; + private: StringRef Data; uint32_t Size; uint32_t Flags; + uint32_t NParameters; + ParametersArray Parameters; public: RootSignature(StringRef Data) : Data(Data) {} @@ -131,6 +136,10 @@ class RootSignature { uint32_t getSize() const { return Size; } uint32_t getFlags() const { return Flags; } + + uint32_t getNParameters() const { return NParameters; } + + ParametersArray getParameters() const { return Parameters; } }; class PSVRuntimeInfo { diff --git a/llvm/include/llvm/ObjectYAML/DXContainerYAML.h b/llvm/include/llvm/ObjectYAML/DXContainerYAML.h index a82083fa18de6..a368d5bf3634a 100644 --- a/llvm/include/llvm/ObjectYAML/DXContainerYAML.h +++ b/llvm/include/llvm/ObjectYAML/DXContainerYAML.h @@ -80,6 +80,8 @@ struct RootSignatureDesc { uint32_t getEncodedFlags(); uint32_t Size; + uint32_t NumParameters; + SmallVector Parameters; #include "llvm/BinaryFormat/DXContainerConstants.def" }; @@ -187,6 +189,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::ResourceBindInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::SignatureElement) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::PSVInfo::MaskVector) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::SignatureParameter) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::dxbc::RootParameter) LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::PSV::SemanticKind) LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::PSV::ComponentType) LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::PSV::InterpolationMode) @@ -195,6 +198,8 @@ LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::PSV::ResourceKind) LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::D3DSystemValue) LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::SigComponentType) LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::SigMinPrecision) +LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::RootParameterType) +LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::ShaderVisibilityFlag) namespace llvm { @@ -259,6 +264,14 @@ template <> struct MappingTraits { DXContainerYAML::RootSignatureDesc &RootSignature); }; +template <> struct MappingTraits { + static void mapping(IO &IO, dxbc::RootParameter &RootParameter); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, dxbc::RootConstants &RootConstants); +}; + } // namespace yaml } // namespace llvm diff --git a/llvm/lib/BinaryFormat/DXContainer.cpp b/llvm/lib/BinaryFormat/DXContainer.cpp index 97ceb16ccf53f..d1a1f1f544137 100644 --- a/llvm/lib/BinaryFormat/DXContainer.cpp +++ b/llvm/lib/BinaryFormat/DXContainer.cpp @@ -60,6 +60,26 @@ ArrayRef> dxbc::getSigComponentTypes() { return ArrayRef(SigComponentTypes); } +#define SHADER_VISIBILITY(Val, Enum) {#Enum, ShaderVisibilityFlag::Enum}, + +static const EnumEntry ShaderVisibilityFlags[] = { +#include "llvm/BinaryFormat/DXContainerConstants.def" +}; + +ArrayRef> dxbc::getShaderVisibilityFlags() { + return ArrayRef(ShaderVisibilityFlags); +} + +#define ROOT_PARAMETER(Val, Enum) {#Enum, RootParameterType::Enum}, + +static const EnumEntry RootParameterTypes[] = { +#include "llvm/BinaryFormat/DXContainerConstants.def" +}; + +ArrayRef> dxbc::getRootParameterTypes() { + return ArrayRef(RootParameterTypes); +} + #define SEMANTIC_KIND(Val, Enum) {#Enum, PSV::SemanticKind::Enum}, static const EnumEntry SemanticKindNames[] = { diff --git a/llvm/lib/MC/DXContainerRootSignature.cpp b/llvm/lib/MC/DXContainerRootSignature.cpp index 4e085654a1e5e..0ac72be0d3b66 100644 --- a/llvm/lib/MC/DXContainerRootSignature.cpp +++ b/llvm/lib/MC/DXContainerRootSignature.cpp @@ -7,16 +7,26 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/DXContainerRootSignature.h" +#include "llvm/BinaryFormat/DXContainer.h" #include "llvm/Support/EndianStream.h" -#include "llvm/Support/SwapByteOrder.h" -#include using namespace llvm; using namespace llvm::mcdxbc; void RootSignatureHeader::write(raw_ostream &OS) { - uint32_t SizeInfo = sizeof(this); + uint32_t SizeInfo = sizeof(RootSignatureHeader); + uint32_t ParamsSize = Parameters.size(); support::endian::write(OS, SizeInfo, llvm::endianness::little); support::endian::write(OS, Flags, llvm::endianness::little); + support::endian::write(OS, ParamsSize, llvm::endianness::little); + + if (Parameters.size() > 0) { + uint32_t BindingSize = sizeof(dxbc::RootParameter); + + support::endian::write(OS, BindingSize, llvm::endianness::little); + + for (const auto &Param : Parameters) + OS.write(reinterpret_cast(&Param), BindingSize); + } } diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp index 6743911059cfd..627433e38f51c 100644 --- a/llvm/lib/Object/DXContainer.cpp +++ b/llvm/lib/Object/DXContainer.cpp @@ -251,6 +251,26 @@ Error DirectX::RootSignature::parse() { Flags = support::endian::read(Current); Current += sizeof(uint32_t); + NParameters = + support::endian::read(Current); + Current += sizeof(uint32_t); + + if (NParameters > 0) { + + Parameters.Stride = + support::endian::read(Current); + Current += sizeof(uint32_t); + + size_t BindingDataSize = Parameters.Stride * NParameters; + Parameters.Data = Data.substr(Current - Data.begin(), BindingDataSize); + + if (Parameters.Data.size() < BindingDataSize) + return parseFailed( + "Resource binding data extends beyond the bounds of the part"); + + Current += BindingDataSize; + } + return Error::success(); } diff --git a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp index ada7383ea3c6b..ecf3714d29d61 100644 --- a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp +++ b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp @@ -268,6 +268,7 @@ void DXContainerWriter::writeParts(raw_ostream &OS) { mcdxbc::RootSignatureHeader Header; Header.Flags = P.RootSignature->getEncodedFlags(); + Header.Parameters = P.RootSignature->Parameters; Header.write(OS); break; diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp index fd85d75dc32eb..9174c1f11e2a2 100644 --- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp +++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp @@ -32,8 +32,11 @@ DXContainerYAML::ShaderFeatureFlags::ShaderFeatureFlags(uint64_t FlagData) { DXContainerYAML::RootSignatureDesc::RootSignatureDesc( const object::DirectX::RootSignature &Data) - : Size(Data.getSize()) { + : Size(Data.getSize()), NumParameters(Data.getNParameters()) { uint32_t Flags = Data.getFlags(); + for (const auto &Param : Data.getParameters()) + Parameters.push_back(Param); + #define ROOT_ELEMENT_FLAG(Num, Val, Str) \ Val = (Flags & (uint32_t)dxbc::RootElementFlag::Val) > 0; #include "llvm/BinaryFormat/DXContainerConstants.def" @@ -207,9 +210,50 @@ void MappingTraits::mapping( IO.mapRequired("Parameters", S.Parameters); } +void MappingTraits::mapping(IO &IO, + dxbc::RootParameter &S) { + + IO.mapRequired("Type", S.ParameterType); + IO.mapRequired("ShaderVisibility", S.ShaderVisibility); + + switch (S.ParameterType) { + + case dxbc::RootParameterType::Constants32Bit: + IO.mapRequired("Constants", S.Constants); + break; + case dxbc::RootParameterType::DescriptorTable: + case dxbc::RootParameterType::CBV: + case dxbc::RootParameterType::SRV: + case dxbc::RootParameterType::UAV: + break; + } +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, dxbc::RootParameterType &Value) { + for (const auto &E : dxbc::getRootParameterTypes()) + IO.enumCase(Value, E.Name.str().c_str(), E.Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, dxbc::ShaderVisibilityFlag &Value) { + for (const auto &E : dxbc::getShaderVisibilityFlags()) + IO.enumCase(Value, E.Name.str().c_str(), E.Value); +} + +void MappingTraits::mapping(IO &IO, + dxbc::RootConstants &S) { + + IO.mapRequired("Num32BitValues", S.Num32BitValues); + IO.mapRequired("ShaderRegister", S.ShaderRegister); + IO.mapRequired("RegisterSpace", S.RegisterSpace); +} + void MappingTraits::mapping( IO &IO, DXContainerYAML::RootSignatureDesc &S) { IO.mapRequired("Size", S.Size); + IO.mapRequired("NumParameters", S.NumParameters); + IO.mapRequired("Parameters", S.Parameters); #define ROOT_ELEMENT_FLAG(Num, Val, Str) IO.mapOptional(#Val, S.Val, false); #include "llvm/BinaryFormat/DXContainerConstants.def" } diff --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt index 26315db891b57..89fe494dea71c 100644 --- a/llvm/lib/Target/DirectX/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/CMakeLists.txt @@ -33,7 +33,7 @@ add_llvm_target(DirectXCodeGen DXILResourceAccess.cpp DXILShaderFlags.cpp DXILTranslateMetadata.cpp - + DXILRootSignature.cpp LINK_COMPONENTS Analysis AsmPrinter diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp index 7a0bd6a7c8869..37108f92718df 100644 --- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp +++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "DXILRootSignature.h" #include "DXILShaderFlags.h" #include "DirectX.h" #include "llvm/ADT/SmallVector.h" @@ -23,6 +24,7 @@ #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" #include "llvm/MC/DXContainerPSVInfo.h" +#include "llvm/MC/DXContainerRootSignature.h" #include "llvm/Pass.h" #include "llvm/Support/MD5.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -41,6 +43,7 @@ class DXContainerGlobals : public llvm::ModulePass { GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name, StringRef SectionName); void addSignature(Module &M, SmallVector &Globals); + void addRootSignature(Module &M, SmallVector &Globals); void addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV); void addPipelineStateValidationInfo(Module &M, SmallVector &Globals); @@ -60,6 +63,7 @@ class DXContainerGlobals : public llvm::ModulePass { void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); AU.addRequired(); + AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); @@ -73,6 +77,7 @@ bool DXContainerGlobals::runOnModule(Module &M) { Globals.push_back(getFeatureFlags(M)); Globals.push_back(computeShaderHash(M)); addSignature(M, Globals); + addRootSignature(M, Globals); addPipelineStateValidationInfo(M, Globals); appendToCompilerUsed(M, Globals); return true; @@ -144,6 +149,27 @@ void DXContainerGlobals::addSignature(Module &M, Globals.emplace_back(buildSignature(M, OutputSig, "dx.osg1", "OSG1")); } +void DXContainerGlobals::addRootSignature(Module &M, + SmallVector &Globals) { + + std::optional MRS = + getAnalysis().getRootSignature(); + if (!MRS.has_value()) + return; + + SmallString<256> Data; + raw_svector_ostream OS(Data); + + RootSignatureHeader RSH; + RSH.Flags = MRS->Flags; + + RSH.write(OS); + + Constant *Constant = + ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false); + Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.rts0", "RTS0")); +} + void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) { const DXILBindingMap &DBM = getAnalysis().getBindingMap(); diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.cpp b/llvm/lib/Target/DirectX/DXILRootSignature.cpp new file mode 100644 index 0000000000000..c86be5bd9eb67 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILRootSignature.cpp @@ -0,0 +1,158 @@ +//===- DXILRootSignature.cpp - DXIL Root Signature helper objects ----===// +// +// 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 file contains helper objects and APIs for working with DXIL +/// Root Signatures. +/// +//===----------------------------------------------------------------------===// +#include "DXILRootSignature.h" +#include "DirectX.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Module.h" +#include + +using namespace llvm; +using namespace llvm::dxil; + +static bool reportError(Twine Message) { + report_fatal_error(Message, false); + return true; +} + +static bool parseRootFlags(ModuleRootSignature *MRS, MDNode *RootFlagNode) { + + if (RootFlagNode->getNumOperands() != 2) + return reportError("Invalid format for RootFlag Element"); + + auto *Flag = mdconst::extract(RootFlagNode->getOperand(1)); + uint32_t Value = Flag->getZExtValue(); + + // Root Element validation, as specified: + // https://github.com/llvm/wg-hlsl/blob/main/proposals/0002-root-signature-in-clang.md#validations-during-dxil-generation + if ((Value & ~0x80000fff) != 0) + return reportError("Invalid flag value for RootFlag"); + + MRS->Flags = Value; + return false; +} + +static bool parseRootSignatureElement(ModuleRootSignature *MRS, + MDNode *Element) { + MDString *ElementText = cast(Element->getOperand(0)); + if (ElementText == nullptr) + return reportError("Invalid format for Root Element"); + + RootSignatureElementKind ElementKind = + StringSwitch(ElementText->getString()) + .Case("RootFlags", RootSignatureElementKind::RootFlags) + .Case("RootConstants", RootSignatureElementKind::RootConstants) + .Case("RootCBV", RootSignatureElementKind::RootDescriptor) + .Case("RootSRV", RootSignatureElementKind::RootDescriptor) + .Case("RootUAV", RootSignatureElementKind::RootDescriptor) + .Case("Sampler", RootSignatureElementKind::RootDescriptor) + .Case("DescriptorTable", RootSignatureElementKind::DescriptorTable) + .Case("StaticSampler", RootSignatureElementKind::StaticSampler) + .Default(RootSignatureElementKind::None); + + switch (ElementKind) { + + case RootSignatureElementKind::RootFlags: { + return parseRootFlags(MRS, Element); + break; + } + + case RootSignatureElementKind::RootConstants: + case RootSignatureElementKind::RootDescriptor: + case RootSignatureElementKind::DescriptorTable: + case RootSignatureElementKind::StaticSampler: + case RootSignatureElementKind::None: + return reportError("Invalid Root Element: " + ElementText->getString()); + break; + } + + return true; +} + +bool ModuleRootSignature::parse(NamedMDNode *Root) { + bool HasError = false; + + /** Root Signature are specified as following in the metadata: + + !dx.rootsignatures = !{!2} ; list of function/root signature pairs + !2 = !{ ptr @main, !3 } ; function, root signature + !3 = !{ !4, !5, !6, !7 } ; list of root signature elements + + So for each MDNode inside dx.rootsignatures NamedMDNode + (the Root parameter of this function), the parsing process needs + to loop through each of it's operand and process the pairs function + signature pair. + */ + + for (unsigned int Sid = 0; Sid < Root->getNumOperands(); Sid++) { + MDNode *Node = dyn_cast(Root->getOperand(Sid)); + + if (Node == nullptr || Node->getNumOperands() != 2) + return reportError("Invalid format for Root Signature Definition. Pairs " + "of function, root signature expected."); + + // Get the Root Signature Description from the function signature pair. + MDNode *RS = dyn_cast(Node->getOperand(1).get()); + + if (RS == nullptr) + return reportError("Missing Root Signature Metadata node."); + + // Loop through the Root Elements of the root signature. + for (unsigned int Eid = 0; Eid < RS->getNumOperands(); Eid++) { + + MDNode *Element = dyn_cast(RS->getOperand(Eid)); + if (Element == nullptr) + return reportError("Missing Root Element Metadata Node."); + + HasError = HasError || parseRootSignatureElement(this, Element); + } + } + return HasError; +} + +ModuleRootSignature ModuleRootSignature::analyzeModule(Module &M) { + ModuleRootSignature MRS; + + NamedMDNode *RootSignatureNode = M.getNamedMetadata("dx.rootsignatures"); + if (RootSignatureNode) { + if (MRS.parse(RootSignatureNode)) + llvm_unreachable("Invalid Root Signature Metadata."); + } + + return MRS; +} + +AnalysisKey RootSignatureAnalysis::Key; + +ModuleRootSignature RootSignatureAnalysis::run(Module &M, + ModuleAnalysisManager &AM) { + return ModuleRootSignature::analyzeModule(M); +} + +//===----------------------------------------------------------------------===// +bool RootSignatureAnalysisWrapper::runOnModule(Module &M) { + + this->MRS = MRS = ModuleRootSignature::analyzeModule(M); + + return false; +} + +void RootSignatureAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); +} + +char RootSignatureAnalysisWrapper::ID = 0; + +INITIALIZE_PASS(RootSignatureAnalysisWrapper, "dx-root-signature-analysis", + "DXIL Root Signature Analysis", true, true) diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.h b/llvm/lib/Target/DirectX/DXILRootSignature.h new file mode 100644 index 0000000000000..f89fb0f00b5a4 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILRootSignature.h @@ -0,0 +1,74 @@ +//===- DXILRootSignature.h - DXIL Root Signature helper objects +//---------------===// +// +// 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 file contains helper objects and APIs for working with DXIL +/// Root Signatures. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Metadata.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" +#include + +namespace llvm { +namespace dxil { + +enum class RootSignatureElementKind { + None = 0, + RootFlags = 1, + RootConstants = 2, + RootDescriptor = 3, + DescriptorTable = 4, + StaticSampler = 5 +}; + +struct ModuleRootSignature { + uint32_t Flags; + + ModuleRootSignature() = default; + + bool parse(NamedMDNode *Root); + + static ModuleRootSignature analyzeModule(Module &M); +}; + +class RootSignatureAnalysis : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static AnalysisKey Key; + +public: + RootSignatureAnalysis() = default; + + using Result = ModuleRootSignature; + + ModuleRootSignature run(Module &M, ModuleAnalysisManager &AM); +}; + +/// Wrapper pass for the legacy pass manager. +/// +/// This is required because the passes that will depend on this are codegen +/// passes which run through the legacy pass manager. +class RootSignatureAnalysisWrapper : public ModulePass { + std::optional MRS; + +public: + static char ID; + + RootSignatureAnalysisWrapper() : ModulePass(ID) {} + + const std::optional &getRootSignature() { return MRS; } + + bool runOnModule(Module &M) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +} // namespace dxil +} // namespace llvm diff --git a/llvm/lib/Target/DirectX/DirectX.h b/llvm/lib/Target/DirectX/DirectX.h index add23587de7d5..953ac3eb82098 100644 --- a/llvm/lib/Target/DirectX/DirectX.h +++ b/llvm/lib/Target/DirectX/DirectX.h @@ -77,6 +77,9 @@ void initializeDXILPrettyPrinterLegacyPass(PassRegistry &); /// Initializer for dxil::ShaderFlagsAnalysisWrapper pass. void initializeShaderFlagsAnalysisWrapperPass(PassRegistry &); +/// Initializer for dxil::RootSignatureAnalysisWrapper pass. +void initializeRootSignatureAnalysisWrapperPass(PassRegistry &); + /// Initializer for DXContainerGlobals pass. void initializeDXContainerGlobalsPass(PassRegistry &); diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp index ecb1bf775f857..93745d7a5cb0d 100644 --- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp +++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp @@ -61,6 +61,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTarget() { initializeDXILTranslateMetadataLegacyPass(*PR); initializeDXILResourceMDWrapperPass(*PR); initializeShaderFlagsAnalysisWrapperPass(*PR); + initializeRootSignatureAnalysisWrapperPass(*PR); initializeDXILFinalizeLinkageLegacyPass(*PR); } diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Error.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Error.ll new file mode 100644 index 0000000000000..cbcd8e56c1c04 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Error.ll @@ -0,0 +1,17 @@ +; RUN: not llc %s --filetype=obj -o - 2>&1 | FileCheck %s + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: LLVM ERROR: Invalid format for Root Signature Definition. Pairs of function, root signature expected. + + +define void @main() #0 { +entry: + ret void +} + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!1} ; list of function/root signature pairs +!1= !{ !"RootFlags" } ; function, root signature diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Error.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Error.ll new file mode 100644 index 0000000000000..9b4208011bba5 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Error.ll @@ -0,0 +1,19 @@ +; RUN: not llc %s --filetype=obj -o - 2>&1 | FileCheck %s + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: LLVM ERROR: Invalid Root Element: NOTRootFlags + + +define void @main() #0 { +entry: + ret void +} + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !4 } ; list of root signature elements +!4 = !{ !"NOTRootFlags", i32 1 } ; 1 = allow_input_assembler_input_layout diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll new file mode 100644 index 0000000000000..85e6f4d6748d5 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll @@ -0,0 +1,19 @@ +; RUN: not llc %s --filetype=obj -o - 2>&1 | FileCheck %s + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: LLVM ERROR: Invalid flag value for RootFlag + + +define void @main() #0 { +entry: + ret void +} + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !4 } ; list of root signature elements +!4 = !{ !"RootFlags", i32 2147487744 } ; 1 = allow_input_assembler_input_layout diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll new file mode 100644 index 0000000000000..04a4f378ecb39 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll @@ -0,0 +1,32 @@ +; RUN: opt %s -dxil-embed -dxil-globals -S -o - | FileCheck %s +; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: @dx.rts0 = private constant [12 x i8] c"{{.*}}", section "RTS0", align 4 + + +define void @main() #0 { +entry: + ret void +} + + + + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !4 } ; list of root signature elements +!4 = !{ !"RootFlags", i32 1 } ; 1 = allow_input_assembler_input_layout + + +; DXC: - Name: RTS0 +; DXC-NEXT: Size: 12 +; DXC-NEXT: RootSignature: +; DXC-NEXT: Size: 64 +; DXC-NEXT: NumParameters: 0 +; DXC-NEXT: Parameters: [] +; DXC-NEXT: AllowInputAssemblerInputLayout: true diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootElement-Error.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootElement-Error.ll new file mode 100644 index 0000000000000..501e3438943a3 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootElement-Error.ll @@ -0,0 +1,18 @@ +; RUN: not llc %s --filetype=obj -o - 2>&1 | FileCheck %s + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: LLVM ERROR: Missing Root Element Metadata Node. + + +define void @main() #0 { +entry: + ret void +} + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !"NOTRootElements" } ; list of root signature elements diff --git a/llvm/test/CodeGen/DirectX/llc-pipeline.ll b/llvm/test/CodeGen/DirectX/llc-pipeline.ll index b071557249414..fc0a7833ea2f0 100644 --- a/llvm/test/CodeGen/DirectX/llc-pipeline.ll +++ b/llvm/test/CodeGen/DirectX/llc-pipeline.ll @@ -33,6 +33,7 @@ ; CHECK-ASM-NEXT: Print Module IR ; CHECK-OBJ-NEXT: DXIL Embedder +; CHECK-OBJ-NEXT: DXIL Root Signature Analysis ; CHECK-OBJ-NEXT: DXContainer Global Emitter ; CHECK-OBJ-NEXT: FunctionPass Manager ; CHECK-OBJ-NEXT: Lazy Machine Block Frequency Analysis diff --git a/llvm/test/ObjectYAML/DXContainer/RootSignature-Flags.yaml b/llvm/test/ObjectYAML/DXContainer/RootSignature-Flags.yaml index 6f10bd2f74b46..2da4ef8db9682 100644 --- a/llvm/test/ObjectYAML/DXContainer/RootSignature-Flags.yaml +++ b/llvm/test/ObjectYAML/DXContainer/RootSignature-Flags.yaml @@ -10,13 +10,29 @@ Header: PartOffsets: [ 60 ] Parts: - Name: RTS0 - Size: 8 + Size: 40 RootSignature: - Size: 8 + Size: 64 + NumParameters: 1 + Parameters: + - Type: Constants32Bit + ShaderVisibility: All + Constants: + Num32BitValues: 3 + ShaderRegister: 1 + RegisterSpace: 2 AllowInputAssemblerInputLayout: true - -#CHECK: - Name: RTS0 -#CHECK-NEXT: Size: 8 -#CHECK-NEXT: RootSignature: -#CHECK-NEXT: Size: 8 -#CHECK-NEXT: AllowInputAssemblerInputLayout: true + +#CHECK: - Name: RTS0 +#CHECK-NEXT: Size: 40 +#CHECK-NEXT: RootSignature: +#CHECK-NEXT: Size: 64 +#CHECK-NEXT: NumParameters: 1 +#CHECK-NEXT: Parameters: +#CHECK-NEXT: - Type: Constants32Bit +#CHECK-NEXT: ShaderVisibility: All +#CHECK-NEXT: Constants: +#CHECK-NEXT: Num32BitValues: 3 +#CHECK-NEXT: ShaderRegister: 1 +#CHECK-NEXT: RegisterSpace: 2 +#CHECK-NEXT: AllowInputAssemblerInputLayout: true