Skip to content

Commit 7e9d4c5

Browse files
committed
[HLSL] Use static create methods to initialize resources in arrays
Use static methods __createFromBinding and __createFromImplicitBinding to initialize resources in resource arrays. Depends on llvm#156544 Part 3 of llvm#154221
1 parent e7d6ee6 commit 7e9d4c5

File tree

9 files changed

+183
-194
lines changed

9 files changed

+183
-194
lines changed

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,6 @@ class SemaHLSL : public SemaBase {
241241

242242
bool initGlobalResourceDecl(VarDecl *VD);
243243
bool initGlobalResourceArrayDecl(VarDecl *VD);
244-
void createResourceRecordCtorArgs(const Type *ResourceTy, StringRef VarName,
245-
HLSLResourceBindingAttr *RBA,
246-
HLSLVkBindingAttr *VkBinding,
247-
uint32_t ArrayIndex,
248-
llvm::SmallVectorImpl<Expr *> &Args);
249244
};
250245

251246
} // namespace clang

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 74 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
#include "CGHLSLRuntime.h"
16+
#include "Address.h"
1617
#include "CGDebugInfo.h"
1718
#include "CodeGenFunction.h"
1819
#include "CodeGenModule.h"
@@ -38,6 +39,7 @@
3839
#include "llvm/Support/ErrorHandling.h"
3940
#include "llvm/Support/FormatVariadic.h"
4041
#include <cstdint>
42+
#include <optional>
4143

4244
using namespace clang;
4345
using namespace CodeGen;
@@ -148,14 +150,22 @@ static Value *buildNameForResource(llvm::StringRef BaseName,
148150
.getPointer();
149151
}
150152

151-
static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
152-
llvm::Value *ThisPtr, llvm::Value *Range,
153-
llvm::Value *Index, StringRef Name,
154-
HLSLResourceBindingAttr *RBA,
155-
HLSLVkBindingAttr *VkBinding,
156-
CallArgList &Args) {
153+
static CXXMethodDecl *lookupMethod(CXXRecordDecl *Record, StringRef Name,
154+
StorageClass SC = SC_None) {
155+
for (auto *Method : Record->methods()) {
156+
if (Method->getStorageClass() == SC && Method->getName() == Name)
157+
return Method;
158+
}
159+
return nullptr;
160+
}
161+
162+
static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
163+
CodeGenModule &CGM, CXXRecordDecl *ResourceDecl, llvm::Value *Range,
164+
llvm::Value *Index, StringRef Name, HLSLResourceBindingAttr *RBA,
165+
HLSLVkBindingAttr *VkBinding, CallArgList &Args) {
157166
assert((VkBinding || RBA) && "at least one a binding attribute expected");
158167

168+
ASTContext &AST = CGM.getContext();
159169
std::optional<uint32_t> RegisterSlot;
160170
uint32_t SpaceNo = 0;
161171
if (VkBinding) {
@@ -167,44 +177,57 @@ static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
167177
SpaceNo = RBA->getSpaceNumber();
168178
}
169179

170-
ASTContext &AST = CD->getASTContext();
180+
CXXMethodDecl *CreateMethod = nullptr;
171181
Value *NameStr = buildNameForResource(Name, CGM);
172182
Value *Space = llvm::ConstantInt::get(CGM.IntTy, SpaceNo);
173183

174-
Args.add(RValue::get(ThisPtr), CD->getThisType());
175184
if (RegisterSlot.has_value()) {
176185
// explicit binding
177186
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RegisterSlot.value());
178187
Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
179-
Args.add(RValue::get(Space), AST.UnsignedIntTy);
180-
Args.add(RValue::get(Range), AST.IntTy);
181-
Args.add(RValue::get(Index), AST.UnsignedIntTy);
182-
188+
CreateMethod = lookupMethod(ResourceDecl, "__createFromBinding", SC_Static);
183189
} else {
184190
// implicit binding
185-
assert(RBA && "missing implicit binding attribute");
186191
auto *OrderID =
187192
llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID());
188-
Args.add(RValue::get(Space), AST.UnsignedIntTy);
189-
Args.add(RValue::get(Range), AST.IntTy);
190-
Args.add(RValue::get(Index), AST.UnsignedIntTy);
191193
Args.add(RValue::get(OrderID), AST.UnsignedIntTy);
194+
CreateMethod =
195+
lookupMethod(ResourceDecl, "__createFromImplicitBinding", SC_Static);
192196
}
197+
Args.add(RValue::get(Space), AST.UnsignedIntTy);
198+
Args.add(RValue::get(Range), AST.IntTy);
199+
Args.add(RValue::get(Index), AST.UnsignedIntTy);
193200
Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst()));
201+
202+
return CreateMethod;
203+
}
204+
205+
static void callResourceInitMethod(CodeGenFunction &CGF,
206+
CXXMethodDecl *CreateMethod,
207+
CallArgList &Args, Address ReturnAddress) {
208+
llvm::Constant *CalleeFn = CGF.CGM.GetAddrOfFunction(CreateMethod);
209+
const FunctionProtoType *Proto =
210+
CreateMethod->getType()->getAs<FunctionProtoType>();
211+
const CGFunctionInfo &FnInfo =
212+
CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, Proto, false);
213+
ReturnValueSlot ReturnValue(ReturnAddress, false);
214+
CGCallee Callee(CGCalleeInfo(Proto), CalleeFn);
215+
CGF.EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr);
194216
}
195217

