https://github.com/s-perron updated 
https://github.com/llvm/llvm-project/pull/156075

>From aaecbc5efd38190e8aedd9b3e3c95b2ede791a09 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Fri, 29 Aug 2025 13:40:55 -0400
Subject: [PATCH 1/9] [HLSL] Add copy assignment and construtor to resource
 types

The wrapper used to hold the handle for resource type has just the
default copy constructor and assignment operator. This causes clang to
insert memcpys when it does an assignment of a resource type. The
memcpy then cause optimizations to fail when the memcpy is turned into a
load and store of an i64.

To fix this, we should define copying of a resource type by adding the
operator= and copy constructor.

This exposed an issue in the hanlding of OpaqueValueExpr. If there were
OpaqueValueExpr in the sub tree of an OpaqueValueExpr, there were not
getting evaluated correctly, where causing an assert. This fixs that,
creating an exception for HLSLOutArgExpr nodes. Their OpaqueValueExpr
need to be handled different, and are already handled correctly.

Partially fixes #154669
---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           |  20 ++-
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp |  69 ++++++++++
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h   |   2 +
 clang/lib/Sema/HLSLExternalSemaSource.cpp     |   2 +
 .../CodeGenHLSL/builtins/hlsl_resource_t.hlsl |  12 +-
 .../debug/rwbuffer_debug_info.hlsl            |   4 +-
 .../implicit-norecurse-attrib.hlsl            |   2 +-
 .../resources/res-array-local-multi-dim.hlsl  | 114 +++++++++-------
 .../resources/res-array-local1.hlsl           | 128 +++++++++---------
 .../resources/res-array-local3.hlsl           | 124 ++++++++---------
 10 files changed, 291 insertions(+), 186 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f32d01ae78658..99a654aec29e5 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -762,11 +762,27 @@ llvm::Instruction 
*CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
 
 class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
 public:
-  llvm::SmallPtrSet<OpaqueValueExpr *, 8> OVEs;
+  llvm::SmallVector<OpaqueValueExpr *, 8> OVEs;
+  llvm::SmallPtrSet<OpaqueValueExpr *, 8> Visited;
   OpaqueValueVisitor() {}
 
+  bool VisitHLSLOutArgExpr(HLSLOutArgExpr *) {
+    // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues
+    // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this
+    // traversal, the temporary containing the copy out will not have
+    // been created yet.
+    return false;
+  }
+
   bool VisitOpaqueValueExpr(OpaqueValueExpr *E) {
-    OVEs.insert(E);
+    // Traverse the source expression first.
+    if (E->getSourceExpr())
+      TraverseStmt(E->getSourceExpr());
+
+    // Then add this OVE if we haven't seen it before.
+    if (Visited.insert(E).second)
+      OVEs.push_back(E);
+
     return true;
   }
 };
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 806800cb7b213..6c39fe504d3f3 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -676,6 +676,75 @@ 
BuiltinTypeDeclBuilder::addHandleConstructorFromImplicitBinding() {
       .finalize();
 }
 
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() {
+  if (Record->isCompleteDefinition())
+    return *this;
+
+  ASTContext &AST = SemaRef.getASTContext();
+  QualType RecordType = AST.getCanonicalTagType(Record);
+  QualType ConstRecordType = RecordType.withConst();
+  QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType);
+
+  using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+  BuiltinTypeMethodBuilder Builder(*this, "", AST.VoidTy, false, true);
+  Builder.addParam("other", ConstRecordRefType);
+  Builder.ensureCompleteDecl();
+
+  ParmVarDecl *OtherParam = Builder.Method->getParamDecl(0);
+
+  Expr *OtherDeclRef = DeclRefExpr::Create(
+      AST, NestedNameSpecifierLoc(), SourceLocation(), OtherParam, false,
+      DeclarationNameInfo(OtherParam->getDeclName(), SourceLocation()),
+      ConstRecordType, VK_LValue);
+
+  FieldDecl *HandleField = getResourceHandleField();
+  Expr *OtherHandleMemberExpr = MemberExpr::CreateImplicit(
+      AST, OtherDeclRef, false, HandleField, HandleField->getType(), VK_LValue,
+      OK_Ordinary);
+
+  return Builder.assign(PH::Handle, OtherHandleMemberExpr).finalize();
+}
+
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
+  if (Record->isCompleteDefinition())
+    return *this;
+
+  ASTContext &AST = SemaRef.getASTContext();
+  QualType RecordType = AST.getCanonicalTagType(Record);
+  QualType ConstRecordType = RecordType.withConst();
+  QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType);
+  QualType RecordRefType = AST.getLValueReferenceType(RecordType);
+
+  using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+  DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal);
+  BuiltinTypeMethodBuilder Builder(*this, Name, RecordRefType, false, false);
+  Builder.addParam("other", ConstRecordRefType);
+  Builder.ensureCompleteDecl();
+
+  ParmVarDecl *OtherParam = Builder.Method->getParamDecl(0);
+  Expr *OtherDeclRef = DeclRefExpr::Create(
+      AST, NestedNameSpecifierLoc(), SourceLocation(), OtherParam, false,
+      DeclarationNameInfo(OtherParam->getDeclName(), SourceLocation()),
+      ConstRecordType, VK_LValue);
+
+  FieldDecl *HandleField = getResourceHandleField();
+  Expr *OtherHandleMemberExpr = MemberExpr::CreateImplicit(
+      AST, OtherDeclRef, false, HandleField, HandleField->getType(), VK_LValue,
+      OK_Ordinary);
+
+  Builder.assign(PH::Handle, OtherHandleMemberExpr);
+
+  // return *this;
+  CXXThisExpr *This = CXXThisExpr::Create(
+      AST, SourceLocation(), Builder.Method->getFunctionObjectParameterType(),
+      true);
+  Builder.StmtsList.push_back(This);
+
+  return Builder.finalize();
+}
+
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
   ASTContext &AST = Record->getASTContext();
   DeclarationName Subscript =
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 098b72692bd3a..4c4c2083a8440 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -80,6 +80,8 @@ class BuiltinTypeDeclBuilder {
   BuiltinTypeDeclBuilder &addDefaultHandleConstructor();
   BuiltinTypeDeclBuilder &addHandleConstructorFromBinding();
   BuiltinTypeDeclBuilder &addHandleConstructorFromImplicitBinding();
+  BuiltinTypeDeclBuilder &addCopyConstructor();
+  BuiltinTypeDeclBuilder &addCopyAssignmentOperator();
 
   // Builtin types methods
   BuiltinTypeDeclBuilder &addLoadMethods();
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp 
b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 726581d131623..8c893c0c30baf 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -132,6 +132,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl 
*Decl, Sema &S,
   return BuiltinTypeDeclBuilder(S, Decl)
       .addHandleMember(RC, IsROV, RawBuffer)
       .addDefaultHandleConstructor()
+      .addCopyConstructor()
+      .addCopyAssignmentOperator()
       .addHandleConstructorFromBinding()
       .addHandleConstructorFromImplicitBinding();
 }
diff --git a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl 
b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
index 24114b11c7602..1f64037e1f9b4 100644
--- a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
@@ -21,9 +21,9 @@ void fb(handle_float_t a) {
     handle_float_t b = a;
 }
 
