Author: Helena Kotas
Date: 2026-05-27T23:08:30-07:00
New Revision: 9cd3c0b99e5df66adcc96a2fc03b9b177d6ca487

URL: 
https://github.com/llvm/llvm-project/commit/9cd3c0b99e5df66adcc96a2fc03b9b177d6ca487
DIFF: 
https://github.com/llvm/llvm-project/commit/9cd3c0b99e5df66adcc96a2fc03b9b177d6ca487.diff

LOG: [HLSL] Codegen for handling global resource array initialization (#198891)

When a global resource array is accessed - whether it is declared at a
global scope or as part of a global struct instance - all of its
resource elements should be initialized from binding into a temporary
local resource array. This change intercepts the Clang codegen at the
relevant places to allow `CGHLSLRuntime` handle this special global
resource array initialization.

Fixes #187087
Fixes #198888

Added: 
    clang/test/CodeGenHLSL/resources/res-array-global-to-local.hlsl
    clang/test/CodeGenHLSL/resources/resources-in-structs-array-to-local.hlsl

Modified: 
    clang/lib/CodeGen/CGExpr.cpp
    clang/lib/CodeGen/CGExprAgg.cpp
    clang/lib/CodeGen/CGHLSLRuntime.cpp
    clang/lib/CodeGen/CGHLSLRuntime.h
    clang/test/CodeGenHLSL/resources/res-array-local2.hlsl
    clang/test/CodeGenHLSL/resources/resource-bindings.hlsl

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 77fd47ed42f03..0160b353f8f32 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3460,6 +3460,16 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction 
&CGF,
       return CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
   }
 
+  // Global HLSL resource arrays initialized on access; create a temporary with
+  // the initialized global resource array.
+  if (CGF.getLangOpts().HLSL && VD->getType()->isHLSLResourceRecordArray()) {
+    std::optional<LValue> LV =
+        CGF.CGM.getHLSLRuntime().emitGlobalResourceArrayAsLValue(
+            CGF, VD, E->getExprLoc());
+    if (LV.has_value())
+      return LV.value();
+  }
+
   llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
 
   if (VD->getTLSKind() != VarDecl::TLS_None)
@@ -6767,9 +6777,14 @@ LValue CodeGenFunction::EmitHLSLArrayAssignLValue(const 
BinaryOperator *E) {
 
   // If the RHS is a global resource array, copy all individual resources
   // into LHS.
-  if (E->getRHS()->getType()->isHLSLResourceRecordArray())
-    if (CGM.getHLSLRuntime().emitResourceArrayCopy(LHS, E->getRHS(), *this))
+  if (E->getRHS()->getType()->isHLSLResourceRecordArray()) {
+    AggValueSlot Slot = AggValueSlot::forAddr(
+        LHS.getAddress(), Qualifiers(), AggValueSlot::IsDestructed_t(true),
+        AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false),
+        AggValueSlot::DoesNotOverlap);
+    if (CGM.getHLSLRuntime().emitGlobalResourceArray(*this, E->getRHS(), Slot))
       return LHS;
+  }
 
   // In C the RHS of an assignment operator is an RValue.
   // EmitAggregateAssign takes an LValue for the RHS. Instead we can call

diff  --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 9f42ea09e3617..befc2659b2f4c 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -972,6 +972,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
     [[fallthrough]];
 
   case CK_HLSLArrayRValue:
+    if (CGF.getLangOpts().HLSL &&
+        E->getSubExpr()->getType()->isHLSLResourceRecordArray())
+      if (CGF.CGM.getHLSLRuntime().emitGlobalResourceArray(CGF, E, Dest))
+        break;
     Visit(E->getSubExpr());
     break;
   case CK_HLSLAggregateSplatCast: {

diff  --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 911d8f1523f7c..33d76cbda494a 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -194,6 +194,8 @@ static const ValueDecl *getArrayDecl(ASTContext &AST, const 
Expr *E) {
   E = E->IgnoreImpCasts();
   if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(E))
     return DRE->getDecl();
+  if (auto *OVE = dyn_cast<OpaqueValueExpr>(E))
+    E = OVE->getSourceExpr()->IgnoreImpCasts();
   if (isa<MemberExpr>(E))
     return findAssociatedResourceDeclForStruct(AST, cast<MemberExpr>(E));
   return nullptr;
@@ -296,12 +298,13 @@ static void callResourceInitMethod(CodeGenFunction &CGF,
   CGF.EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr);
 }
 
