Skip to content

Commit b6dfa3d

Browse files
authored
[HLSL][NFC] Add helper struct to simplify dealing with resource binding attributes (#161254)
Add new `ResourceBindingAttrs` struct that holds resource binding attributes `HLSLResourceBindingAttr` and `HLSLVkBindingAttr` and provides helper methods to simplify dealing with resource bindings. This code is placed in the AST library to be shared between Sema and CodeGen. This change has been done in preparation of a third binding attribute coming soon to represent `[[vk::counter_binding()]]`. This new attribute and more helper member functions will be added to `ResourceBindingAttrs` and will be used in both Sema and in CodeGen to implement resource counter initialization.
1 parent ca84f2a commit b6dfa3d

File tree

4 files changed

+118
-89
lines changed

4 files changed

+118
-89
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===- HLSLResource.h - Routines for HLSL resources and bindings ----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file provides shared routines to help analyze HLSL resources and
10+
// theirs bindings during Sema and CodeGen.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CLANG_AST_HLSLRESOURCE_H
15+
#define LLVM_CLANG_AST_HLSLRESOURCE_H
16+
17+
#include "clang/AST/ASTContext.h"
18+
#include "clang/AST/Attrs.inc"
19+
#include "clang/AST/DeclBase.h"
20+
#include "clang/Basic/TargetInfo.h"
21+
22+
namespace clang {
23+
24+
class HLSLResourceBindingAttr;
25+
class HLSLRVkBindingAttr;
26+
27+
namespace hlsl {
28+
29+
struct ResourceBindingAttrs {
30+
HLSLResourceBindingAttr *RegBinding;
31+
HLSLVkBindingAttr *VkBinding;
32+
33+
ResourceBindingAttrs(const Decl *D) {
34+
RegBinding = D->getAttr<HLSLResourceBindingAttr>();
35+
bool IsSpirv = D->getASTContext().getTargetInfo().getTriple().isSPIRV();
36+
VkBinding = IsSpirv ? D->getAttr<HLSLVkBindingAttr>() : nullptr;
37+
}
38+
39+
bool hasBinding() const { return RegBinding || VkBinding; }
40+
bool isExplicit() const {
41+
return (RegBinding && RegBinding->hasRegisterSlot()) || VkBinding;
42+
}
43+
44+
unsigned getSlot() const {
45+
assert(isExplicit() && "no explicit binding");
46+
if (VkBinding)
47+
return VkBinding->getBinding();
48+
if (RegBinding && RegBinding->hasRegisterSlot())
49+
return RegBinding->getSlotNumber();
50+
llvm_unreachable("no explicit binding");
51+
}
52+
53+
unsigned getSpace() const {
54+
if (VkBinding)
55+
return VkBinding->getSet();
56+
if (RegBinding)
57+
return RegBinding->getSpaceNumber();
58+
return 0;
59+
}
60+
61+
bool hasImplicitOrderID() const {
62+
return RegBinding && RegBinding->hasImplicitBindingOrderID();
63+
}
64+
65+
unsigned getImplicitOrderID() const {
66+
assert(hasImplicitOrderID());
67+
return RegBinding->getImplicitBindingOrderID();
68+
}
69+
};
70+
71+
} // namespace hlsl
72+
73+
} // namespace clang
74+
75+
#endif // LLVM_CLANG_AST_HLSLRESOURCE_H

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 31 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "clang/AST/ASTContext.h"
2222
#include "clang/AST/Attrs.inc"
2323
#include "clang/AST/Decl.h"
24+
#include "clang/AST/HLSLResource.h"
2425
#include "clang/AST/RecursiveASTVisitor.h"
2526
#include "clang/AST/Type.h"
2627
#include "clang/Basic/TargetOptions.h"
@@ -131,35 +132,24 @@ static CXXMethodDecl *lookupMethod(CXXRecordDecl *Record, StringRef Name,
131132

132133
static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
133134
CodeGenModule &CGM, CXXRecordDecl *ResourceDecl, llvm::Value *Range,
134-
llvm::Value *Index, StringRef Name, HLSLResourceBindingAttr *RBA,
135-
HLSLVkBindingAttr *VkBinding, CallArgList &Args) {
136-
assert((VkBinding || RBA) && "at least one a binding attribute expected");
135+
llvm::Value *Index, StringRef Name, ResourceBindingAttrs &Binding,
136+
CallArgList &Args) {
137+
assert(Binding.hasBinding() && "at least one binding attribute expected");
137138

138139
ASTContext &AST = CGM.getContext();
139-
std::optional<uint32_t> RegisterSlot;
140-
uint32_t SpaceNo = 0;
141-
if (VkBinding) {
142-
RegisterSlot = VkBinding->getBinding();
143-
SpaceNo = VkBinding->getSet();
144-
} else {
145-
if (RBA->hasRegisterSlot())
146-
RegisterSlot = RBA->getSlotNumber();
147-
SpaceNo = RBA->getSpaceNumber();
148-
}
149-
150140
CXXMethodDecl *CreateMethod = nullptr;
151141
Value *NameStr = buildNameForResource(Name, CGM);
152-
Value *Space = llvm::ConstantInt::get(CGM.IntTy, SpaceNo);
142+
Value *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
153143

154-
if (RegisterSlot.has_value()) {
144+
if (Binding.isExplicit()) {
155145
// explicit binding
156-
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RegisterSlot.value());
146+
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
157147
Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
158148
CreateMethod = lookupMethod(ResourceDecl, "__createFromBinding", SC_Static);
159149
} else {
160150
// implicit binding
161151
auto *OrderID =
162-
llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID());
152+
llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
163153
Args.add(RValue::get(OrderID), AST.UnsignedIntTy);
164154
CreateMethod =
165155
lookupMethod(ResourceDecl, "__createFromImplicitBinding", SC_Static);
@@ -194,8 +184,8 @@ static std::optional<llvm::Value *> initializeLocalResourceArray(
194184
CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl,
195185
const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot,
196186
llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
197-
HLSLResourceBindingAttr *RBA, HLSLVkBindingAttr *VkBinding,
198-
ArrayRef<llvm::Value *> PrevGEPIndices, SourceLocation ArraySubsExprLoc) {
187+
ResourceBindingAttrs &Binding, ArrayRef<llvm::Value *> PrevGEPIndices,
188+
SourceLocation ArraySubsExprLoc) {
199189

200190
ASTContext &AST = CGF.getContext();
201191
llvm::IntegerType *IntTy = CGF.CGM.IntTy;
@@ -220,7 +210,7 @@ static std::optional<llvm::Value *> initializeLocalResourceArray(
220210
}
221211
std::optional<llvm::Value *> MaybeIndex = initializeLocalResourceArray(
222212
CGF, ResourceDecl, SubArrayTy, ValueSlot, Range, Index, ResourceName,
223-
RBA, VkBinding, GEPIndices, ArraySubsExprLoc);
213+
Binding, GEPIndices, ArraySubsExprLoc);
224214
if (!MaybeIndex)
225215
return std::nullopt;
226216
Index = *MaybeIndex;
@@ -244,8 +234,7 @@ static std::optional<llvm::Value *> initializeLocalResourceArray(
244234

245235
CallArgList Args;
246236
CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
247-
CGF.CGM, ResourceDecl, Range, Index, ResourceName, RBA, VkBinding,
248-
Args);
237+
CGF.CGM, ResourceDecl, Range, Index, ResourceName, Binding, Args);
249238

250239
if (!CreateMethod)
251240
// This can happen if someone creates an array of structs that looks like
@@ -439,14 +428,7 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
439428
emitBufferGlobalsAndMetadata(BufDecl, BufGV);
440429

441430
// Initialize cbuffer from binding (implicit or explicit)
442-
if (HLSLVkBindingAttr *VkBinding = BufDecl->getAttr<HLSLVkBindingAttr>()) {
443-
initializeBufferFromBinding(BufDecl, BufGV, VkBinding);
444-
} else {
445-
HLSLResourceBindingAttr *RBA = BufDecl->getAttr<HLSLResourceBindingAttr>();
446-
assert(RBA &&
447-
"cbuffer/tbuffer should always have resource binding attribute");
448-
initializeBufferFromBinding(BufDecl, BufGV, RBA);
449-
}
431+
initializeBufferFromBinding(BufDecl, BufGV);
450432
}
451433