196218
// Initializes local resource array variable. For multi-dimensional arrays it
197219
// calls itself recursively to initialize its sub-arrays. The Index used in the
198220
// resource constructor calls will begin at StartIndex and will be incremented
199221
// for each array element. The last used resource Index is returned to the
200-
// caller.
201-
static Value *initializeLocalResourceArray(
202-
CodeGenFunction &CGF, AggValueSlot &ValueSlot,
203-
const ConstantArrayType *ArrayTy, CXXConstructorDecl *CD,
222+
// caller. If the function returns std::nullopt, it indicates an error.
223+
static std::optional<llvm::Value *> initializeLocalResourceArray(
224+
CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl,
225+
const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot,
204226
llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
205227
HLSLResourceBindingAttr *RBA, HLSLVkBindingAttr *VkBinding,
206228
ArrayRef<llvm::Value *> PrevGEPIndices, SourceLocation ArraySubsExprLoc) {
207229

230+
ASTContext &AST = CGF.getContext();
208231
llvm::IntegerType *IntTy = CGF.CGM.IntTy;
209232
llvm::Value *Index = StartIndex;
210233
llvm::Value *One = llvm::ConstantInt::get(IntTy, 1);
@@ -225,16 +248,19 @@ static Value *initializeLocalResourceArray(
225248
Index = CGF.Builder.CreateAdd(Index, One);
226249
GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
227250
}
228-
Index = initializeLocalResourceArray(
229-
CGF, ValueSlot, SubArrayTy, CD, Range, Index, ResourceName, RBA,
230-
VkBinding, GEPIndices, ArraySubsExprLoc);
251+
std::optional<llvm::Value *> MaybeIndex = initializeLocalResourceArray(
252+
CGF, ResourceDecl, SubArrayTy, ValueSlot, Range, Index, ResourceName,
253+
RBA, VkBinding, GEPIndices, ArraySubsExprLoc);
254+
if (!MaybeIndex)
255+
return std::nullopt;
256+
Index = *MaybeIndex;
231257
}
232258
return Index;
233259
}
234260

235261
// For array of resources, initialize each resource in the array.
236262
llvm::Type *Ty = CGF.ConvertTypeForMem(ElemType);
237-
CharUnits ElemSize = CD->getASTContext().getTypeSizeInChars(ElemType);
263+
CharUnits ElemSize = AST.getTypeSizeInChars(ElemType);
238264
CharUnits Align =
239265
TmpArrayAddr.getAlignment().alignmentOfArrayElement(ElemSize);
240266