-// Initializes local resource array variable. For multi-dimensional arrays it
-// calls itself recursively to initialize its sub-arrays. The Index used in the
-// resource constructor calls will begin at StartIndex and will be incremented
-// for each array element. The last used resource Index is returned to the
-// caller. If the function returns std::nullopt, it indicates an error.
-static std::optional<llvm::Value *> initializeLocalResourceArray(
+// Initializes local resource array variable with global resource array
+// elements. For multi-dimensional arrays it calls itself recursively to
+// initialize its sub-arrays. The Index used in the resource constructor calls
+// will begin at StartIndex and will be incremented for each array element. The
+// last used resource Index is returned to the caller. If the function returns
+// std::nullopt, it indicates an error.
+static std::optional<llvm::Value *> initializeResourceArrayFromGlobal(
     CodeGenFunction &CGF, CXXRecordDecl *ResourceDecl,
     const ConstantArrayType *ArrayTy, AggValueSlot &ValueSlot,
     llvm::Value *Range, llvm::Value *StartIndex, StringRef ResourceName,
@@ -329,9 +332,10 @@ static std::optional<llvm::Value *> 
initializeLocalResourceArray(
         Index = CGF.Builder.CreateAdd(Index, One);
         GEPIndices.back() = llvm::ConstantInt::get(IntTy, I);
       }
-      std::optional<llvm::Value *> MaybeIndex = initializeLocalResourceArray(
-          CGF, ResourceDecl, SubArrayTy, ValueSlot, Range, Index, ResourceName,
-          Binding, GEPIndices, ArraySubsExprLoc);
+      std::optional<llvm::Value *> MaybeIndex =
+          initializeResourceArrayFromGlobal(
+              CGF, ResourceDecl, SubArrayTy, ValueSlot, Range, Index,
+              ResourceName, Binding, GEPIndices, ArraySubsExprLoc);
       if (!MaybeIndex)
         return std::nullopt;
       Index = *MaybeIndex;
@@ -1443,7 +1447,7 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
     // needs to be initialized.
     const ConstantArrayType *ArrayTy =
         cast<ConstantArrayType>(ResultTy.getTypePtr());
-    std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
+    std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
         CGF, ResourceTy->getAsCXXRecordDecl(), ArrayTy, ValueSlot, Range, 
Index,
         ArrayDecl->getName(), Binding, {llvm::ConstantInt::get(CGM.IntTy, 0)},
         ArraySubsExpr->getExprLoc());
@@ -1453,20 +1457,15 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
   return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
 }
 
-// If RHSExpr is a global resource array, initialize all of its resources and
-// set them into LHS. Returns false if no copy has been performed and the
-// array copy should be handled by Clang codegen.
-bool CGHLSLRuntime::emitResourceArrayCopy(LValue &LHS, Expr *RHSExpr,
-                                          CodeGenFunction &CGF) {
-  QualType ResultTy = RHSExpr->getType();
-  assert(ResultTy->isHLSLResourceRecordArray() && "expected resource array");
-
-  // Let Clang codegen handle local and static resource array copies.
-  const VarDecl *ArrayDecl =
-      dyn_cast_or_null<VarDecl>(getArrayDecl(CGF.CGM.getContext(), RHSExpr));
-  if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
-      ArrayDecl->getStorageClass() == SC_Static)
-    return false;
+// Initialize all resources of a global resource array into provided slot.
+bool CGHLSLRuntime::initializeGlobalResourceArray(CodeGenFunction &CGF,
+                                                  const VarDecl *ArrayDecl,
+                                                  SourceLocation Loc,
+                                                  AggValueSlot &DestSlot) {
+  assert(ArrayDecl->getType()->isHLSLResourceRecordArray() &&
+         ArrayDecl->hasGlobalStorage() &&
+         ArrayDecl->getStorageClass() != SC_Static &&
+         "expected global non-static resource array");
 
   // Find binding info for the resource array. For implicit binding
   // the HLSLResourceBindingAttr should have been added by SemaHLSL.
@@ -1476,27 +1475,63 @@ bool CGHLSLRuntime::emitResourceArrayCopy(LValue &LHS, 
Expr *RHSExpr,
 
   // Find the individual resource type.
   ASTContext &AST = ArrayDecl->getASTContext();
-  QualType ResTy = AST.getBaseElementType(ResultTy);
-  const auto *ResArrayTy = cast<ConstantArrayType>(ResultTy.getTypePtr());
-
-  // Use the provided LHS for the result.
-  AggValueSlot ValueSlot = AggValueSlot::forAddr(
-      LHS.getAddress(), Qualifiers(), AggValueSlot::IsDestructed_t(true),
-      AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false),
-      AggValueSlot::DoesNotOverlap);
+  QualType ResTy = AST.getBaseElementType(ArrayDecl->getType());
+  const auto *ResArrayTy =
+      cast<ConstantArrayType>(ArrayDecl->getType().getTypePtr());
 
   // Create Value for index and total array size (= range size).
   int Size = getTotalArraySize(AST, ResArrayTy);
   llvm::Value *Zero = llvm::ConstantInt::get(CGM.IntTy, 0);
   llvm::Value *Range = llvm::ConstantInt::get(CGM.IntTy, Size);
 
-  // Initialize individual resources in the array into LHS.
-  std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
-      CGF, ResTy->getAsCXXRecordDecl(), ResArrayTy, ValueSlot, Range, Zero,
-      ArrayDecl->getName(), Binding, {Zero}, RHSExpr->getExprLoc());
+  // Initialize individual resources in the array into DestSlot.
+  std::optional<llvm::Value *> EndIndex = initializeResourceArrayFromGlobal(
+      CGF, ResTy->getAsCXXRecordDecl(), ResArrayTy, DestSlot, Range, Zero,
+      ArrayDecl->getName(), Binding, {Zero}, Loc);
   return EndIndex.has_value();
 }
 
+// If the expression is a global resource array, initialize all of its 
resources
+// into Dest. Returns false if no initialization has been performed and the
+// array copy should be handled by the default codegen.
+bool CGHLSLRuntime::emitGlobalResourceArray(CodeGenFunction &CGF, const Expr 
*E,
+                                            AggValueSlot &DestSlot) {
+  assert(E->getType()->isHLSLResourceRecordArray() &&
+         "expected resource array");
+
+  // Find the array declaration for the expression. Fallback to the default
+  // handling if it's not a global resource array.
+  const VarDecl *ArrayDecl =
+      dyn_cast_or_null<VarDecl>(getArrayDecl(CGF.CGM.getContext(), E));
+  if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
+      ArrayDecl->getStorageClass() == SC_Static)
+    return false;
+
+  return initializeGlobalResourceArray(CGF, ArrayDecl, E->getExprLoc(),
+                                       DestSlot);
+}
+
+// If the expression is a global resource array, create a temporary and
+// initialize all of its resources, and return it as an LValue. Returns nullopt
+// if no initialization has been performed and the handling should follow the
+// default path.
+std::optional<LValue> CGHLSLRuntime::emitGlobalResourceArrayAsLValue(
+    CodeGenFunction &CGF, const VarDecl *ArrayDecl, SourceLocation Loc) {
+  assert(ArrayDecl->getType()->isHLSLResourceRecordArray() &&
+         "expected resource array declaration");
+
+  if (!ArrayDecl->hasGlobalStorage() ||
+      ArrayDecl->getStorageClass() == SC_Static)
+    return std::nullopt;
+
+  AggValueSlot TmpArraySlot =
+      CGF.CreateAggTemp(ArrayDecl->getType(), "tmpResArray");
+  if (initializeGlobalResourceArray(CGF, ArrayDecl, Loc, TmpArraySlot))
+    return CGF.MakeAddrLValue(TmpArraySlot.getAddress(), ArrayDecl->getType(),
+                              AlignmentSource::Decl);
+  return std::nullopt;
+}
+
 RawAddress CGHLSLRuntime::createBufferMatrixTempAddress(const LValue &LV,
                                                         SourceLocation Loc,
                                                         CodeGenFunction &CGF) {
@@ -1588,18 +1623,16 @@ CGHLSLRuntime::emitResourceMemberExpr(CodeGenFunction 
&CGF,
           ME->getType()->isHLSLResourceRecordArray()) &&
          "expected resource member expression");
 
-  if (ME->getType()->isHLSLResourceRecordArray()) {
-    // FIXME: Handle member access of the whole array of resources
-    // (llvm/llvm-project#187087). Access to individual resource array elements
-    // is already handled in emitResourceArraySubscriptExpr.
-    return std::nullopt;
-  }
-
   const VarDecl *ResourceVD =
       findAssociatedResourceDeclForStruct(CGF.CGM.getContext(), ME);
   if (!ResourceVD)
     return std::nullopt;
 
+  // Handle member of resource array type.
+  if (ResourceVD->getType()->isHLSLResourceRecordArray())
+    return emitGlobalResourceArrayAsLValue(CGF, ResourceVD, ME->getExprLoc());
+
+  // Handle member that is an individual resource.
   GlobalVariable *ResGV =
       cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(ResourceVD));
   const DataLayout &DL = CGM.getDataLayout();

