Skip to content

[SPIR-V] Add SPV_EXT_descriptor_heap + SPV_KHR_untyped_pointers codegen - #8517

Open
Jonathan Zakharov (jzakharovnv) wants to merge 19 commits into
microsoft:mainfrom
jzakharovnv:pr1-descriptor-heap-core
Open

[SPIR-V] Add SPV_EXT_descriptor_heap + SPV_KHR_untyped_pointers codegen#8517
Jonathan Zakharov (jzakharovnv) wants to merge 19 commits into
microsoft:mainfrom
jzakharovnv:pr1-descriptor-heap-core

Conversation

@jzakharovnv

@jzakharovnv Jonathan Zakharov (jzakharovnv) commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Building off of #8281, this PR adds a native lowering via SPV_EXT_descriptor_heap and SPV_KHR_untyped_pointers and is part 1/3 in a series.

ResourceDescriptorHeap and SamplerDescriptorHeap are lowered to untyped variables decorated with ResourceHeapEXT and SamplerHeapEXT. Each heap access emits OpUntypedAccessChainKHR into a runtime array of the appropriate descriptor type. Buffer-like resources (StructuredBuffer, ByteAddressBuffer, ConstantBuffer, TextureBuffer) use OpTypeBufferEXT and OpBufferPointerEXT; image and sampler resources use OpLoad. Interlocked operations on RWTexture use OpUntypedImageTexelPointerEXT.

Requires -fspv-target-env=vulkan1.3.

Assisted by an AI agent.

Diego Novillo (@dnovillo)

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

✅ With the latest revision this PR passed the C/C++ code formatter.

@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

@microsoft-github-policy-service agree company="NVIDIA"