-// CHECK: define hidden void @_Z2fcN4hlsl8RWBufferIDv4_fEE(ptr noundef 
byval(%"class.hlsl::RWBuffer") align 4 %a)
-// CHECK: call void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef 
byval(%"class.hlsl::RWBuffer") align 4 %agg.tmp)
-// CHECK: declare hidden void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef 
byval(%"class.hlsl::RWBuffer") align 4)
+// CHECK: define hidden void @_Z2fcN4hlsl8RWBufferIDv4_fEE(ptr dead_on_return 
noundef %a)
+// CHECK: call void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr dead_on_return noundef 
%{{.*}})
+// CHECK: declare hidden void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr 
dead_on_return noundef)
 void foo2(RWBuffer<float4> buf);
 
 void fc(RWBuffer<float4> a) {
@@ -39,9 +39,9 @@ struct MyStruct {
   int2 i;
 };
 
-// CHECK: define hidden void @_Z2feN4hlsl16StructuredBufferI8MyStructEE(ptr 
noundef byval(%"class.hlsl::StructuredBuffer") align 4 %a)
-// CHECK: call void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr noundef 
byval(%"class.hlsl::StructuredBuffer") align 4 %agg.tmp)
-// CHECK: declare hidden void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr 
noundef byval(%"class.hlsl::StructuredBuffer") align 4)
+// CHECK: define hidden void @_Z2feN4hlsl16StructuredBufferI8MyStructEE(ptr 
dead_on_return noundef %a)
+// CHECK: call void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr 
dead_on_return noundef %{{.*}})
+// CHECK: declare hidden void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr 
dead_on_return noundef)
 void foo3(StructuredBuffer<MyStruct> buf);
 
 void fe(StructuredBuffer<MyStruct> a) {
diff --git a/clang/test/CodeGenHLSL/debug/rwbuffer_debug_info.hlsl 
b/clang/test/CodeGenHLSL/debug/rwbuffer_debug_info.hlsl
index db0388e41eae9..76ea87fd534c1 100644
--- a/clang/test/CodeGenHLSL/debug/rwbuffer_debug_info.hlsl
+++ b/clang/test/CodeGenHLSL/debug/rwbuffer_debug_info.hlsl
@@ -1,11 +1,11 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -x hlsl -emit-llvm 
-disable-llvm-passes -o - -hlsl-entry main %s -debug-info-kind=standalone 
-dwarf-version=4  | FileCheck %s
 
 
-// CHECK: [[DWTag:![0-9]+]] = distinct !DICompositeType(tag: 
DW_TAG_class_type, name: "RWBuffer<float>", 
+// CHECK: [[DWTag:![0-9]+]] = distinct !DICompositeType(tag: 
DW_TAG_class_type, name: "RWBuffer<float>",
+// CHECK: [[thisType:![0-9]+]] = !DIDerivedType(tag: DW_TAG_reference_type, 
baseType: [[DWTag]], size: 32)
 // CHECK: [[RWBuffer:![0-9]+]] = distinct !DISubprogram(name: "RWBuffer",
 // CHECK-SAME: scope: [[DWTag]]
 // CHECK: [[FirstThis:![0-9]+]] = !DILocalVariable(name: "this", arg: 1, 
scope: [[RWBuffer]], type: [[thisType:![0-9]+]]
-// CHECK: [[thisType]] = !DIDerivedType(tag: DW_TAG_reference_type, baseType: 
[[DWTag]], size: 32)
 RWBuffer<float> Out : register(u7, space4);
 
 [numthreads(8,1,1)]
diff --git a/clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl 
b/clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl
index 60238cbf8eff5..0c96b73ac6cb1 100644
--- a/clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl
+++ b/clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl
@@ -31,7 +31,7 @@ uint Find(Node SortedTree[MAX], uint key) {
 }
 
 // CHECK: Function Attrs:{{.*}}norecurse
