@@ -84,6 +84,124 @@ void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer,
84
84
RootSignatureValMD->addOperand (MDVals);
85
85
}
86
86
87
+ // If the specified expr is a simple decay from an array to pointer,
88
+ // return the array subexpression. Otherwise, return nullptr.
89
+ static const Expr *getSubExprFromArrayDecayOperand (const Expr *E) {
90
+ const auto *CE = dyn_cast<CastExpr>(E);
91
+ if (!CE || CE->getCastKind () != CK_ArrayToPointerDecay)
92
+ return nullptr ;
93
+ return CE->getSubExpr ();
94
+ }
95
+
96
+ // Find array variable declaration from nested array subscript AST nodes
97
+ static const ValueDecl *getArrayDecl (const ArraySubscriptExpr *ASE) {
98
+ const Expr *E = nullptr ;
99
+ while (ASE != nullptr ) {
100
+ E = getSubExprFromArrayDecayOperand (ASE->getBase ());
101
+ if (!E)
102
+ return nullptr ;
103
+ ASE = dyn_cast<ArraySubscriptExpr>(E);
104
+ }
105
+ if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
106
+ return DRE->getDecl ();
107
+ return nullptr ;
108
+ }
109
+
110
+ // Get the total size of the array, or -1 if the array is unbounded.
111
+ static int getTotalArraySize (const clang::Type *Ty) {
112
+ assert (Ty->isArrayType () && " expected array type" );
113
+ if (Ty->isIncompleteArrayType ())
114
+ return -1 ;
115
+ int Size = 1 ;
116
+ while (const auto *CAT = dyn_cast<ConstantArrayType>(Ty)) {
117
+ Size *= CAT->getSExtSize ();
118
+ Ty = CAT->getArrayElementTypeNoTypeQual ();
119
+ }
120
+ return Size;
121
+ }
122
+
123
+ // Find constructor decl for a specific resource record type and binding
124
+ // (implicit vs. explicit). The constructor has 6 parameters.
125
+ // For explicit binding the signature is:
126
+ // void(unsigned, unsigned, int, unsigned, const char *).
127
+ // For implicit binding the signature is:
128
+ // void(unsigned, int, unsigned, unsigned, const char *).
129
+ static CXXConstructorDecl *findResourceConstructorDecl (ASTContext &AST,
130
+ QualType ResTy,
131
+ bool ExplicitBinding) {
132
+ SmallVector<QualType> ExpParmTypes = {
133
+ AST.UnsignedIntTy , AST.UnsignedIntTy , AST.UnsignedIntTy ,
134
+ AST.UnsignedIntTy , AST.getPointerType (AST.CharTy .withConst ())};
135
+ ExpParmTypes[ExplicitBinding ? 2 : 1 ] = AST.IntTy ;
136
+
137
+ CXXRecordDecl *ResDecl = ResTy->getAsCXXRecordDecl ();
138
+ for (auto *Ctor : ResDecl->ctors ()) {
139
+ if (Ctor->getNumParams () != ExpParmTypes.size ())
140
+ continue ;
141
+ ParmVarDecl **ParmIt = Ctor->param_begin ();
142
+ QualType *ExpTyIt = ExpParmTypes.begin ();
143
+ for (; ParmIt != Ctor->param_end () && ExpTyIt != ExpParmTypes.end ();
144
+ ++ParmIt, ++ExpTyIt) {
145
+ if ((*ParmIt)->getType () != *ExpTyIt)
146
+ break ;
147
+ }
148
+ if (ParmIt == Ctor->param_end ())
149
+ return Ctor;
150
+ }
151
+ llvm_unreachable (" did not find constructor for resource class" );
152
+ }
153
+
154
+ static Value *buildNameForResource (llvm::StringRef BaseName,
155
+ CodeGenModule &CGM) {
156
+ std::string Str (BaseName);
157
+ std::string GlobalName (Str + " .str" );
158
+ return CGM.GetAddrOfConstantCString (Str, GlobalName.c_str ()).getPointer ();
159
+ }
160
+
161
+ static void createResourceCtorArgs (CodeGenModule &CGM, CXXConstructorDecl *CD,
162
+ llvm::Value *ThisPtr, llvm::Value *Range,
163
+ llvm::Value *Index, StringRef Name,
164
+ HLSLResourceBindingAttr *RBA,
165
+ HLSLVkBindingAttr *VkBinding,
166
+ CallArgList &Args) {
167
+ assert ((VkBinding || RBA) && " at least one a binding attribute expected" );
168
+
169
+ std::optional<uint32_t > RegisterSlot;
170
+ uint32_t SpaceNo = 0 ;
171
+ if (VkBinding) {
172
+ RegisterSlot = VkBinding->getBinding ();
173
+ SpaceNo = VkBinding->getSet ();
174
+ } else if (RBA) {
175
+ if (RBA->hasRegisterSlot ())
176
+ RegisterSlot = RBA->getSlotNumber ();
177
+ SpaceNo = RBA->getSpaceNumber ();
178
+ }
179
+
180
+ ASTContext &AST = CD->getASTContext ();
181
+ Value *NameStr = buildNameForResource (Name, CGM);
182
+ Value *Space = llvm::ConstantInt::get (CGM.IntTy , SpaceNo);
183
+
184
+ Args.add (RValue::get (ThisPtr), CD->getThisType ());
185
+ if (RegisterSlot.has_value ()) {
186
+ // explicit binding
187
+ auto *RegSlot = llvm::ConstantInt::get (CGM.IntTy , RegisterSlot.value ());
188
+ Args.add (RValue::get (RegSlot), AST.UnsignedIntTy );
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
+
193
+ } else {
194
+ // implicit binding
195
+ auto *OrderID =
196
+ llvm::ConstantInt::get (CGM.IntTy , RBA->getImplicitBindingOrderID ());
197
+ Args.add (RValue::get (Space), AST.UnsignedIntTy );
198
+ Args.add (RValue::get (Range), AST.IntTy );
199
+ Args.add (RValue::get (Index), AST.UnsignedIntTy );
200
+ Args.add (RValue::get (OrderID), AST.UnsignedIntTy );
201
+ }
202
+ Args.add (RValue::get (NameStr), AST.getPointerType (AST.CharTy .withConst ()));
203
+ }
204
+
87
205
} // namespace
88
206
89
207
llvm::Type *
@@ -590,13 +708,6 @@ static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
590
708
CGM.AddCXXGlobalInit (InitResFunc);
591
709
}
592
710
593
- static Value *buildNameForResource (llvm::StringRef BaseName,
594
- CodeGenModule &CGM) {
595
- std::string Str (BaseName);
596
- std::string GlobalName (Str + " .str" );
597
- return CGM.GetAddrOfConstantCString (Str, GlobalName.c_str ()).getPointer ();
598
- }
599
-
600
711
void CGHLSLRuntime::initializeBufferFromBinding (const HLSLBufferDecl *BufDecl,
601
712
llvm::GlobalVariable *GV,
602
713
HLSLVkBindingAttr *VkBinding) {
@@ -624,17 +735,13 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
624
735
auto *Index = llvm::ConstantInt::get (CGM.IntTy , 0 );
625
736
auto *RangeSize = llvm::ConstantInt::get (CGM.IntTy , 1 );
626
737
auto *Space = llvm::ConstantInt::get (CGM.IntTy , RBA->getSpaceNumber ());
627
- Value *Name = nullptr ;
738
+ Value *Name = buildNameForResource (BufDecl-> getName (), CGM) ;
628
739
629
740
llvm::Intrinsic::ID IntrinsicID =
630
741
RBA->hasRegisterSlot ()
631
742
? CGM.getHLSLRuntime ().getCreateHandleFromBindingIntrinsic ()
632
743
: CGM.getHLSLRuntime ().getCreateHandleFromImplicitBindingIntrinsic ();
633
744
634
- std::string Str (BufDecl->getName ());
635
- std::string GlobalName (Str + " .str" );
636
- Name = CGM.GetAddrOfConstantCString (Str, GlobalName.c_str ()).getPointer ();
637
-
638
745
// buffer with explicit binding
639
746
if (RBA->hasRegisterSlot ()) {
640
747
auto *RegSlot = llvm::ConstantInt::get (CGM.IntTy , RBA->getSlotNumber ());
@@ -701,3 +808,95 @@ void CGHLSLRuntime::emitInitListOpaqueValues(CodeGenFunction &CGF,
701
808
}
702
809
}
703
810
}
811
+
812
+ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr (
813
+ const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
814
+ assert (ArraySubsExpr->getType ()->isHLSLResourceRecord () ||
815
+ ArraySubsExpr->getType ()->isHLSLResourceRecordArray () &&
816
+ " expected resource array subscript expression" );
817
+
818
+ // let clang codegen handle local resource array subscrips
819
+ const VarDecl *ArrayDecl = dyn_cast<VarDecl>(getArrayDecl (ArraySubsExpr));
820
+ if (!ArrayDecl || !ArrayDecl->hasGlobalStorage ())
821
+ return std::nullopt;
822
+
823
+ // FIXME: this is not yet implemented (llvm/llvm-project#145426)
824
+ assert (!ArraySubsExpr->getType ()->isArrayType () &&
825
+ " indexing of array subsets it not supported yet" );
826
+
827
+ // get total array size (= range size)
828
+ const Type *ResArrayTy = ArrayDecl->getType ().getTypePtr ();
829
+ assert (ResArrayTy->isHLSLResourceRecordArray () &&
830
+ " expected array of resource classes" );
831
+ llvm::Value *Range =
832
+ llvm::ConstantInt::get (CGM.IntTy , getTotalArraySize (ResArrayTy));
833
+
834
+ // Iterate through all nested array subscript expressions to calculate
835
+ // the index in the flattened resource array (if this is a multi-
836
+ // dimensional array). The index is calculated as a sum of all indices
837
+ // multiplied by the total size of the array at that level.
838
+ Value *Index = nullptr ;
839
+ Value *Multiplier = nullptr ;
840
+ const ArraySubscriptExpr *ASE = ArraySubsExpr;
841
+ while (ASE != nullptr ) {
842
+ Value *SubIndex = CGF.EmitScalarExpr (ASE->getIdx ());
843
+ if (const auto *ArrayTy =
844
+ dyn_cast<ConstantArrayType>(ASE->getType ().getTypePtr ())) {
845
+ Value *SubMultiplier =
846
+ llvm::ConstantInt::get (CGM.IntTy , ArrayTy->getSExtSize ());
847
+ Multiplier = Multiplier ? CGF.Builder .CreateMul (Multiplier, SubMultiplier)
848
+ : SubMultiplier;
849
+ SubIndex = CGF.Builder .CreateMul (SubIndex, Multiplier);
850
+ }
851
+
852
+ Index = Index ? CGF.Builder .CreateAdd (Index, SubIndex) : SubIndex;
853
+ ASE = dyn_cast<ArraySubscriptExpr>(
854
+ getSubExprFromArrayDecayOperand (ASE->getBase ()));
855
+ }
856
+
857
+ // find binding info for the resource array
858
+ // (for implicit binding an HLSLResourceBindingAttr should have been added by
859
+ // SemaHLSL)
860
+ QualType ResourceTy = ArraySubsExpr->getType ();
861
+ HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr <HLSLVkBindingAttr>();
862
+ HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr <HLSLResourceBindingAttr>();
863
+ assert ((VkBinding || RBA) && " resource array must have a binding attribute" );
864
+
865
+ // lookup the resource class constructor based on the resource type and
866
+ // binding
867
+ CXXConstructorDecl *CD =
868
+ findResourceConstructorDecl (ArrayDecl->getASTContext (), ResourceTy,
869
+ VkBinding || RBA->hasRegisterSlot ());
870
+
871
+ // create a temporary variable for the resource class instance (we need to
872
+ // return an LValue)
873
+ RawAddress TmpVar = CGF.CreateMemTemp (ResourceTy);
874
+ if (auto *Size = CGF.EmitLifetimeStart (
875
+ CGM.getDataLayout ().getTypeAllocSize (TmpVar.getElementType ()),
876
+ TmpVar.getPointer ())) {
877
+ CGF.pushFullExprCleanup <CodeGenFunction::CallLifetimeEnd>(
878
+ NormalEHLifetimeMarker, TmpVar, Size);
879
+ }
880
+ AggValueSlot ValueSlot = AggValueSlot::forAddr (
881
+ TmpVar, Qualifiers (), AggValueSlot::IsDestructed_t (true ),
882
+ AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t (false ),
883
+ AggValueSlot::MayOverlap);
884
+
885
+ Address ThisAddress = ValueSlot.getAddress ();
886
+ llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo (
887
+ ThisAddress, CD->getThisType ()->getPointeeType ());
888
+
889
+ // assemble the constructor parameters
890
+ CallArgList Args;
891
+ createResourceCtorArgs (CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName (),
892
+ RBA, VkBinding, Args);
893
+
894
+ // call the constructor
895
+ CGF.EmitCXXConstructorCall (CD, Ctor_Complete, false , false , ThisAddress, Args,
896
+ ValueSlot.mayOverlap (),
897
+ ArraySubsExpr->getExprLoc (),
898
+ ValueSlot.isSanitizerChecked ());
899
+
900
+ return CGF.MakeAddrLValue (TmpVar, ArraySubsExpr->getType (),
901
+ AlignmentSource::Decl);
902
+ }
0 commit comments