[PIX] Inline helper functions before shader debugging - #8853
Open
Damyan Pepper (damyanp) wants to merge 1 commit into
Open
[PIX] Inline helper functions before shader debugging#8853Damyan Pepper (damyanp) wants to merge 1 commit into
Damyan Pepper (damyanp) wants to merge 1 commit into
Conversation
PIX maps one shader invocation to one record stream in the debug UAV, and one stream to exactly one function. A [noinline] helper instrumented as its own function looks like a second invocation of a thread that runs once. PIX discards those records, and you cannot step into the helper. The debug instrumentation always emits RawBufferStore. That operation is legal only from shader model 6.2, so shader models 6.0 and 6.1 get an invalid module. The pass creates the tools UAV before it knows whether there is anything to instrument. A library that contains only helpers therefore gains a UAV although the pass reports that it changed nothing. Inlining happens before the pass numbers instructions or creates shadow storage. Every prepass does it, so the debug, non-uniform-resource-index, and debug-break pipelines all see the same module shape. A library module is left alone, because each exported function is its own invocation. The runtime invokes the patch-constant function of a hull shader directly. That function therefore survives inlining, and the pass instruments it. The pass selects an invocation of it by primitive alone, because OutputControlPointID is valid only in the control point phase. A function that survives inlining is named in the pass report as UninlinedFunction:<name>, so PIX does not offer a range with no records. The pass reports it and continues, instead of stopping the process. Assisted-by: Copilot Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: ac42a8d8-c740-45a3-9a2d-7cfc39b92853
Damyan Pepper (damyanp)
requested a review
from Austin Kinross (austinkinross)
August 28, 2026 03:56
Damyan Pepper (damyanp)
marked this pull request as ready for review
August 28, 2026 03:57
Contributor
There was a problem hiding this comment.
Pull request overview
Updates PIX instrumentation to inline helper functions, support older shader models, and avoid unnecessary debug UAVs.
Changes:
- Inlines non-entry helpers before PIX prepasses and reports survivors.
- Instruments hull patch-constant functions.
- Uses
BufferStorebefore shader model 6.2 and adds regression coverage.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tools/clang/unittests/HLSL/PixTest.cpp |
Adds PIX regression tests and helpers. |
tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexInHelperFunction.hlsl |
Tests resource indexing after helper inlining. |
tools/clang/test/HLSLFileCheck/pix/DebugStoreOpcodeByShaderModel.hlsl |
Tests store opcode selection. |
tools/clang/test/HLSLFileCheck/pix/DebugNoInlineHelperFunction.hlsl |
Tests debug information after inlining. |
tools/clang/test/HLSLFileCheck/pix/DebugHullPatchConstantFunction.hlsl |
Tests hull patch-constant instrumentation. |
tools/clang/test/HLSLFileCheck/pix/DebugBreakInstrumentationInHelperFunction.hlsl |
Tests debug-break helper inlining. |
lib/DxilPIXPasses/PixPassHelpers.h |
Declares the inlining helper. |
lib/DxilPIXPasses/PixPassHelpers.cpp |
Implements helper inlining and survivor collection. |
lib/DxilPIXPasses/DxilDebugInstrumentation.cpp |
Updates instrumentation targets and store operations. |
lib/DxilPIXPasses/DxilDbgValueToDbgDeclare.cpp |
Runs inlining before shadow-storage generation. |
lib/DxilPIXPasses/DxilAnnotateWithVirtualRegister.cpp |
Runs inlining before annotation and reports survivors. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+605
to
612
| if (M.HasDxilModule() || | ||
| M.getNamedMetadata(hlsl::DxilMDHelper::kDxilVersionMDName) != nullptr) { | ||
| PIXPassHelpers::InlineNonEntryFunctions(M.GetOrCreateDxilModule()); | ||
| } | ||
|
|
||
| auto GlobalEmbeddedArrayStorage = GatherGlobalEmbeddedArrayStorage(M); | ||
|
|
||
| bool Changed = false; |
| // llvm::InlineFunction is the mechanical inliner and ignores inlining | ||
| // attributes. Clear the attribute so the module carries no claim that | ||
| // contradicts its own shape. | ||
| function->removeFnAttr(llvm::Attribute::NoInline); |
Comment on lines
+133
to
+135
| llvm::SmallVector<llvm::Function *, 4> UninlinedFunctions; | ||
| PIXPassHelpers::InlineNonEntryFunctions(M.GetOrCreateDxilModule(), | ||
| &UninlinedFunctions); |
Austin Kinross (austinkinross)
approved these changes
Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PIX maps one shader invocation to one record stream in the debug UAV, and one stream to exactly one function. A [noinline] helper instrumented as its own function looks like a second invocation of a thread that runs once. PIX discards those records, and you cannot step into the helper.
The debug instrumentation always emits RawBufferStore. That operation is legal only from shader model 6.2, so shader models 6.0 and 6.1 get an invalid module.
The pass creates the tools UAV before it knows whether there is anything to instrument. A library that contains only helpers therefore gains a UAV although the pass reports that it changed nothing.
Inlining happens before the pass numbers instructions or creates shadow storage. Every prepass does it, so the debug, non-uniform-resource-index, and debug-break pipelines all see the same module shape. A library module is left alone, because each exported function is its own invocation. The runtime invokes the patch-constant function of a hull shader directly. That function therefore survives inlining, and the pass instruments it. The pass selects an invocation of it by primitive alone, because OutputControlPointID is valid only in the control point phase.
A function that survives inlining is named in the pass report as UninlinedFunction:, so PIX does not offer a range with no records. The pass reports it and continues, instead of stopping the process.
Assisted-by: Copilot
Stack created with GitHub Stacks CLI • Give Feedback 💬