-// CHECK: define noundef i1 @_Z8InitTreeA100_4NodeN4hlsl8RWBufferIDv4_jEEj(ptr 
noundef byval([100 x %struct.Node]) align 1 %tree, ptr noundef 
byval(%"class.hlsl::RWBuffer") align 4 %encodedTree, i32 noundef %maxDepth) 
[[Attr:\#[0-9]+]]
+// CHECK: define noundef i1 @_Z8InitTreeA100_4NodeN4hlsl8RWBufferIDv4_jEEj(ptr 
noundef byval([100 x %struct.Node]) align 1 %tree, ptr dead_on_return noundef 
%encodedTree, i32 noundef %maxDepth) [[Attr:\#[0-9]+]]
 // CHECK: ret i1
 // Initialize tree with given buffer
 // Imagine the inout works
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
index d803882fd2f72..d9bd944ba6297 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
@@ -1,49 +1,65 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
-// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
-
-// This test verifies handling of multi-dimensional local arrays of resources
-// when used as a function argument and local variable.
-
-// CHECK: @_ZL1A = internal global %"class.hlsl::RWBuffer" poison, align 4
-// CHECK: @_ZL1B = internal global %"class.hlsl::RWBuffer" poison, align 4
-
-RWBuffer<float> A : register(u10);
-RWBuffer<float> B : register(u20);
-RWStructuredBuffer<float> Out;
-
-// NOTE: _ZN4hlsl8RWBufferIfEixEj is the subscript operator for 
RWBuffer<float> and
-//       _ZN4hlsl18RWStructuredBufferIfEixEj is the subscript operator for 
RWStructuredBuffer<float>
-
-// CHECK: define {{.*}} float @_Z3fooA2_A2_N4hlsl8RWBufferIfEE(ptr noundef 
byval([2 x [2 x %"class.hlsl::RWBuffer"]]) align 4 %Arr)
-// CHECK-NEXT: entry:
-float foo(RWBuffer<float> Arr[2][2]) {
-// CHECK-NEXT: %[[Arr_1_Ptr:.*]] = getelementptr inbounds [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %Arr, i32 0, i32 1
-// CHECK-NEXT: %[[Arr_1_1_Ptr:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %[[Arr_1_Ptr]], i32 0, i32 1
-// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr 
{{.*}} %[[Arr_1_1_Ptr]], i32 noundef 0)
-// CHECK-NEXT: %[[Value:.*]] = load float, ptr %[[BufPtr]], align 4
-// CHECK-NEXT: ret float %[[Value]]
-  return Arr[1][1][0];
-}
-
-// CHECK: define internal void @_Z4mainv()
-// CHECK-NEXT: entry:
-[numthreads(4,1,1)]
-void main() {
-// CHECK-NEXT: %L = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
-// CHECK-NEXT: %[[Tmp:.*]] = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 
4
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %L, ptr align 4 
@_ZL1A, i32 4, i1 false)
-// CHECK-NEXT: %[[Ptr1:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", 
ptr %L, i32 1
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr1]], ptr 
align 4 @_ZL1B, i32 4, i1 false)
-// CHECK-NEXT: %[[Ptr2:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %L, i32 1
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr2]], ptr 
align 4 @_ZL1A, i32 4, i1 false)
-// CHECK-NEXT: %[[Ptr3:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", 
ptr %[[Ptr2]], i32 1
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr3]], ptr 
align 4 @_ZL1B, i32 4, i1 false)
-  RWBuffer<float> L[2][2] = { { A, B }, { A, B } };
-
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp]], ptr 
align 4 %L, i32 16, i1 false)
-// CHECK-NEXT: %[[ReturnedValue:.*]] = call {{.*}}float 
@_Z3fooA2_A2_N4hlsl8RWBufferIfEE(ptr noundef byval([2 x [2 x 
%"class.hlsl::RWBuffer"]]) align 4 %[[Tmp]])
-// CHECK-NEXT: %[[OutBufPtr:.*]] = call {{.*}} ptr 
@_ZN4hlsl18RWStructuredBufferIfEixEj(ptr {{.*}} @_ZL3Out, i32 noundef 0)
-// CHECK-NEXT: store float %[[ReturnedValue]], ptr %[[OutBufPtr]], align 4
-// CHECK-NEXT: ret void
-  Out[0] = foo(L);
-}
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// This test verifies handling of multi-dimensional local arrays of resources
+// when used as a function argument and local variable.
+
+// CHECK: @_ZL1A = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL1B = internal global %"class.hlsl::RWBuffer" poison, align 4
+
+RWBuffer<float> A : register(u10);
+RWBuffer<float> B : register(u20);
+RWStructuredBuffer<float> Out;
+
+// NOTE: _ZN4hlsl8RWBufferIfEixEj is the subscript operator for 
RWBuffer<float> and
+//       _ZN4hlsl18RWStructuredBufferIfEixEj is the subscript operator for 
RWStructuredBuffer<float>
+
+// CHECK: define {{.*}} float @_Z3fooA2_A2_N4hlsl8RWBufferIfEE(ptr noundef 
byval([2 x [2 x %"class.hlsl::RWBuffer"]]) align 4 %Arr)
+// CHECK-NEXT: entry:
+float foo(RWBuffer<float> Arr[2][2]) {
+// CHECK-NEXT: %[[Arr_1_Ptr:.*]] = getelementptr inbounds [2 x [2 x 
%"class.hlsl::RWBuffer"]], ptr %Arr, i32 0, i32 1
+// CHECK-NEXT: %[[Arr_1_1_Ptr:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %[[Arr_1_Ptr]], i32 0, i32 1
+// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr 
{{.*}} %[[Arr_1_1_Ptr]], i32 noundef 0)
+// CHECK-NEXT: %[[Value:.*]] = load float, ptr %[[BufPtr]], align 4
+// CHECK-NEXT: ret float %[[Value]]
+  return Arr[1][1][0];
+}
+
+// CHECK: define internal void @_Z4mainv()
+// CHECK-NEXT: entry:
+[numthreads(4,1,1)]
+void main() {
+// CHECK: %L = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
+// CHECK: %[[ref_tmp:.*]] = alloca %"class.hlsl::RWBuffer", align 4
+// CHECK: %[[ref_tmp1:.*]] = alloca %"class.hlsl::RWBuffer", align 4
+// CHECK: %[[ref_tmp2:.*]] = alloca %"class.hlsl::RWBuffer", align 4
+// CHECK: %[[ref_tmp3:.*]] = alloca %"class.hlsl::RWBuffer", align 4
+// CHECK: %[[ref_tmp4:.*]] = alloca %"class.hlsl::RWBuffer", align 4
+// CHECK: %[[ref_tmp5:.*]] = alloca %"class.hlsl::RWBuffer", align 4
+// CHECK: %[[ref_tmp6:.*]] = alloca %"class.hlsl::RWBuffer", align 4
+// CHECK: %[[ref_tmp7:.*]] = alloca %"class.hlsl::RWBuffer", align 4
+// CHECK: %[[agg_tmp:.*]] = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
+// CHECK: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp]], ptr noundef nonnull align 4 dereferenceable(4) 
@_ZL1A)
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp1]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp2]], ptr noundef nonnull align 4 
dereferenceable(4) @_ZL1B)
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp3]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp2]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp4]], ptr noundef nonnull align 4 
dereferenceable(4) @_ZL1A)
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp5]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp4]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp6]], ptr noundef nonnull align 4 
dereferenceable(4) @_ZL1B)
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp7]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp6]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %L, ptr noundef nonnull align 4 dereferenceable(4) 
%[[ref_tmp1]])
+// CHECK-NEXT: %[[arrayinit_element:.*]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %L, i32 1
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[arrayinit_element]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp3]])
+// CHECK-NEXT: %[[arrayinit_element8:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %L, i32 1
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[arrayinit_element8]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp5]])
+// CHECK-NEXT: %[[arrayinit_element9:.*]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %[[arrayinit_element8]], i32 1
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[arrayinit_element9]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp7]])
+  RWBuffer<float> L[2][2] = { { A, B }, { A, B } };
+
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[agg_tmp]], ptr align 
4 %L, i32 16, i1 false)
+// CHECK-NEXT: %[[ReturnedValue:.*]] = call {{.*}}float 
@_Z3fooA2_A2_N4hlsl8RWBufferIfEE(ptr noundef byval([2 x [2 x 
%"class.hlsl::RWBuffer"]]) align 4 %[[agg_tmp]])
+// CHECK-NEXT: %[[OutBufPtr:.*]] = call {{.*}} ptr 
@_ZN4hlsl18RWStructuredBufferIfEixEj(ptr {{.*}} @_ZL3Out, i32 noundef 0)
+// CHECK-NEXT: store float %[[ReturnedValue]], ptr %[[OutBufPtr]], align 4
+// CHECK-NEXT: ret void
+  Out[0] = foo(L);
+}
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
index c0d508b1395c3..9e31f4f150c52 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
@@ -1,64 +1,64 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
-// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
-
-// This test verifies local arrays of resources in HLSL.
-
-// CHECK: @_ZL1A = internal global %"class.hlsl::RWBuffer" poison, align 4
-// CHECK: @_ZL1B = internal global %"class.hlsl::RWBuffer" poison, align 4
-// CHECK: @_ZL1C = internal global %"class.hlsl::RWBuffer" poison, align 4
-
-RWBuffer<float> A : register(u1);
-RWBuffer<float> B : register(u2);
-RWBuffer<float> C : register(u3);
-RWStructuredBuffer<float> Out : register(u0);
-
-// CHECK: define internal void @_Z4mainv()
-// CHECK-NEXT: entry:
-[numthreads(4,1,1)]
-void main() {
-// CHECK-NEXT:  %First = alloca [3 x %"class.hlsl::RWBuffer"], align 4
-// CHECK-NEXT:  %Second = alloca [4 x %"class.hlsl::RWBuffer"], align 4
-  RWBuffer<float> First[3] = { A, B, C };
-  RWBuffer<float> Second[4];
-
-// Verify initialization of First array from an initialization list
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %First, ptr align 
4 @_ZL1A, i32 4, i1 false)
-// CHECK-NEXT: %[[Ptr1:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", 
ptr %First, i32 1
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr1]], ptr 
align 4 @_ZL1B, i32 4, i1 false)
-// CHECK-NEXT: %[[Ptr2:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", 
ptr %First, i32 2
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr2]], ptr 
align 4 @_ZL1C, i32 4, i1 false)
-
-// Verify default initialization of Second array, which means there is a loop 
iterating
-// over the array elements and calling the default constructor for each
-// CHECK-NEXT: %[[ArrayBeginPtr:.*]] = getelementptr inbounds [4 x 
%"class.hlsl::RWBuffer"], ptr %Second, i32 0, i32 0
-// CHECK-NEXT: %[[ArrayEndPtr:.*]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %[[ArrayBeginPtr]], i32 4
-// CHECK-NEXT: br label %[[ArrayInitLoop:.*]]
-// CHECK: [[ArrayInitLoop]]:
-// CHECK-NEXT: %[[ArrayCurPtr:.*]] = phi ptr [ %[[ArrayBeginPtr]], %entry ], [ 
%[[ArrayNextPtr:.*]], %[[ArrayInitLoop]] ]
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1Ev(ptr {{.*}} %[[ArrayCurPtr]])
-// CHECK-NEXT: %[[ArrayNextPtr]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %[[ArrayCurPtr]], i32 1
-// CHECK-NEXT: %[[ArrayInitDone:.*]] = icmp eq ptr %[[ArrayNextPtr]], 
%[[ArrayEndPtr]]
-// CHECK-NEXT: br i1 %[[ArrayInitDone]], label %[[AfterArrayInit:.*]], label 
%[[ArrayInitLoop]]
-// CHECK: [[AfterArrayInit]]:
-
-// Initialize First[2] with C
-// CHECK: %[[Ptr3:.*]] = getelementptr inbounds [4 x %"class.hlsl::RWBuffer"], 
ptr %Second, i32 0, i32 2
-// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Ptr3]], ptr align 4 
@_ZL1C, i32 4, i1 false)
-  Second[2] = C;
-
-  // NOTE: _ZN4hlsl8RWBufferIfEixEj is the subscript operator for 
RWBuffer<float>
-
-// get First[1][0] value
-// CHECK: %[[First_1_Ptr:.*]] = getelementptr inbounds [3 x 
%"class.hlsl::RWBuffer"], ptr %First, i32 0, i32 1
-// CHECK: %[[BufPtr1:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr 
{{.*}} %[[First_1_Ptr]], i32 noundef 0)
-// CHECK: %[[Value1:.*]] = load float, ptr %[[BufPtr1]], align 4
-
-// get Second[2][0] value
-// CHECK: %[[Second_2_Ptr:.*]] = getelementptr inbounds [4 x 
%"class.hlsl::RWBuffer"], ptr %Second, i32 0, i32 2
-// CHECK: %[[BufPtr2:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr 
{{.*}} %[[Second_2_Ptr]], i32 noundef 0)
-// CHECK: %[[Value2:.*]] = load float, ptr %[[BufPtr2]], align 4
-
-// add them
-// CHECK: %{{.*}} = fadd {{.*}} float %[[Value1]], %[[Value2]]
-  Out[0] = First[1][0] + Second[2][0];
-}
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// This test verifies local arrays of resources in HLSL.
+
+// CHECK: @_ZL1A = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL1B = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL1C = internal global %"class.hlsl::RWBuffer" poison, align 4
+
+RWBuffer<float> A : register(u1);
+RWBuffer<float> B : register(u2);
+RWBuffer<float> C : register(u3);
+RWStructuredBuffer<float> Out : register(u0);
+
+// CHECK: define internal void @_Z4mainv()
+// CHECK-NEXT: entry:
+[numthreads(4,1,1)]
+void main() {
+// CHECK-NEXT:  %First = alloca [3 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT:  %Second = alloca [4 x %"class.hlsl::RWBuffer"], align 4
+  RWBuffer<float> First[3] = { A, B, C };
+  RWBuffer<float> Second[4];
+
+// Verify initialization of First array from an initialization list
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} %First, ptr 
{{.*}} @_ZL1A)
+// CHECK-NEXT: %[[Ptr1:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", 
ptr %First, i32 1
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} %[[Ptr1]], 
ptr {{.*}} @_ZL1B)
+// CHECK-NEXT: %[[Ptr2:.*]] = getelementptr inbounds %"class.hlsl::RWBuffer", 
ptr %First, i32 2
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} %[[Ptr2]], 
ptr {{.*}} @_ZL1C)
+
+// Verify default initialization of Second array, which means there is a loop 
iterating
+// over the array elements and calling the default constructor for each
+// CHECK-NEXT: %[[ArrayBeginPtr:.*]] = getelementptr inbounds [4 x 
%"class.hlsl::RWBuffer"], ptr %Second, i32 0, i32 0
+// CHECK-NEXT: %[[ArrayEndPtr:.*]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %[[ArrayBeginPtr]], i32 4
+// CHECK-NEXT: br label %[[ArrayInitLoop:.*]]
+// CHECK: [[ArrayInitLoop]]:
+// CHECK-NEXT: %[[ArrayCurPtr:.*]] = phi ptr [ %[[ArrayBeginPtr]], %entry ], [ 
%[[ArrayNextPtr:.*]], %[[ArrayInitLoop]] ]
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1Ev(ptr {{.*}} %[[ArrayCurPtr]])
+// CHECK-NEXT: %[[ArrayNextPtr]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %[[ArrayCurPtr]], i32 1
+// CHECK-NEXT: %[[ArrayInitDone:.*]] = icmp eq ptr %[[ArrayNextPtr]], 
%[[ArrayEndPtr]]
+// CHECK-NEXT: br i1 %[[ArrayInitDone]], label %[[AfterArrayInit:.*]], label 
%[[ArrayInitLoop]]
+// CHECK: [[AfterArrayInit]]:
+
+// Initialize First[2] with C
+// CHECK: %[[Ptr3:.*]] = getelementptr inbounds [4 x %"class.hlsl::RWBuffer"], 
ptr %Second, i32 0, i32 2
+// CHECK: call {{.*}} @_ZN4hlsl8RWBufferIfEaSERKS1_(ptr {{.*}} %[[Ptr3]], ptr 
{{.*}} @_ZL1C)
+  Second[2] = C;
+
+  // NOTE: _ZN4hlsl8RWBufferIfEixEj is the subscript operator for 
RWBuffer<float>
+
+// get First[1][0] value
+// CHECK: %[[First_1_Ptr:.*]] = getelementptr inbounds [3 x 
%"class.hlsl::RWBuffer"], ptr %First, i32 0, i32 1
+// CHECK: %[[BufPtr1:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr 
{{.*}} %[[First_1_Ptr]], i32 noundef 0)
+// CHECK: %[[Value1:.*]] = load float, ptr %[[BufPtr1]], align 4
+
+// get Second[2][0] value
+// CHECK: %[[Second_2_Ptr:.*]] = getelementptr inbounds [4 x 
%"class.hlsl::RWBuffer"], ptr %Second, i32 0, i32 2
+// CHECK: %[[BufPtr2:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIfEixEj(ptr 
{{.*}} %[[Second_2_Ptr]], i32 noundef 0)
+// CHECK: %[[Value2:.*]] = load float, ptr %[[BufPtr2]], align 4
+
+// add them
+// CHECK: %{{.*}} = fadd {{.*}} float %[[Value1]], %[[Value2]]
+  Out[0] = First[1][0] + Second[2][0];
+}
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
index e5bcdc651254f..21ca3f4a98f99 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
@@ -1,62 +1,62 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
-// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
-
-// This test verifies handling of local arrays of resources when used
-// as a function argument that is modified inside the function.
-
-// CHECK: @_ZL1X = internal global %"class.hlsl::RWBuffer" poison, align 4
-// CHECK: @_ZL1Y = internal global %"class.hlsl::RWBuffer" poison, align 4
-
-RWBuffer<int> X : register(u0);
-RWBuffer<int> Y : register(u1);
-
-// CHECK: define {{.*}} @_Z6SomeFnA2_N4hlsl8RWBufferIiEEji(
-// CHECK-SAME: ptr noundef byval([2 x %"class.hlsl::RWBuffer"]) align 4 %B, 
i32 noundef %Idx, i32 noundef %Val0)
-// CHECK-NEXT: entry:
-// CHECK-NEXT: %[[Idx_addr:.*]] = alloca i32, align 4
-// CHECK-NEXT: %[[Val0_addr:.*]] = alloca i32, align 4
-// CHECK-NEXT: store i32 %Idx, ptr %[[Idx_addr]], align 4
-// CHECK-NEXT: store i32 %Val0, ptr %[[Val0_addr]], align 4
-void SomeFn(RWBuffer<int> B[2], uint Idx, int Val0) {
-
-// CHECK-NEXT: %[[B_0_Ptr:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %B, i32 0, i32 0
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[B_0_Ptr]], ptr 
align 4 @_ZL1Y, i32 4, i1 false)
-  B[0] = Y;
-
-// NOTE: _ZN4hlsl8RWBufferIiEixEj is the subscript operator for RWBuffer<int>
-
-// CHECK-NEXT: %[[Val0:.*]] = load i32, ptr %[[Val0_addr]], align 4
-// CHECK-NEXT: %[[B_0_Ptr:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %B, i32 0, i32 0
-// CHECK-NEXT: %[[Idx:.*]] = load i32, ptr %[[Idx_addr]], align 4
-// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIiEixEj(ptr 
{{.*}} %[[B_0_Ptr]], i32 noundef %[[Idx]])
-// CHECK-NEXT: store i32 %[[Val0]], ptr %[[BufPtr]], align 4
-  B[0][Idx] = Val0;
-}
-
-// CHECK: define {{.*}} void @_Z4mainj(i32 noundef %GI)
-// CHECK-NEXT: entry:
-// CHECK-NEXT: %[[GI_addr:.*]] = alloca i32, align 4
-[numthreads(4,1,1)]
-void main(uint GI : SV_GroupIndex) {
-// CHECK-NEXT: %A = alloca [2 x %"class.hlsl::RWBuffer"], align 4
-// CHECK-NEXT: %[[Tmp:.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
-// CHECK-NEXT: store i32 %GI, ptr %GI.addr, align 4
-
-// Initialization of array A with resources X and Y
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %A, ptr align 4 
@_ZL1X, i32 4, i1 false)
-// CHECK-NEXT: %[[A_1_Ptr:.*]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %A, i32 1
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[A_1_Ptr]], ptr 
align 4 @_ZL1Y, i32 4, i1 false)
-  RWBuffer<int> A[2] = {X, Y};
-
-// Verify that SomeFn is called with a local copy of the array A
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp]], ptr 
align 4 %A, i32 8, i1 false)
-// CHECK-NEXT: %[[GI:.*]] = load i32, ptr %[[GI_addr]], align 4
-// CHECK-NEXT: call void @_Z6SomeFnA2_N4hlsl8RWBufferIiEEji(ptr noundef 
byval([2 x %"class.hlsl::RWBuffer"]) align 4 %[[Tmp]], i32 noundef %[[GI]], i32 
noundef 1)
-  SomeFn(A, GI, 1);
-
-// CHECK-NEXT: %[[A_0_Ptr:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %A, i32 0, i32 0
-// CHECK-NEXT: %[[GI:.*]] = load i32, ptr %[[GI_addr]], align 4
-// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIiEixEj(ptr 
{{.*}} %[[A_0_Ptr]], i32 noundef %[[GI]])
-// CHECK-NEXT: store i32 2, ptr %[[BufPtr]], align 4
-  A[0][GI] = 2;
-}
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
+// RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// This test verifies handling of local arrays of resources when used
+// as a function argument that is modified inside the function.
+
+// CHECK: @_ZL1X = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL1Y = internal global %"class.hlsl::RWBuffer" poison, align 4
+
+RWBuffer<int> X : register(u0);
+RWBuffer<int> Y : register(u1);
+
+// CHECK: define {{.*}} @_Z6SomeFnA2_N4hlsl8RWBufferIiEEji(
+// CHECK-SAME: ptr noundef byval([2 x %"class.hlsl::RWBuffer"]) align 4 %B, 
i32 noundef %Idx, i32 noundef %Val0)
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[Idx_addr:.*]] = alloca i32, align 4
+// CHECK-NEXT: %[[Val0_addr:.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 %Idx, ptr %[[Idx_addr]], align 4
+// CHECK-NEXT: store i32 %Val0, ptr %[[Val0_addr]], align 4
+void SomeFn(RWBuffer<int> B[2], uint Idx, int Val0) {
+
+// CHECK-NEXT: %[[B_0_Ptr:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %B, i32 0, i32 0
+// CHECK-NEXT: call {{.*}} @_ZN4hlsl8RWBufferIiEaSERKS1_(ptr {{.*}} 
%[[B_0_Ptr]], ptr {{.*}} @_ZL1Y)
+  B[0] = Y;
+
+// NOTE: _ZN4hlsl8RWBufferIiEixEj is the subscript operator for RWBuffer<int>
+
+// CHECK-NEXT: %[[Val0:.*]] = load i32, ptr %[[Val0_addr]], align 4
+// CHECK-NEXT: %[[B_0_Ptr:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %B, i32 0, i32 0
+// CHECK-NEXT: %[[Idx:.*]] = load i32, ptr %[[Idx_addr]], align 4
+// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIiEixEj(ptr 
{{.*}} %[[B_0_Ptr]], i32 noundef %[[Idx]])
+// CHECK-NEXT: store i32 %[[Val0]], ptr %[[BufPtr]], align 4
+  B[0][Idx] = Val0;
+}
+
+// CHECK: define {{.*}} void @_Z4mainj(i32 noundef %GI)
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[GI_addr:.*]] = alloca i32, align 4
+[numthreads(4,1,1)]
+void main(uint GI : SV_GroupIndex) {
+// CHECK-NEXT: %A = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: %[[Tmp:.*]] = alloca [2 x %"class.hlsl::RWBuffer"], align 4
+// CHECK-NEXT: store i32 %GI, ptr %GI.addr, align 4
+
+// Initialization of array A with resources X and Y
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1ERKS1_(ptr {{.*}} %A, ptr 
{{.*}} @_ZL1X)
+// CHECK-NEXT: %[[A_1_Ptr:.*]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %A, i32 1
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1ERKS1_(ptr {{.*}} 
%[[A_1_Ptr]], ptr {{.*}} @_ZL1Y)
+  RWBuffer<int> A[2] = {X, Y};
+
+// Verify that SomeFn is called with a local copy of the array A
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[Tmp]], ptr 
align 4 %A, i32 8, i1 false)
+// CHECK-NEXT: %[[GI:.*]] = load i32, ptr %[[GI_addr]], align 4
+// CHECK-NEXT: call void @_Z6SomeFnA2_N4hlsl8RWBufferIiEEji(ptr noundef 
byval([2 x %"class.hlsl::RWBuffer"]) align 4 %[[Tmp]], i32 noundef %[[GI]], i32 
noundef 1)
+  SomeFn(A, GI, 1);
+
+// CHECK-NEXT: %[[A_0_Ptr:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %A, i32 0, i32 0
+// CHECK-NEXT: %[[GI:.*]] = load i32, ptr %[[GI_addr]], align 4
+// CHECK-NEXT: %[[BufPtr:.*]] = call {{.*}} ptr @_ZN4hlsl8RWBufferIiEixEj(ptr 
{{.*}} %[[A_0_Ptr]], i32 noundef %[[GI]])
+// CHECK-NEXT: store i32 2, ptr %[[BufPtr]], align 4
+  A[0][GI] = 2;
+}

