https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/152452
>From 4e153a4da8b990a1d07d6d1d63d2be74ed45e2eb Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Thu, 7 Aug 2025 00:37:23 -0700 Subject: [PATCH 1/2] [HLSL] Add implicit binding attribute to resource arrays without binding and make them static If a resource array does not have an explicit binding attribute, SemaHLSL will add an implicit one. The attribute will be used to transfer implicit binding order ID to the codegen, the same way as it is done for HLSLBufferDecls. This is necessary in order to generate correct initialization of resources in an array that does not have an explicit binding. This change also marks resource arrays declared at a global scope as `static`, which is what is already done for standalone resources. --- clang/lib/Sema/SemaHLSL.cpp | 57 +++++++++++++++---- .../test/AST/HLSL/resource_binding_attr.hlsl | 28 +++++++-- 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 873efdae38f18..ffb996e79409c 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -71,6 +71,10 @@ static RegisterType getRegisterType(ResourceClass RC) { llvm_unreachable("unexpected ResourceClass value"); } +static RegisterType getRegisterType(const HLSLAttributedResourceType *ResTy) { + return getRegisterType(ResTy->getAttrs().ResourceClass); +} + // Converts the first letter of string Slot to RegisterType. // Returns false if the letter does not correspond to a valid register type. static bool convertToRegisterType(StringRef Slot, RegisterType *RT) { @@ -342,6 +346,17 @@ static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) { return Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray(); } +static const HLSLAttributedResourceType * +getResourceArrayHandleType(VarDecl *VD) { + assert(VD->getType()->isHLSLResourceRecordArray() && + "expected array of resource records"); + const Type *Ty = VD->getType()->getUnqualifiedDesugaredType(); + while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) { + Ty = CAT->getArrayElementTypeNoTypeQual()->getUnqualifiedDesugaredType(); + } + return HLSLAttributedResourceType::findHandleTypeOnResource(Ty); +} + // Returns true if the type is a leaf element type that is not valid to be // included in HLSL Buffer, such as a resource class, empty struct, zero-sized // array, or a builtin intangible type. Returns false it is a valid leaf element @@ -568,16 +583,13 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) { BufDecl->addLayoutStruct(LS); } -static void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl, - uint32_t ImplicitBindingOrderID) { - RegisterType RT = - BufDecl->isCBuffer() ? RegisterType::CBuffer : RegisterType::SRV; +static void addImplicitBindingAttrToDecl(Sema &S, Decl *D, RegisterType RT, + uint32_t ImplicitBindingOrderID) { auto *Attr = HLSLResourceBindingAttr::CreateImplicit(S.getASTContext(), "", "0", {}); - std::optional<unsigned> RegSlot; - Attr->setBinding(RT, RegSlot, 0); + Attr->setBinding(RT, std::nullopt, 0); Attr->setImplicitBindingOrderID(ImplicitBindingOrderID); - BufDecl->addAttr(Attr); + D->addAttr(Attr); } // Handle end of cbuffer/tbuffer declaration @@ -600,7 +612,10 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) { if (RBA) RBA->setImplicitBindingOrderID(OrderID); else - addImplicitBindingAttrToBuffer(SemaRef, BufDecl, OrderID); + addImplicitBindingAttrToDecl(SemaRef, BufDecl, + BufDecl->isCBuffer() ? RegisterType::CBuffer + : RegisterType::SRV, + OrderID); } SemaRef.PopDeclContext(); @@ -1906,7 +1921,7 @@ static bool DiagnoseLocalRegisterBinding(Sema &S, SourceLocation &ArgLoc, if (const HLSLAttributedResourceType *AttrResType = HLSLAttributedResourceType::findHandleTypeOnResource( VD->getType().getTypePtr())) { - if (RegType == getRegisterType(AttrResType->getAttrs().ResourceClass)) + if (RegType == getRegisterType(AttrResType)) return true; S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch) @@ -2439,8 +2454,8 @@ void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) { HLSLBufferDecl *DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer( SemaRef.getASTContext(), SemaRef.getCurLexicalContext(), DefaultCBufferDecls); - addImplicitBindingAttrToBuffer(SemaRef, DefaultCBuffer, - getNextImplicitBindingOrderID()); + addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, RegisterType::CBuffer, + getNextImplicitBindingOrderID()); SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer); createHostLayoutStructForBuffer(SemaRef, DefaultCBuffer); @@ -3633,7 +3648,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { const Type *VarType = VD->getType().getTypePtr(); while (VarType->isArrayType()) VarType = VarType->getArrayElementTypeNoTypeQual(); - if (VarType->isHLSLResourceRecord() || + if (isResourceRecordTypeOrArrayOf(VD) || VD->hasAttr<HLSLVkConstantIdAttr>()) { // Make the variable for resources static. The global externally visible // storage is accessed through the handle, which is a member. The variable @@ -3643,6 +3658,24 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { // process explicit bindings processExplicitBindingsOnDecl(VD); + + if (VD->getType()->isHLSLResourceRecordArray()) { + // If the resource array does not have an explicit binding attribute, + // create an implicit one. It will be used to transfer implicit binding + // order_ID to codegen. + if (!VD->hasAttr<HLSLVkBindingAttr>()) { + HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>(); + if (!RBA || !RBA->hasRegisterSlot()) { + uint32_t OrderID = getNextImplicitBindingOrderID(); + if (RBA) + RBA->setImplicitBindingOrderID(OrderID); + else + addImplicitBindingAttrToDecl( + SemaRef, VD, getRegisterType(getResourceArrayHandleType(VD)), + OrderID); + } + } + } } deduceAddressSpace(VD); diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl index c073cd4dc1476..e8e79e44b8f0c 100644 --- a/clang/test/AST/HLSL/resource_binding_attr.hlsl +++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl @@ -20,20 +20,24 @@ export float foo() { return a + b; } -// CHECK: VarDecl {{.*}} UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>' +// CHECK: VarDecl {{.*}} UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>' static // CHECK: HLSLResourceBindingAttr {{.*}} "u3" "space0" RWBuffer<float> UAV : register(u3); -// CHECK: VarDecl {{.*}} UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>' +// CHECK: VarDecl {{.*}} UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>' static // CHECK: HLSLResourceBindingAttr {{.*}} "u2" "space0" -// CHECK: VarDecl {{.*}} UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>' +// CHECK: VarDecl {{.*}} UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>' static // CHECK: HLSLResourceBindingAttr {{.*}} "u4" "space0" RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4); -// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>' +// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>' static // CHECK: HLSLResourceBindingAttr {{.*}} "" "space5" RWBuffer<float> UAV3 : register(space5); +// CHECK: VarDecl {{.*}} UAV_Array 'RWBuffer<float>[10]' static +// CHECK: HLSLResourceBindingAttr {{.*}} "u10" "space6" +RWBuffer<float> UAV_Array[10] : register(u10, space6); + // // Default constants ($Globals) layout annotations @@ -56,3 +60,19 @@ struct S { // CHECK: VarDecl {{.*}} s 'hlsl_constant S' // CHECK: HLSLResourceBindingAttr {{.*}} "c10" "space0 S s : register(c10); + +// +// Implicit binding + +// Constant buffers should have implicit binding attribute added by SemaHLSL +// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB2 +// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer +// CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0" +cbuffer CB2 { + float4 c; +} + +// Resource arrays should have implicit binding attribute added by SemaHLSL +// CHECK: VarDecl {{.*}} SB 'StructuredBuffer<float>[10]' static +// CHECK: HLSLResourceBindingAttr {{.*}} Implicit "" "0" +StructuredBuffer<float> SB[10]; >From e12a7a97db2e4abb25c31eda5f77e86bd8b8aa03 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Thu, 7 Aug 2025 01:17:55 -0700 Subject: [PATCH 2/2] update test --- clang/test/AST/HLSL/resource_binding_attr.hlsl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl index e8e79e44b8f0c..05d5eb0d619d8 100644 --- a/clang/test/AST/HLSL/resource_binding_attr.hlsl +++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl @@ -20,21 +20,21 @@ export float foo() { return a + b; } -// CHECK: VarDecl {{.*}} UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>' static +// CHECK: VarDecl {{.*}} UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>' // CHECK: HLSLResourceBindingAttr {{.*}} "u3" "space0" RWBuffer<float> UAV : register(u3); -// CHECK: VarDecl {{.*}} UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>' static +// CHECK: VarDecl {{.*}} UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>' // CHECK: HLSLResourceBindingAttr {{.*}} "u2" "space0" -// CHECK: VarDecl {{.*}} UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>' static +// CHECK: VarDecl {{.*}} UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>' // CHECK: HLSLResourceBindingAttr {{.*}} "u4" "space0" RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4); -// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>' static +// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>' // CHECK: HLSLResourceBindingAttr {{.*}} "" "space5" RWBuffer<float> UAV3 : register(space5); -// CHECK: VarDecl {{.*}} UAV_Array 'RWBuffer<float>[10]' static +// CHECK: VarDecl {{.*}} UAV_Array 'RWBuffer<float>[10]' // CHECK: HLSLResourceBindingAttr {{.*}} "u10" "space6" RWBuffer<float> UAV_Array[10] : register(u10, space6); @@ -73,6 +73,6 @@ cbuffer CB2 { } // Resource arrays should have implicit binding attribute added by SemaHLSL -// CHECK: VarDecl {{.*}} SB 'StructuredBuffer<float>[10]' static +// CHECK: VarDecl {{.*}} SB 'StructuredBuffer<float>[10]' // CHECK: HLSLResourceBindingAttr {{.*}} Implicit "" "0" StructuredBuffer<float> SB[10]; _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits