1818#include " CodeGenModule.h"
1919#include " TargetInfo.h"
2020#include " clang/AST/ASTContext.h"
21+ #include " clang/AST/Attrs.inc"
2122#include " clang/AST/Decl.h"
2223#include " clang/AST/RecursiveASTVisitor.h"
2324#include " clang/AST/Type.h"
3637#include " llvm/Support/Alignment.h"
3738#include " llvm/Support/ErrorHandling.h"
3839#include " llvm/Support/FormatVariadic.h"
40+ #include < cstdint>
3941
4042using namespace clang ;
4143using namespace CodeGen ;
@@ -190,6 +192,71 @@ static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
190192 Args.add (RValue::get (NameStr), AST.getPointerType (AST.CharTy .withConst ()));
191193}
192194
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 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+ 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+ // 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+ // recursively initialize the sub-array
228+ Index = initializeLocalResourceArray (
229+ CGF, ValueSlot, SubArrayTy, CD, Range, Index, ResourceName, RBA,
230+ VkBinding, GEPIndices, ArraySubsExprLoc);
231+ }
232+ return Index;
233+ }
234+
235+ // array of resources - initialize each resource in the array
236+ llvm::Type *Ty = CGF.ConvertTypeForMem (ElemType);
237+ CharUnits ElemSize = CD->getASTContext ().getTypeSizeInChars (ElemType);
238+ CharUnits Align =
239+ TmpArrayAddr.getAlignment ().alignmentOfArrayElement (ElemSize);
240+
241+ for (uint64_t I = 0 ; I < ArraySize; I++) {
242+ if (I > 0 ) {
243+ Index = CGF.Builder .CreateAdd (Index, One);
244+ GEPIndices.back () = llvm::ConstantInt::get (IntTy, I);
245+ }
246+ Address ThisAddress =
247+ CGF.Builder .CreateGEP (TmpArrayAddr, GEPIndices, Ty, Align);
248+ llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (ThisAddress, ElemType);
249+
250+ 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 ());
256+ }
257+ return Index;
258+ }
259+
193260} // namespace
194261
195262llvm::Type *
@@ -802,16 +869,14 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
802869 ArraySubsExpr->getType ()->isHLSLResourceRecordArray () &&
803870 " expected resource array subscript expression" );
804871
805- // let clang codegen handle local resource array subscripts
806- const VarDecl *ArrayDecl = dyn_cast<VarDecl>(getArrayDecl (ArraySubsExpr));
872+ // Let clang codegen handle local resource array subscripts,
873+ // or when the subscript references on opaque expression (as part of
874+ // ArrayInitLoopExpr AST node).
875+ const VarDecl *ArrayDecl =
876+ dyn_cast_or_null<VarDecl>(getArrayDecl (ArraySubsExpr));
807877 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage ())
808878 return std::nullopt ;
809879
810- if (ArraySubsExpr->getType ()->isArrayType ())
811- // FIXME: this is not yet implemented (llvm/llvm-project#145426)
812- llvm_unreachable (
813- " indexing of sub-arrays of multidimensional arrays not supported yet" );
814-
815880 // get the resource array type
816881 ASTContext &AST = ArrayDecl->getASTContext ();
817882 const Type *ResArrayTy = ArrayDecl->getType ().getTypePtr ();
@@ -832,26 +897,30 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
832897 CGM.IntTy , AST.getConstantArrayElementCount (ArrayTy));
833898 SubIndex = CGF.Builder .CreateMul (SubIndex, Multiplier);
834899 }
835-
836900 Index = Index ? CGF.Builder .CreateAdd (Index, SubIndex) : SubIndex;
837901 ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase ()->IgnoreParenImpCasts ());
838902 }
839903
840904 // find binding info for the resource array (for implicit binding
841905 // an HLSLResourceBindingAttr should have been added by SemaHLSL)
842- QualType ResourceTy = ArraySubsExpr->getType ();
843906 HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr <HLSLVkBindingAttr>();
844907 HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr <HLSLResourceBindingAttr>();
845908 assert ((VkBinding || RBA) && " resource array must have a binding attribute" );
846909
910+ // Find the individual resource type
911+ QualType ResultTy = ArraySubsExpr->getType ();
912+ QualType ResourceTy =
913+ ResultTy->isArrayType () ? AST.getBaseElementType (ResultTy) : ResultTy;
914+
847915 // lookup the resource class constructor based on the resource type and
848916 // binding
849917 CXXConstructorDecl *CD = findResourceConstructorDecl (
850918 AST, ResourceTy, VkBinding || RBA->hasRegisterSlot ());
851919
852- // create a temporary variable for the resource class instance (we need to
920+ // create a temporary variable for the result, which is either going
921+ // to be a single resource instance or a local array of resources (we need to
853922 // return an LValue)
854- RawAddress TmpVar = CGF.CreateMemTemp (ResourceTy );
923+ RawAddress TmpVar = CGF.CreateMemTemp (ResultTy );
855924 if (CGF.EmitLifetimeStart (TmpVar.getPointer ()))
856925 CGF.pushFullExprCleanup <CodeGenFunction::CallLifetimeEnd>(
857926 NormalEHLifetimeMarker, TmpVar);
@@ -860,26 +929,35 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
860929 TmpVar, Qualifiers (), AggValueSlot::IsDestructed_t (true ),
861930 AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t (false ),
862931 AggValueSlot::DoesNotOverlap);
863-
864- Address ThisAddress = ValueSlot.getAddress ();
865- llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (
866- ThisAddress, CD->getThisType ()->getPointeeType ());
932+ Address TmpVarAddress = ValueSlot.getAddress ();
867933
868934 // get total array size (= range size)
869935 llvm::Value *Range =
870936 llvm::ConstantInt::get (CGM.IntTy , getTotalArraySize (AST, ResArrayTy));
871937
872- // assemble the constructor parameters
873- CallArgList Args;
874- createResourceCtorArgs (CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName (),
875- RBA, VkBinding, Args);
876-
877- // call the constructor
878- CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , ThisAddress, Args,
879- ValueSlot.mayOverlap (),
880- ArraySubsExpr->getExprLoc (),
881- ValueSlot.isSanitizerChecked ());
882-
883- return CGF.MakeAddrLValue (TmpVar, ArraySubsExpr->getType (),
884- AlignmentSource::Decl);
938+ // if the result of the subscript operation is a single resource - call the
939+ // constructor
940+ if (ResultTy == ResourceTy) {
941+ QualType ThisType = CD->getThisType ()->getPointeeType ();
942+ llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (TmpVarAddress, ThisType);
943+
944+ // assemble the constructor parameters
945+ CallArgList Args;
946+ createResourceCtorArgs (CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName (),
947+ RBA, VkBinding, Args);
948+ // call the constructor
949+ CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , TmpVarAddress,
950+ Args, ValueSlot.mayOverlap (),
951+ ArraySubsExpr->getExprLoc (),
952+ ValueSlot.isSanitizerChecked ());
953+ } else {
954+ // result of the subscript operation is a local resource array
955+ const ConstantArrayType *ArrayTy =
956+ cast<ConstantArrayType>(ResultTy.getTypePtr ());
957+ initializeLocalResourceArray (CGF, ValueSlot, ArrayTy, CD, Range, Index,
958+ ArrayDecl->getName (), RBA, VkBinding,
959+ {llvm::ConstantInt::get (CGM.IntTy , 0 )},
960+ ArraySubsExpr->getExprLoc ());
961+ }
962+ return CGF.MakeAddrLValue (TmpVar, ResultTy, AlignmentSource::Decl);
885963}
0 commit comments