>From 7b048368fc299c29d306727ccfe5bf7b793424c1 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Wed, 3 Sep 2025 13:35:42 -0400
Subject: [PATCH 2/9] Refactor functions building the constructors.

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 81 +++++++++----------
 .../resources/res-array-local-multi-dim.hlsl  |  2 +-
 2 files changed, 39 insertions(+), 44 deletions(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 6c39fe504d3f3..26e48a18b2bf5 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -156,6 +156,9 @@ struct BuiltinTypeMethodBuilder {
   BuiltinTypeDeclBuilder &finalize();
   Expr *getResourceHandleExpr();
 
+  BuiltinTypeMethodBuilder &getResourceHandle(PlaceHolder ResourceRecord);
+  BuiltinTypeMethodBuilder &returnThis();
+
 private:
   void createDecl();
 
@@ -332,7 +335,7 @@ Expr 
*BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
   return DeclRefExpr::Create(
       AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,
       DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()),
-      ParamDecl->getType(), VK_PRValue);
+      ParamDecl->getType().getNonReferenceType(), VK_PRValue);
 }
 
 BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
@@ -431,6 +434,29 @@ Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
                                     OK_Ordinary);
 }
 
+BuiltinTypeMethodBuilder &
+BuiltinTypeMethodBuilder::getResourceHandle(PlaceHolder ResourceRecord) {
+  ensureCompleteDecl();
+
+  Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
+
+  ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+  FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
+  MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
+      AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
+      OK_Ordinary);
+  StmtsList.push_back(HandleExpr);
+  return *this;
+}
+
+BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() {
+  ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+  CXXThisExpr *ThisExpr = CXXThisExpr::Create(
+      AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
+  StmtsList.push_back(ThisExpr);
+  return *this;
+}
+
 template <typename... Ts>
 BuiltinTypeMethodBuilder &
 BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
@@ -687,23 +713,11 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addCopyConstructor() {
 
   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
 
-  BuiltinTypeMethodBuilder Builder(*this, "", AST.VoidTy, false, true);
-  Builder.addParam("other", ConstRecordRefType);
-  Builder.ensureCompleteDecl();
-
-  ParmVarDecl *OtherParam = Builder.Method->getParamDecl(0);
-
-  Expr *OtherDeclRef = DeclRefExpr::Create(
-      AST, NestedNameSpecifierLoc(), SourceLocation(), OtherParam, false,
-      DeclarationNameInfo(OtherParam->getDeclName(), SourceLocation()),
-      ConstRecordType, VK_LValue);
-
-  FieldDecl *HandleField = getResourceHandleField();
-  Expr *OtherHandleMemberExpr = MemberExpr::CreateImplicit(
-      AST, OtherDeclRef, false, HandleField, HandleField->getType(), VK_LValue,
-      OK_Ordinary);
-
-  return Builder.assign(PH::Handle, OtherHandleMemberExpr).finalize();
+  return BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true)
+      .addParam("other", ConstRecordRefType)
+      .getResourceHandle(PH::_0)
+      .assign(PH::Handle, PH::LastStmt)
+      .finalize();
 }
 
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
@@ -717,32 +731,13 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
   QualType RecordRefType = AST.getLValueReferenceType(RecordType);
 
   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