diff  --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index d7ac2346f2428..4be6d1c1271ac 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -79,6 +79,7 @@ namespace CodeGen {
 class CodeGenModule;
 class CodeGenFunction;
 class LValue;
+class AggValueSlot;
 
 class CGHLSLOffsetInfo {
   SmallVector<uint32_t> Offsets;
@@ -299,7 +300,12 @@ class CGHLSLRuntime {
   std::optional<LValue>
   emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E,
                                  CodeGenFunction &CGF);
-  bool emitResourceArrayCopy(LValue &LHS, Expr *RHSExpr, CodeGenFunction &CGF);
+
+  bool emitGlobalResourceArray(CodeGenFunction &CGF, const Expr *E,
+                               AggValueSlot &DestSlot);
+  std::optional<LValue>
+  emitGlobalResourceArrayAsLValue(CodeGenFunction &CGF,
+                                  const VarDecl *ArrayDecl, SourceLocation 
Loc);
 
   std::optional<LValue> emitBufferArraySubscriptExpr(
       const ArraySubscriptExpr *E, CodeGenFunction &CGF,
@@ -349,6 +355,11 @@ class CGHLSLRuntime {
                              HLSLAppliedSemanticAttr *Semantic,
                              std::optional<unsigned> Index);
 
+  bool initializeGlobalResourceArray(CodeGenFunction &CGF,
+                                     const VarDecl *ArrayDecl,
+                                     SourceLocation Loc,
+                                     AggValueSlot &DestSlot);
+
   llvm::Triple::ArchType getArch();
 
   llvm::DenseMap<const clang::RecordType *, llvm::StructType *> LayoutTypes;

diff  --git a/clang/test/CodeGenHLSL/resources/res-array-global-to-local.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global-to-local.hlsl
new file mode 100644
index 0000000000000..44a9ae6695e77
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/res-array-global-to-local.hlsl
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library 
-finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck 
%s -check-prefixes=CHECK
+
+// CHECK: [[BufA:@.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 
1
+// CHECK: [[BufB:@.*]] = private unnamed_addr constant [2 x i8] c"B\00", align 
1
+
+// one-dimensional array
+RWBuffer<float> A[2] : register(u10, space1);
+
+// multi-dimensional array
+[[vk::binding(13)]] 
+RWBuffer<float> B[2][2] : register(u13, space0);
+
+void useArray(RWBuffer<float> LocalArg[2]) {
+}
+
+void useMultiArray(RWBuffer<float> LocalArg[2][2]) {
+}
+
+// CHECK-LABEL: case1
+// CHECK: %LocalOne = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK: [[ArrayTmp:%.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+
+// - Initialize all resources of the global array into a local temporary.
+// CHECK: [[ArrayPtr0:%.*]] = getelementptr [2 x %"class.hlsl::RWBuffer"], ptr 
[[ArrayTmp]], i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr0]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 0, ptr noundef 
[[BufA]])
+// CHECK-NEXT: [[ArrayPtr1:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[ArrayTmp]], i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr1]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 1, ptr noundef 
[[BufA]])
+
+// - Copy from temporary to local array (in a loop)
+// CHECK: %arrayinit.begin = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %LocalOne, i32 0, i32 0
+// CHECK: arrayinit.body:
+// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer(hlsl::RWBuffer<float> 
const&)(ptr {{.*}}, ptr {{.*}})
+// CHECK: arrayinit.end:
+// CHECK: ret void
+void case1() {
+  // local one-dimensional array initialized with global array
+  RWBuffer<float> LocalOne[2] = A;
+}
+
+// CHECK-LABEL: case2
+// CHECK: %LocalTwo = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+
+// - Local array is first initialized to poison using the default constructor 
(in a loop)
+//
+// CHECK: %array.begin = getelementptr inbounds [2 x %"class.hlsl::RWBuffer"], 
ptr %LocalTwo, i32 0, i32 0
+// CHECK: arrayctor.loop
+// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer()(ptr {{.*}})
+// CHECK: arrayctor.cont:
+
+// - Initialize individual resource elements directly into the local array
+// CHECK: [[ArrayPtr0:%.*]] = getelementptr [2 x %"class.hlsl::RWBuffer"], ptr 
%LocalTwo, i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr0]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 0, ptr noundef 
[[BufA]])
+// CHECK-NEXT: [[ArrayPtr1:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr %LocalTwo, i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr1]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 1, ptr noundef 
[[BufA]])
+// CHECK: ret void
+void case2() {
+  // local one-dimensional array initialized with assignment
+  RWBuffer<float> LocalTwo[2];
+  LocalTwo = A;
+}
+
+// CHECK-LABEL: case3
+// CHECK: [[AggTmp:%.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: [[ArrayPtr0:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[AggTmp]], i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr0]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 0, ptr noundef 
[[BufA]])
+// CHECK-NEXT: [[ArrayPtr1:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[AggTmp]], i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr1]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 1, ptr noundef 
[[BufA]])
+// CHECK-NEXT: call void @useArray(hlsl::RWBuffer<float> [2])(ptr {{.*}} 
[[AggTmp]])
+void case3() {
+  // resource array as function argument
+  useArray(A);
+}
+
+// CHECK-LABEL: case4
+// CHECK: %LocalThree = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
+// CHECK: [[TmpResArray:%.*]] = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], 
align 4
+
+// - Initialize all resources of the global array into a local temporary.
+// CHECK: [[ArrayPtr00:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[TmpResArray]], i32 0, i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr00]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 0, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr01:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[TmpResArray]], i32 0, i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr01]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 1, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr10:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[TmpResArray]], i32 0, i32 1, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr10]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 2, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr11:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[TmpResArray]], i32 0, i32 1, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr11]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 3, ptr noundef 
[[BufB]])
+
+// - Copy from temporary to local array (in a double loop)
+// CHECK: %arrayinit.begin = getelementptr inbounds [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalThree, i32 0, i32 0
+// CHECK: arrayinit.body:
+// CHECK: arrayinit.body2:
+// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer(hlsl::RWBuffer<float> 
const&)(ptr {{.*}}, ptr {{.*}})
+// CHECK: arrayinit.end:
+// CHECK: arrayinit.end{{[0-9]+}}:
+// CHECK: ret void
+void case4() {
+  // local multi-dimensional array initialized with global array
+  RWBuffer<float> LocalThree[2][2] = B;
+}
+
+// CHECK-LABEL: case5
+// CHECK: %LocalFour = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
+
+// - Local array is first initialized to poison using the default constructor 
(in a loop)
+//
+// CHECK: %array.begin = getelementptr inbounds [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 0, i32 0
+// CHECK: arrayctor.loop
+// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer()(ptr {{.*}})
+// CHECK: arrayctor.cont:
+
+// - Initialize individual resource elements directly into the local array
+// CHECK: [[ArrayPtr00:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr00]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 0, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr01:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr01]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 1, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr10:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 1, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr10]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 2, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr11:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 1, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr11]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 3, ptr noundef 
[[BufB]])
+// CHECK: ret void
+void case5() {
+  // local multi-dimensional array initialized with assignment
+  RWBuffer<float> LocalFour[2][2];
+  LocalFour = B;
+}
+
+// CHECK-LABEL: case6
+// CHECK: [[AggTmp:%.*]] = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
+// CHECK: [[ArrayPtr00:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[AggTmp]], i32 0, i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr00]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 0, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr01:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[AggTmp]], i32 0, i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr01]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 1, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr10:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[AggTmp]], i32 0, i32 1, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr10]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 2, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr11:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[AggTmp]], i32 0, i32 1, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr11]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 3, ptr noundef 
[[BufB]])
+// CHECK-NEXT: call void @useMultiArray(hlsl::RWBuffer<float> [2][2])(ptr 
noundef byval([2 x [2 x %"class.hlsl::RWBuffer"]]) align 4 %agg.tmp)
+// CHECK: ret void
+void case6() {
+  // resource array as function argument
+  useMultiArray(B);
+}
+
+// CHECK-LABEL: case7
+// CHECK: [[AggTmp:%.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK: [[Tmp:%.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: [[ArrayPtr0:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[Tmp]], i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr0]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 2, ptr noundef 
[[BufB]])
+// CHECK-NEXT: [[ArrayPtr1:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[Tmp]], i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr1]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 3, ptr noundef 
[[BufB]])
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AggTmp]], ptr 
align 4 [[Tmp]], i32 8, i1 false)
+// CHECK-NEXT: call void @useArray(hlsl::RWBuffer<float> [2])(ptr noundef 
byval([2 x %"class.hlsl::RWBuffer"]) align 4 [[AggTmp]])
+void case7() {
+  // subset of multi-dimensional resource array as function argument
+  useArray(B[1]);
+}

