18
18
#include " CodeGenModule.h"
19
19
#include " TargetInfo.h"
20
20
#include " clang/AST/ASTContext.h"
21
+ #include " clang/AST/Attrs.inc"
21
22
#include " clang/AST/Decl.h"
22
23
#include " clang/AST/RecursiveASTVisitor.h"
23
24
#include " clang/AST/Type.h"
36
37
#include " llvm/Support/Alignment.h"
37
38
#include " llvm/Support/ErrorHandling.h"
38
39
#include " llvm/Support/FormatVariadic.h"
40
+ #include < cstdint>
39
41
40
42
using namespace clang ;
41
43
using namespace CodeGen ;
@@ -190,6 +192,70 @@ static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
190
192
Args.add (RValue::get (NameStr), AST.getPointerType (AST.CharTy .withConst ()));
191
193
}
192
194
195
+ // Initializes local resource array variable. For multi-dimensional arrays it
196
+ // calls itself recursively to initialize its sub-arrays. The Index used in the
197
+ // resource constructor calls will begin at StartIndex and will be incremented
198
+ // for each array element. The last used resource Index is returned to the
199
+ // caller.
200
+ static Value *initializeLocalResourceArray (
201
+ CodeGenFunction &CGF, AggValueSlot &ValueSlot,
202
+ const ConstantArrayType *ArrayTy, CXXConstructorDecl *CD,
203
+ llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
204
+ HLSLResourceBindingAttr *RBA, HLSLVkBindingAttr *VkBinding,
205
+ ArrayRef<llvm::Value *> PrevGEPIndices, SourceLocation ArraySubsExprLoc) {
206
+
207
+ llvm::IntegerType *IntTy = CGF.CGM .IntTy ;
208
+ llvm::Value *Index = StartIndex;
209
+ llvm::Value *One = llvm::ConstantInt::get (IntTy, 1 );
210
+ const uint64_t ArraySize = ArrayTy->getSExtSize ();
211
+ QualType ElemType = ArrayTy->getElementType ();
212
+ Address TmpArrayAddr = ValueSlot.getAddress ();
213
+
214
+ // Add additional index to the getelementptr call indices.
215
+ // This index will be updated for each array element in the loops below.
216
+ SmallVector<llvm::Value *> GEPIndices (PrevGEPIndices);
217
+ GEPIndices.push_back (llvm::ConstantInt::get (IntTy, 0 ));
218
+
219
+ // For array of arrays, recursively initialize the sub-arrays.
220
+ if (ElemType->isArrayType ()) {
221
+ const ConstantArrayType *SubArrayTy = cast<ConstantArrayType>(ElemType);
222
+ for (uint64_t I = 0 ; I < ArraySize; I++) {
223
+ if (I > 0 ) {
224
+ Index = CGF.Builder .CreateAdd (Index, One);
225
+ GEPIndices.back () = llvm::ConstantInt::get (IntTy, I);
226
+ }
227
+ Index = initializeLocalResourceArray (
228
+ CGF, ValueSlot, SubArrayTy, CD, Range, Index, ResourceName, RBA,
229
+ VkBinding, GEPIndices, ArraySubsExprLoc);
230
+ }
231
+ return Index;
232
+ }
233
+
234
+ // For array of resources, initialize each resource in the array.
235
+ llvm::Type *Ty = CGF.ConvertTypeForMem (ElemType);
236
+ CharUnits ElemSize = CD->getASTContext ().getTypeSizeInChars (ElemType);
237
+ CharUnits Align =
238
+ TmpArrayAddr.getAlignment ().alignmentOfArrayElement (ElemSize);
239
+
240
+ for (uint64_t I = 0 ; I < ArraySize; I++) {
241
+ if (I > 0 ) {
242
+ Index = CGF.Builder .CreateAdd (Index, One);
243
+ GEPIndices.back () = llvm::ConstantInt::get (IntTy, I);
244
+ }
245
+ Address ThisAddress =
246
+ CGF.Builder .CreateGEP (TmpArrayAddr, GEPIndices, Ty, Align);
247
+ llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (ThisAddress, ElemType);
248
+
249
+ CallArgList Args;
250
+ createResourceCtorArgs (CGF.CGM , CD, ThisPtr, Range, Index, ResourceName,
251
+ RBA, VkBinding, Args);
252
+ CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , ThisAddress,
253
+ Args, ValueSlot.mayOverlap (), ArraySubsExprLoc,
254
+ ValueSlot.isSanitizerChecked ());
255
+ }
256
+ return Index;
257
+ }
258
+
193
259
} // namespace
194
260
195
261
llvm::Type *
@@ -796,16 +862,14 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
796
862
ArraySubsExpr->getType ()->isHLSLResourceRecordArray () &&
797
863
" expected resource array subscript expression" );
798
864
799
- // let clang codegen handle local resource array subscripts
800
- const VarDecl *ArrayDecl = dyn_cast<VarDecl>(getArrayDecl (ArraySubsExpr));
865
+ // Let clang codegen handle local resource array subscripts,
866
+ // or when the subscript references on opaque expression (as part of
867
+ // ArrayInitLoopExpr AST node).
868
+ const VarDecl *ArrayDecl =
869
+ dyn_cast_or_null<VarDecl>(getArrayDecl (ArraySubsExpr));
801
870
if (!ArrayDecl || !ArrayDecl->hasGlobalStorage ())
802
871
return std::nullopt ;
803
872
804
- if (ArraySubsExpr->getType ()->isArrayType ())
805
- // FIXME: this is not yet implemented (llvm/llvm-project#145426)
806
- llvm_unreachable (
807
- " indexing of sub-arrays of multidimensional arrays not supported yet" );
808
-
809
873
// get the resource array type
810
874
ASTContext &AST = ArrayDecl->getASTContext ();
811
875
const Type *ResArrayTy = ArrayDecl->getType ().getTypePtr ();
@@ -826,26 +890,30 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
826
890
CGM.IntTy , AST.getConstantArrayElementCount (ArrayTy));
827
891
SubIndex = CGF.Builder .CreateMul (SubIndex, Multiplier);
828
892
}
829
-
830
893
Index = Index ? CGF.Builder .CreateAdd (Index, SubIndex) : SubIndex;
831
894
ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase ()->IgnoreParenImpCasts ());
832
895
}
833
896
834
- // find binding info for the resource array (for implicit binding
835
- // an HLSLResourceBindingAttr should have been added by SemaHLSL)
836
- QualType ResourceTy = ArraySubsExpr->getType ();
897
+ // Find binding info for the resource array. For implicit binding
898
+ // an HLSLResourceBindingAttr should have been added by SemaHLSL.
837
899
HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr <HLSLVkBindingAttr>();
838
900
HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr <HLSLResourceBindingAttr>();
839
901
assert ((VkBinding || RBA) && " resource array must have a binding attribute" );
840
902
841
- // lookup the resource class constructor based on the resource type and
842
- // binding
903
+ // Find the individual resource type.
904
+ QualType ResultTy = ArraySubsExpr->getType ();
905
+ QualType ResourceTy =
906
+ ResultTy->isArrayType () ? AST.getBaseElementType (ResultTy) : ResultTy;
907
+
908
+ // Lookup the resource class constructor based on the resource type and
909
+ // binding.
843
910
CXXConstructorDecl *CD = findResourceConstructorDecl (
844
911
AST, ResourceTy, VkBinding || RBA->hasRegisterSlot ());
845
912
846
- // create a temporary variable for the resource class instance (we need to
847
- // return an LValue)
848
- RawAddress TmpVar = CGF.CreateMemTemp (ResourceTy);
913
+ // Create a temporary variable for the result, which is either going
914
+ // to be a single resource instance or a local array of resources (we need to
915
+ // return an LValue).
916
+ RawAddress TmpVar = CGF.CreateMemTemp (ResultTy);
849
917
if (CGF.EmitLifetimeStart (TmpVar.getPointer ()))
850
918
CGF.pushFullExprCleanup <CodeGenFunction::CallLifetimeEnd>(
851
919
NormalEHLifetimeMarker, TmpVar);
@@ -854,26 +922,36 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
854
922
TmpVar, Qualifiers (), AggValueSlot::IsDestructed_t (true ),
855
923
AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t (false ),
856
924
AggValueSlot::DoesNotOverlap);
925
+ Address TmpVarAddress = ValueSlot.getAddress ();
857
926
858
- Address ThisAddress = ValueSlot.getAddress ();
859
- llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (
860
- ThisAddress, CD->getThisType ()->getPointeeType ());
861
-
862
- // get total array size (= range size)
927
+ // Calculate total array size (= range size).
863
928
llvm::Value *Range =
864
929
llvm::ConstantInt::get (CGM.IntTy , getTotalArraySize (AST, ResArrayTy));
865
930
866
- // assemble the constructor parameters
867
- CallArgList Args;
868
- createResourceCtorArgs (CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName (),
869
- RBA, VkBinding, Args);
870
-
871
- // call the constructor
872
- CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , ThisAddress, Args,
873
- ValueSlot.mayOverlap (),
874
- ArraySubsExpr->getExprLoc (),
875
- ValueSlot.isSanitizerChecked ());
876
-
877
- return CGF.MakeAddrLValue (TmpVar, ArraySubsExpr->getType (),
878
- AlignmentSource::Decl);
931
+ // If the result of the subscript operation is a single resource, call the
932
+ // constructor.
933
+ if (ResultTy == ResourceTy) {
934
+ QualType ThisType = CD->getThisType ()->getPointeeType ();
935
+ llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (TmpVarAddress, ThisType);
936
+
937
+ // Assemble the constructor parameters.
938
+ CallArgList Args;
939
+ createResourceCtorArgs (CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName (),
940
+ RBA, VkBinding, Args);
941
+ // Call the constructor.
942
+ CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , TmpVarAddress,
943
+ Args, ValueSlot.mayOverlap (),
944
+ ArraySubsExpr->getExprLoc (),
945
+ ValueSlot.isSanitizerChecked ());
946
+ } else {
947
+ // The result of the subscript operation is a local resource array which
948
+ // needs to be initialized.
949
+ const ConstantArrayType *ArrayTy =
950
+ cast<ConstantArrayType>(ResultTy.getTypePtr ());
951
+ initializeLocalResourceArray (CGF, ValueSlot, ArrayTy, CD, Range, Index,
952
+ ArrayDecl->getName (), RBA, VkBinding,
953
+ {llvm::ConstantInt::get (CGM.IntTy , 0 )},
954
+ ArraySubsExpr->getExprLoc ());
955
+ }
956
+ return CGF.MakeAddrLValue (TmpVar, ResultTy, AlignmentSource::Decl);
879
957
}
0 commit comments