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"
3536#include " llvm/Support/Alignment.h"
3637#include " llvm/Support/ErrorHandling.h"
3738#include " llvm/Support/FormatVariadic.h"
39+ #include < optional>
3840
3941using namespace clang ;
4042using namespace CodeGen ;
@@ -84,6 +86,110 @@ void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer,
8486 RootSignatureValMD->addOperand (MDVals);
8587}
8688
89+ // If the specified expr is a simple decay from an array to pointer,
90+ // return the array subexpression. Otherwise, return nullptr.
91+ static const Expr *getSubExprFromArrayDecayOperand (const Expr *E) {
92+ const auto *CE = dyn_cast<CastExpr>(E);
93+ if (!CE || CE->getCastKind () != CK_ArrayToPointerDecay)
94+ return nullptr ;
95+ return CE->getSubExpr ();
96+ }
97+
98+ // Find array variable declaration from nested array subscript AST nodes
99+ static const ValueDecl *getArrayDecl (const ArraySubscriptExpr *ASE) {
100+ const Expr *E = nullptr ;
101+ while (ASE != nullptr ) {
102+ E = getSubExprFromArrayDecayOperand (ASE->getBase ());
103+ if (!E)
104+ return nullptr ;
105+ ASE = dyn_cast<ArraySubscriptExpr>(E);
106+ }
107+ if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
108+ return DRE->getDecl ();
109+ return nullptr ;
110+ }
111+
112+ // Get the total size of the array, or -1 if the array is unbounded.
113+ static int getTotalArraySize (const clang::Type *Ty) {
114+ assert (Ty->isArrayType () && " expected array type" );
115+ if (Ty->isIncompleteArrayType ())
116+ return -1 ;
117+ int Size = 1 ;
118+ while (const auto *CAT = dyn_cast<ConstantArrayType>(Ty)) {
119+ Size *= CAT->getSExtSize ();
120+ Ty = CAT->getArrayElementTypeNoTypeQual ();
121+ }
122+ return Size;
123+ }
124+
125+ // Find constructor decl for a specific resource record type and binding
126+ // (implicit vs. explicit). The constructor has 6 parameters.
127+ // For explicit binding the signature is:
128+ // void(unsigned, unsigned, int, unsigned, const char *).
129+ // For implicit binding the signature is:
130+ // void(unsigned, int, unsigned, unsigned, const char *).
131+ static CXXConstructorDecl *findResourceConstructorDecl (ASTContext &AST,
132+ QualType ResTy,
133+ bool ExplicitBinding) {
134+ SmallVector<QualType> ExpParmTypes = {
135+ AST.UnsignedIntTy , AST.UnsignedIntTy , AST.UnsignedIntTy ,
136+ AST.UnsignedIntTy , AST.getPointerType (AST.CharTy .withConst ())};
137+ ExpParmTypes[ExplicitBinding ? 2 : 1 ] = AST.IntTy ;
138+
139+ CXXRecordDecl *ResDecl = ResTy->getAsCXXRecordDecl ();
140+ for (auto *Ctor : ResDecl->ctors ()) {
141+ if (Ctor->getNumParams () != ExpParmTypes.size ())
142+ continue ;
143+ ParmVarDecl **ParmIt = Ctor->param_begin ();
144+ QualType *ExpTyIt = ExpParmTypes.begin ();
145+ for (; ParmIt != Ctor->param_end () && ExpTyIt != ExpParmTypes.end ();
146+ ++ParmIt, ++ExpTyIt) {
147+ if ((*ParmIt)->getType () != *ExpTyIt)
148+ break ;
149+ }
150+ if (ParmIt == Ctor->param_end ())
151+ return Ctor;
152+ }
153+ llvm_unreachable (" did not find constructor for resource class" );
154+ }
155+
156+ static Value *buildNameForResource (llvm::StringRef BaseName,
157+ CodeGenModule &CGM) {
158+ std::string Str (BaseName);
159+ std::string GlobalName (Str + " .str" );
160+ return CGM.GetAddrOfConstantCString (Str, GlobalName.c_str ()).getPointer ();
161+ }
162+
163+ static void createResourceCtorArgs (CodeGenModule &CGM, CXXConstructorDecl *CD,
164+ llvm::Value *ThisPtr, llvm::Value *Range,
165+ llvm::Value *Index, StringRef Name,
166+ HLSLResourceBindingAttr *RBA,
167+ CallArgList &Args) {
168+ ASTContext &AST = CD->getASTContext ();
169+ Value *NameStr = buildNameForResource (Name, CGM);
170+ Value *Space = llvm::ConstantInt::get (CGM.IntTy , RBA->getSpaceNumber ());
171+
172+ Args.add (RValue::get (ThisPtr), CD->getThisType ());
173+ if (RBA->hasRegisterSlot ()) {
174+ // explicit binding
175+ auto *RegSlot = llvm::ConstantInt::get (CGM.IntTy , RBA->getSlotNumber ());
176+ Args.add (RValue::get (RegSlot), AST.UnsignedIntTy );
177+ Args.add (RValue::get (Space), AST.UnsignedIntTy );
178+ Args.add (RValue::get (Range), AST.IntTy );
179+ Args.add (RValue::get (Index), AST.UnsignedIntTy );
180+
181+ } else {
182+ // implicit binding
183+ auto *OrderID =
184+ llvm::ConstantInt::get (CGM.IntTy , RBA->getImplicitBindingOrderID ());
185+ Args.add (RValue::get (Space), AST.UnsignedIntTy );
186+ Args.add (RValue::get (Range), AST.IntTy );
187+ Args.add (RValue::get (Index), AST.UnsignedIntTy );
188+ Args.add (RValue::get (OrderID), AST.UnsignedIntTy );
189+ }
190+ Args.add (RValue::get (NameStr), AST.getPointerType (AST.CharTy .withConst ()));
191+ }
192+
87193} // namespace
88194
89195llvm::Type *
@@ -103,13 +209,6 @@ llvm::Triple::ArchType CGHLSLRuntime::getArch() {
103209 return CGM.getTarget ().getTriple ().getArch ();
104210}
105211
106- // Returns true if the type is an HLSL resource class or an array of them
107- static bool isResourceRecordTypeOrArrayOf (const clang::Type *Ty) {
108- while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
109- Ty = CAT->getArrayElementTypeNoTypeQual ();
110- return Ty->isHLSLResourceRecord ();
111- }
112-
113212// Emits constant global variables for buffer constants declarations
114213// and creates metadata linking the constant globals with the buffer global.
115214void CGHLSLRuntime::emitBufferGlobalsAndMetadata (const HLSLBufferDecl *BufDecl,
@@ -146,7 +245,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
146245 if (VDTy.getAddressSpace () != LangAS::hlsl_constant) {
147246 if (VD->getStorageClass () == SC_Static ||
148247 VDTy.getAddressSpace () == LangAS::hlsl_groupshared ||
149- isResourceRecordTypeOrArrayOf ( VDTy. getTypePtr () )) {
248+ VDTy-> isHLSLResourceRecord () || VDTy-> isHLSLResourceRecordArray ( )) {
150249 // Emit static and groupshared variables and resource classes inside
151250 // cbuffer as regular globals
152251 CGM.EmitGlobal (VD);
@@ -679,3 +778,92 @@ void CGHLSLRuntime::emitInitListOpaqueValues(CodeGenFunction &CGF,
679778 }
680779 }
681780}
781+
782+ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr (
783+ const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
784+ assert (ArraySubsExpr->getType ()->isHLSLResourceRecord () ||
785+ ArraySubsExpr->getType ()->isHLSLResourceRecordArray () &&
786+ " expected resource array subscript expression" );
787+
788+ // let clang codegen handle local resource array subscrips
789+ const VarDecl *ArrayDecl = dyn_cast<VarDecl>(getArrayDecl (ArraySubsExpr));
790+ if (!ArrayDecl || !ArrayDecl->hasGlobalStorage ())
791+ return std::nullopt ;
792+
793+ // FIXME: this is not yet implemented (llvm/llvm-project#145426)
794+ assert (!ArraySubsExpr->getType ()->isArrayType () &&
795+ " indexing of array subsets it not supported yet" );
796+
797+ // get total array size (= range size)
798+ const Type *ResArrayTy = ArrayDecl->getType ().getTypePtr ();
799+ assert (ResArrayTy->isHLSLResourceRecordArray () &&
800+ " expected array of resource classes" );
801+ llvm::Value *Range =
802+ llvm::ConstantInt::get (CGM.IntTy , getTotalArraySize (ResArrayTy));
803+
804+ // Iterate through all nested array subscript expressions to calculate
805+ // the index in the flattened resource array (if this is a multi-
806+ // dimensional array). The index is calculated as a sum of all indices
807+ // multiplied by the total size of the array at that level.
808+ Value *Index = nullptr ;
809+ Value *Multiplier = nullptr ;
810+ const ArraySubscriptExpr *ASE = ArraySubsExpr;
811+ while (ASE != nullptr ) {
812+ Value *SubIndex = CGF.EmitScalarExpr (ASE->getIdx ());
813+ if (const auto *ArrayTy =
814+ dyn_cast<ConstantArrayType>(ASE->getType ().getTypePtr ())) {
815+ Value *SubMultiplier =
816+ llvm::ConstantInt::get (CGM.IntTy , ArrayTy->getSExtSize ());
817+ Multiplier = Multiplier ? CGF.Builder .CreateMul (Multiplier, SubMultiplier)
818+ : SubMultiplier;
819+ SubIndex = CGF.Builder .CreateMul (SubIndex, Multiplier);
820+ }
821+
822+ Index = Index ? CGF.Builder .CreateAdd (Index, SubIndex) : SubIndex;
823+ ASE = dyn_cast<ArraySubscriptExpr>(
824+ getSubExprFromArrayDecayOperand (ASE->getBase ()));
825+ }
826+
827+ // find binding info for the resource array
828+ // (for implicit binding it should have been by SemaHLSL)
829+ QualType ResourceTy = ArraySubsExpr->getType ();
830+ HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr <HLSLResourceBindingAttr>();
831+ assert (RBA && " resource array is missing HLSLResourceBindingAttr attribute" );
832+
833+ // lookup the resource class constructor based on the resource type and
834+ // binding
835+ CXXConstructorDecl *CD = findResourceConstructorDecl (
836+ ArrayDecl->getASTContext (), ResourceTy, RBA->hasRegisterSlot ());
837+
838+ // create a temporary variable for the resource class instance (we need to
839+ // return an LValue)
840+ RawAddress TmpVar = CGF.CreateMemTemp (ResourceTy);
841+ if (auto *Size = CGF.EmitLifetimeStart (
842+ CGM.getDataLayout ().getTypeAllocSize (TmpVar.getElementType ()),
843+ TmpVar.getPointer ())) {
844+ CGF.pushFullExprCleanup <CodeGenFunction::CallLifetimeEnd>(
845+ NormalEHLifetimeMarker, TmpVar, Size);
846+ }
847+ AggValueSlot ValueSlot = AggValueSlot::forAddr (
848+ TmpVar, Qualifiers (), AggValueSlot::IsDestructed_t (true ),
849+ AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t (false ),
850+ AggValueSlot::MayOverlap);
851+
852+ Address ThisAddress = ValueSlot.getAddress ();
853+ llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (
854+ ThisAddress, CD->getThisType ()->getPointeeType ());
855+
856+ // assemble the constructor parameters
857+ CallArgList Args;
858+ createResourceCtorArgs (CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName (),
859+ RBA, Args);
860+
861+ // call the constructor
862+ CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , ThisAddress, Args,
863+ ValueSlot.mayOverlap (),
864+ ArraySubsExpr->getExprLoc (),
865+ ValueSlot.isSanitizerChecked ());
866+
867+ return CGF.MakeAddrLValue (TmpVar, ArraySubsExpr->getType (),
868+ AlignmentSource::Decl);
869+ }
0 commit comments