@@ -243,16 +269,18 @@ static Value *initializeLocalResourceArray(
243269
Index = CGF.Builder.CreateAdd(Index, One);
244270
GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
245271
}
246-
Address ThisAddress =
272+
Address ReturnAddress =
247273
CGF.Builder.CreateGEP(TmpArrayAddr, GEPIndices, Ty, Align);
248-
llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo(ThisAddress, ElemType);
249274

250275
CallArgList Args;
251-
createResourceCtorArgs(CGF.CGM, CD, ThisPtr, Range, Index, ResourceName,
252-
RBA, VkBinding, Args);
253-
CGF.EmitCXXConstructorCall(CD, Ctor_Complete, false, false, ThisAddress,
254-
Args, ValueSlot.mayOverlap(), ArraySubsExprLoc,
255-
ValueSlot.isSanitizerChecked());
276+
CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
277+
CGF.CGM, ResourceDecl, Range, Index, ResourceName, RBA, VkBinding,
278+
Args);
279+
280+
if (!CreateMethod)
281+
return std::nullopt;
282+
283+
callResourceInitMethod(CGF, CreateMethod, Args, ReturnAddress);
256284
}
257285
return Index;
258286
}
@@ -906,11 +934,6 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
906934
QualType ResourceTy =
907935
ResultTy->isArrayType() ? AST.getBaseElementType(ResultTy) : ResultTy;
908936

909-
// Lookup the resource class constructor based on the resource type and
910-
// binding.
911-
CXXConstructorDecl *CD = findResourceConstructorDecl(
912-
AST, ResourceTy, VkBinding || RBA->hasRegisterSlot());
913-
914937
// Create a temporary variable for the result, which is either going
915938
// to be a single resource instance or a local array of resources (we need to
916939
// return an LValue).
@@ -923,7 +946,6 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
923946
TmpVar, Qualifiers(), AggValueSlot::IsDestructed_t(true),
924947
AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false),
925948
AggValueSlot::DoesNotOverlap);
926-
Address TmpVarAddress = ValueSlot.getAddress();
927949

928950
// Calculate total array size (= range size).
929951
llvm::Value *Range =
@@ -932,27 +954,27 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
932954
// If the result of the subscript operation is a single resource, call the
933955
// constructor.
934956
if (ResultTy == ResourceTy) {
935-
QualType ThisType = CD->getThisType()->getPointeeType();
936-
llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo(TmpVarAddress, ThisType);
937-
938-
// Assemble the constructor parameters.
939957
CallArgList Args;
940-
createResourceCtorArgs(CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName(),
941-
RBA, VkBinding, Args);
942-
// Call the constructor.
943-
CGF.EmitCXXConstructorCall(CD, Ctor_Complete, false, false, TmpVarAddress,
944-
Args, ValueSlot.mayOverlap(),
945-
ArraySubsExpr->getExprLoc(),
946-
ValueSlot.isSanitizerChecked());
958+
CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs(
959+
CGF.CGM, ResourceTy->getAsCXXRecordDecl(), Range, Index,
960+
ArrayDecl->getName(), RBA, VkBinding, Args);
961+
962+
if (!CreateMethod)
963+
return std::nullopt;
964+
965+
callResourceInitMethod(CGF, CreateMethod, Args, ValueSlot.getAddress());
966+
947967
} else {
948968
// The result of the subscript operation is a local resource array which
949969
// needs to be initialized.
950970
const ConstantArrayType *ArrayTy =
951971
cast<ConstantArrayType>(ResultTy.getTypePtr());
952-
initializeLocalResourceArray(CGF, ValueSlot, ArrayTy, CD, Range, Index,
953-
ArrayDecl->getName(), RBA, VkBinding,
954-
{llvm::ConstantInt::get(CGM.IntTy, 0)},
955-
ArraySubsExpr->getExprLoc());
972+
std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
973+
CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, Index,
974+
ArrayDecl->getName(), RBA, VkBinding,
975+
{llvm::ConstantInt::get(CGM.IntTy, 0)}, ArraySubsExpr->getExprLoc());
976+
if (!EndIndex)
977+
return std::nullopt;
956978
}
957979
return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
958980
}

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 26 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3696,55 +3696,6 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
36963696
deduceAddressSpace(VD);
36973697
}
36983698

