13
13
// ===----------------------------------------------------------------------===//
14
14
15
15
#include " CGHLSLRuntime.h"
16
+ #include " Address.h"
16
17
#include " CGDebugInfo.h"
17
18
#include " CodeGenFunction.h"
18
19
#include " CodeGenModule.h"
39
40
#include " llvm/Support/ErrorHandling.h"
40
41
#include " llvm/Support/FormatVariadic.h"
41
42
#include < cstdint>
43
+ #include < optional>
42
44
43
45
using namespace clang ;
44
46
using namespace CodeGen ;
@@ -111,52 +113,29 @@ static int getTotalArraySize(ASTContext &AST, const clang::Type *Ty) {
111
113
return AST.getConstantArrayElementCount (cast<ConstantArrayType>(Ty));
112
114
}
113
115
114
- // Find constructor decl for a specific resource record type and binding
115
- // (implicit vs. explicit). The constructor has 5 parameters.
116
- // For explicit binding the signature is:
117
- // void(unsigned, unsigned, int, unsigned, const char *).
118
- // For implicit binding the signature is:
119
- // void(unsigned, int, unsigned, unsigned, const char *).
120
- static CXXConstructorDecl *findResourceConstructorDecl (ASTContext &AST,
121
- QualType ResTy,
122
- bool ExplicitBinding) {
123
- std::array<QualType, 5 > ExpParmTypes = {
124
- AST.UnsignedIntTy , AST.UnsignedIntTy , AST.UnsignedIntTy ,
125
- AST.UnsignedIntTy , AST.getPointerType (AST.CharTy .withConst ())};
126
- ExpParmTypes[ExplicitBinding ? 2 : 1 ] = AST.IntTy ;
127
-
128
- CXXRecordDecl *ResDecl = ResTy->getAsCXXRecordDecl ();
129
- for (auto *Ctor : ResDecl->ctors ()) {
130
- if (Ctor->getNumParams () != ExpParmTypes.size ())
131
- continue ;
132
- auto *ParmIt = Ctor->param_begin ();
133
- auto ExpTyIt = ExpParmTypes.begin ();
134
- for (; ParmIt != Ctor->param_end () && ExpTyIt != ExpParmTypes.end ();
135
- ++ParmIt, ++ExpTyIt) {
136
- if ((*ParmIt)->getType () != *ExpTyIt)
137
- break ;
138
- }
139
- if (ParmIt == Ctor->param_end ())
140
- return Ctor;
141
- }
142
- llvm_unreachable (" did not find constructor for resource class" );
143
- }
144
-
145
116
static Value *buildNameForResource (llvm::StringRef BaseName,
146
117
CodeGenModule &CGM) {
147
118
llvm::SmallString<64 > GlobalName = {BaseName, " .str" };
148
119
return CGM.GetAddrOfConstantCString (BaseName.str (), GlobalName.c_str ())
149
120
.getPointer ();
150
121
}
151
122
152
- static void createResourceCtorArgs (CodeGenModule &CGM, CXXConstructorDecl *CD,
153
- llvm::Value *ThisPtr, llvm::Value *Range,
154
- llvm::Value *Index, StringRef Name,
155
- HLSLResourceBindingAttr *RBA,
156
- HLSLVkBindingAttr *VkBinding,
157
- CallArgList &Args) {
123
+ static CXXMethodDecl *lookupMethod (CXXRecordDecl *Record, StringRef Name,
124
+ StorageClass SC = SC_None) {
125
+ for (auto *Method : Record->methods ()) {
126
+ if (Method->getStorageClass () == SC && Method->getName () == Name)
127
+ return Method;
128
+ }
129
+ return nullptr ;
130
+ }
131
+
132
+ static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs (
133
+ CodeGenModule &CGM, CXXRecordDecl *ResourceDecl, llvm::Value *Range,
134
+ llvm::Value *Index, StringRef Name, HLSLResourceBindingAttr *RBA,
135
+ HLSLVkBindingAttr *VkBinding, CallArgList &Args) {
158
136
assert ((VkBinding || RBA) && " at least one a binding attribute expected" );
159
137
138
+ ASTContext &AST = CGM.getContext ();
160
139
std::optional<uint32_t > RegisterSlot;
161
140
uint32_t SpaceNo = 0 ;
162
141
if (VkBinding) {
@@ -168,44 +147,57 @@ static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
168
147
SpaceNo = RBA->getSpaceNumber ();
169
148
}
170
149
171
- ASTContext &AST = CD-> getASTContext () ;
150
+ CXXMethodDecl *CreateMethod = nullptr ;
172
151
Value *NameStr = buildNameForResource (Name, CGM);
173
152
Value *Space = llvm::ConstantInt::get (CGM.IntTy , SpaceNo);
174
153
175
- Args.add (RValue::get (ThisPtr), CD->getThisType ());
176
154
if (RegisterSlot.has_value ()) {
177
155
// explicit binding
178
156
auto *RegSlot = llvm::ConstantInt::get (CGM.IntTy , RegisterSlot.value ());
179
157
Args.add (RValue::get (RegSlot), AST.UnsignedIntTy );
180
- Args.add (RValue::get (Space), AST.UnsignedIntTy );
181
- Args.add (RValue::get (Range), AST.IntTy );
182
- Args.add (RValue::get (Index), AST.UnsignedIntTy );
183
-
158
+ CreateMethod = lookupMethod (ResourceDecl, " __createFromBinding" , SC_Static);
184
159
} else {
185
160
// implicit binding
186
- assert (RBA && " missing implicit binding attribute" );
187
161
auto *OrderID =
188
162
llvm::ConstantInt::get (CGM.IntTy , RBA->getImplicitBindingOrderID ());
189
- Args.add (RValue::get (Space), AST.UnsignedIntTy );
190
- Args.add (RValue::get (Range), AST.IntTy );
191
- Args.add (RValue::get (Index), AST.UnsignedIntTy );
192
163
Args.add (RValue::get (OrderID), AST.UnsignedIntTy );
164
+ CreateMethod =
165
+ lookupMethod (ResourceDecl, " __createFromImplicitBinding" , SC_Static);
193
166
}
167
+ Args.add (RValue::get (Space), AST.UnsignedIntTy );
168
+ Args.add (RValue::get (Range), AST.IntTy );
169
+ Args.add (RValue::get (Index), AST.UnsignedIntTy );
194
170
Args.add (RValue::get (NameStr), AST.getPointerType (AST.CharTy .withConst ()));
171
+
172
+ return CreateMethod;
173
+ }
174
+
175
+ static void callResourceInitMethod (CodeGenFunction &CGF,
176
+ CXXMethodDecl *CreateMethod,
177
+ CallArgList &Args, Address ReturnAddress) {
178
+ llvm::Constant *CalleeFn = CGF.CGM .GetAddrOfFunction (CreateMethod);
179
+ const FunctionProtoType *Proto =
180
+ CreateMethod->getType ()->getAs <FunctionProtoType>();
181
+ const CGFunctionInfo &FnInfo =
182
+ CGF.CGM .getTypes ().arrangeFreeFunctionCall (Args, Proto, false );
183
+ ReturnValueSlot ReturnValue (ReturnAddress, false );
184
+ CGCallee Callee (CGCalleeInfo (Proto), CalleeFn);
185
+ CGF.EmitCall (FnInfo, Callee, ReturnValue, Args, nullptr );
195
186
}
196
187
197
188
// Initializes local resource array variable. For multi-dimensional arrays it
198
189
// calls itself recursively to initialize its sub-arrays. The Index used in the
199
190
// resource constructor calls will begin at StartIndex and will be incremented
200
191
// for each array element. The last used resource Index is returned to the
201
- // caller.
202
- static Value *initializeLocalResourceArray (
203
- CodeGenFunction &CGF, AggValueSlot &ValueSlot ,
204
- const ConstantArrayType *ArrayTy, CXXConstructorDecl *CD ,
192
+ // caller. If the function returns std::nullopt, it indicates an error.
193
+ static std::optional<llvm:: Value *> initializeLocalResourceArray (
194
+ CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl ,
195
+ const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot ,
205
196
llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
206
197
HLSLResourceBindingAttr *RBA, HLSLVkBindingAttr *VkBinding,
207
198
ArrayRef<llvm::Value *> PrevGEPIndices, SourceLocation ArraySubsExprLoc) {
208
199
200
+ ASTContext &AST = CGF.getContext ();
209
201
llvm::IntegerType *IntTy = CGF.CGM .IntTy ;
210
202
llvm::Value *Index = StartIndex;
211
203
llvm::Value *One = llvm::ConstantInt::get (IntTy, 1 );
@@ -226,16 +218,19 @@ static Value *initializeLocalResourceArray(
226
218
Index = CGF.Builder .CreateAdd (Index, One);
227
219
GEPIndices.back () = llvm::ConstantInt::get (IntTy, I);
228
220
}
229
- Index = initializeLocalResourceArray (
230
- CGF, ValueSlot, SubArrayTy, CD, Range, Index, ResourceName, RBA,
231
- VkBinding, GEPIndices, ArraySubsExprLoc);
221
+ std::optional<llvm::Value *> MaybeIndex = initializeLocalResourceArray (
222
+ CGF, ResourceDecl, SubArrayTy, ValueSlot, Range, Index, ResourceName,
223
+ RBA, VkBinding, GEPIndices, ArraySubsExprLoc);
224
+ if (!MaybeIndex)
225
+ return std::nullopt ;
226
+ Index = *MaybeIndex;
232
227
}
233
228
return Index;
234
229
}
235
230
236
231
// For array of resources, initialize each resource in the array.
237
232
llvm::Type *Ty = CGF.ConvertTypeForMem (ElemType);
238
- CharUnits ElemSize = CD-> getASTContext () .getTypeSizeInChars (ElemType);
233
+ CharUnits ElemSize = AST .getTypeSizeInChars (ElemType);
239
234
CharUnits Align =
240
235
TmpArrayAddr.getAlignment ().alignmentOfArrayElement (ElemSize);
241
236
@@ -244,16 +239,21 @@ static Value *initializeLocalResourceArray(
244
239
Index = CGF.Builder .CreateAdd (Index, One);
245
240
GEPIndices.back () = llvm::ConstantInt::get (IntTy, I);
246
241
}
247
- Address ThisAddress =
242
+ Address ReturnAddress =
248
243
CGF.Builder .CreateGEP (TmpArrayAddr, GEPIndices, Ty, Align);
249
- llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (ThisAddress, ElemType);
250
244
251
245
CallArgList Args;
252
- createResourceCtorArgs (CGF.CGM , CD, ThisPtr, Range, Index, ResourceName,
253
- RBA, VkBinding, Args);
254
- CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , ThisAddress,
255
- Args, ValueSlot.mayOverlap (), ArraySubsExprLoc,
256
- ValueSlot.isSanitizerChecked ());
246
+ CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs (
247
+ CGF.CGM , ResourceDecl, Range, Index, ResourceName, RBA, VkBinding,
248
+ Args);
249
+
250
+ if (!CreateMethod)
251
+ // This can happen if someone creates an array of structs that looks like
252
+ // an HLSL resource record array but it does not have the required static
253
+ // create method. No binding will be generated for it.
254
+ return std::nullopt ;
255
+
256
+ callResourceInitMethod (CGF, CreateMethod, Args, ReturnAddress);
257
257
}
258
258
return Index;
259
259
}
@@ -969,11 +969,6 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
969
969
QualType ResourceTy =
970
970
ResultTy->isArrayType () ? AST.getBaseElementType (ResultTy) : ResultTy;
971
971
972
- // Lookup the resource class constructor based on the resource type and
973
- // binding.
974
- CXXConstructorDecl *CD = findResourceConstructorDecl (
975
- AST, ResourceTy, VkBinding || RBA->hasRegisterSlot ());
976
-
977
972
// Create a temporary variable for the result, which is either going
978
973
// to be a single resource instance or a local array of resources (we need to
979
974
// return an LValue).
@@ -986,7 +981,6 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
986
981
TmpVar, Qualifiers (), AggValueSlot::IsDestructed_t (true ),
987
982
AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t (false ),
988
983
AggValueSlot::DoesNotOverlap);
989
- Address TmpVarAddress = ValueSlot.getAddress ();
990
984
991
985
// Calculate total array size (= range size).
992
986
llvm::Value *Range =
@@ -995,27 +989,30 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
995
989
// If the result of the subscript operation is a single resource, call the
996
990
// constructor.
997
991
if (ResultTy == ResourceTy) {
998
- QualType ThisType = CD->getThisType ()->getPointeeType ();
999
- llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (TmpVarAddress, ThisType);
1000
-
1001
- // Assemble the constructor parameters.
1002
992
CallArgList Args;
1003
- createResourceCtorArgs (CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName (),
1004
- RBA, VkBinding, Args);
1005
- // Call the constructor.
1006
- CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , TmpVarAddress,
1007
- Args, ValueSlot.mayOverlap (),
1008
- ArraySubsExpr->getExprLoc (),
1009
- ValueSlot.isSanitizerChecked ());
993
+ CXXMethodDecl *CreateMethod = lookupResourceInitMethodAndSetupArgs (
994
+ CGF.CGM , ResourceTy->getAsCXXRecordDecl (), Range, Index,
995
+ ArrayDecl->getName (), RBA, VkBinding, Args);
996
+
997
+ if (!CreateMethod)
998
+ // This can happen if someone creates an array of structs that looks like
999
+ // an HLSL resource record array but it does not have the required static
1000
+ // create method. No binding will be generated for it.
1001
+ return std::nullopt ;
1002
+
1003
+ callResourceInitMethod (CGF, CreateMethod, Args, ValueSlot.getAddress ());
1004
+
1010
1005
} else {
1011
1006
// The result of the subscript operation is a local resource array which
1012
1007
// needs to be initialized.
1013
1008
const ConstantArrayType *ArrayTy =
1014
1009
cast<ConstantArrayType>(ResultTy.getTypePtr ());
1015
- initializeLocalResourceArray (CGF, ValueSlot, ArrayTy, CD, Range, Index,
1016
- ArrayDecl->getName (), RBA, VkBinding,
1017
- {llvm::ConstantInt::get (CGM.IntTy , 0 )},
1018
- ArraySubsExpr->getExprLoc ());
1010
+ std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray (
1011
+ CGF, ResourceTy->getAsCXXRecordDecl (), ArrayTy, ValueSlot, Range, Index,
1012
+ ArrayDecl->getName (), RBA, VkBinding,
1013
+ {llvm::ConstantInt::get (CGM.IntTy , 0 )}, ArraySubsExpr->getExprLoc ());
1014
+ if (!EndIndex)
1015
+ return std::nullopt ;
1019
1016
}
1020
1017
return CGF.MakeAddrLValue (TmpVar, ResultTy, AlignmentSource::Decl);
1021
1018
}
0 commit comments