@dnovillo Diego Novillo (dnovillo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for this! I just started looking at it and have a couple of questions. I'll add more as I read the PRs.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
@github-project-automation github-project-automation Bot moved this from New to In progress in HLSL Roadmap Jun 8, 2026
Comment thread tools/clang/lib/SPIRV/CapabilityVisitor.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
@Tobski

Tobski commented Jul 7, 2026

Copy link
Copy Markdown

Jonathan Zakharov (@jzakharovnv) I think the OpConstantSizeOfEXT usage in this MR isn't quite right - it looks like you're just taking the stride of the descriptor type being loaded and using that? This works for the sampler heap where there's only one type (samplers), but not for the resource heap.

The stride of all resource descriptors must be the same for all descriptors, and has to be based on the biggest of the buffer/image sizes. This is illustrated in the VK extension doc here: https://docs.vulkan.org/features/latest/features/proposals/VK_EXT_descriptor_heap.html#_shader_model_6_6_samplerheap_and_resourceheap

I might be misunderstanding the code, but I don't see anything for finding the largest of the two sizes? They're both POT, so it is a simple "which is max" calculation, but I don't see it being done in this PR.

@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

Tobski You are right, this is my blunder. Will fix shortly.

@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

Tobski Shared max(image,buffer) stride for descriptor heap resource arrays ought to be closer to the original intent. Please take a look when you can. Thanks!

@Tobski

Tobski commented Jul 13, 2026

Copy link
Copy Markdown

Tobski Shared max(image,buffer) stride for descriptor heap resource arrays ought to be closer to the original intent. Please take a look when you can. Thanks!

Looks right to me now! Thanks!

@dnovillo Diego Novillo (dnovillo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A question on changes that have gone in #8519 that we may to reflect here. Not sure how you want to handle it.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
@dnovillo Diego Novillo (dnovillo) added the spirv Work related to SPIR-V label Jul 17, 2026
@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

Diego Novillo (@dnovillo) In response to your last comment on this PR, yes I think it's more correct to have the TODO commit a part of this initial branch rather than one down the line. Cherrypicked and rebased to reflect this.

@dnovillo Diego Novillo (dnovillo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just one minor change and it's good to from my side.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated

@dnovillo Diego Novillo (dnovillo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. Just one final nit. Thanks for doing this!

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
@damyanp

Copy link
Copy Markdown
Member

[Auto-generated note from Damyan Pepper (@damyanp)]

This looks like a user-visible bug fix/feature change. Please add (or point to) the corresponding entry in docs/ReleaseNotes.md.

If release-note coverage is planned in a related PR (including one that hasn’t been submitted yet), please mention that plan/link so we can avoid duplicate notes.

Copilot AI balanced review requested due to automatic review settings August 4, 2026 00:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds native SPIR-V descriptor-heap lowering using SPV_EXT_descriptor_heap and SPV_KHR_untyped_pointers.

Changes:

  • Implements native image, sampler, and buffer descriptor access.
  • Adds descriptor-size-based runtime-array strides and image atomic support.
  • Expands tests and documents Vulkan 1.3 requirements and limitations.

Reviewed changes

Copilot reviewed 47 out of 47 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tools/clang/unittests/SPIRV/SpirvContextTest.cpp Tests runtime-array type uniqueness.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.typed-formats.hlsl Tests typed image formats.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texturecube.hlsl Tests cube textures and samplers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texture.hlsl Tests texel buffers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texture-sampler-assignment.hlsl Tests resource reassignment.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texture-ms.hlsl Tests multisampled textures.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.texture-dims.hlsl Tests sampled texture dimensions.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.structured-buffer-atomic.hlsl Tests structured-buffer atomics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.static-global.hlsl Tests static global resources.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.sampler-comparison.hlsl Tests comparison samplers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.sample-grad-bias.hlsl Tests sampling operands.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.rwtexture-dims.hlsl Tests RW texture dimensions.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.rwtexture-atomics.hlsl Tests untyped image atomics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.rwbyteaddressbuffer.hlsl Tests writable byte buffers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.nonuniform.hlsl Tests divergent heap indexing.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.mixed-bound.hlsl Tests bound/native resource coexistence.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.mixed-alias.error.hlsl Tests mixed-alias diagnostics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.load-offset.hlsl Tests texture load offsets.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.groupshared.hlsl Tests groupshared coexistence.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.gather.hlsl Tests gather operations.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.function-params.hlsl Tests resource function parameters.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.discarded.error.hlsl Tests discarded-index diagnostics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.counter-ops.error.hlsl Tests unsupported counter diagnostics.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.constant-texture-buffer.hlsl Tests constant and texture buffers.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.constant-buffer-assignment.hlsl Tests constant-buffer reassignment.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.buffer.hlsl Tests native buffer lowering.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.array-stride.hlsl Tests descriptor-array strides.
tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.append-consume.error.hlsl Tests append/consume diagnostics.
tools/clang/test/CodeGenSPIRV/resource-heap-ext-texture.hlsl Removes superseded coverage.
tools/clang/lib/SPIRV/SpirvType.cpp Extends runtime-array equality.
tools/clang/lib/SPIRV/SpirvInstruction.cpp Implements new SPIR-V instructions.
tools/clang/lib/SPIRV/SpirvEmitter.h Declares heap lowering and alias state.
tools/clang/lib/SPIRV/SpirvEmitter.cpp Implements native heap code generation.
tools/clang/lib/SPIRV/SpirvContext.cpp Uniques buffer and stride-ID types.
tools/clang/lib/SPIRV/SpirvBuilder.cpp Builds descriptor sizes and strides.
tools/clang/lib/SPIRV/LowerTypeVisitor.cpp Lowers untyped image pointers.
tools/clang/lib/SPIRV/EmitVisitor.h Declares new emission handlers.
tools/clang/lib/SPIRV/EmitVisitor.cpp Serializes new instructions and decorations.
tools/clang/lib/SPIRV/DeclResultIdMapper.h Declares function alias registration.
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp Implements alias registration.
tools/clang/lib/SPIRV/CapabilityVisitor.cpp Requires Vulkan 1.3 and extensions.
tools/clang/include/clang/SPIRV/SpirvVisitor.h Adds visitor hooks.
tools/clang/include/clang/SPIRV/SpirvType.h Adds stride-ID runtime arrays.
tools/clang/include/clang/SPIRV/SpirvInstruction.h Defines new instruction classes.
tools/clang/include/clang/SPIRV/SpirvContext.h Adds type caches and APIs.
tools/clang/include/clang/SPIRV/SpirvBuilder.h Exposes descriptor-stride builders.
docs/SPIR-V.rst Documents native descriptor heaps.

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Comment thread docs/SPIR-V.rst
Damyan Pepper (damyanp) added a commit that referenced this pull request Aug 6, 2026
Fixes #8603: MergeBinaryOpSelect produced an OpSelect with a vector
result type and a scalar condition, which is only legal in SPIR-V 1.4+
(KhronosGroup/SPIRV-Tools#6827).

This exposes #8740 where the resource-heap-ext-texture.hlsl test fails
validation - for now this is worked around by disabling the test, since
#8517 looks like it is reworking it anyway.

Assisted-by: copilot

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b04b21af-2d8b-4af5-b9ad-1b84073588f5

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 54 out of 54 changed files in this pull request and generated 3 comments.

Suppressed comments (2)

tools/clang/lib/SPIRV/SpirvEmitter.cpp:2983

  • Direct heap-buffer returns bypass the new rejection: this branch handles return ResourceDescriptorHeap[i], then skips the alias-only else if and falls through to loadIfGLValue, which loads the whole buffer interface object and produces the same invalid SPIR-V that the alias diagnostic is meant to prevent. This form is valid HLSL and already appears in sm6_6.descriptorheap.return.counter.hlsl; reject buffer-like resourceType here (or implement pointer propagation) before falling through.
      if (isDescriptorHeap(srcExpr)) {

tools/clang/lib/SPIRV/SpirvEmitter.cpp:3456

  • This guard only runs for a DeclRefExpr, so a direct heap expression such as consume((StructuredBuffer<uint>)ResourceDescriptorHeap[i]) bypasses the diagnostic. The later generic argument path then calls loadIfGLValue on the OpBufferPointerEXT result and attempts to copy the whole buffer interface object into a Function variable, yielding invalid SPIR-V. Apply the heap-buffer rejection to all heap-sourced arguments before narrowing to DeclRefExpr.
    if (const auto *declRefExpr = dyn_cast<DeclRefExpr>(arg)) {

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp
Comment thread tools/clang/lib/SPIRV/SpirvBuilder.cpp Outdated
@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

Diego Novillo (@dnovillo) Chris B (@llvm-beanz) Gregory Roth (@pow2clk) Hi folks. It's time we bring this endless review cycle to an end. To wrap up what I've done: I've gone and made sure to address every human review comment and also done my best to address every Copilot comment. I've just filed #8823 through #8831 so no review gets lost. Any further reviews on these PRs (#8517, #8518, #8519) I will gladly file an issue for, but must draw the somewhere, otherwise this will go on forever. Thanks!

@dnovillo

Copy link
Copy Markdown
Collaborator

Damyan Pepper (@damyanp) Chris B (@llvm-beanz) Gregory Roth (@pow2clk), I would like to propose that we submit this series: #8517, #8518 and #8519.

I have gone over every open thread on all three PRs again. There are no blocking issues left. Gregory Roth (@pow2clk) has also been going over it and did not find major blockers (Gregory, please correct me if this changed since we chatted earlier).

Jonathan Zakharov (@jzakharovnv) has fixed the two remaining blocking issues. The acceleration-structure stride, the CLI stride override, the requestTargetEnv guard and its test, and the release notes are all in. Jonathan Zakharov (@jzakharovnv) has also worked through the Copilot passes and Chris B (@llvm-beanz)'s comments, and the last open design question, whether bare heap indexing should be an error, is settled in favour of following DXIL.

There are some holes where a direct (T)ResourceDescriptorHeap[i] cast bypasses guards that key on a named local alias. This can trigger some error-recovery paths after a diagnostic is emitted. This only happens on bad shaders. Jonathan is filing issues for these to follow up in subsequent PRs.

I think it is better to submit this now since it's protected by a flag, so it shouldn't destabilize anything that does not depend on DH. We have been reviewing this since early June, and at this point I think we learn more by letting developers compile real shaders against it than by continuing to iterate in review. Real usage will find the gaps that matter faster than we are finding them by inspection, and we can keep fixing them in follow-up PRs.

Does this sound reasonable?

Thanks.

@llvm-beanz Chris B (llvm-beanz) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need to work on PR etiquette here a bit. Phrases like "It's time we bring this endless review cycle to an end" come across as passive-aggressive and dismissive of the value code review provides.

From my perspective, I've been waiting on the PR author to re-apply changes baed on feedback I gave weeks ago that they dropped in more recent force-pushes.

I'm not comfortable accepting merging a PR on the basis that the review is taking too long when we have mechanical issues that should have been addressed a long time back which aren't being responded to.

This is not how code review works, and it isn't the culture we want contributing to this project.

@llvm-beanz Chris B (llvm-beanz) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The comment's prefixed with "nit" are nitpicks that don't need to block the change merging, but are things we should be generally looking for.

Especially with AI-assisted code we really need to look closely at code comments to assess if they add value and are correct.

One concern I have generally about some of the comments in this PR is that they describe aspects of other parts of the implementation which may not always remain accurate as other parts of the code change. This can be confusing in the future as the behavior of APIs change it isn't natural to look at all the call sites for documentation of how an API behaves.


void DeclResultIdMapper::registerFnVarAlias(const VarDecl *var,
SpirvInstruction *varInstr) {
if (varInstr)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This seems like it should be an assert, not "silently do nothing" since it is probably a misuse of the API.

I also don't see where this function is used at all so I'm unsure if it belongs here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

You're right, this is a weak helper function and an assert would be alot better. It seems like this function got caught in the messy mishap of trying to break up my monolithic commits into the 3 PRs we have now. That's just to say that the function is used, just not in this PR. I'll do a pass over #8517 #8518 #8519 to see if there any more such cases of misplaced code + any outdated/inlineable funcs + better assert placement. Thanks!

Comment thread tools/clang/lib/SPIRV/SpirvBuilder.cpp Outdated
// the maximum is computed with OpSpecConstantOp over two OpConstantSizeOfEXT
// placeholders. A canonical sampled 2D float image and a Uniform buffer stand
// in as representatives; VkPhysicalDeviceDescriptorHeapPropertiesEXT reports
// one size per category, so subtype and storage class do not affect the size.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: Almost half this diff is code comment, and while comments are good I'm not sure how much value this actually adds. LLMs are way overly verbose and often describe things that aren't really relevant to the code. This is one of those cases. Generally we should clean these up rather than merge them as the LLM writes them.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed, I'm still trying to understand the balance of "why" not "how" comments in DXC. I think my own bias favoring "how" comments has me more okay with what others may consider fluff, but this here is definitely needlessly verbose. I'm doing a pass now over all multi line comments to try to get some better S/N in the documentation.

Comment on lines +5175 to +5178
if (result && !result->isRValue()) {
result = spvBuilder.createLoad(expr->getType(), result,
buffer->getExprLoc(), range);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (result && !result->isRValue()) {
result = spvBuilder.createLoad(expr->getType(), result,
buffer->getExprLoc(), range);
}
if (result && !result->isRValue())
result = spvBuilder.createLoad(expr->getType(), result,
buffer->getExprLoc(), range);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is my bad, will do a pass to make sure the code is following standards everywhere

Comment thread tools/clang/lib/SPIRV/SpirvEmitter.cpp Outdated
// derefOrCreatePointerToValue returns an lvalue (AccessChain) when the base
// is an lvalue. This covers descriptor-heap buffers reached either directly
// (ResourceDescriptorHeap[i].Load()) or through a local alias var.
// StructuredBuffer::Load semantically returns a value, and the AST emits no

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This comment doesn't make sense. ResourceDescriptorHeap[i].Load() is illegal in HLSL (the untyped resources don't have load methods), and StructuredBuffer::Load returns an rvalue, not an lvalue so there is no reason a cast would be present.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, this is a really misleading comment. ResourceDescriptorHeap[i].Load() is nonsense and so is the lvalue cast. What the comment should say is that derefOrCreatePointerToValue produces an AccessChain and StructuredBuffer::Load should return the element value (not ptr) and thus, should be loaded here. I'll make this correction with the next batch of commits.

Comment on lines +5346 to +5351
{
auto stateIt = descriptorHeapVarState.find(dstVar);
if (stateIt != descriptorHeapVarState.end() &&
stateIt->second == DescriptorHeapVarState::Mixed)
return false;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
{
auto stateIt = descriptorHeapVarState.find(dstVar);
if (stateIt != descriptorHeapVarState.end() &&
stateIt->second == DescriptorHeapVarState::Mixed)
return false;
}
auto stateIt = descriptorHeapVarState.find(dstVar);
if (stateIt != descriptorHeapVarState.end() &&
stateIt->second == DescriptorHeapVarState::Mixed)
return false;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oops, will fix to follow coding guidelines. Thanks for pointing out

Comment on lines +9404 to +9410
// SPV_EXT_descriptor_heap: apply a client-API-defined byte stride via an
// ArrayStrideIdEXT decoration. The sampler heap holds a single descriptor
// type, so its stride is the sampler descriptor size. The resource heap is a
// shared flat array in which any resource descriptor may sit at any slot, so
// every resource runtime array must use one common stride: max(sizeof(image),
// sizeof(buffer)). Using the accessed element size would be wrong for the
// resource heap.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: I don't know that this comment adds much value. It is certainly far more verbose than necessary.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, this is crazy verbose. I fixed this in PRs #8518, #8519 since this needed to be rewritten for the case of AccelerationStructures, but neglected to clean up here on this branch. I can clean this up with next set of commits.

if (isImplicitVarDeclInVkNamespace(declRefExpr->getDecl())) {
result = doExpr(cast<VarDecl>(decl)->getInit());
} else if (const auto *varDecl = dyn_cast<VarDecl>(decl)) {
if (auto *alias =

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (auto *alias =
if (SpirvInstruction *alias =

We follow an almost never auto policy.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, this auto is obfuscating. Will fix and make sure newer commits aren't misusing auto.

@dnovillo

Copy link
Copy Markdown
Collaborator

This series of PRs would also address #8243.

Jonathan Zakharov (@jzakharovnv) please check whether this is the case once the review cycle for this series has converged. Thanks.

@jzakharovnv

Copy link
Copy Markdown
Collaborator Author

This series of PRs would also address #8243.

Jonathan Zakharov (Jonathan Zakharov (@jzakharovnv)) please check whether this is the case once the review cycle for this series has converged. Thanks.

Pushing shortly, will test if these PRs fix this issue first thing next week.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Heap atomics across function calls remain invalid, acceleration-structure strides are incomplete, and rasterizer-ordered aliases lose required metadata.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

tools/clang/lib/SPIRV/SpirvEmitter.cpp:5408

  • Heap aliases for rasterizer-ordered buffer resources lose their ROV marker here. The initial emitDescriptorHeapBufferAccess marks its temporary pointer, but aliases later re-create a new OpBufferPointerEXT through this function; without the marker, byte-address-buffer loads/stores will not insert the required invocation-interlock region. Restore the marker from the alias declaration type on every re-derived pointer.
  bufferDataPtr->setStorageClass(
      found->second.bufferPointerType->getStorageClass());
  bufferDataPtr->setLayoutRule(found->second.layoutRule);
  bufferDataPtr->setRValue(false);

tools/clang/lib/SPIRV/SpirvBuilder.cpp:2057

  • The common resource stride omits acceleration-structure descriptors, although doCXXOperatorCallExpr accepts every remaining heap resource type and LowerTypeVisitor lowers RaytracingAccelerationStructure. If such a descriptor is used, all resource arrays are therefore indexed with max(image, buffer) even when the acceleration-structure descriptor is larger. Include OpConstantSizeOfEXT for the acceleration-structure type in the maximum when present, or reject this heap resource kind until that support lands.
  // ResourceDescriptorHeap is a flat array: any descriptor may sit at any slot.
  // DX12 semantics require all resource arrays share stride =
  // max(sizeof(image), sizeof(buffer)).
  • Files reviewed: 53/53 changed files
  • Comments generated: 1
  • Review effort level: Balanced

@@ -0,0 +1,41 @@
// XFAIL: *

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Direct counter operations, acceleration-structure strides, and function-boundary image atomics have unresolved correctness issues.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.image-alias-fn-param.hlsl:1

  • This leaves a valid heap-sourced RWTexture atomic path producing SPIR-V that fails validation, despite the PR advertising RWTexture interlocked support. An unconditional XFAIL also provides no regression protection. Please either propagate the descriptor index across this function boundary or reject this case with a deliberate diagnostic and convert the test to a checked negative test.
  • Files reviewed: 53/53 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment on lines +2055 to +2059
// ResourceDescriptorHeap is a flat array: any descriptor may sit at any slot.
// DX12 semantics require all resource arrays share stride =
// max(sizeof(image), sizeof(buffer)).
// VkPhysicalDeviceDescriptorHeapPropertiesEXT reports one size per category
// (imageDescriptorSize / bufferDescriptorSize); textures lower to
(void)doExpr(object);
}

if (isDescriptorHeapCounterUnsupported(object)) {

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Several unsupported cross-function paths can emit invalid SPIR-V, and acceleration-structure descriptors can receive an incorrect heap stride.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

tools/clang/lib/SPIRV/SpirvEmitter.cpp:3461

  • This guard only catches a bare DeclRefExpr. A direct heap subscript (or a heap alias wrapped in an explicit cast) bypasses it and reaches the ordinary parameter path, although the comment notes that passing the resulting storage-buffer pointer requires unimplemented VariablePointersStorageBuffer support. Detect heap-sourced buffer values via isHeapSourcedValue(arg) regardless of AST shape, or implement the required parameter lowering.
    if (const auto *declRefExpr = dyn_cast<DeclRefExpr>(arg)) {
      // Buffer alias vars are not in astDecls (getDeclEvalInfo would crash);
      // passing by value also requires VariablePointersStorageBuffer + callee
      // parameter type changes (not yet implemented). Emit diagnostic instead.
      // TODO: implement full buffer-alias function-call support
      //       (VariablePointersStorageBuffer + matching createFnParam type).
      const auto *var = dyn_cast<VarDecl>(declRefExpr->getDecl());
      if (var && descriptorHeapBufferAliasVars.count(var)) {

tools/clang/lib/SPIRV/SpirvBuilder.cpp:2060

  • The generic heap lowering also accepts RaytracingAccelerationStructure, but this cached stride only accounts for image and buffer descriptor sizes. The new array-stride test itself notes that acceleration structures require a three-way maximum; if their descriptor size is larger, every heap access is addressed with the wrong stride. Include the acceleration-structure size when that resource kind is supported, or reject native heap accesses to it until then.
  // ResourceDescriptorHeap is a flat array: any descriptor may sit at any slot.
  // DX12 semantics require all resource arrays share stride =
  // max(sizeof(image), sizeof(buffer)).
  // VkPhysicalDeviceDescriptorHeapPropertiesEXT reports one size per category
  // (imageDescriptorSize / bufferDescriptorSize); textures lower to
  // OpTypeImage, so image/buffer covers all relevant HLSL resource kinds. Sizes
  • Files reviewed: 53/53 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment on lines +2983 to +2989
if (isDescriptorHeap(srcExpr)) {
// Direct heap subscript: register the heap variable so the declaration
// mapper can resolve it for the return instruction.
const Expr *base = nullptr;
getDescriptorHeapOperands(srcExpr, &base, /* index= */ nullptr);
const Expr *parentExpr = cast<CastExpr>(parentMap->getParent(srcExpr));
QualType resourceType = parentExpr->getType();
Comment on lines +11120 to +11123
} else if (const auto *decl =
dyn_cast_or_null<VarDecl>(getReferencedDef(base))) {
ptr = emitDescriptorHeapImageTexelPointer(decl, coordInstr, zero,
baseType, srcLoc);

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Descriptor-stride and function-boundary cases can still produce incorrectly addressed or invalid SPIR-V.

Review details

Suppressed comments (4)

tools/clang/lib/SPIRV/SpirvBuilder.cpp:2078

  • This computes the resource stride from image and buffer sizes only, but the generic heap path also lowers RaytracingAccelerationStructure to AccelerationStructureTypeNV (LowerTypeVisitor.cpp:970-972) and routes it through this same stride. If accelerationStructureDescriptorSize exceeds both sizes, accesses use the wrong slot addresses. Include the acceleration-structure size when such descriptors are present, or reject acceleration structures on the native heap until that stride is supported.
  SpirvInstruction *imageSize = getConstantSizeOfEXT(placeholderImage);
  SpirvInstruction *bufferSize = getConstantSizeOfEXT(placeholderBuffer);
  SpirvInstruction *imageIsBigger = createSpecConstantBinaryOp(
      spv::Op::OpUGreaterThan, astContext.BoolTy, imageSize, bufferSize, {});
  resourceHeapArrayStride =
      createSpecConstantTernaryOp(spv::Op::OpSelect, astContext.UnsignedIntTy,
                                  imageIsBigger, imageSize, bufferSize, {});

tools/clang/lib/SPIRV/SpirvEmitter.cpp:2988

  • The direct-subscript branch bypasses the buffer-alias diagnostic below. For return ResourceDescriptorHeap[i] converted to StructuredBuffer, ByteAddressBuffer, ConstantBuffer, or TextureBuffer, doExpr returns a non-rvalue OpBufferPointerEXT; loadIfGLValue then attempts to load/return the whole resource representation, producing the same invalid SPIR-V that the alias branch rejects. Reject direct buffer-like heap returns here as well (or implement cross-function pointer propagation).
      if (isDescriptorHeap(srcExpr)) {
        // Direct heap subscript: register the heap variable so the declaration
        // mapper can resolve it for the return instruction.
        const Expr *base = nullptr;
        getDescriptorHeapOperands(srcExpr, &base, /* index= */ nullptr);
        const Expr *parentExpr = cast<CastExpr>(parentMap->getParent(srcExpr));

tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.image-alias-fn-param.hlsl:5

  • This XFAIL documents a valid shader that still emits invalid SPIR-V when a heap-backed RWTexture crosses a function boundary and is used atomically. The native option therefore silently produces an invalid module for a form covered by the PR's RWTexture atomic support. Propagate the descriptor index into the callee, or emit a hard unsupported diagnostic and convert this into a passing negative test rather than landing a known invalid-codegen path.
    tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.array-stride.hlsl:62
  • Use the possessive “its” here.
// The sampler array just uses the sampler size as it's stride.
  • Files reviewed: 53/53 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spirv Work related to SPIR-V

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

6 participants