3699-
void SemaHLSL::createResourceRecordCtorArgs(
3700-
const Type *ResourceTy, StringRef VarName, HLSLResourceBindingAttr *RBA,
3701-
HLSLVkBindingAttr *VkBinding, uint32_t ArrayIndex,
3702-
llvm::SmallVectorImpl<Expr *> &Args) {
3703-
std::optional<uint32_t> RegisterSlot;
3704-
uint32_t SpaceNo = 0;
3705-
if (VkBinding) {
3706-
RegisterSlot = VkBinding->getBinding();
3707-
SpaceNo = VkBinding->getSet();
3708-
} else if (RBA) {
3709-
if (RBA->hasRegisterSlot())
3710-
RegisterSlot = RBA->getSlotNumber();
3711-
SpaceNo = RBA->getSpaceNumber();
3712-
}
3713-
3714-
ASTContext &AST = SemaRef.getASTContext();
3715-
uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
3716-
uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
3717-
IntegerLiteral *RangeSize = IntegerLiteral::Create(
3718-
AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
3719-
IntegerLiteral *Index =
3720-
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, ArrayIndex),
3721-
AST.UnsignedIntTy, SourceLocation());
3722-
IntegerLiteral *Space =
3723-
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo),
3724-
AST.UnsignedIntTy, SourceLocation());
3725-
StringLiteral *Name = StringLiteral::Create(
3726-
AST, VarName, StringLiteralKind::Ordinary, false,
3727-
AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
3728-
SourceLocation());
3729-
3730-
// resource with explicit binding
3731-
if (RegisterSlot.has_value()) {
3732-
IntegerLiteral *RegSlot = IntegerLiteral::Create(
3733-
AST, llvm::APInt(UIntTySize, RegisterSlot.value()), AST.UnsignedIntTy,
3734-
SourceLocation());
3735-
Args.append({RegSlot, Space, RangeSize, Index, Name});
3736-
} else {
3737-
// resource with implicit binding
3738-
uint32_t OrderID = (RBA && RBA->hasImplicitBindingOrderID())
3739-
? RBA->getImplicitBindingOrderID()
3740-
: getNextImplicitBindingOrderID();
3741-
IntegerLiteral *OrderId =
3742-
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
3743-
AST.UnsignedIntTy, SourceLocation());
3744-
Args.append({Space, RangeSize, Index, OrderId, Name});
3745-
}
3746-
}
3747-
37483699
bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
37493700
assert(VD->getType()->isHLSLResourceRecord() &&
37503701
"expected resource record type");
@@ -3849,28 +3800,37 @@ bool SemaHLSL::initGlobalResourceArrayDecl(VarDecl *VD) {
38493800

38503801
// Individual resources in a resource array are not initialized here. They
38513802
// are initialized later on during codegen when the individual resources are
3852-
// accessed. Codegen will emit a call to the resource constructor with the
3853-
// specified array index. We need to make sure though that the constructor
3803+
// accessed. Codegen will emit a call to the resource initialization method
3804+
// with the specified array index. We need to make sure though that the method
38543805
// for the specific resource type is instantiated, so codegen can emit a call
38553806
// to it when the array element is accessed.
3856-
SmallVector<Expr *> Args;
3857-
QualType ResElementTy = VD->getASTContext().getBaseElementType(VD->getType());
3858-
createResourceRecordCtorArgs(ResElementTy.getTypePtr(), VD->getName(),
3859-
VD->getAttr<HLSLResourceBindingAttr>(),
3860-
VD->getAttr<HLSLVkBindingAttr>(), 0, Args);
38613807

3862-
SourceLocation Loc = VD->getLocation();
3863-
InitializedEntity Entity =
3864-
InitializedEntity::InitializeTemporary(ResElementTy);
3865-
InitializationKind Kind = InitializationKind::CreateDirect(Loc, Loc, Loc);
3866-
InitializationSequence InitSeq(SemaRef, Entity, Kind, Args);
3867-
if (InitSeq.Failed())
3808+
// Find correct initialization method based on the resource binding
3809+
// information.
3810+
ASTContext &AST = SemaRef.getASTContext();
3811+
QualType ResElementTy = AST.getBaseElementType(VD->getType());
3812+
CXXRecordDecl *ResourceDecl = ResElementTy->getAsCXXRecordDecl();
3813+
3814+
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
3815+
HLSLVkBindingAttr *VkBinding = VD->getAttr<HLSLVkBindingAttr>();
3816+
CXXMethodDecl *CreateMethod = nullptr;
3817+
3818+
if (VkBinding || (RBA && RBA->hasRegisterSlot()))
3819+
// Resource has explicit binding.
3820+
CreateMethod = lookupMethod(ResourceDecl, "__createFromBinding", SC_Static);
3821+
else
3822+
// Resource has implicit binding.
3823+
CreateMethod =
3824+
lookupMethod(ResourceDecl, "__createFromImplicitBinding", SC_Static);
3825+
3826+
if (!CreateMethod)
38683827
return false;
38693828

3870-
// This takes care of instantiating and emitting of the constructor that will
3871-
// be called from codegen when the array is accessed.
3872-
ExprResult OneResInit = InitSeq.Perform(SemaRef, Entity, Kind, Args);
3873-
return !OneResInit.isInvalid();
3829+
// Make sure the create method template is instantiated and emitted.
3830+
if (!CreateMethod->isDefined() && CreateMethod->isTemplateInstantiation())
3831+
SemaRef.InstantiateFunctionDefinition(VD->getLocation(), CreateMethod,
3832+
true);
3833+
return true;
38743834
}
38753835

