@@ -96,24 +96,120 @@ void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
9696 RootSignatureValMD->addOperand (MDVals);
9797}
9898
99+ // Given a MemberExpr of a resource or resource array type, find the parent
100+ // VarDecl of the struct or class instance that contains this resource and
101+ // build the full resource name based on the member access path.
102+ //
103+ // For example, for a member access like "myStructArray[0].memberA",
104+ // this function will find the VarDecl of "myStructArray" and use the
105+ // EmbeddedResourceNameBuilder to build the resource name
106+ // "myStructArray.0.memberA".
107+ static const VarDecl *findStructResourceParentDeclAndBuildName (
108+ const MemberExpr *ME , EmbeddedResourceNameBuilder &NameBuilder) {
109+
110+ SmallVector<const Expr *> WorkList;
111+ const VarDecl *VD = nullptr ;
112+ const Expr *E = ME ;
113+
114+ for (;;) {
115+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
116+ assert (isa<VarDecl>(DRE ->getDecl ()) &&
117+ " member expr base is not a var decl" );
118+ VD = cast<VarDecl>(DRE ->getDecl ());
119+ NameBuilder.pushName (VD ->getName ());
120+ break ;
121+ }
122+
123+ WorkList.push_back (E);
124+ if (const auto *MExp = dyn_cast<MemberExpr>(E))
125+ E = MExp->getBase ();
126+ else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
127+ E = ICE ->getSubExpr ();
128+ else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
129+ E = ASE ->getBase ();
130+ else if (isa<CXXThisExpr>(E))
131+ // Resource member access on "this" pointer not yet implemented
132+ // (llvm/llvm-project#190299)
133+ return nullptr ;
134+ else
135+ llvm_unreachable (" unexpected expr type in resource member access" );
136+
137+ assert (E && " expected valid expression" );
138+ }
139+
140+ while (!WorkList.empty ()) {
141+ E = WorkList.pop_back_val ();
142+ if (const auto *ME = dyn_cast<MemberExpr>(E)) {
143+ NameBuilder.pushName (
144+ ME ->getMemberNameInfo ().getName ().getAsIdentifierInfo ()->getName ());
145+ } else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
146+ if (ICE ->getCastKind () == CK_UncheckedDerivedToBase) {
147+ CXXRecordDecl *DerivedRD =
148+ ICE ->getSubExpr ()->getType ()->getAsCXXRecordDecl ();
149+ CXXRecordDecl *BaseRD = ICE ->getType ()->getAsCXXRecordDecl ();
150+ NameBuilder.pushBaseNameHierarchy (DerivedRD, BaseRD);
151+ }
152+ } else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
153+ const Expr *IdxExpr = ASE ->getIdx ();
154+ std::optional<llvm::APSInt> Value =
155+ IdxExpr->getIntegerConstantExpr (VD ->getASTContext ());
156+ assert (Value &&
157+ " expected constant index in struct with resource array access" );
158+ NameBuilder.pushArrayIndex (Value->getZExtValue ());
159+ } else {
160+ llvm_unreachable (" unexpected expr type in resource member access" );
161+ }
162+ }
163+ return VD ;
164+ }
165+
166+ // Given a MemberExpr of a resource or resource array type, find the
167+ // corresponding global resource declaration associated with the owning struct
168+ // or class instance via HLSLAssociatedResourceDeclAttr.
169+ static const VarDecl *
170+ findAssociatedResourceDeclForStruct (ASTContext &AST , const MemberExpr *ME ) {
171+
172+ EmbeddedResourceNameBuilder NameBuilder;
173+ const VarDecl *ParentVD =
174+ findStructResourceParentDeclAndBuildName (ME , NameBuilder);
175+ if (!ParentVD)
176+ return nullptr ;
177+
178+ if (!ParentVD->hasGlobalStorage ())
179+ return nullptr ;
180+
181+ IdentifierInfo *II = NameBuilder.getNameAsIdentifier (AST );
182+ for (const Attr *A : ParentVD->getAttrs ()) {
183+ if (const auto *ADA = dyn_cast<HLSLAssociatedResourceDeclAttr>(A)) {
184+ VarDecl *AssocResVD = ADA ->getResDecl ();
185+ if (AssocResVD->getIdentifier () == II )
186+ return AssocResVD;
187+ }
188+ }
189+ return nullptr ;
190+ }
191+
99192// Find array variable declaration from DeclRef expression
100- static const ValueDecl *getArrayDecl (const Expr *E) {
101- if ( const DeclRefExpr * DRE =
102- dyn_cast_or_null<DeclRefExpr>(E-> IgnoreImpCasts () ))
193+ static const ValueDecl *getArrayDecl (ASTContext & AST , const Expr *E) {
194+ E = E-> IgnoreImpCasts ();
195+ if ( const auto * DRE = dyn_cast_or_null<DeclRefExpr>(E))
103196 return DRE ->getDecl ();
197+ if (isa<MemberExpr>(E))
198+ return findAssociatedResourceDeclForStruct (AST , cast<MemberExpr>(E));
104199 return nullptr ;
105200}
106201
107202// Find array variable declaration from nested array subscript AST nodes
108- static const ValueDecl *getArrayDecl (const ArraySubscriptExpr *ASE ) {
203+ static const ValueDecl *getArrayDecl (ASTContext &AST ,
204+ const ArraySubscriptExpr *ASE ) {
109205 const Expr *E = nullptr ;
110206 while (ASE != nullptr ) {
111207 E = ASE ->getBase ()->IgnoreImpCasts ();
112208 if (!E)
113209 return nullptr ;
114210 ASE = dyn_cast<ArraySubscriptExpr>(E);
115211 }
116- return getArrayDecl (E);
212+ return getArrayDecl (AST , E);
117213}
118214
119215// Get the total size of the array, or 0 if the array is unbounded.
@@ -152,6 +248,10 @@ static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
152248 Value *NameStr = buildNameForResource (Name, CGM );
153249 Value *Space = llvm::ConstantInt::get (CGM .IntTy , Binding.getSpace ());
154250
251+ bool HasCounter = hasCounterHandle (ResourceDecl);
252+ assert ((!HasCounter || Binding.hasCounterImplicitOrderID ()) &&
253+ " resources with counter handle must have a binding with counter "
254+ " implicit order ID" );
155255 if (Binding.isExplicit ()) {
156256 // explicit binding
157257 auto *RegSlot = llvm::ConstantInt::get (CGM .IntTy , Binding.getSlot ());
@@ -174,7 +274,7 @@ static CXXMethodDecl *lookupResourceInitMethodAndSetupArgs(
174274 Args.add (RValue::get (Range), AST .IntTy );
175275 Args.add (RValue::get (Index), AST .UnsignedIntTy );
176276 Args.add (RValue::get (NameStr), AST .getPointerType (AST .CharTy .withConst ()));
177- if (Binding. hasCounterImplicitOrderID () ) {
277+ if (HasCounter ) {
178278 uint32_t CounterBinding = Binding.getCounterImplicitOrderID ();
179279 auto *CounterOrderID = llvm::ConstantInt::get (CGM .IntTy , CounterBinding);
180280 Args.add (RValue::get (CounterOrderID), AST .UnsignedIntTy );
@@ -1243,8 +1343,8 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
12431343 // Let clang codegen handle local and static resource array subscripts,
12441344 // or when the subscript references on opaque expression (as part of
12451345 // ArrayInitLoopExpr AST node).
1246- const VarDecl *ArrayDecl =
1247- dyn_cast_or_null<VarDecl>( getArrayDecl (ArraySubsExpr));
1346+ const VarDecl *ArrayDecl = dyn_cast_or_null<VarDecl>(
1347+ getArrayDecl (CGF . CGM . getContext (), ArraySubsExpr));
12481348 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage () ||
12491349 ArrayDecl->getStorageClass () == SC_Static)
12501350 return std::nullopt ;
@@ -1309,11 +1409,15 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
13091409 CGF .CGM , ResourceTy->getAsCXXRecordDecl (), Range, Index,
13101410 ArrayDecl->getName (), Binding, Args);
13111411
1312- if (!CreateMethod)
1412+ if (!CreateMethod) {
13131413 // This can happen if someone creates an array of structs that looks like
13141414 // an HLSL resource record array but it does not have the required static
13151415 // create method. No binding will be generated for it.
1416+ assert (!ResourceTy->getAsCXXRecordDecl ()->isImplicit () &&
1417+ " create method lookup should always succeed for built-in resource "
1418+ " records" );
13161419 return std::nullopt ;
1420+ }
13171421
13181422 callResourceInitMethod (CGF , CreateMethod, Args, ValueSlot.getAddress ());
13191423
@@ -1341,7 +1445,8 @@ bool CGHLSLRuntime::emitResourceArrayCopy(LValue &LHS, Expr *RHSExpr,
13411445 assert (ResultTy->isHLSLResourceRecordArray () && " expected resource array" );
13421446
13431447 // Let Clang codegen handle local and static resource array copies.
1344- const VarDecl *ArrayDecl = dyn_cast_or_null<VarDecl>(getArrayDecl (RHSExpr));
1448+ const VarDecl *ArrayDecl =
1449+ dyn_cast_or_null<VarDecl>(getArrayDecl (CGF .CGM .getContext (), RHSExpr));
13451450 if (!ArrayDecl || !ArrayDecl->hasGlobalStorage () ||
13461451 ArrayDecl->getStorageClass () == SC_Static)
13471452 return false ;
@@ -1464,6 +1569,37 @@ std::optional<LValue> CGHLSLRuntime::emitBufferArraySubscriptExpr(
14641569 return CGF .MakeAddrLValue (Addr, E->getType (), EltBaseInfo, EltTBAAInfo);
14651570}
14661571
1572+ std::optional<LValue>
1573+ CGHLSLRuntime::emitResourceMemberExpr (CodeGenFunction &CGF ,
1574+ const MemberExpr *ME ) {
1575+ assert ((ME ->getType ()->isHLSLResourceRecord () ||
1576+ ME ->getType ()->isHLSLResourceRecordArray ()) &&
1577+ " expected resource member expression" );
1578+
1579+ if (ME ->getType ()->isHLSLResourceRecordArray ()) {
1580+ // FIXME: Handle member access of the whole array of resources
1581+ // (llvm/llvm-project#187087). Access to individual resource array elements
1582+ // is already handled in emitResourceArraySubscriptExpr.
1583+ return std::nullopt ;
1584+ }
1585+
1586+ const VarDecl *ResourceVD =
1587+ findAssociatedResourceDeclForStruct (CGF .CGM .getContext (), ME );
1588+ if (!ResourceVD)
1589+ return std::nullopt ;
1590+
1591+ GlobalVariable *ResGV =
1592+ cast<GlobalVariable>(CGM .GetAddrOfGlobalVar (ResourceVD));
1593+ const DataLayout &DL = CGM .getDataLayout ();
1594+ llvm::Type *Ty = ResGV->getValueType ();
1595+ CharUnits Align = CharUnits::fromQuantity (DL .getABITypeAlign (Ty));
1596+ Address Addr = Address (ResGV, Ty, Align);
1597+ LValue LV = LValue::MakeAddr (Addr, ME ->getType (), CGM .getContext (),
1598+ LValueBaseInfo (AlignmentSource::Type),
1599+ CGM .getTBAAAccessInfo (ME ->getType ()));
1600+ return LV ;
1601+ }
1602+
14671603namespace {
14681604// / Utility for emitting copies following the HLSL buffer layout rules (ie,
14691605// / copying out of a cbuffer).
0 commit comments