From c8b954825ee75105393f380c12d34e0414526318 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 6 Nov 2025 15:07:46 -0500 Subject: [PATCH 1/3] [SPIRV] Handle associated counters for RWStructuredBuffer in base classes This commit fixes an issue where the associated counters for RWStructuredBuffer were not correctly handled when the buffer was a member of a base class. The changes include: - Updating to recursively traverse base classes and nested structs to find associated counter variables. - Modifying to correctly generate instructions for accessing members of base classes. - Adding a new test case to verify the correct handling of counter variables in base classes. - Updating existing tests to reflect the changes in generation. Fixes https://github.com/microsoft/DirectXShaderCompiler/issues/7787 --- tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | 29 +++++++++++++-- tools/clang/lib/SPIRV/DeclResultIdMapper.h | 9 +---- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 30 +++++++++++---- ...ritance.base-with-byte-address-buffer.hlsl | 5 +-- .../test/CodeGenSPIRV/oo.inheritance.hlsl | 30 ++++++--------- .../oo.struct.derived.methods.override.hlsl | 27 +++++--------- ...tructured-buffer.reconstruct.bitfield.hlsl | 5 +-- ...erface.ps.inheritance.sv_clipdistance.hlsl | 5 +-- ...rwstructured-buffer.baseclass.counter.hlsl | 37 +++++++++++++++++++ 9 files changed, 113 insertions(+), 64 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index f7b1c57ad0..8002188e4a 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -1886,14 +1886,33 @@ void DeclResultIdMapper::createCounterVar( counterVars[decl] = {counterInstr, isAlias}; } +void DeclResultIdMapper::createFieldCounterVars(const DeclaratorDecl *decl) { + llvm::SmallVector indices; + const QualType type = getTypeOrFnRetType(decl); + createFieldCounterVars(decl, type, &indices); +} + void DeclResultIdMapper::createFieldCounterVars( - const DeclaratorDecl *rootDecl, const DeclaratorDecl *decl, + const DeclaratorDecl *rootDecl, const QualType type, llvm::SmallVector *indices) { - const QualType type = getTypeOrFnRetType(decl); const auto *recordType = type->getAs(); assert(recordType); const auto *recordDecl = recordType->getDecl(); + // Handle base classes first + if (const auto *cxxRecordDecl = dyn_cast(recordDecl)) { + // HLSL has at most one base class. + assert(cxxRecordDecl->getNumBases() <= 1 && + "HLSL should have at most one base class."); + if (cxxRecordDecl->getNumBases() > 0) { + const auto &base = *cxxRecordDecl->bases().begin(); + indices->push_back(0); + createFieldCounterVars(rootDecl, base.getType(), indices); + indices->pop_back(); + } + } + + // Now handle the fields of the current class (non-inherited fields) for (const auto *field : recordDecl->fields()) { // Build up the index chain indices->push_back(getNumBaseClasses(type) + field->getFieldIndex()); @@ -1902,9 +1921,11 @@ void DeclResultIdMapper::createFieldCounterVars( if (isRWAppendConsumeSBuffer(fieldType)) createCounterVar(rootDecl, /*declId=*/0, /*isAlias=*/true, indices); else if (fieldType->isStructureType() && - !hlsl::IsHLSLResourceType(fieldType)) + !hlsl::IsHLSLResourceType(fieldType)) { // Go recursively into all nested structs - createFieldCounterVars(rootDecl, field, indices); + const QualType type = getTypeOrFnRetType(field); + createFieldCounterVars(rootDecl, type, indices); + } indices->pop_back(); } diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.h b/tools/clang/lib/SPIRV/DeclResultIdMapper.h index 28502d3d9c..c942280a54 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.h +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.h @@ -912,9 +912,9 @@ class DeclResultIdMapper { /// Creates all assoicated counter variables by recursively visiting decl's /// fields. Handles AssocCounter#3 and AssocCounter#4 (see the comment of /// CounterVarFields). - inline void createFieldCounterVars(const DeclaratorDecl *decl); + void createFieldCounterVars(const DeclaratorDecl *decl); void createFieldCounterVars(const DeclaratorDecl *rootDecl, - const DeclaratorDecl *decl, + const QualType type, llvm::SmallVector *indices); /// Decorates varInstr of the given asType with proper interpolation modes @@ -1197,11 +1197,6 @@ void DeclResultIdMapper::createFnParamCounterVar(const VarDecl *param) { createCounterVarForDecl(param); } -void DeclResultIdMapper::createFieldCounterVars(const DeclaratorDecl *decl) { - llvm::SmallVector indices; - createFieldCounterVars(decl, decl, &indices); -} - } // end namespace spirv } // end namespace clang diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 7029d48d88..31210cafc9 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -4957,10 +4957,6 @@ SpirvEmitter::incDecRWACSBufferCounter(const CXXMemberCallExpr *expr, bool SpirvEmitter::tryToAssignCounterVar(const DeclaratorDecl *dstDecl, const Expr *srcExpr) { - // We are handling associated counters here. Casts should not alter which - // associated counter to manipulate. - srcExpr = srcExpr->IgnoreParenCasts(); - // For parameters of forward-declared functions. We must make sure the // associated counter variable is created. But for forward-declared functions, // the translation of the real definition may not be started yet. @@ -5061,9 +5057,10 @@ SpirvEmitter::getFinalACSBufferCounterInstruction(const Expr *expr) { llvm::SmallVector indexes; if (const auto *arraySubscriptExpr = dyn_cast(expr)) { indexes.push_back(doExpr(arraySubscriptExpr->getIdx())); - } else if (isResourceDescriptorHeap(expr->getType())) { + } else if (isResourceDescriptorHeap(expr->IgnoreParenCasts()->getType())) { const Expr *index = nullptr; - getDescriptorHeapOperands(expr, /* base= */ nullptr, &index); + getDescriptorHeapOperands(expr->IgnoreParenCasts(), /* base= */ nullptr, + &index); assert(index != nullptr && "operator[] had no indices."); indexes.push_back(doExpr(index)); } @@ -5081,9 +5078,10 @@ SpirvEmitter::getFinalACSBufferCounter(const Expr *expr) { if (const auto *decl = getReferencedDef(expr)) return declIdMapper.createOrGetCounterIdAliasPair(decl); - if (isResourceDescriptorHeap(expr->getType())) { + const Expr *expr_withoutcasts = expr->IgnoreParenCasts(); + if (isResourceDescriptorHeap(expr_withoutcasts->getType())) { const Expr *base = nullptr; - getDescriptorHeapOperands(expr, &base, /* index= */ nullptr); + getDescriptorHeapOperands(expr_withoutcasts, &base, /* index= */ nullptr); return declIdMapper.createOrGetCounterIdAliasPair(getReferencedDef(base)); } @@ -8860,7 +8858,23 @@ const Expr *SpirvEmitter::collectArrayStructIndices( return collectArrayStructIndices(subExpr, rawIndex, rawIndices, indices, isMSOutAttribute); } + } else if (castExpr->getCastKind() == CK_UncheckedDerivedToBase || + castExpr->getCastKind() == CK_HLSLDerivedToBase) { + llvm::SmallVector BaseIdx; + getBaseClassIndices(castExpr, &BaseIdx); + if (rawIndex) { + rawIndices->append(BaseIdx.begin(), BaseIdx.end()); + } else { + for (uint32_t Idx : BaseIdx) + indices->push_back(spvBuilder.getConstantInt(astContext.IntTy, + llvm::APInt(32, Idx))); + } + + return collectArrayStructIndices(castExpr->getSubExpr(), rawIndex, + rawIndices, indices, isMSOutAttribute); } + return collectArrayStructIndices(castExpr->getSubExpr(), rawIndex, + rawIndices, indices, isMSOutAttribute); } } diff --git a/tools/clang/test/CodeGenSPIRV/oo.inheritance.base-with-byte-address-buffer.hlsl b/tools/clang/test/CodeGenSPIRV/oo.inheritance.base-with-byte-address-buffer.hlsl index 2f511aba1c..a13f9f2baf 100644 --- a/tools/clang/test/CodeGenSPIRV/oo.inheritance.base-with-byte-address-buffer.hlsl +++ b/tools/clang/test/CodeGenSPIRV/oo.inheritance.base-with-byte-address-buffer.hlsl @@ -12,9 +12,8 @@ struct Base { struct Child : Base { float load(in uint offset) { -// CHECK: %param_this = OpFunctionParameter %_ptr_Function_Child -// CHECK: [[base:%[a-zA-Z0-9_]+]] = OpAccessChain %_ptr_Function_Base %param_this %uint_0 -// CHECK: [[ptrToBuffer:%[a-zA-Z0-9_]+]] = OpAccessChain %_ptr_Function__ptr_Uniform_type_ByteAddressBuffer [[base]] %int_0 +// CHECK: %param_this = OpFunctionParameter %_ptr_Function_Child +// CHECK: [[ptrToBuffer:%[a-zA-Z0-9_]+]] = OpAccessChain %_ptr_Function__ptr_Uniform_type_ByteAddressBuffer %param_this %int_0 %int_0 // This test case is mainly intended to confirm that we emit the following instruction // CHECK: [[buffer:%[a-zA-Z0-9_]+]] = OpLoad %_ptr_Uniform_type_ByteAddressBuffer [[ptrToBuffer]] diff --git a/tools/clang/test/CodeGenSPIRV/oo.inheritance.hlsl b/tools/clang/test/CodeGenSPIRV/oo.inheritance.hlsl index 8dca975ece..154e01fc6f 100644 --- a/tools/clang/test/CodeGenSPIRV/oo.inheritance.hlsl +++ b/tools/clang/test/CodeGenSPIRV/oo.inheritance.hlsl @@ -28,8 +28,7 @@ float4 main() : SV_Target { Derived d; // Accessing a field from the implicit base object -// CHECK: [[base:%[0-9]+]] = OpAccessChain %_ptr_Function_Base %d %uint_0 -// CHECK-NEXT: [[base_a:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[base]] %int_0 +// CHECK: [[base_a:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %d %int_0 %int_0 // CHECK-NEXT: OpStore [[base_a]] {{%[0-9]+}} d.a = 1.; @@ -54,13 +53,11 @@ float4 main() : SV_Target { DerivedAgain dd; // Accessing a field from the deep implicit base object -// CHECK-NEXT: [[base_0:%[0-9]+]] = OpAccessChain %_ptr_Function_Base %dd %uint_0 %uint_0 -// CHECK-NEXT: [[base_a_0:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[base_0]] %int_0 +// CHECK-NEXT: [[base_a_0:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %dd %int_0 %int_0 %int_0 // CHECK-NEXT: OpStore [[base_a_0]] {{%[0-9]+}} dd.a = 6.; // Accessing a field from the immediate implicit base object -// CHECK-NEXT: [[drv:%[0-9]+]] = OpAccessChain %_ptr_Function_Derived %dd %uint_0 -// CHECK-NEXT: [[drv_b:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[drv]] %int_1 +// CHECK-NEXT: [[drv_b:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %dd %int_0 %int_1 // CHECK-NEXT: OpStore [[drv_b]] {{%[0-9]+}} dd.b = 7.; // Accessing fields from the derived object (shadowing) @@ -87,18 +84,15 @@ float4 main() : SV_Target { (Base)dd2 = (Base)d; // Make sure reads are good -// CHECK: [[base_1:%[0-9]+]] = OpAccessChain %_ptr_Function_Base %d %uint_0 -// CHECK-NEXT: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float [[base_1]] %int_0 -// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_1 -// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_2 -// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_3 %int_0 -// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_3 %int_1 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_0 %int_0 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_1 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_2 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_3 %int_0 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %d %int_3 %int_1 return d.a + d.b + d.c + d.x.a + d.x.b + -// CHECK: [[base_2:%[0-9]+]] = OpAccessChain %_ptr_Function_Base %dd %uint_0 %uint_0 -// CHECK-NEXT: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float [[base_2]] %int_0 -// CHECK: [[drv_0:%[0-9]+]] = OpAccessChain %_ptr_Function_Derived %dd %uint_0 -// CHECK-NEXT: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float [[drv_0]] %int_1 -// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %dd %int_1 -// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %dd %int_2 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %dd %int_0 %int_0 %int_0 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %dd %int_0 %int_1 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %dd %int_1 +// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_Function_v4float %dd %int_2 dd.a + dd.b + dd.c + dd.d; } diff --git a/tools/clang/test/CodeGenSPIRV/oo.struct.derived.methods.override.hlsl b/tools/clang/test/CodeGenSPIRV/oo.struct.derived.methods.override.hlsl index 87fc6f9463..53a0ff7b3a 100644 --- a/tools/clang/test/CodeGenSPIRV/oo.struct.derived.methods.override.hlsl +++ b/tools/clang/test/CodeGenSPIRV/oo.struct.derived.methods.override.hlsl @@ -28,8 +28,7 @@ struct C : B { float4 main() : SV_Target { B b; -// CHECK: [[A_ptr:%[0-9]+]] = OpAccessChain %_ptr_Function_A %b %uint_0 -// CHECK: [[base_ptr:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[A_ptr]] %int_0 +// CHECK: [[base_ptr:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %b %int_0 %int_0 // CHECK: OpStore [[base_ptr]] {{%[0-9]+}} b.base = float4(1, 1, 0, 1); // CHECK: [[derived_ptr:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %b %int_1 @@ -42,12 +41,10 @@ float4 main() : SV_Target { b.SetDerived(float4(1, 0, 1, 1)); C c; -// CHECK: [[A_ptr_0:%[0-9]+]] = OpAccessChain %_ptr_Function_A %c %uint_0 %uint_0 -// CHECK: [[base_ptr_0:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[A_ptr_0]] %int_0 +// CHECK: [[base_ptr_0:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %c %int_0 %int_0 %int_0 // CHECK: OpStore [[base_ptr_0]] {{%[0-9]+}} c.base = float4(0,0,0,0); -// CHECK: [[B_ptr:%[0-9]+]] = OpAccessChain %_ptr_Function_B %c %uint_0 -// CHECK: [[derived_ptr_0:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[B_ptr]] %int_1 +// CHECK: [[derived_ptr_0:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %c %int_0 %int_1 // CHECK: OpStore [[derived_ptr_0]] {{%[0-9]+}} c.derived = float4(0,0,0,0); // CHECK: [[c_value_ptr:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %c %int_1 @@ -76,8 +73,7 @@ float4 main() : SV_Target { // CHECK-NEXT: %v = OpFunctionParameter %_ptr_Function_v4float // CHECK-NEXT: %bb_entry_0 = OpLabel // CHECK-NEXT: [[v:%[0-9]+]] = OpLoad %v4float %v -// CHECK-NEXT: [[A_ptr_1:%[0-9]+]] = OpAccessChain %_ptr_Function_A %param_this %uint_0 -// CHECK-NEXT: [[base_ptr_1:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[A_ptr_1]] %int_0 +// CHECK-NEXT: [[base_ptr_1:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %param_this %int_0 %int_0 // CHECK-NEXT: OpStore [[base_ptr_1]] [[v]] // CHECK-NEXT: OpReturn // CHECK-NEXT: OpFunctionEnd @@ -100,8 +96,7 @@ float4 main() : SV_Target { // CHECK-NEXT: %v_1 = OpFunctionParameter %_ptr_Function_v4float // CHECK-NEXT: %bb_entry_2 = OpLabel // CHECK-NEXT: [[v_1:%[0-9]+]] = OpLoad %v4float %v_1 -// CHECK-NEXT: [[A_ptr_2:%[0-9]+]] = OpAccessChain %_ptr_Function_A %param_this_1 %uint_0 %uint_0 -// CHECK-NEXT: [[base_ptr_2:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[A_ptr_2]] %int_0 +// CHECK-NEXT: [[base_ptr_2:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %param_this_1 %int_0 %int_0 %int_0 // CHECK-NEXT: OpStore [[base_ptr_2]] [[v_1]] // CHECK-NEXT: OpReturn // CHECK-NEXT: OpFunctionEnd @@ -112,8 +107,7 @@ float4 main() : SV_Target { // CHECK-NEXT: %v_2 = OpFunctionParameter %_ptr_Function_v4float // CHECK-NEXT: %bb_entry_3 = OpLabel // CHECK-NEXT: [[v_2:%[0-9]+]] = OpLoad %v4float %v_2 -// CHECK-NEXT: [[B_ptr_0:%[0-9]+]] = OpAccessChain %_ptr_Function_B %param_this_2 %uint_0 -// CHECK-NEXT: [[derived_ptr_2:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[B_ptr_0]] %int_1 +// CHECK-NEXT: [[derived_ptr_2:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %param_this_2 %int_0 %int_1 // CHECK-NEXT: OpStore [[derived_ptr_2]] [[v_2]] // CHECK-NEXT: OpReturn // CHECK-NEXT: OpFunctionEnd @@ -133,8 +127,7 @@ float4 main() : SV_Target { // CHECK: %B_GetBase = OpFunction // CHECK-NEXT: %param_this_4 = OpFunctionParameter %_ptr_Function_B // CHECK-NEXT: %bb_entry_5 = OpLabel -// CHECK-NEXT: [[A_ptr_3:%[0-9]+]] = OpAccessChain %_ptr_Function_A %param_this_4 %uint_0 -// CHECK-NEXT: [[base_ptr_3:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[A_ptr_3]] %int_0 +// CHECK-NEXT: [[base_ptr_3:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %param_this_4 %int_0 %int_0 // CHECK-NEXT: [[base:%[0-9]+]] = OpLoad %v4float [[base_ptr_3]] // CHECK-NEXT: OpReturnValue [[base]] // CHECK-NEXT: OpFunctionEnd @@ -152,8 +145,7 @@ float4 main() : SV_Target { // CHECK: %C_GetBase = OpFunction // CHECK-NEXT: %param_this_6 = OpFunctionParameter %_ptr_Function_C // CHECK-NEXT: %bb_entry_7 = OpLabel -// CHECK-NEXT: [[A_ptr_4:%[0-9]+]] = OpAccessChain %_ptr_Function_A %param_this_6 %uint_0 %uint_0 -// CHECK-NEXT: [[base_ptr_4:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[A_ptr_4]] %int_0 +// CHECK-NEXT: [[base_ptr_4:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %param_this_6 %int_0 %int_0 %int_0 // CHECK-NEXT: [[base_0:%[0-9]+]] = OpLoad %v4float [[base_ptr_4]] // CHECK-NEXT: OpReturnValue [[base_0]] // CHECK-NEXT: OpFunctionEnd @@ -162,8 +154,7 @@ float4 main() : SV_Target { // CHECK: %C_GetDerived = OpFunction // CHECK-NEXT: %param_this_7 = OpFunctionParameter %_ptr_Function_C // CHECK-NEXT: %bb_entry_8 = OpLabel -// CHECK-NEXT: [[B_ptr_1:%[0-9]+]] = OpAccessChain %_ptr_Function_B %param_this_7 %uint_0 -// CHECK-NEXT: [[derived_ptr_4:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float [[B_ptr_1]] %int_1 +// CHECK-NEXT: [[derived_ptr_4:%[0-9]+]] = OpAccessChain %_ptr_Function_v4float %param_this_7 %int_0 %int_1 // CHECK-NEXT: [[derived_0:%[0-9]+]] = OpLoad %v4float [[derived_ptr_4]] // CHECK-NEXT: OpReturnValue [[derived_0]] // CHECK-NEXT: OpFunctionEnd diff --git a/tools/clang/test/CodeGenSPIRV/op.structured-buffer.reconstruct.bitfield.hlsl b/tools/clang/test/CodeGenSPIRV/op.structured-buffer.reconstruct.bitfield.hlsl index 49d982b645..3e1a1b3493 100644 --- a/tools/clang/test/CodeGenSPIRV/op.structured-buffer.reconstruct.bitfield.hlsl +++ b/tools/clang/test/CodeGenSPIRV/op.structured-buffer.reconstruct.bitfield.hlsl @@ -19,9 +19,8 @@ void main(uint3 dispatchThreadId : SV_DispatchThreadID) { // CHECK: [[p:%[a-zA-Z0-9_]+]] = OpVariable %_ptr_Function_Derived_0 Function Derived p; -// CHECK: [[tmp:%[0-9]+]] = OpAccessChain %_ptr_Function_Base_0 [[p]] %uint_0 -// CHECK: [[tmp_0:%[0-9]+]] = OpAccessChain %_ptr_Function_uint [[tmp]] %int_0 -// CHECK: OpStore [[tmp_0]] %uint_5 +// CHECK: [[tmp:%[0-9]+]] = OpAccessChain %_ptr_Function_uint [[p]] %int_0 %int_0 +// CHECK: OpStore [[tmp]] %uint_5 p.base = 5; // CHECK: [[tmp_1:%[0-9]+]] = OpAccessChain %_ptr_Function_uint [[p]] %int_1 diff --git a/tools/clang/test/CodeGenSPIRV/spirv.interface.ps.inheritance.sv_clipdistance.hlsl b/tools/clang/test/CodeGenSPIRV/spirv.interface.ps.inheritance.sv_clipdistance.hlsl index b144ef46a2..15046f4a6d 100644 --- a/tools/clang/test/CodeGenSPIRV/spirv.interface.ps.inheritance.sv_clipdistance.hlsl +++ b/tools/clang/test/CodeGenSPIRV/spirv.interface.ps.inheritance.sv_clipdistance.hlsl @@ -16,9 +16,8 @@ float main(PSInput input) : SV_TARGET // CHECK: [[input:%[0-9]+]] = OpCompositeConstruct %PSInput [[parent]] -// CHECK: [[access0:%[0-9]+]] = OpAccessChain %_ptr_Function_Parent %input %uint_0 -// CHECK: [[access1:%[0-9]+]] = OpAccessChain %_ptr_Function_float [[access0]] %int_0 -// CHECK: [[load1:%[0-9]+]] = OpLoad %float [[access1]] +// CHECK: [[access:%[0-9]+]] = OpAccessChain %_ptr_Function_float %input %int_0 %int_0 +// CHECK: [[load1:%[0-9]+]] = OpLoad %float [[access]] return input.clipDistance; } diff --git a/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl b/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl new file mode 100644 index 0000000000..03f521c43d --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl @@ -0,0 +1,37 @@ +// RUN: %dxc -T cs_6_6 -E main %s -spirv 2>&1 | FileCheck %s + +RWStructuredBuffer Buf1; +RWStructuredBuffer Buf2; + +struct A +{ + RWStructuredBuffer Buffer; + + void setBuffer(RWStructuredBuffer value) + { + Buffer = value; + } + + void Increment() { Buffer.IncrementCounter(); } +}; + +struct B : A {}; +struct C : B {}; + +[numthreads(64, 1, 1)] +void main() +{ + B b; + b.Buffer = Buf1; + + C c; + c.Buffer = Buf2; + +// CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_Buf1 %uint_0 +// CHECK: OpAtomicIAdd %int [[ac]] %uint_1 %uint_0 %int_1 + b.Increment(); + +// CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_Buf2 %uint_0 +// CHECK: %18 = OpAtomicIAdd %int [[ac]] %uint_1 %uint_0 %int_1 + c.Increment(); +} From c9d77a75f8ea062c29695368961c6046698248b6 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Fri, 7 Nov 2025 09:27:44 -0500 Subject: [PATCH 2/3] Fix test formatting. --- ...rwstructured-buffer.baseclass.counter.hlsl | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl b/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl index 03f521c43d..aea11502c2 100644 --- a/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl +++ b/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl @@ -5,13 +5,7 @@ RWStructuredBuffer Buf2; struct A { - RWStructuredBuffer Buffer; - - void setBuffer(RWStructuredBuffer value) - { - Buffer = value; - } - + RWStructuredBuffer Buffer; void Increment() { Buffer.IncrementCounter(); } }; @@ -21,17 +15,17 @@ struct C : B {}; [numthreads(64, 1, 1)] void main() { - B b; - b.Buffer = Buf1; + B b; + b.Buffer = Buf1; - C c; - c.Buffer = Buf2; + C c; + c.Buffer = Buf2; -// CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_Buf1 %uint_0 -// CHECK: OpAtomicIAdd %int [[ac]] %uint_1 %uint_0 %int_1 - b.Increment(); + // CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_Buf1 %uint_0 + // CHECK: OpAtomicIAdd %int [[ac]] %uint_1 %uint_0 %int_1 + b.Increment(); -// CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_Buf2 %uint_0 -// CHECK: %18 = OpAtomicIAdd %int [[ac]] %uint_1 %uint_0 %int_1 - c.Increment(); + // CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_Buf2 %uint_0 + // CHECK: %18 = OpAtomicIAdd %int [[ac]] %uint_1 %uint_0 %int_1 + c.Increment(); } From 500c1acf5f0f539b78aa0b3be5800657419dbeaa Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 13 Nov 2025 10:58:03 -0500 Subject: [PATCH 3/3] Add fix for classes. --- tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | 2 +- .../test/CodeGenSPIRV/class-with-counter.hlsl | 29 +++++++++++++++++++ ...rwstructured-buffer.baseclass.counter.hlsl | 2 +- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/class-with-counter.hlsl diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 8002188e4a..33593e3f85 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -1089,7 +1089,7 @@ void DeclResultIdMapper::createCounterVarForDecl(const DeclaratorDecl *decl) { if (!counterVars.count(decl) && isRWAppendConsumeSBuffer(declType)) { createCounterVar(decl, /*declId=*/0, /*isAlias=*/true); - } else if (!fieldCounterVars.count(decl) && declType->isStructureType() && + } else if (!fieldCounterVars.count(decl) && declType->isRecordType() && // Exclude other resource types which are represented as structs !hlsl::IsHLSLResourceType(declType)) { createFieldCounterVars(decl); diff --git a/tools/clang/test/CodeGenSPIRV/class-with-counter.hlsl b/tools/clang/test/CodeGenSPIRV/class-with-counter.hlsl new file mode 100644 index 0000000000..2cce4de020 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/class-with-counter.hlsl @@ -0,0 +1,29 @@ +// RUN: %dxc -T cs_6_8 -E main %s -spirv -fspv-target-env=vulkan1.3 | FileCheck %s + +class A { + RWStructuredBuffer a; +}; + +class B : A { + RWStructuredBuffer b; +}; + +RWStructuredBuffer input; +RWStructuredBuffer output; + +[numthreads(1, 1, 1)] +void main() +{ + B x; + + // CHECK: [[val1_ptr:%[a-zA-Z0-9_]+]] = OpAccessChain %_ptr_StorageBuffer_uint %input %int_0 %uint_1 + // CHECK-NEXT: [[val1:%[a-zA-Z0-9_]+]] = OpLoad %uint [[val1_ptr]] + // CHECK-NEXT: [[val2_ptr:%[a-zA-Z0-9_]+]] = OpAccessChain %_ptr_StorageBuffer_uint %output %int_0 %uint_2 + // CHECK-NEXT: [[val2:%[a-zA-Z0-9_]+]] = OpLoad %uint [[val2_ptr]] + // CHECK-NEXT: [[add_res:%[a-zA-Z0-9_]+]] = OpIAdd %uint [[val1]] [[val2]] + // CHECK-NEXT: [[target_ptr:%[a-zA-Z0-9_]+]] = OpAccessChain %_ptr_StorageBuffer_uint %output %int_0 %uint_0 + // CHECK-NEXT: OpStore [[target_ptr]] [[add_res]] + x.a = input; + x.b = output; + output[0] = x.a[1] + x.b[2]; +} diff --git a/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl b/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl index aea11502c2..70d867dcb7 100644 --- a/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl +++ b/tools/clang/test/CodeGenSPIRV/type.rwstructured-buffer.baseclass.counter.hlsl @@ -26,6 +26,6 @@ void main() b.Increment(); // CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_Buf2 %uint_0 - // CHECK: %18 = OpAtomicIAdd %int [[ac]] %uint_1 %uint_0 %int_1 + // CHECK: OpAtomicIAdd %int [[ac]] %uint_1 %uint_0 %int_1 c.Increment(); }