https://github.com/hekota updated 
https://github.com/llvm/llvm-project/pull/152454

>From 10a06e36e875cbc0259d0d95700e5c4ec9721f1a Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Thu, 7 Aug 2025 00:03:37 -0700
Subject: [PATCH 01/13] [HLSL] Add `isHLSLResourceRecordArray` method to
 `clang::Type`

---
 clang/include/clang/AST/Type.h      |  1 +
 clang/lib/AST/Type.cpp              |  9 +++++++++
 clang/lib/CodeGen/CGHLSLRuntime.cpp |  9 +--------
 clang/lib/Sema/SemaHLSL.cpp         | 15 ++++-----------
 4 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 12dce309127e5..dfcf075e73312 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2724,6 +2724,7 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
   bool isHLSLAttributedResourceType() const;
   bool isHLSLInlineSpirvType() const;
   bool isHLSLResourceRecord() const;
+  bool isHLSLResourceRecordArray() const;
   bool isHLSLIntangibleType()
       const; // Any HLSL intangible type (builtin, array, class)
 
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 141edc881d683..03d7413cf95b4 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5246,6 +5246,15 @@ bool Type::isHLSLResourceRecord() const {
   return HLSLAttributedResourceType::findHandleTypeOnResource(this) != nullptr;
 }
 
+bool Type::isHLSLResourceRecordArray() const {
+  const Type *Ty = getUnqualifiedDesugaredType();
+  if (!Ty->isArrayType())
+    return false;
+  while (isa<ConstantArrayType>(Ty))
+    Ty = Ty->getArrayElementTypeNoTypeQual();
+  return Ty->isHLSLResourceRecord();
+}
+
 bool Type::isHLSLIntangibleType() const {
   const Type *Ty = getUnqualifiedDesugaredType();
 
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f64ac20545fa3..918cb3e38448d 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -103,13 +103,6 @@ llvm::Triple::ArchType CGHLSLRuntime::getArch() {
   return CGM.getTarget().getTriple().getArch();
 }
 
-// Returns true if the type is an HLSL resource class or an array of them
-static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) {
-  while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
-    Ty = CAT->getArrayElementTypeNoTypeQual();
-  return Ty->isHLSLResourceRecord();
-}
-
 // Emits constant global variables for buffer constants declarations
 // and creates metadata linking the constant globals with the buffer global.
 void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
@@ -146,7 +139,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const 
HLSLBufferDecl *BufDecl,
     if (VDTy.getAddressSpace() != LangAS::hlsl_constant) {
       if (VD->getStorageClass() == SC_Static ||
           VDTy.getAddressSpace() == LangAS::hlsl_groupshared ||
-          isResourceRecordTypeOrArrayOf(VDTy.getTypePtr())) {
+          VDTy->isHLSLResourceRecord() || VDTy->isHLSLResourceRecordArray()) {
         // Emit static and groupshared variables and resource classes inside
         // cbuffer as regular globals
         CGM.EmitGlobal(VD);
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 8536e04a129ee..873efdae38f18 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -337,16 +337,9 @@ static bool isZeroSizedArray(const ConstantArrayType *CAT) 
{
   return CAT != nullptr;
 }
 
-// Returns true if the record type is an HLSL resource class or an array of
-// resource classes
-static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
-  while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
-    Ty = CAT->getArrayElementTypeNoTypeQual();
-  return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
-}
-
 static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
-  return isResourceRecordTypeOrArrayOf(VD->getType().getTypePtr());
+  const Type *Ty = VD->getType().getTypePtr();
+  return Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray();
 }
 
 // Returns true if the type is a leaf element type that is not valid to be
@@ -355,7 +348,7 @@ static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
 // type or if it is a record type that needs to be inspected further.
 static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
   Ty = Ty->getUnqualifiedDesugaredType();
-  if (isResourceRecordTypeOrArrayOf(Ty))
+  if (Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray())
     return true;
   if (Ty->isRecordType())
     return Ty->getAsCXXRecordDecl()->isEmpty();
@@ -3597,7 +3590,7 @@ void SemaHLSL::deduceAddressSpace(VarDecl *Decl) {
     return;
 
   // Resource handles.
-  if (isResourceRecordTypeOrArrayOf(Type->getUnqualifiedDesugaredType()))
+  if (Type->isHLSLResourceRecord() || Type->isHLSLResourceRecordArray())
     return;
 
   // Only static globals belong to the Private address space.

>From 4e153a4da8b990a1d07d6d1d63d2be74ed45e2eb Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Thu, 7 Aug 2025 00:37:23 -0700
Subject: [PATCH 02/13] [HLSL] Add implicit binding attribute to resource
 arrays without binding and make them static

If a resource array does not have an explicit binding attribute, SemaHLSL will 
add
an implicit one. The attribute will be used to transfer implicit binding order 
ID
to the codegen, the same way as it is done for HLSLBufferDecls. This is 
necessary
in order to generate correct initialization of resources in an array that does 
not
have an explicit binding.

This change also marks resource arrays declared at a global scope as `static`, 
which
is what is already done for standalone resources.
---
 clang/lib/Sema/SemaHLSL.cpp                   | 57 +++++++++++++++----
 .../test/AST/HLSL/resource_binding_attr.hlsl  | 28 +++++++--
 2 files changed, 69 insertions(+), 16 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 873efdae38f18..ffb996e79409c 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -71,6 +71,10 @@ static RegisterType getRegisterType(ResourceClass RC) {
   llvm_unreachable("unexpected ResourceClass value");
 }
 
+static RegisterType getRegisterType(const HLSLAttributedResourceType *ResTy) {
+  return getRegisterType(ResTy->getAttrs().ResourceClass);
+}
+
 // Converts the first letter of string Slot to RegisterType.
 // Returns false if the letter does not correspond to a valid register type.
 static bool convertToRegisterType(StringRef Slot, RegisterType *RT) {
@@ -342,6 +346,17 @@ static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
   return Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray();
 }
 
+static const HLSLAttributedResourceType *
+getResourceArrayHandleType(VarDecl *VD) {
+  assert(VD->getType()->isHLSLResourceRecordArray() &&
+         "expected array of resource records");
+  const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
+  while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) {
+    Ty = CAT->getArrayElementTypeNoTypeQual()->getUnqualifiedDesugaredType();
+  }
+  return HLSLAttributedResourceType::findHandleTypeOnResource(Ty);
+}
+
 // Returns true if the type is a leaf element type that is not valid to be
 // included in HLSL Buffer, such as a resource class, empty struct, zero-sized
 // array, or a builtin intangible type. Returns false it is a valid leaf 
element
@@ -568,16 +583,13 @@ void createHostLayoutStructForBuffer(Sema &S, 
HLSLBufferDecl *BufDecl) {
   BufDecl->addLayoutStruct(LS);
 }
 
-static void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl,
-                                           uint32_t ImplicitBindingOrderID) {
-  RegisterType RT =
-      BufDecl->isCBuffer() ? RegisterType::CBuffer : RegisterType::SRV;
+static void addImplicitBindingAttrToDecl(Sema &S, Decl *D, RegisterType RT,
+                                         uint32_t ImplicitBindingOrderID) {
   auto *Attr =
       HLSLResourceBindingAttr::CreateImplicit(S.getASTContext(), "", "0", {});
-  std::optional<unsigned> RegSlot;
-  Attr->setBinding(RT, RegSlot, 0);
+  Attr->setBinding(RT, std::nullopt, 0);
   Attr->setImplicitBindingOrderID(ImplicitBindingOrderID);
-  BufDecl->addAttr(Attr);
+  D->addAttr(Attr);
 }
 
 // Handle end of cbuffer/tbuffer declaration
@@ -600,7 +612,10 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation 
RBrace) {
     if (RBA)
       RBA->setImplicitBindingOrderID(OrderID);
     else
-      addImplicitBindingAttrToBuffer(SemaRef, BufDecl, OrderID);
+      addImplicitBindingAttrToDecl(SemaRef, BufDecl,
+                                   BufDecl->isCBuffer() ? RegisterType::CBuffer
+                                                        : RegisterType::SRV,
+                                   OrderID);
   }
 
   SemaRef.PopDeclContext();