diff  --git a/clang/test/CodeGenHLSL/resources/res-array-local2.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local2.hlsl
index cde351fe6e66f..0aaa608258669 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local2.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local2.hlsl
@@ -3,7 +3,11 @@
 
 // This test verifies handling of local arrays of resources when used as a 
function argument.
 
-// CHECK: @_ZL1A = internal global [3 x %"class.hlsl::RWBuffer"] poison, align 
4
+// Resource array elements are initialized on access; there should never a 
global
+// array of resources (unless it is static).
+// CHECK-NOT: @_ZL1A = internal global [3 x %"class.hlsl::RWBuffer"] poison, 
align 4
+
+// CHECK: [[BufA:@.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 
1
 
 RWBuffer<float> A[3] : register(u0);
 RWStructuredBuffer<float> Out : register(u0);
@@ -28,10 +32,15 @@ float foo(RWBuffer<float> LocalA[3]) {
 [numthreads(4,1,1)]
 void main() {
 // Check that the `main` function calls `foo` with a local copy of the array
-// CHECK-NEXT: %[[Tmp:.*]] = alloca [3 x %"class.hlsl::RWBuffer"], align 4
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp]], ptr 
align 4 @_ZL1A, i32 12, i1 false)
+// CHECK-NEXT: [[Tmp:%.*]] = alloca [3 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: [[TmpPtr0:%.*]] = getelementptr [3 x %"class.hlsl::RWBuffer"], 
ptr [[Tmp]], i32 0, i32 0
+// CHECK-NEXT: call void 
@_ZN4hlsl8RWBufferIfE19__createFromBindingEjjijPKc(ptr {{.*}} [[TmpPtr0]], i32 
noundef 0, i32 noundef 0, i32 noundef 3, i32 noundef 0, ptr noundef [[BufA]])
+// CHECK-NEXT: [[TmpPtr1:%.*]] = getelementptr [3 x %"class.hlsl::RWBuffer"], 
ptr [[Tmp]], i32 0, i32 1
+// CHECK-NEXT: call void 
@_ZN4hlsl8RWBufferIfE19__createFromBindingEjjijPKc(ptr {{.*}} [[TmpPtr1]], i32 
noundef 0, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef [[BufA]])
+// CHECK-NEXT: [[TmpPtr2:%.*]] = getelementptr [3 x %"class.hlsl::RWBuffer"], 
ptr [[Tmp]], i32 0, i32 2
+// CHECK-NEXT: call void 
@_ZN4hlsl8RWBufferIfE19__createFromBindingEjjijPKc(ptr {{.*}} [[TmpPtr2]], i32 
noundef 0, i32 noundef 0, i32 noundef 3, i32 noundef 2, ptr noundef [[BufA]])
 
