From 9976585da04fe55530cad34b873f73ffcefc1fed Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Mon, 24 Aug 2026 18:54:08 -0700 Subject: [PATCH] [PIX] Skip NURI handles with no instruction number The non-uniform resource index pass writes each diagnostic bit at an address that it computes from the PIX instruction number of the handle. If a handle has no instruction number, the value stays at 0. A debug build stops at an assertion. A release build writes the bit for instruction 0 and gives the diagnostic to an unrelated instruction. Library helper functions are the usual source of these handles. The pass ignores such a handle instead of guessing. An absent record is correct. A record at instruction 0 is wrong. The report NuriNotInstrumentedMissingInstructionNumber tells the caller that the data is not complete. The pass reads the instruction number before it makes the UAV. A module whose dynamic handles all lack an instruction number therefore gets no UAV that it cannot use. A PIX build that does not read the new report keeps its current behavior. Assisted-by: Copilot Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40dc9de3-617e-4caf-ab0d-fba0a033ed93 --- ...NonUniformResourceIndexInstrumentation.cpp | 25 +++++++++++++----- ...UniformResourceIndexInstructionNumber.hlsl | 23 ++++++++++++++++ .../NonUniformResourceIndexLibraryHelper.hlsl | 26 +++++++++++++++++++ ...formResourceIndexNoInstructionNumbers.hlsl | 22 ++++++++++++++++ 4 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexInstructionNumber.hlsl create mode 100644 tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexLibraryHelper.hlsl create mode 100644 tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexNoInstructionNumbers.hlsl diff --git a/lib/DxilPIXPasses/DxilNonUniformResourceIndexInstrumentation.cpp b/lib/DxilPIXPasses/DxilNonUniformResourceIndexInstrumentation.cpp index 3c7a542648..d1e7fa0fd8 100644 --- a/lib/DxilPIXPasses/DxilNonUniformResourceIndexInstrumentation.cpp +++ b/lib/DxilPIXPasses/DxilNonUniformResourceIndexInstrumentation.cpp @@ -59,6 +59,10 @@ bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) { std::map FunctionToUAVHandle; + // Set if any dynamically indexed handle lacks the PIX instruction ordinal + // this pass needs to address its diagnostic. + bool FoundHandleWithoutInstructionNumber = false; + // This is the main pass that will iterate through all of the resources that // are dynamically indexed. If not already marked NonUniformResourceIndex, // then insert WaveActiveAllEqual to determine if the index is uniform @@ -72,6 +76,16 @@ bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) { return true; } + // Address each diagnostic by the PIX instruction ordinal. Skip a + // handle that has no ordinal instead of writing a record for + // instruction 0. + uint32_t InstructionNumber = 0; + if (!pix_dxil::PixDxilInstNum::FromInst(CreateHandle, + &InstructionNumber)) { + FoundHandleWithoutInstructionNumber = true; + return true; + } + if (!PixUAVResource) { PixUAVResource = PIXPassHelpers::CreateGlobalUAVResource(DM, 0, "PixUAVResource"); @@ -97,12 +111,6 @@ bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) { IRBuilder<> Builder(CreateHandle); - uint32_t InstructionNumber = 0; - if (!pix_dxil::PixDxilInstNum::FromInst(CreateHandle, - &InstructionNumber)) { - DXASSERT_NOMSG(false); - } - // The output UAV is treated as a bit array where each bit corresponds // to an instruction number. This determines what byte offset to write // our result to based on the instruction number. @@ -161,6 +169,11 @@ bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) { } } + if (FoundHandleWithoutInstructionNumber && OSOverride != nullptr) { + formatted_raw_ostream FOS(*OSOverride); + FOS << "\nNuriNotInstrumentedMissingInstructionNumber\n"; + } + return modified; } diff --git a/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexInstructionNumber.hlsl b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexInstructionNumber.hlsl new file mode 100644 index 0000000000..d002fed467 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexInstructionNumber.hlsl @@ -0,0 +1,23 @@ +// RUN: %dxc -Emain -Tps_6_0 %s | %opt -S -dxil-annotate-with-virtual-regs -hlsl-dxil-non-uniform-resource-index-instrumentation | %FileCheck %s + +// With the annotation prepass in place, the diagnostic is addressed to +// the ordinal of the createHandle that performed the unmarked dynamic +// indexing. The pass encodes that ordinal as a shift. A shift of zero +// aliases the diagnostic onto bit 0. +// +// Match any non-zero shift rather than a literal ordinal. A createHandle +// whose index comes from an interpolated input is never the first +// numbered instruction. + +// CHECK-NOT: NuriNotInstrumentedMissingInstructionNumber +// CHECK: @dx.op.waveActiveAllEqual +// CHECK: shl i32 %{{[0-9]+}}, {{[1-9][0-9]*}} +// CHECK: @dx.op.atomicBinOp.i32(i32 78 + +Texture2D tex[8] : register(t0); + +float4 main(float2 uv : TEXCOORD0) : SV_TARGET +{ + uint index = uv.x * uv.y; + return tex[index].Load(int3(0, 0, 0)); +} diff --git a/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexLibraryHelper.hlsl b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexLibraryHelper.hlsl new file mode 100644 index 0000000000..348385b083 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexLibraryHelper.hlsl @@ -0,0 +1,26 @@ +// RUN: %dxc -T lib_6_6 -Od %s | %opt -S -dxil-annotate-with-virtual-regs -hlsl-dxil-non-uniform-resource-index-instrumentation | %FileCheck %s + +// Coverage for an unmarked dynamic index that stays in a library helper. +// The helper remains a separate function. The diagnostic is addressed to +// a non-zero instruction ordinal. + +// CHECK-NOT: NuriNotInstrumentedMissingInstructionNumber +// CHECK: define void {{.*}}IndexInHelper +// CHECK: @dx.op.waveActiveAllEqual +// CHECK: shl i32 %{{[0-9]+}}, {{[1-9][0-9]*}} +// CHECK: @dx.op.atomicBinOp.i32(i32 78 + +RWTexture2D RT[] : register(u0); + +[noinline] +export void IndexInHelper(uint index) +{ + float2 rayIndex = DispatchRaysIndex().xy; + RT[index][rayIndex] = 1; +} + +[shader("raygeneration")] +void RayGen() +{ + IndexInHelper(DispatchRaysIndex().x); +} diff --git a/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexNoInstructionNumbers.hlsl b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexNoInstructionNumbers.hlsl new file mode 100644 index 0000000000..d810401b4e --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexNoInstructionNumbers.hlsl @@ -0,0 +1,22 @@ +// RUN: %dxc -Emain -Tps_6_0 %s | %opt -S -hlsl-dxil-non-uniform-resource-index-instrumentation | %FileCheck %s + +// This pass addresses each diagnostic by the PIX instruction ordinal. +// This RUN line omits the annotation prepass, so no createHandle carries +// an ordinal. The pass leaves the handle uninstrumented and reports the +// missing precondition. +// +// The pass writes its messages to the same stream as the -S module print, +// and writes them before the module, so the message checks come first. + +// CHECK-NOT: FoundDynamicIndexingNoNuri +// CHECK: NuriNotInstrumentedMissingInstructionNumber +// CHECK-NOT: @dx.op.waveActiveAllEqual +// CHECK-NOT: @dx.op.atomicBinOp + +Texture2D tex[8] : register(t0); + +float4 main(float2 uv : TEXCOORD0) : SV_TARGET +{ + uint index = uv.x * uv.y; + return tex[index].Load(int3(0, 0, 0)); +}