Skip to content

[DirectX] Validate registers are bound to root signature #146785

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 50 commits into
base: users/joaosaffran/152229
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
0e8828c
refactoring
Jun 26, 2025
2edd215
refactoring
Jun 26, 2025
242545e
clean up
Jul 2, 2025
3f8dec4
format
Jul 2, 2025
3b1ce3b
formating
Jul 2, 2025
f5720af
fix import issues
Jul 4, 2025
ea54904
formating
Jul 4, 2025
a49aa19
refactoring
Jun 26, 2025
d90676f
init refactoring
Jun 26, 2025
a04eb9f
adding validation
Jul 2, 2025
5994b8f
clean
Jul 2, 2025
e8b14bf
implementing
Jul 4, 2025
8f40e83
finish implementing && fix tests
Jul 4, 2025
28350b2
fix issue
Jul 5, 2025
4fd2e0b
sync parent
Jul 5, 2025
e25ee87
sync parent
Jul 5, 2025
881dd36
address comments
Jul 7, 2025
8779ee9
Merge branch 'refactoring/updating-return-root-sig-analysis' into val…
Jul 7, 2025
c16f15b
fix test
Jul 8, 2025
c7d5be7
format
Jul 8, 2025
cc5afae
address changes
Jul 8, 2025
571a0ef
fix tests
Jul 8, 2025
974d4bc
Merge branch 'refactoring/updating-return-root-sig-analysis' into val…
Jul 8, 2025
e0bc862
add preserved
Jul 8, 2025
b5a0b32
addressing comments
Jul 10, 2025
00a74af
Merge branch 'main' into validation/check-descriptors-are-bound
Jul 10, 2025
5ccb842
updating
Jul 11, 2025
5423aba
format
Jul 14, 2025
a7637a7
adding tests
Jul 14, 2025
da42c0c
clean up
Jul 14, 2025
edb015d
address comments
Jul 15, 2025
9f3888e
adding root constants
Jul 15, 2025
578a03b
clean
Jul 15, 2025
b4a0e16
moving code arround
Jul 17, 2025
ef14638
clean
Jul 17, 2025
662c3a8
addressing comments
Jul 21, 2025
260633c
address comments
Jul 25, 2025
d42f156
Merge branch 'main' into validation/check-descriptors-are-bound
Jul 31, 2025
9ee3a4b
Merge branch 'main' into validation/check-descriptors-are-bound
Jul 31, 2025
6db6224
update code
Aug 1, 2025
04658b8
cleanup
Aug 1, 2025
adf3feb
address comments from inbelic
Aug 5, 2025
fc338b5
Merge branch 'validation/overlapping-ranges' into validation/check-de…
Aug 6, 2025
f5b5b3e
clean
Aug 6, 2025
03d571a
clean?
Aug 6, 2025
ef51048
format
Aug 6, 2025
21675e6
formating
Aug 6, 2025
47662f0
Merge branch 'validation/overlapping-ranges' into validation/check-de…
Aug 8, 2025
6da5fb0
format
Aug 8, 2025
0c72dcf
addressing inbelic comments
Aug 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,51 @@ struct OverlappingRanges {
llvm::SmallVector<OverlappingRanges>
findOverlappingRanges(llvm::SmallVector<RangeInfo> &Infos);

class RootSignatureBindingValidation {
private:
llvm::SmallVector<RangeInfo, 16> Bindings;
struct TypeRange {
uint32_t Start;
uint32_t End;
};
std::unordered_map<dxil::ResourceClass, TypeRange> Ranges;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think we can simplify this logic as denote here:

I think we could implement this much simpler with something like:

using TypedBinding = std::pair<Type, ResourceBinding>;
llvm::SmallVector<TypedBinding> Bindings;

and then below, instead of Range.find we do a llvm::lower_bound(Bindings, ...) with respect to the type. So that Bindings will be grouped together by type.

Or addBinding just becomes a push_back and then we do llvm::sort by group before returning them in getBindingsOfType

Then getBindingsOfType can take advantage of the sorted nature to return it. I don't think there would be any harm in returning an array ref of TypedBinding either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure, that would make it easier, since we would need to make sure the array is sorted as well as using lower_bound to keep track of where each element starts. I am not opposed to this strategy thought, just want to hear @bogner opinion on this first.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LLVM Programmers manual explicitly states:

We never use containers like unordered_map because they are generally very expensive (each insertion requires a malloc).

(Source: https://llvm.org/docs/ProgrammersManual.html#other-map-like-container-options)

llvm::DenseMap is generally preferred. That said, since dxil::ResourceClass has a valid value range [0,3], maybe we should just declare a 4-element array...

Copy link
Contributor

@bogner bogner Jul 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done with an insert-then-query approach, so the sorted vector is a reasonable suggestion. That said, this is the third implementation of pretty much the same algorithm for calculating binding ranges at this point. See my top level comment.


public:
void addBinding(dxil::ResourceClass Type, const RangeInfo &Binding) {
auto It = Ranges.find(Type);

if (It == Ranges.end()) {
uint32_t InsertPos = Bindings.size();
Bindings.push_back(Binding);
Ranges[Type] = {InsertPos, InsertPos + 1};
} else {
uint32_t InsertPos = It->second.End;
Bindings.insert(Bindings.begin() + InsertPos, Binding);

It->second.End++;

for (auto &[Type, Range] : Ranges) {
if (Range.Start > InsertPos) {
Range.Start++;
Range.End++;
}
}
}
}

llvm::ArrayRef<RangeInfo>
getBindingsOfType(const dxil::ResourceClass &Type) const {
auto It = Ranges.find(Type);
if (It == Ranges.end()) {
return {};
}
return llvm::ArrayRef<RangeInfo>(Bindings.data() + It->second.Start,
It->second.End - It->second.Start);
}
};
llvm::SmallVector<RangeInfo>
findUnboundRanges(const llvm::SmallVectorImpl<RangeInfo> &Ranges,
const llvm::ArrayRef<RangeInfo> &Bindings);
} // namespace rootsig
} // namespace hlsl
} // namespace llvm
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/MC/DXContainerRootSignature.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MC_DXCONTAINERROOTSIGNATURE_H
#define LLVM_MC_DXCONTAINERROOTSIGNATURE_H

