From 04fb0c2cebd954f088a2535dfdc8f803c2454952 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 2 Oct 2025 16:28:53 -0700 Subject: [PATCH] [HLSL] Preserve HLSLVkBindingAttr even if the target is not SPIR-V The attribute needs to be preserved for rewriter scenarios. Two places are updated to use the ResourceBindingAttrs helper struct to make sure the HLSLVkBindingAttr is ignored when the target is DirectX. --- clang/include/clang/AST/HLSLResource.h | 5 +++ clang/lib/Sema/SemaHLSL.cpp | 35 ++++++++----------- .../test/AST/HLSL/resource_binding_attr.hlsl | 3 +- clang/test/AST/HLSL/vk_binding_attr.hlsl | 27 ++++++-------- 4 files changed, 30 insertions(+), 40 deletions(-) diff --git a/clang/include/clang/AST/HLSLResource.h b/clang/include/clang/AST/HLSLResource.h index 9cdd81b2d8dab..7440050c7b2b9 100644 --- a/clang/include/clang/AST/HLSLResource.h +++ b/clang/include/clang/AST/HLSLResource.h @@ -69,6 +69,11 @@ struct ResourceBindingAttrs { assert(hasImplicitOrderID()); return RegBinding->getImplicitBindingOrderID(); } + + void setImplicitOrderID(unsigned Value) const { + assert(hasBinding() && !isExplicit() && !hasImplicitOrderID()); + RegBinding->setImplicitBindingOrderID(Value); + } }; } // namespace hlsl diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 129b03c07c0bd..8dd234cb5d8ec 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -598,18 +598,17 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) { validatePackoffset(SemaRef, BufDecl); - // create buffer layout struct createHostLayoutStructForBuffer(SemaRef, BufDecl); - HLSLVkBindingAttr *VkBinding = Dcl->getAttr(); - HLSLResourceBindingAttr *RBA = Dcl->getAttr(); - if (!VkBinding && (!RBA || !RBA->hasRegisterSlot())) { + // Handle implicit binding if needed. + ResourceBindingAttrs ResourceAttrs(Dcl); + if (!ResourceAttrs.isExplicit()) { SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding); // Use HLSLResourceBindingAttr to transfer implicit binding order_ID // to codegen. If it does not exist, create an implicit attribute. uint32_t OrderID = getNextImplicitBindingOrderID(); - if (RBA) - RBA->setImplicitBindingOrderID(OrderID); + if (ResourceAttrs.hasBinding()) + ResourceAttrs.setImplicitOrderID(OrderID); else addImplicitBindingAttrToDecl(SemaRef, BufDecl, BufDecl->isCBuffer() ? RegisterType::CBuffer @@ -1590,10 +1589,6 @@ void SemaHLSL::handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL) { } void SemaHLSL::handleVkBindingAttr(Decl *D, const ParsedAttr &AL) { - // The vk::binding attribute only applies to SPIR-V. - if (!getASTContext().getTargetInfo().getTriple().isSPIRV()) - return; - uint32_t Binding = 0; if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Binding)) return; @@ -3775,17 +3770,15 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { // 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()) { - HLSLResourceBindingAttr *RBA = VD->getAttr(); - if (!RBA || !RBA->hasRegisterSlot()) { - uint32_t OrderID = getNextImplicitBindingOrderID(); - if (RBA) - RBA->setImplicitBindingOrderID(OrderID); - else - addImplicitBindingAttrToDecl( - SemaRef, VD, getRegisterType(getResourceArrayHandleType(VD)), - OrderID); - } + ResourceBindingAttrs Binding(VD); + if (!Binding.isExplicit()) { + uint32_t OrderID = getNextImplicitBindingOrderID(); + if (Binding.hasBinding()) + Binding.setImplicitOrderID(OrderID); + else + addImplicitBindingAttrToDecl( + SemaRef, VD, getRegisterType(getResourceArrayHandleType(VD)), + OrderID); } } } diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl index c6d93b991fbfc..2de06741cfd46 100644 --- a/clang/test/AST/HLSL/resource_binding_attr.hlsl +++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl @@ -92,9 +92,8 @@ cbuffer CB3 { StructuredBuffer SB[10]; // CHECK: VarDecl {{.*}} SB2 'StructuredBuffer[10]' +// CHECK: HLSLVkBindingAttr {{.*}} 2 0 // DXIL: HLSLResourceBindingAttr {{.*}} Implicit -// DXIL-NOT: HLSLVkBindingAttr -// SPV: HLSLVkBindingAttr {{.*}} 2 0 // SPV-NOT: HLSLResourceBindingAttr {{.*}} Implicit [[vk::binding(2)]] StructuredBuffer SB2[10]; diff --git a/clang/test/AST/HLSL/vk_binding_attr.hlsl b/clang/test/AST/HLSL/vk_binding_attr.hlsl index d08165d7c593d..13e7544eb672c 100644 --- a/clang/test/AST/HLSL/vk_binding_attr.hlsl +++ b/clang/test/AST/HLSL/vk_binding_attr.hlsl @@ -10,8 +10,7 @@ // SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 102 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0 -// SPV: HLSLVkBindingAttr {{.*}} 23 102 -// DXIL-NOT: HLSLVkBindingAttr +// CHECK: HLSLVkBindingAttr {{.*}} 23 102 [[vk::binding(23, 102)]] StructuredBuffer Buf; // CHECK: VarDecl {{.*}} Buf2 'StructuredBuffer':'hlsl::StructuredBuffer' @@ -23,8 +22,7 @@ // SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 1 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 23 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 102 -// SPV: HLSLVkBindingAttr {{.*}} 14 1 -// DXIL-NOT: HLSLVkBindingAttr +// CHECK: HLSLVkBindingAttr {{.*}} 14 1 // CHECK: HLSLResourceBindingAttr {{.*}} "t23" "space102" [[vk::binding(14, 1)]] StructuredBuffer Buf2 : register(t23, space102); @@ -37,15 +35,13 @@ // SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 23 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 102 -// SPV: HLSLVkBindingAttr {{.*}} 14 0 -// DXIL-NOT: HLSLVkBindingAttr +// CHECK: HLSLVkBindingAttr {{.*}} 14 0 // CHECK: HLSLResourceBindingAttr {{.*}} "t23" "space102" [[vk::binding(14)]] StructuredBuffer Buf3 : register(t23, space102); // CHECK: HLSLBufferDecl {{.*}} cbuffer CB // CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer -// SPV-NEXT: HLSLVkBindingAttr {{.*}} 1 2 -// DXIL-NOT: HLSLVkBindingAttr +// CHECK: HLSLVkBindingAttr {{.*}} 1 2 [[vk::binding(1, 2)]] cbuffer CB { float a; } @@ -54,15 +50,14 @@ // CHECK-NEXT: CallExpr {{.*}} 'Buffer':'hlsl::Buffer' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'hlsl::Buffer (*)(unsigned int, unsigned int, int, unsigned int, const char *)' // SPV-NEXT: DeclRefExpr {{.*}} 'hlsl::Buffer (unsigned int, unsigned int, int, unsigned int, const char *)' -// SPV-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'Buffer (unsigned int, unsigned int, int, unsigned int, const char *)' +// SPV-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'hlsl::Buffer (unsigned int, unsigned int, int, unsigned int, const char *)' // SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 24 // SPV-NEXT: IntegerLiteral {{.*}} 'unsigned int' 103 -// DXIL-NEXT: DeclRefExpr {{.*}} 'hlsl::Buffer (unsigned int, unsigned int, int, unsigned int, const char *)' -// DXIL-NEXT-SAME: CXXMethod {{.*}} '__createFromImplicitBinding' 'Buffer (unsigned int, unsigned int, int, unsigned int, const char *)' +// DXIL-NEXT: DeclRefExpr {{.*}} 'hlsl::Buffer (unsigned int, unsigned int, int, unsigned int, const char *)' +// DXIL-NEXT-SAME: CXXMethod {{.*}} '__createFromImplicitBinding' 'hlsl::Buffer (unsigned int, unsigned int, int, unsigned int, const char *)' // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0 -// SPV: HLSLVkBindingAttr {{.*}} 24 103 -// DXIL-NOT: HLSLVkBindingAttr +// CHECK: HLSLVkBindingAttr {{.*}} 24 103 [[vk::binding(24, 103)]] Buffer Buf4; // CHECK: VarDecl {{.*}} Buf5 'RWBuffer':'hlsl::RWBuffer>' @@ -76,8 +71,7 @@ // DXIL-NEXT-SAME: CXXMethod {{.*}} '__createFromImplicitBinding' 'Buffer (unsigned int, unsigned int, int, unsigned int, const char *)' // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 3 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0 -// SPV: HLSLVkBindingAttr {{.*}} 25 104 -// DXIL-NOT: HLSLVkBindingAttr +// CHECK: HLSLVkBindingAttr {{.*}} 25 104 [[vk::binding(25, 104)]] RWBuffer Buf5; // CHECK: VarDecl {{.*}} Buf6 'RWStructuredBuffer':'hlsl::RWStructuredBuffer' @@ -91,6 +85,5 @@ // DXIL-NEXT-SAME: CXXMethod {{.*}} '__createFromBinding' 'hlsl::RWStructuredBuffer (unsigned int, unsigned int, int, unsigned int, const char *)' // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 4 // DXIL-NEXT: IntegerLiteral {{.*}} 'unsigned int' 0 -// SPV: HLSLVkBindingAttr {{.*}} 26 105 -// DXIL-NOT: HLSLVkBindingAttr +// CHECK: HLSLVkBindingAttr {{.*}} 26 105 [[vk::binding(26, 105)]] RWStructuredBuffer Buf6;