@@ -1906,7 +1921,7 @@ static bool DiagnoseLocalRegisterBinding(Sema &S, 
SourceLocation &ArgLoc,
   if (const HLSLAttributedResourceType *AttrResType =
           HLSLAttributedResourceType::findHandleTypeOnResource(
               VD->getType().getTypePtr())) {
-    if (RegType == getRegisterType(AttrResType->getAttrs().ResourceClass))
+    if (RegType == getRegisterType(AttrResType))
       return true;
 
     S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
@@ -2439,8 +2454,8 @@ void 
SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
     HLSLBufferDecl *DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer(
         SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
         DefaultCBufferDecls);
-    addImplicitBindingAttrToBuffer(SemaRef, DefaultCBuffer,
-                                   getNextImplicitBindingOrderID());
+    addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, 
RegisterType::CBuffer,
+                                 getNextImplicitBindingOrderID());
     SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
     createHostLayoutStructForBuffer(SemaRef, DefaultCBuffer);
 
@@ -3633,7 +3648,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
     const Type *VarType = VD->getType().getTypePtr();
     while (VarType->isArrayType())
       VarType = VarType->getArrayElementTypeNoTypeQual();
-    if (VarType->isHLSLResourceRecord() ||
+    if (isResourceRecordTypeOrArrayOf(VD) ||
         VD->hasAttr<HLSLVkConstantIdAttr>()) {
       // Make the variable for resources static. The global externally visible
       // storage is accessed through the handle, which is a member. The 
variable
@@ -3643,6 +3658,24 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
 
     // process explicit bindings
     processExplicitBindingsOnDecl(VD);
+
+    if (VD->getType()->isHLSLResourceRecordArray()) {
+      // If the resource array does not have an explicit binding attribute,
+      // create an implicit one. It will be used to transfer implicit binding
+      // order_ID to codegen.
+      if (!VD->hasAttr<HLSLVkBindingAttr>()) {
+        HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
+        if (!RBA || !RBA->hasRegisterSlot()) {
+          uint32_t OrderID = getNextImplicitBindingOrderID();
+          if (RBA)
+            RBA->setImplicitBindingOrderID(OrderID);
+          else
+            addImplicitBindingAttrToDecl(
+                SemaRef, VD, getRegisterType(getResourceArrayHandleType(VD)),
+                OrderID);
+        }
+      }
+    }
   }
 
   deduceAddressSpace(VD);
diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl 
b/clang/test/AST/HLSL/resource_binding_attr.hlsl
index c073cd4dc1476..e8e79e44b8f0c 100644
--- a/clang/test/AST/HLSL/resource_binding_attr.hlsl
+++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl
@@ -20,20 +20,24 @@ export float foo() {
   return a + b;
 }
 
-// CHECK: VarDecl {{.*}} UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+// CHECK: VarDecl {{.*}} UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>' static
 // CHECK: HLSLResourceBindingAttr {{.*}} "u3" "space0"
 RWBuffer<float> UAV : register(u3);
 
-// CHECK: VarDecl {{.*}} UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+// CHECK: VarDecl {{.*}} UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>' static
 // CHECK: HLSLResourceBindingAttr {{.*}} "u2" "space0"
-// CHECK: VarDecl {{.*}} UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+// CHECK: VarDecl {{.*}} UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>' static
 // CHECK: HLSLResourceBindingAttr {{.*}} "u4" "space0"
 RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4);
 
-// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>' static
 // CHECK: HLSLResourceBindingAttr {{.*}} "" "space5"
 RWBuffer<float> UAV3 : register(space5);
 
+// CHECK: VarDecl {{.*}} UAV_Array 'RWBuffer<float>[10]' static
+// CHECK: HLSLResourceBindingAttr {{.*}} "u10" "space6"
+RWBuffer<float> UAV_Array[10] : register(u10, space6);
+
 //
 // Default constants ($Globals) layout annotations
 
@@ -56,3 +60,19 @@ struct S {
 // CHECK: VarDecl {{.*}} s 'hlsl_constant S'
 // CHECK: HLSLResourceBindingAttr {{.*}} "c10" "space0
 S s : register(c10);
+
+//
+// Implicit binding
+
+// Constant buffers should have implicit binding attribute added by SemaHLSL
+// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB2
+// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
+cbuffer CB2 {
+  float4 c;
+}
+
+// Resource arrays should have implicit binding attribute added by SemaHLSL
+// CHECK: VarDecl {{.*}} SB 'StructuredBuffer<float>[10]' static
+// CHECK: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
+StructuredBuffer<float> SB[10];

>From ac99f5af93d9cbb9cd93299eb5d8efae778fe21f Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Thu, 7 Aug 2025 01:06:42 -0700
Subject: [PATCH 03/13] one more instance to replace

---
 clang/lib/Sema/SemaHLSL.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 873efdae38f18..17f17f8114373 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3630,10 +3630,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
     if (VD->getType()->isHLSLIntangibleType())
       collectResourceBindingsOnVarDecl(VD);
 
-    const Type *VarType = VD->getType().getTypePtr();
-    while (VarType->isArrayType())
-      VarType = VarType->getArrayElementTypeNoTypeQual();
-    if (VarType->isHLSLResourceRecord() ||
+    if (isResourceRecordTypeOrArrayOf(VD) ||
         VD->hasAttr<HLSLVkConstantIdAttr>()) {
       // Make the variable for resources static. The global externally visible
       // storage is accessed through the handle, which is a member. The 
variable

>From e12a7a97db2e4abb25c31eda5f77e86bd8b8aa03 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Thu, 7 Aug 2025 01:17:55 -0700
Subject: [PATCH 04/13] update test

---
 clang/test/AST/HLSL/resource_binding_attr.hlsl | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl 
b/clang/test/AST/HLSL/resource_binding_attr.hlsl
index e8e79e44b8f0c..05d5eb0d619d8 100644
--- a/clang/test/AST/HLSL/resource_binding_attr.hlsl
+++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl
@@ -20,21 +20,21 @@ export float foo() {
   return a + b;
 }
 
-// CHECK: VarDecl {{.*}} UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>' static
+// CHECK: VarDecl {{.*}} UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>'
 // CHECK: HLSLResourceBindingAttr {{.*}} "u3" "space0"
 RWBuffer<float> UAV : register(u3);
 
-// CHECK: VarDecl {{.*}} UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>' static
+// CHECK: VarDecl {{.*}} UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>'
 // CHECK: HLSLResourceBindingAttr {{.*}} "u2" "space0"
-// CHECK: VarDecl {{.*}} UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>' static
+// CHECK: VarDecl {{.*}} UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
 // CHECK: HLSLResourceBindingAttr {{.*}} "u4" "space0"
 RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4);
 
-// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>' static
+// CHECK: VarDecl {{.*}} UAV3 'RWBuffer<float>':'hlsl::RWBuffer<float>'
 // CHECK: HLSLResourceBindingAttr {{.*}} "" "space5"
 RWBuffer<float> UAV3 : register(space5);
 
-// CHECK: VarDecl {{.*}} UAV_Array 'RWBuffer<float>[10]' static
+// CHECK: VarDecl {{.*}} UAV_Array 'RWBuffer<float>[10]'
 // CHECK: HLSLResourceBindingAttr {{.*}} "u10" "space6"
 RWBuffer<float> UAV_Array[10] : register(u10, space6);
 
@@ -73,6 +73,6 @@ cbuffer CB2 {
 }
 
 // Resource arrays should have implicit binding attribute added by SemaHLSL
-// CHECK: VarDecl {{.*}} SB 'StructuredBuffer<float>[10]' static
+// CHECK: VarDecl {{.*}} SB 'StructuredBuffer<float>[10]'
 // CHECK: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
 StructuredBuffer<float> SB[10];

>From 86902233a96b26b710bd39c096cb581f252e09a4 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Thu, 7 Aug 2025 01:30:36 -0700
Subject: [PATCH 05/13] [HLSL] Global resource arrays element access

Adds support for accessing individual resources from fixed-size resource
arrays declared at global scope. When a global resource array is indexed
 to retrieve a specific resource, the codegen translates the 
`ArraySubscriptExpr`
into a constructor call for the corresponding resource record type and binding.

Closes #145424
---
 clang/include/clang/Sema/SemaHLSL.h           |   9 +-
 clang/lib/CodeGen/CGExpr.cpp                  |  10 +
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 223 +++++++++++++++++-
 clang/lib/CodeGen/CGHLSLRuntime.h             |   6 +
 clang/lib/CodeGen/CodeGenModule.cpp           |   4 +-
 clang/lib/Sema/SemaHLSL.cpp                   |  93 ++++++--
 .../resources/res-array-global-multi-dim.hlsl |  32 +++
 .../resources/res-array-global.hlsl           |  59 +++++
 clang/test/CodeGenHLSL/static-local-ctor.hlsl |   5 +-
 9 files changed, 401 insertions(+), 40 deletions(-)
 create mode 100644 
clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
 create mode 100644 clang/test/CodeGenHLSL/resources/res-array-global.hlsl

diff --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index 085c9ed9f3ebd..0c215c6e10013 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -229,10 +229,17 @@ class SemaHLSL : public SemaBase {
 
   void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);
 
-  bool initGlobalResourceDecl(VarDecl *VD);
   uint32_t getNextImplicitBindingOrderID() {
     return ImplicitBindingNextOrderID++;
   }
+
+  bool initGlobalResourceDecl(VarDecl *VD);
+  bool initGlobalResourceArrayDecl(VarDecl *VD);
+  void createResourceRecordCtorArgs(const Type *ResourceTy, StringRef VarName,
+                                    HLSLResourceBindingAttr *RBA,
+                                    HLSLVkBindingAttr *VkBinding,
+                                    uint32_t ArrayIndex,
+                                    llvm::SmallVector<Expr *> &Args);
 };
 
 } // namespace clang
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index ed35a055d8a7f..8c34fb501a3b8 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -16,6 +16,7 @@
 #include "CGCall.h"
 #include "CGCleanup.h"
 #include "CGDebugInfo.h"
+#include "CGHLSLRuntime.h"
 #include "CGObjCRuntime.h"
 #include "CGOpenMPRuntime.h"
 #include "CGRecordLayout.h"
@@ -4532,6 +4533,15 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const 
ArraySubscriptExpr *E,
                                  LHS.getBaseInfo(), TBAAAccessInfo());
   }
 
+  // The HLSL runtime handle the subscript expression on global resource 
arrays.
+  if (getLangOpts().HLSL && (E->getType()->isHLSLResourceRecord() ||
+                             E->getType()->isHLSLResourceRecordArray())) {
+    std::optional<LValue> LV =
+        CGM.getHLSLRuntime().emitResourceArraySubscriptExpr(E, *this);
+    if (LV.has_value())
+      return *LV;
+  }
+
   // All the other cases basically behave like simple offsetting.
 
   // Handle the extvector case we ignored above.
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 918cb3e38448d..a09e540367a18 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -84,6 +84,124 @@ void addRootSignature(llvm::dxbc::RootSignatureVersion 
RootSigVer,
   RootSignatureValMD->addOperand(MDVals);
 }
 