#include "llvm/BinaryFormat/DXContainer.h"
#include <cstdint>
Expand Down Expand Up @@ -116,3 +118,4 @@ struct RootSignatureDesc {
};
} // namespace mcdxbc
} // namespace llvm
#endif // LLVM_MC_DXCONTAINERROOTSIGNATURE_H
26 changes: 26 additions & 0 deletions llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,32 @@ findOverlappingRanges(llvm::SmallVector<RangeInfo> &Infos) {
return Overlaps;
}

llvm::SmallVector<RangeInfo>
findUnboundRanges(const llvm::SmallVectorImpl<RangeInfo> &Ranges,
const llvm::ArrayRef<RangeInfo> &Bindings) {
llvm::SmallVector<RangeInfo> Unbounds;
for (const auto &Range : Ranges) {
bool Bound = false;
// hlsl::rootsig::RangeInfo Range;
// Range.Space = ResBinding.Space;
// Range.LowerBound = ResBinding.LowerBound;
// Range.UpperBound = Range.LowerBound + ResBinding.Size - 1;

for (const auto &Binding : Bindings) {
if (Range.Space == Binding.Space &&
Range.LowerBound >= Binding.LowerBound &&
Range.UpperBound <= Binding.UpperBound) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will forward this comment, just so it doesn't get lost:

Ah yep, sorry.

I guess my original question was about something like:

struct FooData { float data };
ConstantBuffer<FooData> Foo[4] : register(b0);

[RootSignature(DescriptorTable(CBV(b0, numDescriptors =2), CBV(b2, numDescriptors = 2))]

Are all registers successfully bound? IIUC, the current logic wouldn't get something like that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DXC doesn't seem to consider this a valid binding scenario: https://hlsl.godbolt.org/z/vYo4cY7vv. So we might not want to make it valid in clang.

Bound = true;
break;
}
}
if (!Bound) {
Unbounds.push_back(Range);
}
}
return Unbounds;
}

} // namespace rootsig
} // namespace hlsl
} // namespace llvm
2 changes: 2 additions & 0 deletions llvm/lib/Target/DirectX/DXILOpLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -945,6 +946,7 @@ class DXILOpLoweringLegacy : public ModulePass {
AU.addPreserved<DXILResourceWrapperPass>();
AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
AU.addPreserved<ShaderFlagsAnalysisWrapper>();
AU.addPreserved<RootSignatureAnalysisWrapper>();
Copy link
Contributor Author

@joaosaffran joaosaffran Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pass, changes the IR, therefore, in order to preserve the data from RootSignatureAnalysisPass, I need to mark it as preserved.

}
};
char DXILOpLoweringLegacy::ID = 0;
Expand Down
218 changes: 215 additions & 3 deletions llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
//===----------------------------------------------------------------------===//