-// CHECK-NEXT: %[[ReturnedValue:.*]] = call {{.*}} float 
@_Z3fooA3_N4hlsl8RWBufferIfEE(ptr noundef byval([3 x %"class.hlsl::RWBuffer"]) 
align 4 %[[Tmp]])
+// CHECK-NEXT: %[[ReturnedValue:.*]] = call {{.*}} float 
@_Z3fooA3_N4hlsl8RWBufferIfEE(ptr {{.*}} [[Tmp]])
 // CHECK-NEXT: %[[OutBufPtr:.*]] = call {{.*}} ptr 
@_ZNK4hlsl18RWStructuredBufferIfEixEj(ptr {{.*}} @_ZL3Out, i32 noundef 0)
 // CHECK-NEXT: store float %[[ReturnedValue]], ptr %[[OutBufPtr]], align 4
 // CHECK-NEXT: ret void

diff  --git a/clang/test/CodeGenHLSL/resources/resource-bindings.hlsl 
b/clang/test/CodeGenHLSL/resources/resource-bindings.hlsl
index 1d85048db87a8..bd451874c123d 100644
--- a/clang/test/CodeGenHLSL/resources/resource-bindings.hlsl
+++ b/clang/test/CodeGenHLSL/resources/resource-bindings.hlsl
@@ -5,13 +5,15 @@
 // CHECK: %"class.hlsl::RWBuffer.0" = type { target("dx.TypedBuffer", float, 
1, 0, 0) }
 // CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", i32, 
0, 0) }
 // CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", 
%struct.S, 1, 0), target("dx.RawBuffer", %struct.S, 1, 0) }
-// CHECK: %"class.hlsl::RWBuffer.1" = type { target("dx.TypedBuffer", double, 
1, 0, 0) }
 
 // CHECK: @_ZL4U0S0 = internal global %"class.hlsl::RWBuffer" poison, align 4
 // CHECK: @_ZL4U5S3 = internal global %"class.hlsl::RWBuffer.0" poison, align 4
 // CHECK: @_ZL4T2S2 = internal global %"class.hlsl::StructuredBuffer" poison, 
