From c8220949b41c113855929d77536a94d26b6c1683 Mon Sep 17 00:00:00 2001 From: mmoult <30711895+mmoult@users.noreply.github.com> Date: Thu, 30 Jul 2026 14:29:57 -0500 Subject: [PATCH 1/5] [SPIR-V] Follow-up to #8616: exclude entry functions from function-target decoration Resolve some issues raised on the last pull request. Most notably, fix the interaction between decorations on entry points and decorations on regular functions. The pre-existing test for entry points was not specific enough to catch introduced bug. This has been amended. --- docs/ReleaseNotes.md | 4 ++++ tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | 16 ++++++---------- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 12 ++++++++++++ .../spv.intrinsicDecorate.entry.hlsl | 17 +++++++++++++++++ .../spv.intrinsicDecorate.function.error.hlsl | 16 ++++++++-------- .../inline-spirv/spv.intrinsicDecorate.hlsl | 8 +++++++- 6 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.entry.hlsl diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 915142185d..636011464b 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -68,6 +68,10 @@ first shipped in the 1.10.2605 preview. [#8281](https://github.com/microsoft/DirectXShaderCompiler/pull/8281). - Function parameters can now be decorated with inline SPIR-V [#8103](https://github.com/microsoft/DirectXShaderCompiler/issues/8103). +- Functions can now be decorated with inline SPIR-V, and + `[[vk::ext_capability]]`/`[[vk::ext_extension]]` are honored on ordinary + functions + [#8616](https://github.com/microsoft/DirectXShaderCompiler/pull/8616). - Fixed `vk::BufferPointer` cast methods [#8365](https://github.com/microsoft/DirectXShaderCompiler/pull/8365). - Fixed layout-rule propagation for `ConstantBuffer`/`TextureBuffer` function diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 3a88334ffc..67c3df41b5 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -1826,16 +1826,12 @@ SpirvFunction *DeclResultIdMapper::getOrRegisterFn(const FunctionDecl *fn) { spv::LinkageType::Export, fn->getLocation()); } - // Honor inline-SPIR-V attributes placed directly on a function. The - // entry-point path handles these only for entry functions, and the - // vk::ext_instruction path only for functions lowered to an instruction, so a - // plain function was previously skipped and these attributes silently - // dropped. These reuse the same helpers as the variable/parameter paths: - // [[vk::ext_decorate(d, ...)]] -> OpDecorate targeting the OpFunction - // [[vk::ext_capability(c)]] -> OpCapability for the module - // [[vk::ext_extension("...")]] -> OpExtension for the module - decorateWithIntrinsicAttrs(fn, spirvFunction); - registerCapabilitiesAndExtensionsForDecl(fn); + // Note: inline-SPIR-V attributes placed directly on a function + // ([[vk::ext_decorate]] / [[vk::ext_capability]] / [[vk::ext_extension]]) are + // applied in SpirvEmitter::doFunctionDecl, which excludes entry points. For an + // entry point, those attributes are consumed by the stage-variable path (they + // decorate the entry's interface variables, not its OpFunction), so they must + // not be applied to the source function here. // No need to dereference to get the pointer. Function returns that are // stand-alone aliases are already pointers to values. All other cases should diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index f05c0d9553..f5231559cf 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -1635,6 +1635,18 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) { } } + // Apply inline-SPIR-V attributes written directly on an ordinary function to + // its OpFunction: + // [[vk::ext_decorate(d, ...)]] -> OpDecorate targeting the OpFunction + // [[vk::ext_capability(c)]] -> OpCapability for the module + // [[vk::ext_extension("...")]] -> OpExtension for the module + // Entry points are excluded: their function-level attributes apply to stage- + // variables, not the OpFunction. + if (!isEntry) { + declIdMapper.decorateWithIntrinsicAttrs(decl, func); + declIdMapper.registerCapabilitiesAndExtensionsForDecl(decl); + } + if (spirvOptions.debugInfoRich) { if (srcDebugFunction) { spvContext.pushDebugLexicalScope(info, srcDebugFunction); diff --git a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.entry.hlsl b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.entry.hlsl new file mode 100644 index 0000000000..60533fe3e4 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.entry.hlsl @@ -0,0 +1,17 @@ +// RUN: %dxc -T ps_6_0 -E main -fcgl -Vd %s -spirv | FileCheck %s --implicit-check-not "OpDecorate %src_main" + +// A function-level inline-SPIR-V decoration on an *entry point* is consumed by +// the stage-variable path and applied to the entry's interface variable, not to +// the source OpFunction. (An ordinary function is handled the other way -- the +// decoration lands on its OpFunction; see spv.intrinsicDecorate.function.hlsl.) +// +// The --implicit-check-not above asserts the source function (%src_main) is +// never decorated, which is what regressed when function-target handling was +// first added and was not caught because the check below matches any target. + +// CHECK: OpDecorate %out_var_SV_Target Location 23 + +[[vk::ext_decorate(/* Location */ 30, 23)]] +float4 main() : SV_Target { + return 1.0; +} diff --git a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.function.error.hlsl b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.function.error.hlsl index 019628d34b..c209ca7d92 100644 --- a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.function.error.hlsl +++ b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.function.error.hlsl @@ -2,19 +2,19 @@ // vk::ext_decorate_id and vk::ext_decorate_string decorate a value-id target // and have no OpFunction-target form, so applying either to a function must be -// diagnosed rather than silently dropped. +// diagnosed rather than silently dropped. Both are placed on one function so a +// single compilation reports both (translation stops after the first function +// that errors, so separate functions would only surface one). -// CHECK: error: vk::ext_decorate_string is not supported on functions -[[vk::ext_decorate_string(/* UserTypeGOOGLE */ 5636, "myType")]] -[noinline] uint DecorateString(uint x) { return x; } - -// CHECK: error: vk::ext_decorate_id is not supported on functions +// CHECK-DAG: error: vk::ext_decorate_id is not supported on functions +// CHECK-DAG: error: vk::ext_decorate_string is not supported on functions [[vk::ext_decorate_id(/* UniformId */ 27, 13)]] -[noinline] uint DecorateId(uint x) { return x; } +[[vk::ext_decorate_string(/* UserTypeGOOGLE */ 5636, "myType")]] +[noinline] uint Decorated(uint x) { return x; } RWStructuredBuffer buf; [numthreads(1, 1, 1)] void main(uint3 tid : SV_DispatchThreadID) { - buf[0] = DecorateString(tid.x) + DecorateId(tid.x); + buf[0] = Decorated(tid.x); } diff --git a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl index 9e69257956..0d6618e217 100644 --- a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl +++ b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl @@ -1,4 +1,10 @@ -// RUN: %dxc -T ps_6_0 -E main -fcgl -Vd -spirv -fcgl %s -spirv | FileCheck %s +// RUN: %dxc -T ps_6_0 -E main -fcgl -Vd -spirv -fcgl %s -spirv | FileCheck %s --implicit-check-not "OpDecorate %src_main" + +// The --implicit-check-not above asserts the entry's source function is never +// decorated: its function-level [[vk::ext_decorate]] (e.g. Location 23 below) +// must land on the interface variable via the stage-variable path, not on the +// OpFunction. Without this, an errant OpDecorate %src_main went unnoticed +// because the Location check below matches any target. [[vk::ext_decorate(1, 0)]] bool b0; From 832333cd227c9402e0ddbbb8c74efb10411780c7 Mon Sep 17 00:00:00 2001 From: mmoult <30711895+mmoult@users.noreply.github.com> Date: Thu, 30 Jul 2026 14:44:15 -0500 Subject: [PATCH 2/5] Update comments Update code comments for accuracy and brevity. --- .../inline-spirv/spv.intrinsicDecorate.entry.hlsl | 9 ++++----- .../CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl | 8 +++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.entry.hlsl b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.entry.hlsl index 60533fe3e4..28536668b8 100644 --- a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.entry.hlsl +++ b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.entry.hlsl @@ -2,12 +2,11 @@ // A function-level inline-SPIR-V decoration on an *entry point* is consumed by // the stage-variable path and applied to the entry's interface variable, not to -// the source OpFunction. (An ordinary function is handled the other way -- the -// decoration lands on its OpFunction; see spv.intrinsicDecorate.function.hlsl.) +// the source OpFunction. (An ordinary function is handled in another way, see +// spv.intrinsicDecorate.function.hlsl.) // -// The --implicit-check-not above asserts the source function (%src_main) is -// never decorated, which is what regressed when function-target handling was -// first added and was not caught because the check below matches any target. +// The --implicit-check-not above asserts the source function (%src_main) was +// not decorated by the inline assembly intended for the stage variables. // CHECK: OpDecorate %out_var_SV_Target Location 23 diff --git a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl index 0d6618e217..3380d855ab 100644 --- a/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl +++ b/tools/clang/test/CodeGenSPIRV/inline-spirv/spv.intrinsicDecorate.hlsl @@ -1,10 +1,8 @@ // RUN: %dxc -T ps_6_0 -E main -fcgl -Vd -spirv -fcgl %s -spirv | FileCheck %s --implicit-check-not "OpDecorate %src_main" -// The --implicit-check-not above asserts the entry's source function is never -// decorated: its function-level [[vk::ext_decorate]] (e.g. Location 23 below) -// must land on the interface variable via the stage-variable path, not on the -// OpFunction. Without this, an errant OpDecorate %src_main went unnoticed -// because the Location check below matches any target. +// The --implicit-check-not above asserts the entry's source function is not +// decorated by [[vk::ext_decorate]] (e.g. Location 23 below) intended for the +// interface variable. [[vk::ext_decorate(1, 0)]] bool b0; From e9b7aa09511cd9ba98ec803082cda87337a7c2e7 Mon Sep 17 00:00:00 2001 From: mmoult <30711895+mmoult@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:27:42 -0500 Subject: [PATCH 3/5] Revised comments to address reviews --- tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | 8 ++++---- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 11 +++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 67c3df41b5..59730ab7ef 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -1828,10 +1828,10 @@ SpirvFunction *DeclResultIdMapper::getOrRegisterFn(const FunctionDecl *fn) { // Note: inline-SPIR-V attributes placed directly on a function // ([[vk::ext_decorate]] / [[vk::ext_capability]] / [[vk::ext_extension]]) are - // applied in SpirvEmitter::doFunctionDecl, which excludes entry points. For an - // entry point, those attributes are consumed by the stage-variable path (they - // decorate the entry's interface variables, not its OpFunction), so they must - // not be applied to the source function here. + // applied in SpirvEmitter::doFunctionDecl, which excludes entry points. For + // an entry point, those attributes are consumed by the stage-variable path + // (they decorate the entry's interface variables, not its OpFunction), so + // they must not be applied to the source function here. // No need to dereference to get the pointer. Function returns that are // stand-alone aliases are already pointers to values. All other cases should diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index f5231559cf..180d813b2b 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -1635,13 +1635,16 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) { } } - // Apply inline-SPIR-V attributes written directly on an ordinary function to - // its OpFunction: + // Apply inline-SPIR-V attributes written directly on an ordinary function: // [[vk::ext_decorate(d, ...)]] -> OpDecorate targeting the OpFunction // [[vk::ext_capability(c)]] -> OpCapability for the module // [[vk::ext_extension("...")]] -> OpExtension for the module - // Entry points are excluded: their function-level attributes apply to stage- - // variables, not the OpFunction. + // Entry points are excluded because both are already handled for them: + // - decorations: by the stage-variable path (applied to the entry's + // interface variables) + // - capabilities/extensions: by processInlineSpirvAttributes + // Doing it here would mis-target any decorations and redundantly + // re-register capabilities/extensions. if (!isEntry) { declIdMapper.decorateWithIntrinsicAttrs(decl, func); declIdMapper.registerCapabilitiesAndExtensionsForDecl(decl); From aa659ee898d27e9246301b0e5c270ac1d69ec0eb Mon Sep 17 00:00:00 2001 From: mmoult <30711895+mmoult@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:07:54 -0500 Subject: [PATCH 4/5] Move bullet in release notes to correct section Moved from Version 1.9.2607 to the upcoming preview release. --- docs/ReleaseNotes.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 636011464b..63f7a9bd90 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -41,6 +41,13 @@ first shipped in the 1.10.2605 preview. - Restricted the component types allowed in LinAlg matrices [#8608](https://github.com/microsoft/DirectXShaderCompiler/pull/8608). +#### SPIR-V + +- Functions can now be decorated with inline SPIR-V. `[[vk::ext_capability]]` + and `[[vk::ext_extension]]` are now honored on ordinary functions + [#8616](https://github.com/microsoft/DirectXShaderCompiler/pull/8616) + [#8719](https://github.com/microsoft/DirectXShaderCompiler/pull/8719). + ### Version 1.9.2607 #### HLSL Language @@ -68,10 +75,6 @@ first shipped in the 1.10.2605 preview. [#8281](https://github.com/microsoft/DirectXShaderCompiler/pull/8281). - Function parameters can now be decorated with inline SPIR-V [#8103](https://github.com/microsoft/DirectXShaderCompiler/issues/8103). -- Functions can now be decorated with inline SPIR-V, and - `[[vk::ext_capability]]`/`[[vk::ext_extension]]` are honored on ordinary - functions - [#8616](https://github.com/microsoft/DirectXShaderCompiler/pull/8616). - Fixed `vk::BufferPointer` cast methods [#8365](https://github.com/microsoft/DirectXShaderCompiler/pull/8365). - Fixed layout-rule propagation for `ConstantBuffer`/`TextureBuffer` function From c7b6d517391713811427b46c190e7e7d01ba5910 Mon Sep 17 00:00:00 2001 From: mmoult <30711895+mmoult@users.noreply.github.com> Date: Wed, 5 Aug 2026 14:26:25 -0500 Subject: [PATCH 5/5] Moved comment to the correct section Should be under "Upcoming Release" instead of "Upcoming Preview Release". This is the first bullet under the next release. --- docs/ReleaseNotes.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 63f7a9bd90..2cd92f0fb9 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -22,6 +22,13 @@ The included licenses apply to the following files: Place release notes for the upcoming release below this line and remove this line upon naming the release. Refer to previous for appropriate section names. +#### SPIR-V + +- Functions can now be decorated with inline SPIR-V. `[[vk::ext_capability]]` + and `[[vk::ext_extension]]` are now honored on ordinary functions + [#8616](https://github.com/microsoft/DirectXShaderCompiler/pull/8616) + [#8719](https://github.com/microsoft/DirectXShaderCompiler/pull/8719). + ### Upcoming Preview Release These changes apply to experimental preview shader models only and will not be @@ -41,13 +48,6 @@ first shipped in the 1.10.2605 preview. - Restricted the component types allowed in LinAlg matrices [#8608](https://github.com/microsoft/DirectXShaderCompiler/pull/8608). -#### SPIR-V - -- Functions can now be decorated with inline SPIR-V. `[[vk::ext_capability]]` - and `[[vk::ext_extension]]` are now honored on ordinary functions - [#8616](https://github.com/microsoft/DirectXShaderCompiler/pull/8616) - [#8719](https://github.com/microsoft/DirectXShaderCompiler/pull/8719). - ### Version 1.9.2607 #### HLSL Language