-
   DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal);
-  BuiltinTypeMethodBuilder Builder(*this, Name, RecordRefType, false, false);
-  Builder.addParam("other", ConstRecordRefType);
-  Builder.ensureCompleteDecl();
-
-  ParmVarDecl *OtherParam = Builder.Method->getParamDecl(0);
-  Expr *OtherDeclRef = DeclRefExpr::Create(
-      AST, NestedNameSpecifierLoc(), SourceLocation(), OtherParam, false,
-      DeclarationNameInfo(OtherParam->getDeclName(), SourceLocation()),
-      ConstRecordType, VK_LValue);
-
-  FieldDecl *HandleField = getResourceHandleField();
-  Expr *OtherHandleMemberExpr = MemberExpr::CreateImplicit(
-      AST, OtherDeclRef, false, HandleField, HandleField->getType(), VK_LValue,
-      OK_Ordinary);
-
-  Builder.assign(PH::Handle, OtherHandleMemberExpr);
-
-  // return *this;
-  CXXThisExpr *This = CXXThisExpr::Create(
-      AST, SourceLocation(), Builder.Method->getFunctionObjectParameterType(),
-      true);
-  Builder.StmtsList.push_back(This);
-
-  return Builder.finalize();
+  return BuiltinTypeMethodBuilder(*this, Name, RecordRefType, false, false)
+      .addParam("other", ConstRecordRefType)
+      .getResourceHandle(PH::_0)
+      .assign(PH::Handle, PH::LastStmt)
+      .returnThis()
+      .finalize();
 }
 
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
index d9bd944ba6297..e5d28d659febe 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
@@ -39,7 +39,7 @@ void main() {
 // CHECK: %[[ref_tmp6:.*]] = alloca %"class.hlsl::RWBuffer", align 4
 // CHECK: %[[ref_tmp7:.*]] = alloca %"class.hlsl::RWBuffer", align 4
 // CHECK: %[[agg_tmp:.*]] = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
-// CHECK: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp]], ptr noundef nonnull align 4 dereferenceable(4) 
@_ZL1A)
+// CHECK: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} %[[ref_tmp]], ptr 
{{.*}} @_ZL1A)
 // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp1]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp]])
 // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp2]], ptr noundef nonnull align 4 