38763836
// Returns true if the initialization has been handled.

clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
RWBuffer<float> A[4][3] : register(u2);
77
RWStructuredBuffer<float> Out;
88

9-
// Make sure A[GI.x][GI.y] is translated to a RWBuffer<float> constructor call with range 12 and dynamically calculated index
10-
11-
// NOTE:
12-
// Constructor call for explicit binding has "jjij" in the mangled name and the arguments are (register, space, range_size, index, name).
9+
// Make sure A[GI.x][GI.y] is translated to a RWBuffer<float>::__createFromBinding call
10+
// with range 12 and dynamically calculated index
1311

1412
// CHECK: define internal void @_Z4mainDv3_j(<3 x i32> noundef %GI)
1513
// CHECK: %[[GI_alloca:.*]] = alloca <3 x i32>, align 16
@@ -22,7 +20,8 @@ RWStructuredBuffer<float> Out;
2220
// CHECK: %[[GI_x:.*]] = extractelement <3 x i32> %[[GI]], i32 0
2321
// CHECK: %[[Tmp1:.*]] = mul i32 %[[GI_x]], 3
2422
// CHECK: %[[Index:.*]] = add i32 %[[GI_y]], %[[Tmp1]]
25-
// CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 2, i32 noundef 0, i32 noundef 12, i32 noundef %[[Index]], ptr noundef @A.str)
23+
// CHECK: call void @_ZN4hlsl8RWBufferIfE19__createFromBindingEjjijPKc(ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Tmp0]],
24+
// CHECK-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 12, i32 noundef %[[Index]], ptr noundef @A.str)
2625
[numthreads(4,1,1)]
2726
void main(uint3 GI : SV_GroupThreadID) {
2827
Out[0] = A[GI.x][GI.y][0];

0 commit comments

Comments
 (0)