+// If the specified expr is a simple decay from an array to pointer,
+// return the array subexpression. Otherwise, return nullptr.
+static const Expr *getSubExprFromArrayDecayOperand(const Expr *E) {
+  const auto *CE = dyn_cast<CastExpr>(E);
+  if (!CE || CE->getCastKind() != CK_ArrayToPointerDecay)
+    return nullptr;
+  return CE->getSubExpr();
+}
+
+// Find array variable declaration from nested array subscript AST nodes
+static const ValueDecl *getArrayDecl(const ArraySubscriptExpr *ASE) {
+  const Expr *E = nullptr;
+  while (ASE != nullptr) {
+    E = getSubExprFromArrayDecayOperand(ASE->getBase());
+    if (!E)
+      return nullptr;
+    ASE = dyn_cast<ArraySubscriptExpr>(E);
+  }
+  if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
+    return DRE->getDecl();
+  return nullptr;
+}
+
+// Get the total size of the array, or -1 if the array is unbounded.
+static int getTotalArraySize(const clang::Type *Ty) {
+  assert(Ty->isArrayType() && "expected array type");
+  if (Ty->isIncompleteArrayType())
+    return -1;
+  int Size = 1;
+  while (const auto *CAT = dyn_cast<ConstantArrayType>(Ty)) {
+    Size *= CAT->getSExtSize();
+    Ty = CAT->getArrayElementTypeNoTypeQual();
+  }
+  return Size;
+}
+
+// Find constructor decl for a specific resource record type and binding
+// (implicit vs. explicit). The constructor has 6 parameters.
+// For explicit binding the signature is:
+//   void(unsigned, unsigned, int, unsigned, const char *).
+// For implicit binding the signature is:
+//   void(unsigned, int, unsigned, unsigned, const char *).
+static CXXConstructorDecl *findResourceConstructorDecl(ASTContext &AST,
+                                                       QualType ResTy,
+                                                       bool ExplicitBinding) {
+  SmallVector<QualType> ExpParmTypes = {
+      AST.UnsignedIntTy, AST.UnsignedIntTy, AST.UnsignedIntTy,
+      AST.UnsignedIntTy, AST.getPointerType(AST.CharTy.withConst())};
+  ExpParmTypes[ExplicitBinding ? 2 : 1] = AST.IntTy;
+
+  CXXRecordDecl *ResDecl = ResTy->getAsCXXRecordDecl();
+  for (auto *Ctor : ResDecl->ctors()) {
+    if (Ctor->getNumParams() != ExpParmTypes.size())
+      continue;
+    ParmVarDecl **ParmIt = Ctor->param_begin();
+    QualType *ExpTyIt = ExpParmTypes.begin();
+    for (; ParmIt != Ctor->param_end() && ExpTyIt != ExpParmTypes.end();
+         ++ParmIt, ++ExpTyIt) {
+      if ((*ParmIt)->getType() != *ExpTyIt)
+        break;
+    }
+    if (ParmIt == Ctor->param_end())
+      return Ctor;
+  }
+  llvm_unreachable("did not find constructor for resource class");
+}
+
+static Value *buildNameForResource(llvm::StringRef BaseName,
+                                   CodeGenModule &CGM) {
+  std::string Str(BaseName);
+  std::string GlobalName(Str + ".str");
+  return CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer();
+}
+
+static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
+                                   llvm::Value *ThisPtr, llvm::Value *Range,
+                                   llvm::Value *Index, StringRef Name,
+                                   HLSLResourceBindingAttr *RBA,
+                                   HLSLVkBindingAttr *VkBinding,
+                                   CallArgList &Args) {
+  assert((VkBinding || RBA) && "at least one a binding attribute expected");
+
+  std::optional<uint32_t> RegisterSlot;
+  uint32_t SpaceNo = 0;
+  if (VkBinding) {
+    RegisterSlot = VkBinding->getBinding();
+    SpaceNo = VkBinding->getSet();
+  } else if (RBA) {
+    if (RBA->hasRegisterSlot())
+      RegisterSlot = RBA->getSlotNumber();
+    SpaceNo = RBA->getSpaceNumber();
+  }
+
+  ASTContext &AST = CD->getASTContext();
+  Value *NameStr = buildNameForResource(Name, CGM);
+  Value *Space = llvm::ConstantInt::get(CGM.IntTy, SpaceNo);
+
+  Args.add(RValue::get(ThisPtr), CD->getThisType());
+  if (RegisterSlot.has_value()) {
+    // explicit binding
+    auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RegisterSlot.value());
+    Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
+    Args.add(RValue::get(Space), AST.UnsignedIntTy);
+    Args.add(RValue::get(Range), AST.IntTy);
+    Args.add(RValue::get(Index), AST.UnsignedIntTy);
+
+  } else {
+    // implicit binding
+    auto *OrderID =
+        llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID());
+    Args.add(RValue::get(Space), AST.UnsignedIntTy);
+    Args.add(RValue::get(Range), AST.IntTy);
+    Args.add(RValue::get(Index), AST.UnsignedIntTy);
+    Args.add(RValue::get(OrderID), AST.UnsignedIntTy);
+  }
+  Args.add(RValue::get(NameStr), AST.getPointerType(AST.CharTy.withConst()));
+}
+
 } // namespace
 
 llvm::Type *
@@ -590,13 +708,6 @@ static void initializeBuffer(CodeGenModule &CGM, 
llvm::GlobalVariable *GV,
   CGM.AddCXXGlobalInit(InitResFunc);
 }
 
-static Value *buildNameForResource(llvm::StringRef BaseName,
-                                   CodeGenModule &CGM) {
-  std::string Str(BaseName);
-  std::string GlobalName(Str + ".str");
-  return CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer();
-}
-
 void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
                                                 llvm::GlobalVariable *GV,
                                                 HLSLVkBindingAttr *VkBinding) {
@@ -624,17 +735,13 @@ void CGHLSLRuntime::initializeBufferFromBinding(const 
HLSLBufferDecl *BufDecl,
   auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
   auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
   auto *Space = llvm::ConstantInt::get(CGM.IntTy, RBA->getSpaceNumber());
-  Value *Name = nullptr;
+  Value *Name = buildNameForResource(BufDecl->getName(), CGM);
 
   llvm::Intrinsic::ID IntrinsicID =
       RBA->hasRegisterSlot()
           ? CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic()
           : CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
 
-  std::string Str(BufDecl->getName());
-  std::string GlobalName(Str + ".str");
-  Name = CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer();
-
   // buffer with explicit binding
   if (RBA->hasRegisterSlot()) {
     auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
@@ -701,3 +808,95 @@ void 
CGHLSLRuntime::emitInitListOpaqueValues(CodeGenFunction &CGF,
     }
   }
 }
+
+std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
+    const ArraySubscriptExpr *ArraySubsExpr, CodeGenFunction &CGF) {
+  assert(ArraySubsExpr->getType()->isHLSLResourceRecord() ||
+         ArraySubsExpr->getType()->isHLSLResourceRecordArray() &&
+             "expected resource array subscript expression");
+
+  // let clang codegen handle local resource array subscrips
+  const VarDecl *ArrayDecl = dyn_cast<VarDecl>(getArrayDecl(ArraySubsExpr));
+  if (!ArrayDecl || !ArrayDecl->hasGlobalStorage())
+    return std::nullopt;
+
+  // FIXME: this is not yet implemented (llvm/llvm-project#145426)
+  assert(!ArraySubsExpr->getType()->isArrayType() &&
+         "indexing of array subsets it not supported yet");
+
+  // get total array size (= range size)
+  const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
+  assert(ResArrayTy->isHLSLResourceRecordArray() &&
+         "expected array of resource classes");
+  llvm::Value *Range =
+      llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(ResArrayTy));
+
+  // Iterate through all nested array subscript expressions to calculate
+  // the index in the flattened resource array (if this is a multi-
+  // dimensional array). The index is calculated as a sum of all indices
+  // multiplied by the total size of the array at that level.
+  Value *Index = nullptr;
+  Value *Multiplier = nullptr;
+  const ArraySubscriptExpr *ASE = ArraySubsExpr;
+  while (ASE != nullptr) {
+    Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx());
+    if (const auto *ArrayTy =
+            dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) {
+      Value *SubMultiplier =
+          llvm::ConstantInt::get(CGM.IntTy, ArrayTy->getSExtSize());
+      Multiplier = Multiplier ? CGF.Builder.CreateMul(Multiplier, 
SubMultiplier)
+                              : SubMultiplier;
+      SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier);
+    }
+
+    Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex;
+    ASE = dyn_cast<ArraySubscriptExpr>(
+        getSubExprFromArrayDecayOperand(ASE->getBase()));
+  }
+
+  // find binding info for the resource array
+  // (for implicit binding an HLSLResourceBindingAttr should have been added by
+  // SemaHLSL)
+  QualType ResourceTy = ArraySubsExpr->getType();
+  HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr<HLSLVkBindingAttr>();
+  HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr<HLSLResourceBindingAttr>();
+  assert((VkBinding || RBA) && "resource array must have a binding attribute");
+
+  // lookup the resource class constructor based on the resource type and
+  // binding
+  CXXConstructorDecl *CD =
+      findResourceConstructorDecl(ArrayDecl->getASTContext(), ResourceTy,
+                                  VkBinding || RBA->hasRegisterSlot());
+
+  // create a temporary variable for the resource class instance (we need to
+  // return an LValue)
+  RawAddress TmpVar = CGF.CreateMemTemp(ResourceTy);
+  if (auto *Size = CGF.EmitLifetimeStart(
+          CGM.getDataLayout().getTypeAllocSize(TmpVar.getElementType()),
+          TmpVar.getPointer())) {
+    CGF.pushFullExprCleanup<CodeGenFunction::CallLifetimeEnd>(
+        NormalEHLifetimeMarker, TmpVar, Size);
+  }
+  AggValueSlot ValueSlot = AggValueSlot::forAddr(
+      TmpVar, Qualifiers(), AggValueSlot::IsDestructed_t(true),
+      AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false),
+      AggValueSlot::MayOverlap);
+
+  Address ThisAddress = ValueSlot.getAddress();
+  llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo(
+      ThisAddress, CD->getThisType()->getPointeeType());
+
+  // assemble the constructor parameters
+  CallArgList Args;
+  createResourceCtorArgs(CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName(),
+                         RBA, VkBinding, Args);
+
+  // call the constructor
+  CGF.EmitCXXConstructorCall(CD, Ctor_Complete, false, false, ThisAddress, 
Args,
+                             ValueSlot.mayOverlap(),
+                             ArraySubsExpr->getExprLoc(),
+                             ValueSlot.isSanitizerChecked());
+
+  return CGF.MakeAddrLValue(TmpVar, ArraySubsExpr->getType(),
+                            AlignmentSource::Decl);
+}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 31d1728da9c56..b872f9ef0e9b6 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -68,6 +68,7 @@ class Type;
 class RecordType;
 class DeclContext;
 class HLSLPackOffsetAttr;