dereferenceable(4) @_ZL1B)
 // CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp3]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp2]])

>From 404b3c2f95d515e0f10d3c3a5f9451ded15af41d Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Wed, 3 Sep 2025 15:30:40 -0400
Subject: [PATCH 3/9] Fix failing sema test

---
 clang/test/SemaHLSL/Language/InitLists.hlsl | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl 
b/clang/test/SemaHLSL/Language/InitLists.hlsl
index 3607dfd8aedbc..24f0bf3106761 100644
--- a/clang/test/SemaHLSL/Language/InitLists.hlsl
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -121,6 +121,7 @@ void Err2(RWBuffer<float4> B) {
 // expected-note@#ContainsResource{{candidate constructor (the implicit copy 
constructor) not viable: no known conversion from 'vector<int, 2>' (vector of 2 
'int' values) to 'const ContainsResource &' for 1st argument}}
 // expected-note@#ContainsResource{{candidate constructor (the implicit move 
constructor) not viable: no known conversion from 'vector<int, 2>' (vector of 2 
'int' values) to 'ContainsResource &&' for 1st argument}}
 
-// These notes refer to the RWBuffer constructors that do not have source 
locations
-// expected-note@*{{candidate constructor (the implicit copy constructor) not 
viable}}
-// expected-note@*{{candidate constructor (the implicit move constructor) not 
viable}}
+// This note refers to the RWBuffer copy constructor that do not have a source 
locations
+// expected-note@*{{candidate constructor not viable}}
+  
+

