Skip to content

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

Open
Jonathan Zakharov (jzakharovnv) wants to merge 17 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 17 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 2 comments.

Suppressed comments (4)

tools/clang/unittests/SPIRV/SpirvContextTest.cpp:1

  • Using integer-to-pointer reinterpret_cast in tests can be implementation-defined and may fail on platforms with non-flat pointer models (or under certain sanitizers). Since the test only needs stable distinct pointer identities, prefer deriving pointers from real storage (e.g., addresses of suitably aligned dummy storage) rather than forging small integer addresses.
    tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.image-alias-fn-param.hlsl:1
  • LIT directives like // XFAIL: are parsed, not treated as free-form comments. The second XFAIL: line reads like explanatory text rather than a valid XFAIL condition and can be mis-parsed or silently ignored depending on the harness. Keep a single valid XFAIL: directive (e.g., *), and convert the explanation into a normal comment (e.g., // Reason:) to avoid directive parsing issues.
    tools/clang/test/CodeGenSPIRV/sm6_6.descriptorheap.ext.array-stride.hlsl:62
  • Grammatically, this should be possessive 'its' rather than the contraction 'it's'.
// Every resource runtime array shares the one resource stride. 
// The sampler array just uses the sampler size as it's stride.

tools/clang/include/clang/SPIRV/SpirvInstruction.h:2286

  • This new instruction stores SSA operands but does not define a replaceOperand(...) override (unlike several other operand-bearing instructions in this PR). If the codebase relies on replaceOperand during cloning/legalization/remapping passes, adding an override here would prevent future maintenance issues and keep operand-remapping behavior consistent.
/// \brief OpSpecConstantOp instruction where the operation is ternary.
class SpirvSpecConstantTernaryOp : public SpirvInstruction {
public:
  SpirvSpecConstantTernaryOp(spv::Op specConstantOp, QualType resultType,
                             SourceLocation loc, SpirvInstruction *operand1,
                             SpirvInstruction *operand2,
                             SpirvInstruction *operand3);

  DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvSpecConstantTernaryOp)

  // For LLVM-style RTTI
  static bool classof(const SpirvInstruction *inst) {
    return inst->getKind() == IK_SpecConstantTernaryOp;
  }

  bool invokeVisitor(Visitor *v) override;

  spv::Op getSpecConstantopcode() const { return specOp; }
  SpirvInstruction *getOperand1() const { return operand1; }
  SpirvInstruction *getOperand2() const { return operand2; }
  SpirvInstruction *getOperand3() const { return operand3; }

private:
  spv::Op specOp;
  SpirvInstruction *operand1;
  SpirvInstruction *operand2;
  SpirvInstruction *operand3;
};

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

Copy link
Copy Markdown
Collaborator

All the blocker issues I had found earlier are now gone. This is ready to go. A couple of things to do beforehand:

  1. Resolve the merge conflicts so checks can run
  2. Address Chris B (@llvm-beanz)'s comment in [SPIR-V] Add SPV_EXT_descriptor_heap + SPV_KHR_untyped_pointers codegen #8517 (comment)

Gregory Roth (@pow2clk) could you please give this another look?

Building off of microsoft#8281, this commit adds a native lowering via SPV_EXT_descriptor_heap and SPV_KHR_untyped_pointers.

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 AI.
CapabilityVisitor::visitInstructionAllTypes was dropping the bool
return of requestTargetEnv, so a vk<1.3 target-env would emit the
diagnostic but keep lowering.

Added sm6_6.descriptorheap.ext.targetenv.error.hlsl to cover rejection
of -fspv-use-descriptor-heap with -fspv-target-env=vulkan1.2.

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
@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!

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