#include "DXILPostOptimizationValidation.h"
#include "DXILRootSignature.h"
#include "DXILShaderFlags.h"
#include "DirectX.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Analysis/DXILMetadataAnalysis.h"
#include "llvm/Analysis/DXILResource.h"
#include "llvm/Frontend/HLSL/RootSignatureValidations.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicsDirectX.h"
Expand All @@ -24,6 +26,48 @@ using namespace llvm;
using namespace llvm::dxil;

namespace {
static const char *ResourceClassToString(llvm::dxil::ResourceClass Class) {
switch (Class) {
case ResourceClass::SRV:
return "SRV";
case ResourceClass::UAV:
return "UAV";
case ResourceClass::CBuffer:
return "CBuffer";
case ResourceClass::Sampler:
return "Sampler";
}
}

static ResourceClass RangeToResourceClass(uint32_t RangeType) {
using namespace dxbc;
switch (static_cast<DescriptorRangeType>(RangeType)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this even be a separate enum? It looks like DescriptorRangeType is identical to ResourceClass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DescriptorRangeType is supposed to match the binary format representation, so it uses 32 bits and the numbers are supposed to match the ones used in DXC when creating the binary file. Other than that, I think it might be possible to reuse ResourceClass in place of DescriptorRangeType, if we remember to do the correct conversions when reading and writing. My only concern is to create a dependency that might make future code harder to maintain, since we currently extend ResourceClass without the concern of breaking the binary file. Thoughts ?

case DescriptorRangeType::SRV:
return ResourceClass::SRV;
case DescriptorRangeType::UAV:
return ResourceClass::UAV;
case DescriptorRangeType::CBV:
return ResourceClass::CBuffer;
case DescriptorRangeType::Sampler:
return ResourceClass::Sampler;
}
}

ResourceClass ParameterToResourceClass(uint32_t Type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type has been validated before this point right? So we know it is a valid type.

Can we just do ResourceClass(Type) instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No because RootSignatureParameter and ResourceClass don't use the same numbers to represent the same resources, for example, the first uses 4 to represent UAV, while the later uses 1.

using namespace dxbc;
switch (Type) {
case llvm::to_underlying(RootParameterType::Constants32Bit):
return ResourceClass::CBuffer;
case llvm::to_underlying(RootParameterType::SRV):
return ResourceClass::SRV;
case llvm::to_underlying(RootParameterType::UAV):
return ResourceClass::UAV;
case llvm::to_underlying(RootParameterType::CBV):
return ResourceClass::CBuffer;
default:
llvm_unreachable("Unknown RootParameterType");
}
}

static void reportInvalidDirection(Module &M, DXILResourceMap &DRM) {
for (const auto &UAV : DRM.uavs()) {
Expand Down Expand Up @@ -84,8 +128,150 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
}
}

static void reportRegNotBound(Module &M,
llvm::hlsl::rootsig::RangeInfo Unbound) {
SmallString<128> Message;
raw_svector_ostream OS(Message);
OS << "register " << ResourceClassToString(Unbound.Class)
<< " (space=" << Unbound.Space << ", register=" << Unbound.LowerBound
<< ")"
<< " is not defined in Root Signature";
M.getContext().diagnose(DiagnosticInfoGeneric(Message));
}

static dxbc::ShaderVisibility
tripleToVisibility(llvm::Triple::EnvironmentType ET) {
assert((ET == Triple::Pixel || ET == Triple::Vertex ||
ET == Triple::Geometry || ET == Triple::Hull ||
ET == Triple::Domain || ET == Triple::Mesh ||
ET == Triple::Compute) &&
"Invalid Triple to shader stage conversion");

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 hlsl::rootsig::RootSignatureBindingValidation
initRSBindingValidation(const mcdxbc::RootSignatureDesc &RSD,
dxbc::ShaderVisibility Visibility) {

hlsl::rootsig::RootSignatureBindingValidation Validation;

for (size_t I = 0; I < RSD.ParametersContainer.size(); I++) {
const auto &[Type, Loc] =
RSD.ParametersContainer.getTypeAndLocForParameter(I);

const auto &Header = RSD.ParametersContainer.getHeader(I);
if (Header.ShaderVisibility !=
llvm::to_underlying(dxbc::ShaderVisibility::All) &&
Header.ShaderVisibility != llvm::to_underlying(Visibility))
continue;

switch (Type) {
case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit): {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than using llvm::to_underlying on all the cases, why not convert the int to enum and handle the potential error outside the switch? That will make the code easier to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was originally a design decision. The decision was made to avoid converting uint_32t to enum in obj2yaml/yaml2obj and when reading and writing root signature to/from the binary format. This simplified the code at the time.

dxbc::RTS0::v1::RootConstants Const =
RSD.ParametersContainer.getConstant(Loc);

hlsl::rootsig::RangeInfo Binding;
Binding.LowerBound = Const.ShaderRegister;
Binding.Space = Const.RegisterSpace;
Binding.UpperBound = Binding.LowerBound;

// Root Constants Bind to CBuffers
Validation.addBinding(ResourceClass::CBuffer, Binding);

break;
}

case llvm::to_underlying(dxbc::RootParameterType::SRV):
case llvm::to_underlying(dxbc::RootParameterType::UAV):
case llvm::to_underlying(dxbc::RootParameterType::CBV): {
dxbc::RTS0::v2::RootDescriptor Desc =
RSD.ParametersContainer.getRootDescriptor(Loc);

hlsl::rootsig::RangeInfo Binding;
Binding.LowerBound = Desc.ShaderRegister;
Binding.Space = Desc.RegisterSpace;
Binding.UpperBound = Binding.LowerBound;

Validation.addBinding(ParameterToResourceClass(Type), Binding);
break;
}
case llvm::to_underlying(dxbc::RootParameterType::DescriptorTable): {
const mcdxbc::DescriptorTable &Table =
RSD.ParametersContainer.getDescriptorTable(Loc);

for (const dxbc::RTS0::v2::DescriptorRange &Range : Table.Ranges) {
hlsl::rootsig::RangeInfo Binding;
Binding.LowerBound = Range.BaseShaderRegister;
Binding.Space = Range.RegisterSpace;
Binding.UpperBound = Binding.LowerBound + Range.NumDescriptors - 1;
Validation.addBinding(RangeToResourceClass(Range.RangeType), Binding);
}
break;
}
}
}

return Validation;
}

std::optional<mcdxbc::RootSignatureDesc>
getRootSignature(RootSignatureBindingInfo &RSBI,
dxil::ModuleMetadataInfo &MMI) {
if (MMI.EntryPropertyVec.size() == 0)
return std::nullopt;
std::optional<mcdxbc::RootSignatureDesc> RootSigDesc =
RSBI.getDescForFunction(MMI.EntryPropertyVec[0].Entry);
if (!RootSigDesc)
return std::nullopt;
return RootSigDesc;
}

static void reportUnboundRegisters(
Module &M,
const llvm::hlsl::rootsig::RootSignatureBindingValidation &Validation,
ResourceClass Class,
const iterator_range<SmallVectorImpl<dxil::ResourceInfo>::iterator>
&Resources) {
SmallVector<hlsl::rootsig::RangeInfo> Ranges;
for (auto Res = Resources.begin(), End = Resources.end(); Res != End; Res++) {
ResourceInfo::ResourceBinding ResBinding = Res->getBinding();
hlsl::rootsig::RangeInfo Range;
Range.Space = ResBinding.Space;
Range.LowerBound = ResBinding.LowerBound;
Range.UpperBound = Range.LowerBound + ResBinding.Size - 1;
Range.Class = Class;
Ranges.push_back(Range);
}

SmallVector<hlsl::rootsig::RangeInfo> Unbounds =
hlsl::rootsig::findUnboundRanges(Ranges,
Validation.getBindingsOfType(Class));
for (const auto &Unbound : Unbounds)
reportRegNotBound(M, Unbound);
}

static void reportErrors(Module &M, DXILResourceMap &DRM,
DXILResourceBindingInfo &DRBI) {
DXILResourceBindingInfo &DRBI,
RootSignatureBindingInfo &RSBI,
dxil::ModuleMetadataInfo &MMI) {
if (DRM.hasInvalidCounterDirection())
reportInvalidDirection(M, DRM);

Expand All @@ -94,14 +280,30 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,

assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in "
"DXILResourceImplicitBinding pass");

if (auto RSD = getRootSignature(RSBI, MMI)) {

llvm::hlsl::rootsig::RootSignatureBindingValidation Validation =
initRSBindingValidation(*RSD, tripleToVisibility(MMI.ShaderProfile));

reportUnboundRegisters(M, Validation, ResourceClass::CBuffer,
DRM.cbuffers());
reportUnboundRegisters(M, Validation, ResourceClass::UAV, DRM.uavs());
reportUnboundRegisters(M, Validation, ResourceClass::Sampler,
DRM.samplers());
reportUnboundRegisters(M, Validation, ResourceClass::SRV, DRM.srvs());
}
}
} // namespace