452434
void CGHLSLRuntime::addRootSignature(
@@ -810,44 +792,29 @@ static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
810792
}
811793

812794
void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
813-
llvm::GlobalVariable *GV,
814-
HLSLVkBindingAttr *VkBinding) {
815-
assert(VkBinding && "expect a nonnull binding attribute");
816-
auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
817-
auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
818-
auto *Set = llvm::ConstantInt::get(CGM.IntTy, VkBinding->getSet());
819-
auto *Binding = llvm::ConstantInt::get(CGM.IntTy, VkBinding->getBinding());
820-
Value *Name = buildNameForResource(BufDecl->getName(), CGM);
821-
llvm::Intrinsic::ID IntrinsicID =
822-
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
823-
824-
SmallVector<Value *> Args{Set, Binding, RangeSize, Index, Name};
825-
initializeBuffer(CGM, GV, IntrinsicID, Args);
826-
}
795+
llvm::GlobalVariable *GV) {
796+
ResourceBindingAttrs Binding(BufDecl);
797+
assert(Binding.hasBinding() &&
798+
"cbuffer/tbuffer should always have resource binding attribute");
827799

828-
void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
829-
llvm::GlobalVariable *GV,
830-
HLSLResourceBindingAttr *RBA) {
831-
assert(RBA && "expect a nonnull binding attribute");
832800
auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
833801
auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
834-
auto *Space = llvm::ConstantInt::get(CGM.IntTy, RBA->getSpaceNumber());
802+
auto *Space = llvm::ConstantInt::get(CGM.IntTy, Binding.getSpace());
835803
Value *Name = buildNameForResource(BufDecl->getName(), CGM);
836804

837-
llvm::Intrinsic::ID IntrinsicID =
838-
RBA->hasRegisterSlot()
839-
? CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic()
840-
: CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
841-
842805
// buffer with explicit binding
843-
if (RBA->hasRegisterSlot()) {
844-
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
806+
if (Binding.isExplicit()) {
807+
llvm::Intrinsic::ID IntrinsicID =
808+
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
809+
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, Binding.getSlot());
845810
SmallVector<Value *> Args{Space, RegSlot, RangeSize, Index, Name};
846811
initializeBuffer(CGM, GV, IntrinsicID, Args);
847812
} else {
848813
// buffer with implicit binding
814+
llvm::Intrinsic::ID IntrinsicID =
815+
CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
849816
auto *OrderID =
850-
llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID());
817+
llvm::ConstantInt::get(CGM.IntTy, Binding.getImplicitOrderID());
851818
SmallVector<Value *> Args{OrderID, Space, RangeSize, Index, Name};
852819
initializeBuffer(CGM, GV, IntrinsicID, Args);
853820
}
@@ -960,9 +927,9 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
960927

