diff --git a/llvm/include/llvm/Support/DXILABI.h b/llvm/include/llvm/Support/DXILABI.h index b479f7c73eba3..397906a3466c5 100644 --- a/llvm/include/llvm/Support/DXILABI.h +++ b/llvm/include/llvm/Support/DXILABI.h @@ -17,6 +17,7 @@ #ifndef LLVM_SUPPORT_DXILABI_H #define LLVM_SUPPORT_DXILABI_H +#include "llvm/ADT/StringRef.h" #include namespace llvm { @@ -99,6 +100,8 @@ enum class SamplerFeedbackType : uint32_t { const unsigned MinWaveSize = 4; const unsigned MaxWaveSize = 128; +StringRef getResourceClassName(ResourceClass RC); + } // namespace dxil } // namespace llvm diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp index 629fa7cddb9d4..5aeee6f681114 100644 --- a/llvm/lib/Analysis/DXILResource.cpp +++ b/llvm/lib/Analysis/DXILResource.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" +#include "llvm/Support/DXILABI.h" #include "llvm/Support/FormatVariadic.h" #include #include @@ -29,20 +30,6 @@ using namespace llvm; using namespace dxil; -static StringRef getResourceClassName(ResourceClass RC) { - switch (RC) { - case ResourceClass::SRV: - return "SRV"; - case ResourceClass::UAV: - return "UAV"; - case ResourceClass::CBuffer: - return "CBuffer"; - case ResourceClass::Sampler: - return "Sampler"; - } - llvm_unreachable("Unhandled ResourceClass"); -} - static StringRef getResourceKindName(ResourceKind RK) { switch (RK) { case ResourceKind::Texture1D: diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 10b6101d73277..b7578dd580072 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -182,6 +182,7 @@ add_llvm_component_library(LLVMSupport DivisionByConstantInfo.cpp DAGDeltaAlgorithm.cpp DJB.cpp + DXILABI.cpp DynamicAPInt.cpp ELFAttributes.cpp ELFAttrParserCompact.cpp diff --git a/llvm/lib/Support/DXILABI.cpp b/llvm/lib/Support/DXILABI.cpp new file mode 100644 index 0000000000000..c6499b21613fb --- /dev/null +++ b/llvm/lib/Support/DXILABI.cpp @@ -0,0 +1,20 @@ +//===-- DXILABI.cpp - ABI Sensitive Values for DXIL --------------*- C++-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements functions that can be reused accross different stages +// dxil generation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/DXContainer.h" +#include "llvm/Support/ScopedPrinter.h" +using namespace llvm; + +StringRef dxil::getResourceClassName(dxil::ResourceClass RC) { + return enumToStringRef(RC, dxbc::getResourceClasses()); +} diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp index 26a113d2d5260..a1ef2578f00aa 100644 --- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp +++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp @@ -162,8 +162,7 @@ void DXContainerGlobals::addRootSignature(Module &M, auto &RSA = getAnalysis().getRSInfo(); const Function *EntryFunction = MMI.EntryPropertyVec[0].Entry; - const std::optional &RS = - RSA.getDescForFunction(EntryFunction); + const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(EntryFunction); if (!RS) return; diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 0ec15a629d0a2..247ba7d93b3c2 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -9,6 +9,7 @@ #include "DXILOpLowering.h" #include "DXILConstants.h" #include "DXILOpBuilder.h" +#include "DXILRootSignature.h" #include "DXILShaderFlags.h" #include "DirectX.h" #include "llvm/ADT/SmallVector.h" @@ -918,6 +919,7 @@ PreservedAnalyses DXILOpLowering::run(Module &M, ModuleAnalysisManager &MAM) { PA.preserve(); PA.preserve(); PA.preserve(); + PA.preserve(); return PA; } @@ -945,6 +947,7 @@ class DXILOpLoweringLegacy : public ModulePass { AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); + AU.addPreserved(); } }; char DXILOpLoweringLegacy::ID = 0; diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp index 398dcbb8d1737..095665683ed58 100644 --- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp +++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "DXILPostOptimizationValidation.h" +#include "DXILRootSignature.h" #include "DXILShaderFlags.h" #include "DirectX.h" #include "llvm/ADT/SmallString.h" @@ -17,13 +18,45 @@ #include "llvm/IR/IntrinsicsDirectX.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" +#include "llvm/Support/DXILABI.h" #define DEBUG_TYPE "dxil-post-optimization-validation" using namespace llvm; using namespace llvm::dxil; -namespace { +static ResourceClass toResourceClass(dxbc::DescriptorRangeType RangeType) { + using namespace dxbc; + switch (RangeType) { + case DescriptorRangeType::SRV: + return ResourceClass::SRV; + case DescriptorRangeType::UAV: + return ResourceClass::UAV; + case DescriptorRangeType::CBV: + return ResourceClass::CBuffer; + case DescriptorRangeType::Sampler: + return ResourceClass::Sampler; + } + llvm_unreachable("Unknown DescriptorRangeType"); +} + +static ResourceClass toResourceClass(dxbc::RootParameterType Type) { + using namespace dxbc; + switch (Type) { + case RootParameterType::Constants32Bit: + return ResourceClass::CBuffer; + case RootParameterType::SRV: + return ResourceClass::SRV; + case RootParameterType::UAV: + return ResourceClass::UAV; + case RootParameterType::CBV: + return ResourceClass::CBuffer; + case dxbc::RootParameterType::DescriptorTable: + llvm_unreachable("DescriptorTable is not convertible to ResourceClass"); + break; + } + llvm_unreachable("Unknown RootParameterType"); +} static void reportInvalidDirection(Module &M, DXILResourceMap &DRM) { for (const auto &UAV : DRM.uavs()) { @@ -84,8 +117,126 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) { } } +static void +reportOverlappingRegisters(Module &M, + const llvm::hlsl::BindingInfoBuilder::Binding &R1, + const llvm::hlsl::BindingInfoBuilder::Binding &R2) { + SmallString<128> Message; + + raw_svector_ostream OS(Message); + OS << "resource " << getResourceClassName(R1.RC) << " (space=" << R1.Space + << ", registers=[" << R1.LowerBound << ", " << R1.UpperBound + << "]) overlaps with resource " << getResourceClassName(R2.RC) + << " (space=" << R2.Space << ", registers=[" << R2.LowerBound << ", " + << R2.UpperBound << "])"; + M.getContext().diagnose(DiagnosticInfoGeneric(Message)); +} + +static dxbc::ShaderVisibility +tripleToVisibility(llvm::Triple::EnvironmentType ET) { + switch (ET) { + case Triple::Pixel: + return dxbc::ShaderVisibility::Pixel; + case Triple::Vertex: + return dxbc::ShaderVisibility::Vertex; + case Triple::Geometry: + return dxbc::ShaderVisibility::Geometry; + case Triple::Hull: + return dxbc::ShaderVisibility::Hull; + case Triple::Domain: + return dxbc::ShaderVisibility::Domain; + case Triple::Mesh: + return dxbc::ShaderVisibility::Mesh; + case Triple::Compute: + return dxbc::ShaderVisibility::All; + default: + llvm_unreachable("Invalid triple to shader stage conversion"); + } +} + +static void validateRootSignature(Module &M, + const mcdxbc::RootSignatureDesc &RSD, + dxil::ModuleMetadataInfo &MMI) { + + hlsl::BindingInfoBuilder Builder; + dxbc::ShaderVisibility Visibility = tripleToVisibility(MMI.ShaderProfile); + SmallVector IDs; + for (const mcdxbc::RootParameterInfo &ParamInfo : RSD.ParametersContainer) { + dxbc::ShaderVisibility ParamVisibility = + static_cast(ParamInfo.Header.ShaderVisibility); + if (ParamVisibility != dxbc::ShaderVisibility::All && + ParamVisibility != Visibility) + continue; + dxbc::RootParameterType ParamType = + static_cast(ParamInfo.Header.ParameterType); + switch (ParamType) { + case dxbc::RootParameterType::Constants32Bit: { + dxbc::RTS0::v1::RootConstants Const = + RSD.ParametersContainer.getConstant(ParamInfo.Location); + Builder.trackBinding(dxil::ResourceClass::CBuffer, Const.RegisterSpace, + Const.ShaderRegister, Const.ShaderRegister, + &IDs.emplace_back()); + break; + } + + case dxbc::RootParameterType::SRV: + case dxbc::RootParameterType::UAV: + case dxbc::RootParameterType::CBV: { + dxbc::RTS0::v2::RootDescriptor Desc = + RSD.ParametersContainer.getRootDescriptor(ParamInfo.Location); + Builder.trackBinding(toResourceClass(static_cast( + ParamInfo.Header.ParameterType)), + Desc.RegisterSpace, Desc.ShaderRegister, + Desc.ShaderRegister, &IDs.emplace_back()); + + break; + } + case dxbc::RootParameterType::DescriptorTable: { + const mcdxbc::DescriptorTable &Table = + RSD.ParametersContainer.getDescriptorTable(ParamInfo.Location); + + for (const dxbc::RTS0::v2::DescriptorRange &Range : Table.Ranges) { + uint32_t UpperBound = + Range.NumDescriptors == ~0U + ? Range.BaseShaderRegister + : Range.BaseShaderRegister + Range.NumDescriptors - 1; + Builder.trackBinding( + toResourceClass( + static_cast(Range.RangeType)), + Range.RegisterSpace, Range.BaseShaderRegister, UpperBound, + &IDs.emplace_back()); + } + break; + } + } + } + + for (const dxbc::RTS0::v1::StaticSampler &S : RSD.StaticSamplers) + Builder.trackBinding(dxil::ResourceClass::Sampler, S.RegisterSpace, + S.ShaderRegister, S.ShaderRegister, + &IDs.emplace_back()); + + Builder.calculateBindingInfo( + [&M](const llvm::hlsl::BindingInfoBuilder &Builder, + const llvm::hlsl::BindingInfoBuilder::Binding &ReportedBinding) { + const llvm::hlsl::BindingInfoBuilder::Binding &Overlaping = + Builder.findOverlapping(ReportedBinding); + reportOverlappingRegisters(M, ReportedBinding, Overlaping); + }); +} + +static mcdxbc::RootSignatureDesc * +getRootSignature(RootSignatureBindingInfo &RSBI, + dxil::ModuleMetadataInfo &MMI) { + if (MMI.EntryPropertyVec.size() == 0) + return nullptr; + return RSBI.getDescForFunction(MMI.EntryPropertyVec[0].Entry); +} + static void reportErrors(Module &M, DXILResourceMap &DRM, - DXILResourceBindingInfo &DRBI) { + DXILResourceBindingInfo &DRBI, + RootSignatureBindingInfo &RSBI, + dxil::ModuleMetadataInfo &MMI) { if (DRM.hasInvalidCounterDirection()) reportInvalidDirection(M, DRM); @@ -94,14 +245,19 @@ static void reportErrors(Module &M, DXILResourceMap &DRM, assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in " "DXILResourceImplicitBinding pass"); + + if (mcdxbc::RootSignatureDesc *RSD = getRootSignature(RSBI, MMI)) + validateRootSignature(M, *RSD, MMI); } -} // namespace PreservedAnalyses DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) { DXILResourceMap &DRM = MAM.getResult(M); DXILResourceBindingInfo &DRBI = MAM.getResult(M); - reportErrors(M, DRM, DRBI); + RootSignatureBindingInfo &RSBI = MAM.getResult(M); + ModuleMetadataInfo &MMI = MAM.getResult(M); + + reportErrors(M, DRM, DRBI, RSBI, MMI); return PreservedAnalyses::all(); } @@ -113,7 +269,12 @@ class DXILPostOptimizationValidationLegacy : public ModulePass { getAnalysis().getResourceMap(); DXILResourceBindingInfo &DRBI = getAnalysis().getBindingInfo(); - reportErrors(M, DRM, DRBI); + RootSignatureBindingInfo &RSBI = + getAnalysis().getRSInfo(); + dxil::ModuleMetadataInfo &MMI = + getAnalysis().getModuleMetadata(); + + reportErrors(M, DRM, DRBI, RSBI, MMI); return false; } StringRef getPassName() const override { @@ -125,10 +286,13 @@ class DXILPostOptimizationValidationLegacy : public ModulePass { void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.addRequired(); AU.addRequired(); + AU.addRequired(); + AU.addRequired(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); + AU.addPreserved(); } }; char DXILPostOptimizationValidationLegacy::ID = 0; @@ -139,6 +303,8 @@ INITIALIZE_PASS_BEGIN(DXILPostOptimizationValidationLegacy, DEBUG_TYPE, INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass) INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass) INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass) +INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass) +INITIALIZE_PASS_DEPENDENCY(RootSignatureAnalysisWrapper) INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE, "DXIL Post Optimization Validation", false, false) diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.h b/llvm/lib/Target/DirectX/DXILRootSignature.h index 254b7ff504633..b990b6c7410ac 100644 --- a/llvm/lib/Target/DirectX/DXILRootSignature.h +++ b/llvm/lib/Target/DirectX/DXILRootSignature.h @@ -43,13 +43,11 @@ class RootSignatureBindingInfo { iterator end() { return FuncToRsMap.end(); } - std::optional - getDescForFunction(const Function *F) { + mcdxbc::RootSignatureDesc *getDescForFunction(const Function *F) { const auto FuncRs = find(F); if (FuncRs == end()) - return std::nullopt; - - return FuncRs->second; + return nullptr; + return &FuncRs->second; } }; diff --git a/llvm/test/CodeGen/DirectX/llc-pipeline.ll b/llvm/test/CodeGen/DirectX/llc-pipeline.ll index 151603a7161c5..c31d2194a8de5 100644 --- a/llvm/test/CodeGen/DirectX/llc-pipeline.ll +++ b/llvm/test/CodeGen/DirectX/llc-pipeline.ll @@ -33,9 +33,9 @@ ; CHECK-NEXT: DXIL Module Metadata analysis ; CHECK-NEXT: DXIL Shader Flag Analysis ; CHECK-NEXT: DXIL Translate Metadata +; CHECK-NEXT: DXIL Root Signature Analysis ; CHECK-NEXT: DXIL Post Optimization Validation ; CHECK-NEXT: DXIL Op Lowering -; CHECK-NEXT: DXIL Root Signature Analysis ; CHECK-NEXT: DXIL Prepare Module ; CHECK-ASM-NEXT: DXIL Metadata Pretty Printer diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbuffer-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbuffer-range.ll new file mode 100644 index 0000000000000..3d3f57d136845 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbuffer-range.ll @@ -0,0 +1,15 @@ +; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s +; CHECK: error: resource CBV (space=0, registers=[2, 2]) overlaps with resource CBV (space=0, registers=[0, 2]) + +define void @CSMain() "hlsl.shader"="compute" { +entry: + ret void +} + +; RootConstants(num32BitConstants=4, b2), DescriptorTable(CBV(b0, numDescriptors=3)) +!dx.rootsignatures = !{!0} +!0 = !{ptr @CSMain, !1, i32 2} +!1 = !{!2, !3} +!2 = !{!"RootConstants", i32 0, i32 2, i32 0, i32 4} +!3 = !{!"DescriptorTable", i32 0, !4} +!4 = !{!"CBV", i32 3, i32 0, i32 0, i32 -1, i32 4} diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-descriptor-table-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-descriptor-table-range.ll new file mode 100644 index 0000000000000..6ca53f8897225 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-descriptor-table-range.ll @@ -0,0 +1,15 @@ +; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s +; CHECK: error: resource UAV (space=10, registers=[4294967295, 4294967295]) overlaps with resource UAV (space=10, registers=[4294967295, 4294967295]) +define void @CSMain() "hlsl.shader"="compute" { +entry: + ret void +} + +; DescriptorTable(UAV(u0, numDescriptors=unbounded)), DescriptorTable(UAV(u2, numDescriptors=4)) +!dx.rootsignatures = !{!0} +!0 = !{ptr @CSMain, !1, i32 2} +!1 = !{!2, !4} +!2 = !{!"DescriptorTable", i32 0, !3} +!3 = !{!"UAV", i32 -1, i32 -1, i32 10, i32 -1, i32 2} +!4 = !{!"DescriptorTable", i32 0, !5} +!5 = !{ !"UAV", i32 -1, i32 -1, i32 10, i32 5, i32 2 } diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-root-descriptor-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-root-descriptor-range.ll new file mode 100644 index 0000000000000..4e6a3e7e49608 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-root-descriptor-range.ll @@ -0,0 +1,14 @@ +; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s +; CHECK: error: resource UAV (space=1, registers=[3, 3]) overlaps with resource UAV (space=1, registers=[0, 3]) + +define void @CSMain() "hlsl.shader"="compute" { +entry: + ret void +} + +!dx.rootsignatures = !{!0} +!0 = !{ptr @CSMain, !1, i32 2} +!1 = !{!2, !4} +!2 = !{!"RootUAV", i32 0, i32 3, i32 1, i32 4} +!4 = !{!"DescriptorTable", i32 0, !5} +!5 = !{!"UAV", i32 4, i32 0, i32 1, i32 -1, i32 2} diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler.ll new file mode 100644 index 0000000000000..90f4c6f683e8b --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler.ll @@ -0,0 +1,14 @@ +; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s +; CHECK: error: resource Sampler (space=0, registers=[42, 42]) overlaps with resource Sampler (space=0, registers=[42, 42]) + +define void @CSMain() "hlsl.shader"="compute" { +entry: + ret void +} + +!dx.rootsignatures = !{!0} +!0 = !{ptr @CSMain, !1, i32 2} +!1 = !{!2, !3} +!2 = !{ !"StaticSampler", i32 5, i32 4, i32 5, i32 3, float 0x3FF7CCCCC0000000, i32 10, i32 2, i32 1, float -1.270000e+02, float 1.220000e+02, i32 42, i32 0, i32 0 } +!3 = !{!"DescriptorTable", i32 0, !4} +!4 = !{!"Sampler", i32 1, i32 42, i32 0, i32 -1, i32 0} diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-static-sampler-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-static-sampler-range.ll new file mode 100644 index 0000000000000..66649f7ffc653 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-static-sampler-range.ll @@ -0,0 +1,13 @@ +; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s +; CHECK: error: resource Sampler (space=0, registers=[42, 42]) overlaps with resource Sampler (space=0, registers=[42, 42]) + +define void @CSMain() "hlsl.shader"="compute" { +entry: + ret void +} + +!dx.rootsignatures = !{!0} +!0 = !{ptr @CSMain, !1, i32 2} +!1 = !{!2, !3} +!2 = !{ !"StaticSampler", i32 5, i32 4, i32 5, i32 3, float 0x3FF7CCCCC0000000, i32 10, i32 2, i32 1, float -1.270000e+02, float 1.220000e+02, i32 42, i32 0, i32 0 } +!3 = !{ !"StaticSampler", i32 4, i32 2, i32 3, i32 5, float 0x3FF6CCCCC0000000, i32 9, i32 3, i32 2, float -1.280000e+02, float 1.280000e+02, i32 42, i32 0, i32 0 } diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation.ll new file mode 100644 index 0000000000000..42545886b6312 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation.ll @@ -0,0 +1,28 @@ +; RUN: opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 +; expected-no-diagnostics + + +; Root Signature( +; CBV(b3, space=1, visibility=SHADER_VISIBILITY_ALL) +; DescriptorTable(SRV(t0, space=0, numDescriptors=1), visibility=SHADER_VISIBILITY_ALL) +; DescriptorTable(Sampler(s0, numDescriptors=2), visibility=SHADER_VISIBILITY_VERTEX) +; DescriptorTable(UAV(u0, numDescriptors=unbounded), visibility=SHADER_VISIBILITY_ALL) + + +define void @CSMain() "hlsl.shader"="compute" { +entry: + ret void +} + +!dx.rootsignatures = !{!0} + +!0 = !{ptr @CSMain, !1, i32 2} +!1 = !{!2, !3, !5, !7, !9} +!2 = !{!"RootCBV", i32 0, i32 3, i32 1, i32 4} +!9 = !{!"RootConstants", i32 0, i32 2, i32 0, i32 4} +!3 = !{!"DescriptorTable", i32 0, !4} +!4 = !{!"SRV", i32 1, i32 0, i32 0, i32 -1, i32 0} +!5 = !{!"DescriptorTable", i32 0, !6} +!6 = !{!"Sampler", i32 5, i32 3, i32 2, i32 -1, i32 0} +!7 = !{!"DescriptorTable", i32 0, !8} +!8 = !{!"UAV", i32 -1, i32 0, i32 0, i32 -1, i32 2}