>From a3d7123b7b1c9618122ebaf680b25ed1944c4016 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Wed, 3 Sep 2025 15:59:25 -0400
Subject: [PATCH 4/9] Add checks for copy constructor and operator=

---
 .../test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 26 +++++++++++++++++++
 .../test/AST/HLSL/StructuredBuffers-AST.hlsl  | 26 +++++++++++++++++++
 clang/test/AST/HLSL/TypedBuffers-AST.hlsl     | 26 +++++++++++++++++++
 3 files changed, 78 insertions(+)

diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl 
b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
index f85194496942b..75948be053344 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -56,6 +56,32 @@ RESOURCE Buffer;
 // CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
 // CHECK-NEXT: AlwaysInlineAttr
 
+// Copy constructor
+
+// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (const 
hlsl::[[RESOURCE]] &)' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} other 'const hlsl::[[RESOURCE]] &'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: BinaryOperator {{.*}} '='
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const hlsl::[[RESOURCE]]' ParmVar {{.*}} 
'other' 'const hlsl::[[RESOURCE]] &'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// operator=
+
+// CHECK: CXXMethodDecl {{.*}} operator= 'hlsl::[[RESOURCE]] &(const 
hlsl::[[RESOURCE]] &)'
+// CHECK-NEXT: ParmVarDecl {{.*}} other 'const hlsl::[[RESOURCE]] &'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: BinaryOperator {{.*}} '='
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const hlsl::[[RESOURCE]]' ParmVar {{.*}} 
'other' 'const hlsl::[[RESOURCE]] &'
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-NEXT: AlwaysInlineAttr
+
 // Constructor from binding
 
 // CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, unsigned 
int, int, unsigned int, const char *)' inline
diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl 
b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
index 6ee7145c7e538..0fa1d53923739 100644
--- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
@@ -103,6 +103,32 @@ RESOURCE<float> Buffer;
 // CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue 
implicit this
 // CHECK-NEXT: AlwaysInlineAttr
 
+// Copy constructor
+
+// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> 'void (const 
hlsl::[[RESOURCE]]<element_type> &)' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} other 'const 
hlsl::[[RESOURCE]]<element_type> &'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: BinaryOperator {{.*}} '='
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue 
implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const hlsl::[[RESOURCE]]<element_type>' 
ParmVar {{.*}} 'other' 'const hlsl::[[RESOURCE]]<element_type> &'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// operator=
+
+// CHECK: CXXMethodDecl {{.*}} operator= 'hlsl::[[RESOURCE]]<element_type> 
&(const hlsl::[[RESOURCE]]<element_type> &)'
+// CHECK-NEXT: ParmVarDecl {{.*}} other 'const 
hlsl::[[RESOURCE]]<element_type> &'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: BinaryOperator {{.*}} '='
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue 
implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const hlsl::[[RESOURCE]]<element_type>' 
ParmVar {{.*}} 'other' 'const hlsl::[[RESOURCE]]<element_type> &'
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue 
implicit this
+// CHECK-NEXT: AlwaysInlineAttr
+
 // Constructor from binding
 
 // CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> 'void (unsigned 
int, unsigned int, int, unsigned int, const char *)' inline
diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl 
b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
index e7f000e9c1b70..7c3bc28fca677 100644
--- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
@@ -78,6 +78,32 @@ RESOURCE<float> Buffer;
 // CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue 
implicit this
 // CHECK-NEXT: AlwaysInlineAttr
 
+// Copy constructor
+
+// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> 'void (const 
hlsl::[[RESOURCE]]<element_type> &)' inline
+// CHECK-NEXT: ParmVarDecl {{.*}} other 'const 
hlsl::[[RESOURCE]]<element_type> &'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: BinaryOperator {{.*}} '='
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue 
implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const hlsl::[[RESOURCE]]<element_type>' 
ParmVar {{.*}} 'other' 'const hlsl::[[RESOURCE]]<element_type> &'
+// CHECK-NEXT: AlwaysInlineAttr
+
+// operator=
+
+// CHECK: CXXMethodDecl {{.*}} operator= 'hlsl::[[RESOURCE]]<element_type> 
&(const hlsl::[[RESOURCE]]<element_type> &)'
+// CHECK-NEXT: ParmVarDecl {{.*}} other 'const 
hlsl::[[RESOURCE]]<element_type> &'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: BinaryOperator {{.*}} '='
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue 
implicit this
+// CHECK-NEXT: MemberExpr {{.*}} lvalue .__handle
+// CHECK-NEXT: DeclRefExpr {{.*}} 'const hlsl::[[RESOURCE]]<element_type>' 
ParmVar {{.*}} 'other' 'const hlsl::[[RESOURCE]]<element_type> &'
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue 
implicit this
+// CHECK-NEXT: AlwaysInlineAttr
+
 // Constructor from binding
 
 // CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]]<element_type> 'void (unsigned 
int, unsigned int, int, unsigned int, const char *)' inline

>From 219139a6a48f2ff80b3506bbb958887b65e07182 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Wed, 3 Sep 2025 15:59:25 -0400
Subject: [PATCH 5/9] Remove OVE related changes.

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           | 20 ++-----------------
 .../resources/res-array-local-multi-dim.hlsl  |  3 +++
 2 files changed, 5 insertions(+), 18 deletions(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index c5660bc518712..442d8505cc0ed 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -828,27 +828,11 @@ llvm::Instruction 
*CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
 
 class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
 public:
-  llvm::SmallVector<OpaqueValueExpr *, 8> OVEs;
-  llvm::SmallPtrSet<OpaqueValueExpr *, 8> Visited;
+  llvm::SmallPtrSet<OpaqueValueExpr *, 8> OVEs;
   OpaqueValueVisitor() {}
 
-  bool VisitHLSLOutArgExpr(HLSLOutArgExpr *) {
-    // These need to be bound in CodeGenFunction::EmitHLSLOutArgLValues
-    // or CodeGenFunction::EmitHLSLOutArgExpr. If they are part of this
-    // traversal, the temporary containing the copy out will not have
-    // been created yet.
-    return false;
-  }
-
   bool VisitOpaqueValueExpr(OpaqueValueExpr *E) {
-    // Traverse the source expression first.
-    if (E->getSourceExpr())
-      TraverseStmt(E->getSourceExpr());
-
-    // Then add this OVE if we haven't seen it before.
-    if (Visited.insert(E).second)
-      OVEs.push_back(E);
-
+    OVEs.insert(E);
     return true;
   }
 };
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
index e5d28d659febe..a8a50ef2e2c47 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute 
-finclude-default-header \
 // RUN:   -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
 
+// https://github.com/llvm/llvm-project/issues/156786
+// XFAIL: *
+
 // This test verifies handling of multi-dimensional local arrays of resources
 // when used as a function argument and local variable.
 