961928
// Find binding info for the resource array. For implicit binding
962929
// an HLSLResourceBindingAttr should have been added by SemaHLSL.
963-
HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr<HLSLVkBindingAttr>();
964-
HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr<HLSLResourceBindingAttr>();
965-
assert((VkBinding || RBA) && "resource array must have a binding attribute");
930+
ResourceBindingAttrs Binding(ArrayDecl);
931+
assert((Binding.hasBinding()) &&
932+
"resource array must have a binding attribute");
966933

967934
// Find the individual resource type.
968935
QualType ResultTy = ArraySubsExpr->getType();
@@ -992,7 +959,7 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
992959
CallArgList Args;
993960
CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
994961
CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index,
995-
ArrayDecl->getName(), RBA, VkBinding, Args);
962+
ArrayDecl->getName(), Binding, Args);
996963

997964
if (!CreateMethod)
998965
// This can happen if someone creates an array of structs that looks like
@@ -1009,8 +976,8 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
1009976
cast<ConstantArrayType>(ResultTy.getTypePtr());
1010977
std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
1011978
CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index,
1012-
ArrayDecl->getName(), RBA, VkBinding,
1013-
{llvm::ConstantInt::get(CGM.IntTy, 0)}, ArraySubsExpr->getExprLoc());
979+
ArrayDecl->getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)},
980+
ArraySubsExpr->getExprLoc());
1014981
if (!EndIndex)
1015982
return std::nullopt;
1016983
}

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,7 @@ class CGHLSLRuntime {
200200
void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
201201
llvm::GlobalVariable *BufGV);
202202
void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
203-
llvm::GlobalVariable *GV,
204-
HLSLVkBindingAttr *VkBinding);
205-
void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
206-
llvm::GlobalVariable *GV,
207-
HLSLResourceBindingAttr *RBA);
203+
llvm::GlobalVariable *GV);
208204
llvm::Triple::ArchType getArch();
209205