+class ArraySubscriptExpr;
 
 class FunctionDecl;
 
@@ -75,6 +76,7 @@ namespace CodeGen {
 
 class CodeGenModule;
 class CodeGenFunction;
+class LValue;
 
 class CGHLSLRuntime {
 public:
@@ -164,6 +166,10 @@ class CGHLSLRuntime {
                                llvm::TargetExtType *LayoutTy);
   void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E);
 
+  std::optional<LValue>
+  emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E,
+                                 CodeGenFunction &CGF);
+
 private:
   void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
                                     llvm::GlobalVariable *BufGV);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 834b1c067d84c..1498c5d75fa53 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5775,8 +5775,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl 
*D,
       if (D->getType()->isReferenceType())
         T = D->getType();
 
-      if (getLangOpts().HLSL &&
-          D->getType().getTypePtr()->isHLSLResourceRecord()) {
+      if (getLangOpts().HLSL && (D->getType()->isHLSLResourceRecord() ||
+                                 D->getType()->isHLSLResourceRecordArray())) {
         Init = llvm::PoisonValue::get(getTypes().ConvertType(ASTTy));
         NeedsGlobalCtor = true;
       } else if (getLangOpts().CPlusPlus) {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 6811f3f27603b..7de529fc898ad 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -357,6 +357,14 @@ getResourceArrayHandleType(VarDecl *VD) {
   return HLSLAttributedResourceType::findHandleTypeOnResource(Ty);
 }
 
+// returns the element type of an array (including multi-dimensional array)
+static QualType getArrayElementType(QualType Ty) {
+  assert(Ty->isArrayType() && "expected array type");
+  while (const ArrayType *AT = dyn_cast<ArrayType>(Ty.getTypePtr()))
+    Ty = AT->getElementType();
+  return Ty;
+}
+
 // Returns true if the type is a leaf element type that is not valid to be
 // included in HLSL Buffer, such as a resource class, empty struct, zero-sized
 // array, or a builtin intangible type. Returns false it is a valid leaf 
element
@@ -3698,11 +3706,14 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD,
   return true;
 }
 
-bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
+void SemaHLSL::createResourceRecordCtorArgs(const Type *ResourceTy,
+                                            StringRef VarName,
+                                            HLSLResourceBindingAttr *RBA,
+                                            HLSLVkBindingAttr *VkBinding,
+                                            uint32_t ArrayIndex,
+                                            llvm::SmallVector<Expr *> &Args) {
   std::optional<uint32_t> RegisterSlot;
   uint32_t SpaceNo = 0;
-  HLSLVkBindingAttr *VkBinding = VD->getAttr<HLSLVkBindingAttr>();
-  HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
   if (VkBinding) {
     RegisterSlot = VkBinding->getBinding();
     SpaceNo = VkBinding->getSet();
@@ -3717,12 +3728,12 @@ bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
   uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
   IntegerLiteral *RangeSize = IntegerLiteral::Create(
       AST, llvm::APInt(IntTySize, 1), AST.IntTy, SourceLocation());
-  IntegerLiteral *Index = IntegerLiteral::Create(
-      AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy, SourceLocation());
+  IntegerLiteral *Index =
+      IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, ArrayIndex),
+                             AST.UnsignedIntTy, SourceLocation());
   IntegerLiteral *Space =
       IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo),
                              AST.UnsignedIntTy, SourceLocation());
-  StringRef VarName = VD->getName();
   StringLiteral *Name = StringLiteral::Create(
       AST, VarName, StringLiteralKind::Ordinary, false,
       AST.getStringLiteralArrayType(AST.CharTy.withConst(), VarName.size()),
@@ -3733,18 +3744,57 @@ bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
     IntegerLiteral *RegSlot = IntegerLiteral::Create(
         AST, llvm::APInt(UIntTySize, RegisterSlot.value()), AST.UnsignedIntTy,
         SourceLocation());
-    Expr *Args[] = {RegSlot, Space, RangeSize, Index, Name};
-    return initVarDeclWithCtor(SemaRef, VD, Args);
+    Args.append({RegSlot, Space, RangeSize, Index, Name});
+  } else {
+    // resource with implicit binding
+    uint32_t OrderID = (RBA && RBA->hasImplicitBindingOrderID())
+                           ? RBA->getImplicitBindingOrderID()
+                           : getNextImplicitBindingOrderID();
+    IntegerLiteral *OrderId =
+        IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, OrderID),
+                               AST.UnsignedIntTy, SourceLocation());
+    Args.append({Space, RangeSize, Index, OrderId, Name});
   }
+}
 
-  // resource with implicit binding
-  IntegerLiteral *OrderId = IntegerLiteral::Create(
-      AST, llvm::APInt(UIntTySize, getNextImplicitBindingOrderID()),
-      AST.UnsignedIntTy, SourceLocation());
-  Expr *Args[] = {Space, RangeSize, Index, OrderId, Name};
+bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) {
+  SmallVector<Expr *> Args;
+  createResourceRecordCtorArgs(VD->getType().getTypePtr(), VD->getName(),
+                               VD->getAttr<HLSLResourceBindingAttr>(),
+                               VD->getAttr<HLSLVkBindingAttr>(), 0, Args);
   return initVarDeclWithCtor(SemaRef, VD, Args);
 }
 