PreservedAnalyses
DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) {
DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
DXILResourceBindingInfo &DRBI = MAM.getResult<DXILResourceBindingAnalysis>(M);
reportErrors(M, DRM, DRBI);
RootSignatureBindingInfo &RSBI = MAM.getResult<RootSignatureAnalysis>(M);
ModuleMetadataInfo &MMI = MAM.getResult<DXILMetadataAnalysis>(M);

reportErrors(M, DRM, DRBI, RSBI, MMI);
return PreservedAnalyses::all();
}

Expand All @@ -113,7 +315,12 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
getAnalysis<DXILResourceWrapperPass>().getResourceMap();
DXILResourceBindingInfo &DRBI =
getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
reportErrors(M, DRM, DRBI);
RootSignatureBindingInfo &RSBI =
getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
dxil::ModuleMetadataInfo &MMI =
getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();

reportErrors(M, DRM, DRBI, RSBI, MMI);
return false;
}
StringRef getPassName() const override {
Expand All @@ -125,10 +332,13 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.addRequired<DXILResourceWrapperPass>();
AU.addRequired<DXILResourceBindingWrapperPass>();
AU.addRequired<DXILMetadataAnalysisWrapperPass>();
AU.addRequired<RootSignatureAnalysisWrapper>();
AU.addPreserved<DXILResourceWrapperPass>();
AU.addPreserved<DXILResourceBindingWrapperPass>();
AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
AU.addPreserved<ShaderFlagsAnalysisWrapper>();
AU.addPreserved<RootSignatureAnalysisWrapper>();
}
};
char DXILPostOptimizationValidationLegacy::ID = 0;
Expand All @@ -139,6 +349,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)

Expand Down
Loading
Loading