210206
llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes;

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/AST/DeclarationName.h"
2020
#include "clang/AST/DynamicRecursiveASTVisitor.h"
2121
#include "clang/AST/Expr.h"
22+
#include "clang/AST/HLSLResource.h"
2223
#include "clang/AST/Type.h"
2324
#include "clang/AST/TypeLoc.h"
2425
#include "clang/Basic/Builtins.h"
@@ -52,6 +53,7 @@
5253
#include <utility>
5354

5455
using namespace clang;
56+
using namespace clang::hlsl;
5557
using RegisterType = HLSLResourceBindingAttr::RegisterType;
5658

5759
static CXXRecordDecl *createHostLayoutStruct(Sema &S,
@@ -3799,41 +3801,30 @@ bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
37993801
uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
38003802
uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
38013803

3802-
// Gather resource binding information from attributes.
3803-
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
3804-
HLSLVkBindingAttr *VkBinding = VD->getAttr<HLSLVkBindingAttr>();
3805-
std::optional<uint32_t> RegisterSlot;
3806-
uint32_t SpaceNo = 0;
3807-
if (VkBinding) {
3808-
RegisterSlot = VkBinding->getBinding();
3809-
SpaceNo = VkBinding->getSet();
3810-
} else if (RBA) {
3811-
if (RBA->hasRegisterSlot())
3812-
RegisterSlot = RBA->getSlotNumber();
3813-
SpaceNo = RBA->getSpaceNumber();
3814-
}
3804+
// Gather resource binding attributes.
3805+
ResourceBindingAttrs Binding(VD);
38153806

38163807
// Find correct initialization method and create its arguments.
38173808
QualType ResourceTy = VD->getType();
38183809
CXXRecordDecl *ResourceDecl = ResourceTy->getAsCXXRecordDecl();
38193810
CXXMethodDecl *CreateMethod = nullptr;
38203811
llvm::SmallVector<Expr *> Args;
38213812

3822-
if (RegisterSlot.has_value()) {
3813+
if (Binding.isExplicit()) {
38233814
// The resource has explicit binding.
38243815
CreateMethod = lookupMethod(SemaRef, ResourceDecl, "__createFromBinding",
38253816
VD->getLocation());
3826-
IntegerLiteral *RegSlot = IntegerLiteral::Create(
3827-
AST, llvm::APInt(UIntTySize, RegisterSlot.value()), AST.UnsignedIntTy,
3828-
SourceLocation());
3817+
IntegerLiteral *RegSlot =
3818+
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSlot()),
3819+
AST.UnsignedIntTy, SourceLocation());
38293820
Args.push_back(RegSlot);
38303821
} else {
38313822
// The resource has implicit binding.
38323823
CreateMethod =
38333824
lookupMethod(SemaRef, ResourceDecl, "__createFromImplicitBinding",
38343825
VD->getLocation());
3835-
uint32_t OrderID = (RBA && RBA->hasImplicitBindingOrderID())
3836-
? RBA->getImplicitBindingOrderID()
3826+
uint32_t OrderID = (Binding.hasImplicitOrderID())
3827+
? Binding.getImplicitOrderID()
38373828
: getNextImplicitBindingOrderID();
38383829
IntegerLiteral *OrderId =
38393830
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
@@ -3848,7 +3839,7 @@ bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
38483839
return false;
38493840

38503841
IntegerLiteral *Space =
3851-
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo),
3842+
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Binding.getSpace()),
38523843
AST.UnsignedIntTy, SourceLocation());
38533844
Args.push_back(Space);
38543845

0 commit comments

Comments
 (0)