>From 307ef1aea6287a0aac273c2b4b06d8cc24f864a0 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Wed, 3 Sep 2025 22:24:25 -0400
Subject: [PATCH 6/9] Change getResourceHandle to template function.

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

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 26e48a18b2bf5..a7b5ed121d845 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -156,7 +156,8 @@ struct BuiltinTypeMethodBuilder {
   BuiltinTypeDeclBuilder &finalize();
   Expr *getResourceHandleExpr();
 
-  BuiltinTypeMethodBuilder &getResourceHandle(PlaceHolder ResourceRecord);
+  template <typename T>
+  BuiltinTypeMethodBuilder &getResourceHandle(T ResourceRecord);
   BuiltinTypeMethodBuilder &returnThis();
 
 private:
@@ -434,8 +435,9 @@ Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
                                     OK_Ordinary);
 }
 
+template <typename T>
 BuiltinTypeMethodBuilder &
-BuiltinTypeMethodBuilder::getResourceHandle(PlaceHolder ResourceRecord) {
+BuiltinTypeMethodBuilder::getResourceHandle(T ResourceRecord) {
   ensureCompleteDecl();
 
   Expr *ResourceExpr = convertPlaceholder(ResourceRecord);

>From 480ed259b50cf18dad5be0f227f73b9e641c2b2c Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Fri, 5 Sep 2025 10:33:54 -0400
Subject: [PATCH 7/9] Fixes from code reviews.

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 14 +++++++-----
 .../resources/res-array-local-multi-dim.hlsl  | 22 +++++++++----------
 2 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 0a2d64065729f..3359d0b23f914 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -445,8 +445,8 @@ BuiltinTypeMethodBuilder::getResourceHandle(T 
ResourceRecord) {
   ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
   FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
   MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
-      AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
-      OK_Ordinary);
+      AST, ResourceExpr, /*IsArrow=*/false, HandleField, 
HandleField->getType(),
+      VK_LValue, OK_Ordinary);
   StmtsList.push_back(HandleExpr);
   return *this;
 }
@@ -454,7 +454,8 @@ BuiltinTypeMethodBuilder::getResourceHandle(T 
ResourceRecord) {
 BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() {
   ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
   CXXThisExpr *ThisExpr = CXXThisExpr::Create(
-      AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
+      AST, SourceLocation(), Method->getFunctionObjectParameterType(),
+      /*IsImplicit=*/true);
   StmtsList.push_back(ThisExpr);
   return *this;
 }
@@ -715,10 +716,11 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addCopyConstructor() {
 
   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
 
-  return BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true)
+  return BuiltinTypeMethodBuilder(*this, /*Name=*/"", AST.VoidTy,
+                                  /*IsConst=*/false, /*IsCtor=*/true)
       .addParam("other", ConstRecordRefType)
       .getResourceHandle(PH::_0)
-      .assign(PH::Handle, PH::LastStmt)
+      .assign(PH.Handle, PH.LastStmt)
       .finalize();
 }
 
@@ -734,7 +736,7 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
 
   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
   DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal);
-  return BuiltinTypeMethodBuilder(*this, Name, RecordRefType, false, false)
+  return BuiltinTypeMethodBuilder(*this, Name, RecordRefType)
       .addParam("other", ConstRecordRefType)
       .getResourceHandle(PH::_0)
       .assign(PH::Handle, PH::LastStmt)
diff --git a/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
index a8a50ef2e2c47..7956e40de1438 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
@@ -43,20 +43,20 @@ void main() {
 // CHECK: %[[ref_tmp7:.*]] = alloca %"class.hlsl::RWBuffer", align 4
 // CHECK: %[[agg_tmp:.*]] = alloca [2 x [2 x %"class.hlsl::RWBuffer"]], align 4
 // CHECK: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} %[[ref_tmp]], ptr 
{{.*}} @_ZL1A)
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp1]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp]])
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp2]], ptr noundef nonnull align 4 
dereferenceable(4) @_ZL1B)
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp3]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp2]])
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp4]], ptr noundef nonnull align 4 
dereferenceable(4) @_ZL1A)
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp5]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp4]])
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp6]], ptr noundef nonnull align 4 
dereferenceable(4) @_ZL1B)
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[ref_tmp7]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp6]])
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %L, ptr noundef nonnull align 4 dereferenceable(4) 
%[[ref_tmp1]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[ref_tmp1]], ptr {{.*}} %[[ref_tmp]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[ref_tmp2]], ptr {{.*}} @_ZL1B)
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[ref_tmp3]], ptr {{.*}} %[[ref_tmp2]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[ref_tmp4]], ptr {{.*}} @_ZL1A)
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[ref_tmp5]], ptr {{.*}} %[[ref_tmp4]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[ref_tmp6]], ptr {{.*}} @_ZL1B)
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[ref_tmp7]], ptr {{.*}} %[[ref_tmp6]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} %L, ptr 
{{.*}} %[[ref_tmp1]])
 // CHECK-NEXT: %[[arrayinit_element:.*]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %L, i32 1
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[arrayinit_element]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp3]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[arrayinit_element]], ptr {{.*}} %[[ref_tmp3]])
 // CHECK-NEXT: %[[arrayinit_element8:.*]] = getelementptr inbounds [2 x 
%"class.hlsl::RWBuffer"], ptr %L, i32 1
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[arrayinit_element8]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp5]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[arrayinit_element8]], ptr {{.*}} %[[ref_tmp5]])
 // CHECK-NEXT: %[[arrayinit_element9:.*]] = getelementptr inbounds 
%"class.hlsl::RWBuffer", ptr %[[arrayinit_element8]], i32 1
-// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr noundef nonnull 
align 4 dereferenceable(4) %[[arrayinit_element9]], ptr noundef nonnull align 4 
dereferenceable(4) %[[ref_tmp7]])
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} 
%[[arrayinit_element9]], ptr {{.*}} %[[ref_tmp7]])
   RWBuffer<float> L[2][2] = { { A, B }, { A, B } };
 
 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %[[agg_tmp]], ptr align 
4 %L, i32 16, i1 false)

>From 2708a6195ba26145ce7f9809d7aac5f30b4494c1 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Fri, 5 Sep 2025 10:35:33 -0400
Subject: [PATCH 8/9] Remove blank lines

---
 clang/test/SemaHLSL/Language/InitLists.hlsl | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl 
b/clang/test/SemaHLSL/Language/InitLists.hlsl
index 24f0bf3106761..a02b6f9d5a767 100644
--- a/clang/test/SemaHLSL/Language/InitLists.hlsl
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -123,5 +123,3 @@ void Err2(RWBuffer<float4> B) {
 
 // This note refers to the RWBuffer copy constructor that do not have a source 
locations
 // expected-note@*{{candidate constructor not viable}}
-  
-

>From 9da9f4f18b000f3400b8272f9c7ca1c4246aff94 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenper...@google.com>
Date: Sat, 6 Sep 2025 07:22:28 -0400
Subject: [PATCH 9/9] Fix use of PH

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 3359d0b23f914..b8591b0fe475a 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -720,7 +720,7 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addCopyConstructor() {
                                   /*IsConst=*/false, /*IsCtor=*/true)
       .addParam("other", ConstRecordRefType)
       .getResourceHandle(PH::_0)
-      .assign(PH.Handle, PH.LastStmt)
+      .assign(PH::Handle, PH::LastStmt)
       .finalize();
 }
 

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

Reply via email to