+bool SemaHLSL::initGlobalResourceArrayDecl(VarDecl *VD) {
+  assert(VD->getType()->isHLSLResourceRecordArray() &&
+         "expected array of resource records");
+
+  // Individual resources in a resource array are not initialized here. They
+  // are initialized later on during codegen when the individual resources are
+  // accessed. Codegen will emit a call to the resource constructor with the
+  // specified array index. We need to make sure though that the constructor
+  // for the specific resource type is instantiated, so codegen can emit a call
+  // to it when the array element is accessed.
+  SmallVector<Expr *> Args;
+  QualType ResElementTy = getArrayElementType(VD->getType());
+  createResourceRecordCtorArgs(ResElementTy.getTypePtr(), VD->getName(),
+                               VD->getAttr<HLSLResourceBindingAttr>(),
+                               VD->getAttr<HLSLVkBindingAttr>(), 0, Args);
+
+  SourceLocation Loc = VD->getLocation();
+  InitializedEntity Entity =
+      InitializedEntity::InitializeTemporary(ResElementTy);
+  InitializationKind Kind = InitializationKind::CreateDirect(Loc, Loc, Loc);
+  InitializationSequence InitSeq(SemaRef, Entity, Kind, Args);
+  if (InitSeq.Failed())
+    return false;
+
+  // This takes care of instantiating and emitting of the constructor that will
+  // be called from codegen when the array is accessed.
+  ExprResult OneResInit = InitSeq.Perform(SemaRef, Entity, Kind, Args);
+  return !OneResInit.isInvalid();
+}
+
 // Returns true if the initialization has been handled.
 // Returns false to use default initialization.
 bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) {
@@ -3753,17 +3803,14 @@ bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) {
   if (VD->getType().getAddressSpace() == LangAS::hlsl_constant)
     return true;
 
-  // Initialize resources
-  if (!isResourceRecordTypeOrArrayOf(VD))
-    return false;
-
-  // FIXME: We currectly support only simple resources - no arrays of resources
-  // or resources in user defined structs.
-  // (llvm/llvm-project#133835, llvm/llvm-project#133837)
   // Initialize resources at the global scope
-  if (VD->hasGlobalStorage() && VD->getType()->isHLSLResourceRecord())
-    return initGlobalResourceDecl(VD);
-
+  if (VD->hasGlobalStorage()) {
+    const Type *Ty = VD->getType().getTypePtr();
+    if (Ty->isHLSLResourceRecord())
+      return initGlobalResourceDecl(VD);
+    if (Ty->isHLSLResourceRecordArray())
+      return initGlobalResourceArrayDecl(VD);
+  }
   return false;
 }
 
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
new file mode 100644
index 0000000000000..97df14769b132
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+// RUN: %clang_cc1 -finclude-default-header -triple 
spirv-unknown-vulkan-compute \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// CHECK: @[[BufB:.*]] = private unnamed_addr constant [2 x i8] c"B\00", align 
1
+// CHECK: @[[BufC:.*]] = private unnamed_addr constant [2 x i8] c"C\00", align 
1
+// CHECK: @[[BufD:.*]] = private unnamed_addr constant [2 x i8] c"D\00", align 
1
+
+RWBuffer<float> B[4][4] : register(u2);
+RWBuffer<int> C[2][2][5] : register(u10, space1);
+RWBuffer<uint> D[10][5]; // implicit binding -> u18, space0
+
+RWStructuredBuffer<float> Out;
+
+[numthreads(4,1,1)]
+void main() {
+  // CHECK: define internal{{.*}} void @_Z4mainv()
+  // CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp1:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer
+
+  // Make sure that B[2][3] is translated to a RWBuffer<float> constructor 
call for explicit binding (u2, space0) with range 16 and index 14
+  // CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], 
i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef 
@[[BufB]])
+
+  // Make sure that C[1][0][3] is translated to a RWBuffer<int> constructor 
call for explicit binding (u10, space1) with range 20 and index 13
+  // CHECK: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp1]], 
i32 noundef 10, i32 noundef 1, i32 noundef 20, i32 noundef 13, ptr noundef 
@[[BufC]])
+
+  // Make sure that D[9][2] is translated to a RWBuffer<uint> constructor call 
for implicit binding (u18, space0) with range 50 and index 47
+  // CHECK: call void @_ZN4hlsl8RWBufferIjEC1EjijjPKc(ptr {{.*}} %[[Tmp2]], 
i32 noundef 0, i32 noundef 50, i32 noundef 47, i32 noundef 0, ptr noundef 
@[[BufD]])
+  Out[0] =  B[3][2][0] + (float)C[1][0][3][0] + (float)D[9][2][0];
+}
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
new file mode 100644
index 0000000000000..26526e9a5c9d8
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s 
-check-prefixes=CHECK,DXIL
+// RUN: %clang_cc1 -finclude-default-header -triple 
spirv-unknown-vulkan-compute \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s 
-check-prefixes=CHECK,SPV
+
+// 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
+// CHECK: @[[BufC:.*]] = private unnamed_addr constant [2 x i8] c"C\00", align 
1
+// CHECK: @[[BufD:.*]] = private unnamed_addr constant [2 x i8] c"D\00", align 
1
+
+// different explicit binding for DXIL and SPIR-V
+[[vk::binding(12, 2)]]
+RWBuffer<float> A[4] : register(u10, space1);
+
+[[vk::binding(13)]] // SPIR-V explicit binding 13, set 0
+RWBuffer<int> B[5]; // DXIL implicit binding in space0
+
+// same explicit binding for both DXIL and SPIR-V
+// (SPIR-V takes the binding from register annotation if there is no 
vk::binding attribute))
+RWBuffer<int> C[3] : register(u2);
+
+// implicit binding for both DXIL and SPIR-V in space/set 0 
+RWBuffer<double> D[10];
+
+RWStructuredBuffer<float> Out;
+
+[numthreads(4,1,1)]
+void main() {
+  // CHECK: define internal{{.*}} void @_Z4mainv()
+  // CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp1:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer
+
+  // Make sure A[2] is translated to a RWBuffer<float> constructor call with 
range 4 and index 2
+  // and DXIL explicit binding (u10, space1)
+  // and SPIR-V explicit binding (binding 12, set 2) 
+  // DXIL: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 
noundef 10, i32 noundef 1, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
+  // SPV: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 
noundef 12, i32 noundef 2, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
+
+  // Make sure B[3] is translated to a RWBuffer<int> constructor call with 
range 5 and index 3
+  // and DXIL for implicit binding in space0, order id 0
+  // and SPIR-V explicit binding (binding 13, set 0)
+  // DXIL: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Tmp1]], i32 
noundef 0, i32 noundef 5, i32 noundef 3, i32 noundef 0, ptr noundef @[[BufB]])
+  // SPV: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp1]], i32 
noundef 13, i32 noundef 0, i32 noundef 5, i32 noundef 3, ptr noundef @[[BufB]])
+
+  // Make sure C[1] is translated to a RWBuffer<int> constructor call with 
range 3 and index 1
+  // and DXIL explicit binding (u2, space0) 
+  // and SPIR-V explicit binding (binding 2, set 0)
+  // DXIL: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp2]], i32 
noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]])
+  // SPV: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp2]], i32 
noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]])
+
+  // Make sure D[7] is translated to a RWBuffer<doublet> constructor call with 
range 10 and index 7
+  // and DXIL for implicit binding in space0, order id 1
+  // and SPIR-V explicit binding (binding 13, set 0), order id 0
+  // DXIL: call void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr {{.*}} %[[Tmp3]], i32 
noundef 0, i32 noundef 10, i32 noundef 7, i32 noundef 1, ptr noundef @[[BufD]])
+  // SPV: call void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr {{.*}} %[[Tmp3]], i32 
noundef 0, i32 noundef 10, i32 noundef 7, i32 noundef 0, ptr noundef @[[BufD]])
+  Out[0] = A[2][0] + (float)B[3][0] + (float)C[1][0] + (float)D[7][0];
+}
diff --git a/clang/test/CodeGenHLSL/static-local-ctor.hlsl 
b/clang/test/CodeGenHLSL/static-local-ctor.hlsl
index 87f49b8bf7ac7..9a4bf66f030ed 100644
--- a/clang/test/CodeGenHLSL/static-local-ctor.hlsl
+++ b/clang/test/CodeGenHLSL/static-local-ctor.hlsl
@@ -2,7 +2,7 @@
 
 // Verify that no per variable _Init_thread instructions are emitted for 
non-trivial static locals
 // These would normally be emitted by the MicrosoftCXXABI, but the DirectX 
backend should exlude them
-// Instead, check for the guardvar oparations that should protect the 
constructor initialization should
+// Instead, check for the guardvar operations that should protect the 
constructor initialization should
 // only take place once.
 
 RWBuffer<int> buf[10];