align 4
 // CHECK: @_ZL4T3S0 = internal global %"class.hlsl::RWStructuredBuffer" 
poison, align 4
-// CHECK: @_ZL5Array = internal global [10 x %"class.hlsl::RWBuffer.1"] 
poison, align 4
+
+// Resource array elements are initialized on access; there should never a 
global
+// array of resources (unless it is static).
+// CHECK-NOT: @_ZL5Array = internal global [10 x %"class.hlsl::RWBuffer.1"] 
poison, align 4
 
 // CHECK: call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
 // CHECK-SAME: 
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(
@@ -40,8 +42,4 @@ RWBuffer<double> Array[10] : register(u4, space0);
 
 [numthreads(4,1,1)]
 void main() {
-  // Reference Array to ensure it is emitted and we can test that it is 
initialized
-  // to poison, but do not index it.
-  // Non-array resources are always emitted because they have a constructor 
initializer.
-  (void)Array;
 }

diff  --git 
a/clang/test/CodeGenHLSL/resources/resources-in-structs-array-to-local.hlsl 
b/clang/test/CodeGenHLSL/resources/resources-in-structs-array-to-local.hlsl
new file mode 100644
index 0000000000000..0a83517f36cbc
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/resources-in-structs-array-to-local.hlsl
@@ -0,0 +1,162 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library 
-finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck 
%s -check-prefixes=CHECK
+
+// CHECK: @A.Bufs.str = private unnamed_addr constant [7 x i8] c"A.Bufs\00", 
align 1
+// CHECK: @B.Bufs.str = private unnamed_addr constant [7 x i8] c"B.Bufs\00", 
align 1
+
+// structs with one-dimensional array
+struct StructA {
+  RWBuffer<float> Bufs[2];
+};
+StructA A : register(u10, space1);
+
+// struct with multi-dimensional array
+struct StructB {
+  RWBuffer<float> Bufs[2][2];
+};
+StructB B : register(u13, space0);
+
+void useArray(RWBuffer<float> LocalArg[2]) {
+}
+
+void useMultiArray(RWBuffer<float> LocalArg[2][2]) {
+}
+
+// CHECK-LABEL: case1
+// CHECK: %LocalOne = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK: [[ArrayTmp:%.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+
+// - Initialize all resources of the global array into a local temporary.
+// CHECK: [[ArrayPtr0:%.*]] = getelementptr [2 x %"class.hlsl::RWBuffer"], ptr 
[[ArrayTmp]], i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr0]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 0, ptr noundef 
@A.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr1:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[ArrayTmp]], i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr1]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 1, ptr noundef 
@A.Bufs.str)
+
+// - Copy from temporary to local array (in a loop)
+// CHECK: %arrayinit.begin = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %LocalOne, i32 0, i32 0
+// CHECK: arrayinit.body:
+// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer(hlsl::RWBuffer<float> 
const&)(ptr {{.*}}, ptr {{.*}})
+// CHECK: arrayinit.end:
+// CHECK: ret void
+void case1() {
+  // local one-dimensional array initialialized with global array
+  RWBuffer<float> LocalOne[2] = A.Bufs;
+}
+
+// CHECK-LABEL: case2
+// CHECK: %LocalTwo = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+
+// - Local array is first initialized to poison using the default constructor 
(in a loop)
+//
+// CHECK: %array.begin = getelementptr inbounds [2 x %"class.hlsl::RWBuffer"], 
ptr %LocalTwo, i32 0, i32 0
+// CHECK: arrayctor.loop
+// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer()(ptr {{.*}})
+// CHECK: arrayctor.cont:
+
+// - Initialize individual resource elements directly into the local array
+// CHECK: [[ArrayPtr0:%.*]] = getelementptr [2 x %"class.hlsl::RWBuffer"], ptr 
%LocalTwo, i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr0]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 0, ptr noundef 
@A.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr1:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr %LocalTwo, i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr1]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 1, ptr noundef 
@A.Bufs.str)
+// CHECK: ret void
+void case2() {
+  // local one-dimensional array initialialized with assignment
+  RWBuffer<float> LocalTwo[2];
+  LocalTwo = A.Bufs;
+}
+
+// CHECK-LABEL: case3
+// CHECK: [[AggTmp:%.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: [[ArrayPtr0:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[AggTmp]], i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr0]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 0, ptr noundef 
@A.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr1:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[AggTmp]], i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr1]], 
i32 noundef 10, i32 noundef 1, i32 noundef 2, i32 noundef 1, ptr noundef 
@A.Bufs.str)
+// CHECK-NEXT: call void @useArray(hlsl::RWBuffer<float> [2])(ptr {{.*}} 
[[AggTmp]])
+void case3() {
+  // resource array as function argument
+  useArray(A.Bufs);
+}
+
+// CHECK-LABEL: case4
+// CHECK: %LocalThree = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
+// CHECK: [[TmpResArray:%.*]] = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], 
align 4
+
+// - Initialize all resources of the global array into a local temporary.
+// CHECK: [[ArrayPtr00:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[TmpResArray]], i32 0, i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr00]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 0, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr01:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[TmpResArray]], i32 0, i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr01]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 1, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr10:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[TmpResArray]], i32 0, i32 1, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr10]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 2, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr11:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[TmpResArray]], i32 0, i32 1, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr11]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 3, ptr noundef 
@B.Bufs.str)
+
+// - Copy from temporary to local array (in a double loop)
+// CHECK: %arrayinit.begin = getelementptr inbounds [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalThree, i32 0, i32 0
+// CHECK: arrayinit.body:
+// CHECK: arrayinit.body2:
+// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer(hlsl::RWBuffer<float> 
const&)(ptr {{.*}}, ptr {{.*}})
+// CHECK: arrayinit.end:
+// CHECK: arrayinit.end{{[0-9]+}}:
+// CHECK: ret void
+void case4() {
+  // local multi-dimensional array initialialized with global array
+  RWBuffer<float> LocalThree[2][2] = B.Bufs;
+}
+
+// CHECK-LABEL: case5
+// CHECK: %LocalFour = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
+
+// - Local array is first initialized to poison using the default constructor 
(in a loop)
+//
+// CHECK: %array.begin = getelementptr inbounds [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 0, i32 0
+// CHECK: arrayctor.loop
+// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer()(ptr {{.*}})
+// CHECK: arrayctor.cont:
+
+// - Initialize individual resource elements directly into the local array
+// CHECK: [[ArrayPtr00:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr00]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 0, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr01:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr01]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 1, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr10:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 1, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr10]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 2, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr11:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %LocalFour, i32 0, i32 1, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr11]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 3, ptr noundef 
@B.Bufs.str)
+// CHECK: ret void
+void case5() {
+  // local multi-dimensional array initialialized with assignment
+  RWBuffer<float> LocalFour[2][2];
+  LocalFour = B.Bufs;
+}
+
+// CHECK-LABEL: case6
+// CHECK: [[AggTmp:%.*]] = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
+// CHECK: [[ArrayPtr00:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[AggTmp]], i32 0, i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr00]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 0, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr01:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[AggTmp]], i32 0, i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr01]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 1, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr10:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[AggTmp]], i32 0, i32 1, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr10]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 2, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr11:%.*]] = getelementptr [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr [[AggTmp]], i32 0, i32 1, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr11]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 3, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: call void @useMultiArray(hlsl::RWBuffer<float> [2][2])(ptr 
noundef byval([2 x [2 x %"class.hlsl::RWBuffer"]]) align 4 %agg.tmp)
+// CHECK: ret void
+void case6() {
+  // resource array as function argument
+  useMultiArray(B.Bufs);
+}
+
+// CHECK-LABEL: case7
+// CHECK: [[AggTmp:%.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK: [[Tmp:%.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: [[ArrayPtr0:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[Tmp]], i32 0, i32 0
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr0]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 2, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: [[ArrayPtr1:%.*]] = getelementptr [2 x 
%"class.hlsl::RWBuffer"], ptr [[Tmp]], i32 0, i32 1
+// CHECK-NEXT: call void 
@hlsl::RWBuffer<float>::__createFromBinding({{.*}})(ptr {{.*}} [[ArrayPtr1]], 
i32 noundef 13, i32 noundef 0, i32 noundef 4, i32 noundef 3, ptr noundef 
@B.Bufs.str)
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AggTmp]], ptr 
align 4 [[Tmp]], i32 8, i1 false)
+// CHECK-NEXT: call void @useArray(hlsl::RWBuffer<float> [2])(ptr noundef 
byval([2 x %"class.hlsl::RWBuffer"]) align 4 [[AggTmp]])
+void case7() {
+  // subset of multi-dimensional resource array as function argument
+  useArray(B.Bufs[1]);
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to