@@ -15,13 +15,14 @@ void InitBuf(RWBuffer<int> buf) {
 // CHECK-NOT: _Init_thread_epoch
 // CHECK: define internal void @_Z4mainv
 // CHECK-NEXT: entry:
+// CHECK-NEXT: [[Tmp0:%.*]] = alloca %"class.hlsl::RWBuffer"
 // CHECK-NEXT: [[Tmp1:%.*]] = alloca %"class.hlsl::RWBuffer"
 // CHECK-NEXT: [[Tmp2:%.*]] = load i8, ptr @_ZGVZ4mainvE5mybuf
 // CHECK-NEXT: [[Tmp3:%.*]] = icmp eq i8 [[Tmp2]], 0
 // CHECK-NEXT: br i1 [[Tmp3]]
 // CHECK-NOT: _Init_thread_header
 // CHECK: init.check:
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1Ejijj
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(
 // CHECK-NEXT: store i8 1, ptr @_ZGVZ4mainvE5mybuf
 // CHECK-NOT: _Init_thread_footer
 

>From f08e2132a29d63a74084a0d486033961127e5b0c Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Mon, 11 Aug 2025 13:11:48 -0700
Subject: [PATCH 06/13] code review feedback, add test for dynamic indexing,
 typedef and identical index

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 17 +++++++-----
 .../resources/res-array-global-dyn-index.hlsl | 26 +++++++++++++++++++
 .../resources/res-array-global-multi-dim.hlsl | 12 ++++++---
 .../resources/res-array-global.hlsl           |  5 ++--
 4 files changed, 47 insertions(+), 13 deletions(-)
 create mode 100644 
clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index a09e540367a18..52fabe9d2983b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -113,7 +113,8 @@ static int getTotalArraySize(const clang::Type *Ty) {
   if (Ty->isIncompleteArrayType())
     return -1;
   int Size = 1;
-  while (const auto *CAT = dyn_cast<ConstantArrayType>(Ty)) {
+  while (const auto *CAT =
+             dyn_cast<ConstantArrayType>(Ty->getUnqualifiedDesugaredType())) {
     Size *= CAT->getSExtSize();
     Ty = CAT->getArrayElementTypeNoTypeQual();
   }
@@ -121,7 +122,7 @@ static int getTotalArraySize(const clang::Type *Ty) {
 }
 
 // Find constructor decl for a specific resource record type and binding
-// (implicit vs. explicit). The constructor has 6 parameters.
+// (implicit vs. explicit). The constructor has 5 parameters.
 // For explicit binding the signature is:
 //   void(unsigned, unsigned, int, unsigned, const char *).
 // For implicit binding the signature is:
@@ -171,7 +172,7 @@ static void createResourceCtorArgs(CodeGenModule &CGM, 
CXXConstructorDecl *CD,
   if (VkBinding) {
     RegisterSlot = VkBinding->getBinding();
     SpaceNo = VkBinding->getSet();
-  } else if (RBA) {
+  } else {
     if (RBA->hasRegisterSlot())
       RegisterSlot = RBA->getSlotNumber();
     SpaceNo = RBA->getSpaceNumber();
@@ -815,7 +816,7 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
          ArraySubsExpr->getType()->isHLSLResourceRecordArray() &&
              "expected resource array subscript expression");
 
-  // let clang codegen handle local resource array subscrips
+  // let clang codegen handle local resource array subscripts
   const VarDecl *ArrayDecl = dyn_cast<VarDecl>(getArrayDecl(ArraySubsExpr));
   if (!ArrayDecl || !ArrayDecl->hasGlobalStorage())
     return std::nullopt;
@@ -824,12 +825,10 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
   assert(!ArraySubsExpr->getType()->isArrayType() &&
          "indexing of array subsets it not supported yet");
 
-  // get total array size (= range size)
+  // get the resource array type
   const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
   assert(ResArrayTy->isHLSLResourceRecordArray() &&
          "expected array of resource classes");
-  llvm::Value *Range =
-      llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(ResArrayTy));
 
   // Iterate through all nested array subscript expressions to calculate
   // the index in the flattened resource array (if this is a multi-
@@ -886,6 +885,10 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
   llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo(
       ThisAddress, CD->getThisType()->getPointeeType());
 
+  // get total array size (= range size)
+  llvm::Value *Range =
+      llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(ResArrayTy));
+
   // assemble the constructor parameters
   CallArgList Args;
   createResourceCtorArgs(CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName(),
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl
new file mode 100644
index 0000000000000..26108aadff958
--- /dev/null
+++ b/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 
1
+
+RWBuffer<float> A[4][3] : register(u2);
+RWStructuredBuffer<float> Out;
+
+// Make sure A[GI.x][GI.y] is translated to a RWBuffer<float> constructor call 
with range 12 and dynamically calculated index
+
+// CHECK: define internal void @_Z4mainDv3_j(<3 x i32> noundef %GI)
+// CHECK: %[[GI_alloca:.*]] = alloca <3 x i32>, align 16
+// CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer
+// CHECK: store <3 x i32> %GI, ptr %[[GI_alloca]]
+
+// CHECK: %[[GI:.*]] = load <3 x i32>, ptr %[[GI_alloca]], align 16
+// CHECK: %[[GI_y:.*]] = extractelement <3 x i32> %[[GI]], i32 1
+// CHECK: %[[GI:.*]] = load <3 x i32>, ptr %[[GI_alloca]], align 16
+// CHECK: %[[GI_x:.*]] = extractelement <3 x i32> %[[GI]], i32 0
+// CHECK: %[[Tmp1:.*]] = mul i32 %[[GI_x]], 3
+// CHECK: %[[Index:.*]] = add i32 %[[GI_y]], %[[Tmp1]]
+// CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 
noundef 2, i32 noundef 0, i32 noundef 12, i32 noundef %[[Index]], ptr noundef 
@A.str)
+[numthreads(4,1,1)]
+void main(uint3 GI : SV_GroupThreadID) {
+  Out[0] = A[GI.x][GI.y][0];
+}
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
index 97df14769b132..5219cf5143c13 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
@@ -9,7 +9,9 @@
 
 RWBuffer<float> B[4][4] : register(u2);
 RWBuffer<int> C[2][2][5] : register(u10, space1);
-RWBuffer<uint> D[10][5]; // implicit binding -> u18, space0
+
+typedef RWBuffer<uint> RWBufferArrayTenByFive[10][5]; // test typedef for the 
resource array type
+RWBufferArrayTenByFive D; // implicit binding -> u18, space0
 
 RWStructuredBuffer<float> Out;
 
@@ -19,8 +21,9 @@ void main() {
   // CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer
   // CHECK: %[[Tmp1:.*]] = alloca %"class.hlsl::RWBuffer
   // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer
+  // CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer
 
-  // Make sure that B[2][3] is translated to a RWBuffer<float> constructor 
call for explicit binding (u2, space0) with range 16 and index 14
+  // Make sure that B[3][2] is translated to a RWBuffer<float> constructor 
call for explicit binding (u2, space0) with range 16 and index 14
   // CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], 
i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef 
@[[BufB]])
 
   // Make sure that C[1][0][3] is translated to a RWBuffer<int> constructor 
call for explicit binding (u10, space1) with range 20 and index 13
@@ -28,5 +31,8 @@ void main() {
 
   // Make sure that D[9][2] is translated to a RWBuffer<uint> constructor call 
for implicit binding (u18, space0) with range 50 and index 47
   // CHECK: call void @_ZN4hlsl8RWBufferIjEC1EjijjPKc(ptr {{.*}} %[[Tmp2]], 
i32 noundef 0, i32 noundef 50, i32 noundef 47, i32 noundef 0, ptr noundef 
@[[BufD]])
-  Out[0] =  B[3][2][0] + (float)C[1][0][3][0] + (float)D[9][2][0];
+
+  // Make sure that the second B[3][2] is translated to the same a 
RWBuffer<float> constructor call as the first B[3][2] subscript
+  // CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp3]], 
i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef 
@[[BufB]])
+  Out[0] =  B[3][2][0] + (float)C[1][0][3][0] + (float)D[9][2][0] + B[3][2][1];
 }
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
index 26526e9a5c9d8..cc0e8cca19953 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
@@ -50,9 +50,8 @@ void main() {
   // DXIL: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp2]], i32 
noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]])
   // SPV: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp2]], i32 
noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]])
 
-  // Make sure D[7] is translated to a RWBuffer<doublet> constructor call with 
range 10 and index 7
-  // and DXIL for implicit binding in space0, order id 1
-  // and SPIR-V explicit binding (binding 13, set 0), order id 0
+  // Make sure D[7] is translated to a RWBuffer<double> constructor call with 
implicit binding
+  // for both DXIL and SPIR-V
   // DXIL: call void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr {{.*}} %[[Tmp3]], i32 
noundef 0, i32 noundef 10, i32 noundef 7, i32 noundef 1, ptr noundef @[[BufD]])
   // SPV: call void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr {{.*}} %[[Tmp3]], i32 
noundef 0, i32 noundef 10, i32 noundef 7, i32 noundef 0, ptr noundef @[[BufD]])
   Out[0] = A[2][0] + (float)B[3][0] + (float)C[1][0] + (float)D[7][0];

>From 227f6ae97dfe128c3a2e43792a1443f6c7375673 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Mon, 11 Aug 2025 15:43:50 -0700
Subject: [PATCH 07/13] fix build break after merge

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 7ab6e335749cb..a5aafc09828a2 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -869,11 +869,9 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
   // create a temporary variable for the resource class instance (we need to
   // return an LValue)
   RawAddress TmpVar = CGF.CreateMemTemp(ResourceTy);
-  if (auto *Size = CGF.EmitLifetimeStart(
-          CGM.getDataLayout().getTypeAllocSize(TmpVar.getElementType()),
-          TmpVar.getPointer())) {
+  if (CGF.EmitLifetimeStart(TmpVar.getPointer())) {
     CGF.pushFullExprCleanup<CodeGenFunction::CallLifetimeEnd>(
-        NormalEHLifetimeMarker, TmpVar, Size);
+        NormalEHLifetimeMarker, TmpVar);
   }
   AggValueSlot ValueSlot = AggValueSlot::forAddr(
       TmpVar, Qualifiers(), AggValueSlot::IsDestructed_t(true),

>From 8bc614ae146014413dcdcee62daac226645ded15 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Tue, 12 Aug 2025 00:30:10 -0700
Subject: [PATCH 08/13] Fix bug - initialize resource arrays to poison, add
 test

---
 clang/lib/CodeGen/CodeGenModule.cpp             | 17 +++++++++--------
 .../resources/resource-bindings.hlsl            | 14 +++++++++++++-
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 44a958a9112f4..590705508b7e8 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5752,11 +5752,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const 
VarDecl *D,
       (D->getType()->isCUDADeviceBuiltinSurfaceType() ||
        D->getType()->isCUDADeviceBuiltinTextureType());
   if (getLangOpts().CUDA &&
-      (IsCUDASharedVar || IsCUDAShadowVar || IsCUDADeviceShadowVar))
+      (IsCUDASharedVar || IsCUDAShadowVar || IsCUDADeviceShadowVar)) {
     Init = llvm::UndefValue::get(getTypes().ConvertTypeForMem(ASTTy));
-  else if (D->hasAttr<LoaderUninitializedAttr>())
+  } else if (getLangOpts().HLSL &&
+             (D->getType()->isHLSLResourceRecord() ||
+              D->getType()->isHLSLResourceRecordArray())) {
+    Init = llvm::PoisonValue::get(getTypes().ConvertType(ASTTy));
+    NeedsGlobalCtor = D->getType()->isHLSLResourceRecord();
+  } else if (D->hasAttr<LoaderUninitializedAttr>()) {
     Init = llvm::UndefValue::get(getTypes().ConvertTypeForMem(ASTTy));
-  else if (!InitExpr) {
+  } else if (!InitExpr) {
     // This is a tentative definition; tentative definitions are
     // implicitly initialized with { 0 }.
     //
@@ -5777,11 +5782,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const 
VarDecl *D,
       if (D->getType()->isReferenceType())
         T = D->getType();
 
-      if (getLangOpts().HLSL && (D->getType()->isHLSLResourceRecord() ||
-                                 D->getType()->isHLSLResourceRecordArray())) {
-        Init = llvm::PoisonValue::get(getTypes().ConvertType(ASTTy));
-        NeedsGlobalCtor = true;
-      } else if (getLangOpts().CPlusPlus) {
+      if (getLangOpts().CPlusPlus) {
         Init = EmitNullConstant(T);
         if (!IsDefinitionAvailableExternally)
           NeedsGlobalCtor = true;
diff --git a/clang/test/CodeGenHLSL/resources/resource-bindings.hlsl 
b/clang/test/CodeGenHLSL/resources/resource-bindings.hlsl
index 0a301346e55be..2d49753e546ca 100644
--- a/clang/test/CodeGenHLSL/resources/resource-bindings.hlsl
+++ b/clang/test/CodeGenHLSL/resources/resource-bindings.hlsl
@@ -4,11 +4,13 @@
 // 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) }
+// 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
 
 // CHECK: %[[HANDLE:.*]] = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
 // CHECK-SAME: 
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(
@@ -42,5 +44,15 @@ struct S {
 };
 RWStructuredBuffer<S> T3S0 : register(u3);
 
+// Resource array elements are initialized on access; make sure there is not 
call
+// to initialize RWBuffer<double>.
+// CHECK-NOT: call target("dx.TypedBuffer", double, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
+RWBuffer<double> Array[10] : register(u4, space0);
+
 [numthreads(4,1,1)]
-void main() {}
+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;
+}

>From f0d05cd65c7673ce4238fc309648cd9601f71f91 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Tue, 12 Aug 2025 12:03:03 -0700
Subject: [PATCH 09/13] Update global_array.hlsl SPIR-V convergence test to use
 custom struct

---
 clang/test/CodeGenHLSL/convergence/global_array.hlsl | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGenHLSL/convergence/global_array.hlsl 
b/clang/test/CodeGenHLSL/convergence/global_array.hlsl
index 030ba48a5f170..c594e3a3e62ae 100644
--- a/clang/test/CodeGenHLSL/convergence/global_array.hlsl
+++ b/clang/test/CodeGenHLSL/convergence/global_array.hlsl
@@ -6,9 +6,15 @@
 
 // CHECK: [[loop_entry]]:
 // CHECK: [[loop_token:%.*]] = call token 
@llvm.experimental.convergence.loop() [ "convergencectrl"(token 
[[entry_token]]) ]
-// CHECK: call void {{.*}} [ "convergencectrl"(token [[loop_token]]) ]
+// CHECK: call spir_func void {{.*}} [ "convergencectrl"(token [[loop_token]]) 
]
 // CHECK: br i1 {{%.*}} label {{%.*}} label %[[loop_entry]]
-RWBuffer<float> e[2];
+
+struct S {
+    int i;
+    S() { i = 10; }
+};
+
+static S s[2];
 
 [numthreads(4,1,1)]
 void main() {

>From ac62921128839c3c4c1d5232d74e8c2b0606ebab Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Tue, 12 Aug 2025 14:22:28 -0700
Subject: [PATCH 10/13] code review feedback - use existing methods on Type and
 ASTContext, avoid alloc, use SmallVectorImpl, formatting

---
 clang/include/clang/Sema/SemaHLSL.h |  2 +-
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 38 +++++++++--------------------
 clang/lib/Sema/SemaHLSL.cpp         | 15 +++---------
 3 files changed, 16 insertions(+), 39 deletions(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index 0c215c6e10013..016456f241eed 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -239,7 +239,7 @@ class SemaHLSL : public SemaBase {
                                     HLSLResourceBindingAttr *RBA,
                                     HLSLVkBindingAttr *VkBinding,
                                     uint32_t ArrayIndex,
-                                    llvm::SmallVector<Expr *> &Args);
+                                    llvm::SmallVectorImpl<Expr *> &Args);
 };
 
 } // namespace clang
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index a5aafc09828a2..e962e2f06afa3 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
 #include "llvm/IR/Constants.h"
@@ -84,20 +85,11 @@ void addRootSignature(llvm::dxbc::RootSignatureVersion 
RootSigVer,
   RootSignatureValMD->addOperand(MDVals);
 }
 
-// If the specified expr is a simple decay from an array to pointer,
-// return the array subexpression. Otherwise, return nullptr.
-static const Expr *getSubExprFromArrayDecayOperand(const Expr *E) {
-  const auto *CE = dyn_cast<CastExpr>(E);
-  if (!CE || CE->getCastKind() != CK_ArrayToPointerDecay)
-    return nullptr;
-  return CE->getSubExpr();
-}
-
 // Find array variable declaration from nested array subscript AST nodes
 static const ValueDecl *getArrayDecl(const ArraySubscriptExpr *ASE) {
   const Expr *E = nullptr;
   while (ASE != nullptr) {
-    E = getSubExprFromArrayDecayOperand(ASE->getBase());
+    E = ASE->getBase()->IgnoreImpCasts();
     if (!E)
       return nullptr;
     ASE = dyn_cast<ArraySubscriptExpr>(E);
@@ -108,17 +100,12 @@ static const ValueDecl *getArrayDecl(const 
ArraySubscriptExpr *ASE) {
 }
 
 // Get the total size of the array, or -1 if the array is unbounded.
-static int getTotalArraySize(const clang::Type *Ty) {
+static int getTotalArraySize(ASTContext &AST, const clang::Type *Ty) {
+  Ty = Ty->getUnqualifiedDesugaredType();
   assert(Ty->isArrayType() && "expected array type");
   if (Ty->isIncompleteArrayType())
     return -1;
-  int Size = 1;
-  while (const auto *CAT =
-             dyn_cast<ConstantArrayType>(Ty->getUnqualifiedDesugaredType())) {
-    Size *= CAT->getSExtSize();
-    Ty = CAT->getArrayElementTypeNoTypeQual();
-  }
-  return Size;
+  return AST.getConstantArrayElementCount(cast<ConstantArrayType>(Ty));
 }
 
 // Find constructor decl for a specific resource record type and binding
@@ -154,9 +141,8 @@ static CXXConstructorDecl 
*findResourceConstructorDecl(ASTContext &AST,
 
 static Value *buildNameForResource(llvm::StringRef BaseName,
                                    CodeGenModule &CGM) {
-  std::string Str(BaseName);
-  std::string GlobalName(Str + ".str");
-  return CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer();
+  llvm::SmallString<64> GlobalName = { BaseName, ".str" };
+  return CGM.GetAddrOfConstantCString(BaseName.str(), 
GlobalName.c_str()).getPointer();
 }
 
 static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
@@ -848,8 +834,7 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
     }
 
     Index = Index ? CGF.Builder.CreateAdd(Index, SubIndex) : SubIndex;
-    ASE = dyn_cast<ArraySubscriptExpr>(
-        getSubExprFromArrayDecayOperand(ASE->getBase()));
+    ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts());
   }
 
   // find binding info for the resource array
@@ -862,8 +847,9 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
 
   // lookup the resource class constructor based on the resource type and
   // binding
+  ASTContext &AST = ArrayDecl->getASTContext();
   CXXConstructorDecl *CD =
-      findResourceConstructorDecl(ArrayDecl->getASTContext(), ResourceTy,
+      findResourceConstructorDecl(AST, ResourceTy,
                                   VkBinding || RBA->hasRegisterSlot());
 
   // create a temporary variable for the resource class instance (we need to
@@ -876,7 +862,7 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
   AggValueSlot ValueSlot = AggValueSlot::forAddr(
       TmpVar, Qualifiers(), AggValueSlot::IsDestructed_t(true),
       AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false),
-      AggValueSlot::MayOverlap);
+      AggValueSlot::DoesNotOverlap);
 
   Address ThisAddress = ValueSlot.getAddress();
   llvm::Value *ThisPtr = CGF.getAsNaturalPointerTo(
@@ -884,7 +870,7 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
 
   // get total array size (= range size)
   llvm::Value *Range =
-      llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(ResArrayTy));
+      llvm::ConstantInt::get(CGM.IntTy, getTotalArraySize(AST, ResArrayTy));
 
   // assemble the constructor parameters
   CallArgList Args;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 0a0c2ba920dba..f782a497b3bb6 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -351,20 +351,11 @@ getResourceArrayHandleType(VarDecl *VD) {
   assert(VD->getType()->isHLSLResourceRecordArray() &&
          "expected array of resource records");
   const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
-  while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) {
+  while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
     Ty = CAT->getArrayElementTypeNoTypeQual()->getUnqualifiedDesugaredType();
-  }
   return HLSLAttributedResourceType::findHandleTypeOnResource(Ty);
 }
 
-// returns the element type of an array (including multi-dimensional array)
-static QualType getArrayElementType(QualType Ty) {
-  assert(Ty->isArrayType() && "expected array type");
-  while (const ArrayType *AT = dyn_cast<ArrayType>(Ty.getTypePtr()))
-    Ty = AT->getElementType();
-  return Ty;
-}
-
 // Returns true if the type is a leaf element type that is not valid to be
 // included in HLSL Buffer, such as a resource class, empty struct, zero-sized
 // array, or a builtin intangible type. Returns false it is a valid leaf 
element
@@ -3711,7 +3702,7 @@ void SemaHLSL::createResourceRecordCtorArgs(const Type 
*ResourceTy,
                                             HLSLResourceBindingAttr *RBA,
                                             HLSLVkBindingAttr *VkBinding,
                                             uint32_t ArrayIndex,
-                                            llvm::SmallVector<Expr *> &Args) {
+                                            llvm::SmallVectorImpl<Expr *> 
&Args) {
   std::optional<uint32_t> RegisterSlot;
   uint32_t SpaceNo = 0;
   if (VkBinding) {
@@ -3776,7 +3767,7 @@ bool SemaHLSL::initGlobalResourceArrayDecl(VarDecl *VD) {
   // for the specific resource type is instantiated, so codegen can emit a call
   // to it when the array element is accessed.
   SmallVector<Expr *> Args;
-  QualType ResElementTy = getArrayElementType(VD->getType());
+  QualType ResElementTy = 
VD->getASTContext().getBaseElementType(VD->getType());
   createResourceRecordCtorArgs(ResElementTy.getTypePtr(), VD->getName(),
                                VD->getAttr<HLSLResourceBindingAttr>(),
                                VD->getAttr<HLSLVkBindingAttr>(), 0, Args);

>From 1600414290e43e1ba5790ea707014f7b66320ea9 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Tue, 12 Aug 2025 14:30:21 -0700
Subject: [PATCH 11/13] clang-format

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 10 +++++-----
 clang/lib/Sema/SemaHLSL.cpp         | 10 ++++------
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index e962e2f06afa3..1c947f36347ec 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -141,8 +141,9 @@ static CXXConstructorDecl 
*findResourceConstructorDecl(ASTContext &AST,
 
 static Value *buildNameForResource(llvm::StringRef BaseName,
                                    CodeGenModule &CGM) {
-  llvm::SmallString<64> GlobalName = { BaseName, ".str" };
-  return CGM.GetAddrOfConstantCString(BaseName.str(), 
GlobalName.c_str()).getPointer();
+  llvm::SmallString<64> GlobalName = {BaseName, ".str"};
+  return CGM.GetAddrOfConstantCString(BaseName.str(), GlobalName.c_str())
+      .getPointer();
 }
 
 static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
@@ -848,9 +849,8 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
   // lookup the resource class constructor based on the resource type and
   // binding
   ASTContext &AST = ArrayDecl->getASTContext();
-  CXXConstructorDecl *CD =
-      findResourceConstructorDecl(AST, ResourceTy,
-                                  VkBinding || RBA->hasRegisterSlot());
+  CXXConstructorDecl *CD = findResourceConstructorDecl(
+      AST, ResourceTy, VkBinding || RBA->hasRegisterSlot());
 
   // create a temporary variable for the resource class instance (we need to
   // return an LValue)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f782a497b3bb6..f87715950c74c 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3697,12 +3697,10 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD,
   return true;
 }
 
-void SemaHLSL::createResourceRecordCtorArgs(const Type *ResourceTy,
-                                            StringRef VarName,
-                                            HLSLResourceBindingAttr *RBA,
-                                            HLSLVkBindingAttr *VkBinding,
-                                            uint32_t ArrayIndex,
-                                            llvm::SmallVectorImpl<Expr *> 
&Args) {
+void SemaHLSL::createResourceRecordCtorArgs(
+    const Type *ResourceTy, StringRef VarName, HLSLResourceBindingAttr *RBA,
+    HLSLVkBindingAttr *VkBinding, uint32_t ArrayIndex,
+    llvm::SmallVectorImpl<Expr *> &Args) {
   std::optional<uint32_t> RegisterSlot;
   uint32_t SpaceNo = 0;
   if (VkBinding) {

>From 00341fa79cb84d01ce34e73f4056d6508cb3abb0 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Tue, 12 Aug 2025 15:07:30 -0700
Subject: [PATCH 12/13] Add note to tests

---
 .../CodeGenHLSL/resources/res-array-global-dyn-index.hlsl | 3 +++
 .../CodeGenHLSL/resources/res-array-global-multi-dim.hlsl | 8 ++++++++
 clang/test/CodeGenHLSL/resources/res-array-global.hlsl    | 8 ++++++++
 3 files changed, 19 insertions(+)

diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl
index 26108aadff958..5b62452ef9844 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-global-dyn-index.hlsl
@@ -8,6 +8,9 @@ RWStructuredBuffer<float> Out;
 
 // Make sure A[GI.x][GI.y] is translated to a RWBuffer<float> constructor call 
with range 12 and dynamically calculated index
 
+// NOTE:
+// Constructor call for explicit binding has "jjij" in the mangled name and 
the arguments are (register, space, range_size, index, name).
+
 // CHECK: define internal void @_Z4mainDv3_j(<3 x i32> noundef %GI)
 // CHECK: %[[GI_alloca:.*]] = alloca <3 x i32>, align 16
 // CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
index 5219cf5143c13..8d664dad58153 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
@@ -23,6 +23,14 @@ void main() {
   // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer
   // CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer
 
+  // NOTE:
+  // Constructor call for explicit binding has "jjij" in the mangled name and 
the arguments are (register, space, range_size, index, name).
+  // For implicit binding the constructor has "jijj" in the mangled name and 
the arguments are (space, range_size, index, order_id, name).
+  // The range_size can be -1 for unbounded arrays, and that is the only 
signed int in the signature.
+  // The order_id argument is a sequential number that is assigned to 
resources with implicit binding and corresponds to the order in which 
+  // the resources were declared. It is needed because implicit bindings are 
assigned later on in an LLVM pass that needs to know the order
+  // of the resource declarations.
+
   // Make sure that B[3][2] is translated to a RWBuffer<float> constructor 
call for explicit binding (u2, space0) with range 16 and index 14
   // CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], 
i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef 
@[[BufB]])
 
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
index cc0e8cca19953..98aed10cb57f0 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
@@ -32,6 +32,14 @@ void main() {
   // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer
   // CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer
 
+  // NOTE:
+  // Constructor call for explicit binding has "jjij" in the mangled name and 
the arguments are (register, space, range_size, index, name).
+  // For implicit binding the constructor has "jijj" in the mangled name and 
the arguments are (space, range_size, index, order_id, name).
+  // The range_size can be -1 for unbounded arrays, and that is the only 
signed int in the signature.
+  // The order_id argument is a sequential number that is assigned to 
resources with implicit binding and corresponds to the order in which 
+  // the resources were declared. It is needed because implicit bindings are 
assigned later on in an LLVM pass that needs to know the order
+  // of the resource declarations.
+
   // Make sure A[2] is translated to a RWBuffer<float> constructor call with 
range 4 and index 2
   // and DXIL explicit binding (u10, space1)
   // and SPIR-V explicit binding (binding 12, set 2) 

>From d1b3e3ab38814cdf3218c2347574ff8e2247ce77 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Fri, 15 Aug 2025 16:48:37 -0700
Subject: [PATCH 13/13] Update resource index calculation & fix formatting

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 1c947f36347ec..062c169d6a440 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -812,6 +812,7 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
          "indexing of array subsets it not supported yet");
 
   // get the resource array type
+  ASTContext &AST = ArrayDecl->getASTContext();
   const Type *ResArrayTy = ArrayDecl->getType().getTypePtr();
   assert(ResArrayTy->isHLSLResourceRecordArray() &&
          "expected array of resource classes");
@@ -821,16 +822,13 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
   // dimensional array). The index is calculated as a sum of all indices
   // multiplied by the total size of the array at that level.
   Value *Index = nullptr;
-  Value *Multiplier = nullptr;
   const ArraySubscriptExpr *ASE = ArraySubsExpr;
   while (ASE != nullptr) {
     Value *SubIndex = CGF.EmitScalarExpr(ASE->getIdx());
     if (const auto *ArrayTy =
             dyn_cast<ConstantArrayType>(ASE->getType().getTypePtr())) {
-      Value *SubMultiplier =
-          llvm::ConstantInt::get(CGM.IntTy, ArrayTy->getSExtSize());
-      Multiplier = Multiplier ? CGF.Builder.CreateMul(Multiplier, 
SubMultiplier)
-                              : SubMultiplier;
+      Value *Multiplier = llvm::ConstantInt::get(
+          CGM.IntTy, AST.getConstantArrayElementCount(ArrayTy));
       SubIndex = CGF.Builder.CreateMul(SubIndex, Multiplier);
     }
 
@@ -838,9 +836,8 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
     ASE = dyn_cast<ArraySubscriptExpr>(ASE->getBase()->IgnoreParenImpCasts());
   }
 
-  // find binding info for the resource array
-  // (for implicit binding an HLSLResourceBindingAttr should have been added by
-  // SemaHLSL)
+  // find binding info for the resource array (for implicit binding
+  // an HLSLResourceBindingAttr should have been added by SemaHLSL)
   QualType ResourceTy = ArraySubsExpr->getType();
   HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr<HLSLVkBindingAttr>();
   HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr<HLSLResourceBindingAttr>();
@@ -848,17 +845,16 @@ std::optional<LValue> 
CGHLSLRuntime::emitResourceArraySubscriptExpr(
 
   // lookup the resource class constructor based on the resource type and
   // binding
-  ASTContext &AST = ArrayDecl->getASTContext();
   CXXConstructorDecl *CD = findResourceConstructorDecl(
       AST, ResourceTy, VkBinding || RBA->hasRegisterSlot());
 
   // create a temporary variable for the resource class instance (we need to
   // return an LValue)
   RawAddress TmpVar = CGF.CreateMemTemp(ResourceTy);
-  if (CGF.EmitLifetimeStart(TmpVar.getPointer())) {
+  if (CGF.EmitLifetimeStart(TmpVar.getPointer()))
     CGF.pushFullExprCleanup<CodeGenFunction::CallLifetimeEnd>(
         NormalEHLifetimeMarker, TmpVar);
-  }
+
   AggValueSlot ValueSlot = AggValueSlot::forAddr(
       TmpVar, Qualifiers(), AggValueSlot::IsDestructed_t(true),
       AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false),

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to