Author: Steven Perron
Date: 2025-09-06T11:50:03Z
New Revision: 54ed459e3ed83bcc6570b885e9c9e65ab65dae75

URL: 
https://github.com/llvm/llvm-project/commit/54ed459e3ed83bcc6570b885e9c9e65ab65dae75
DIFF: 
https://github.com/llvm/llvm-project/commit/54ed459e3ed83bcc6570b885e9c9e65ab65dae75.diff

LOG: [HLSL] Add copy assignment and construtor to resource types (#156075)

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.

Partially fixes #154669

Added: 
    

Modified: 
    clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
    clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
    clang/lib/Sema/HLSLExternalSemaSource.cpp
    clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
    clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
    clang/test/AST/HLSL/TypedBuffers-AST.hlsl
    clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
    clang/test/CodeGenHLSL/debug/rwbuffer_debug_info.hlsl
    clang/test/CodeGenHLSL/implicit-norecurse-attrib.hlsl
    clang/test/CodeGenHLSL/resources/res-array-local-multi-dim.hlsl
    clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
    clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
    clang/test/SemaHLSL/Language/InitLists.hlsl

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 7830cdd18c6cd..b8591b0fe475a 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -156,6 +156,10 @@ struct BuiltinTypeMethodBuilder {
   BuiltinTypeDeclBuilder &finalize();
   Expr *getResourceHandleExpr();
 
+  template <typename T>
+  BuiltinTypeMethodBuilder &getResourceHandle(T ResourceRecord);
+  BuiltinTypeMethodBuilder &returnThis();
+
 private:
   void createDecl();
 
@@ -332,7 +336,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 +435,31 @@ Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
                                     OK_Ordinary);
 }
 
+template <typename T>
+BuiltinTypeMethodBuilder &
+BuiltinTypeMethodBuilder::getResourceHandle(T ResourceRecord) {
+  ensureCompleteDecl();
+
+  Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
+
+  ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+  FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
+  MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
+      AST, ResourceExpr, /*IsArrow=*/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(),
+      /*IsImplicit=*/true);
+  StmtsList.push_back(ThisExpr);
+  return *this;
+}
+
 template <typename... Ts>
 BuiltinTypeMethodBuilder &
 BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
@@ -676,6 +705,45 @@ 
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;
+
+  return BuiltinTypeMethodBuilder(*this, /*Name=*/"", AST.VoidTy,
+                                  /*IsConst=*/false, /*IsCtor=*/true)
+      .addParam("other", ConstRecordRefType)
+      .getResourceHandle(PH::_0)
+      .assign(PH::Handle, PH::LastStmt)
+      .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);
+  return BuiltinTypeMethodBuilder(*this, Name, RecordRefType)
+      .addParam("other", ConstRecordRefType)
+      .getResourceHandle(PH::_0)
+      .assign(PH::Handle, PH::LastStmt)
+      .returnThis()
+      .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/AST/HLSL/ByteAddressBuffers-AST.hlsl 
b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
index 90794eb69ef46..f2a3a74931a6a 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 e028936e397ac..23ed410a8efce 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 02c8cf86c8c8b..4e3cdeab74b31 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

diff  --git a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl 
b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
index 75d9fb8582b3d..116de8eb857a4 100644
--- a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
@@ -26,9 +26,9 @@ void fb(CustomResource a) {
     CustomResource 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) {
@@ -44,9 +44,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 9b5602f9f67ef..7956e40de1438 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.
 
@@ -29,19 +32,35 @@ float foo(RWBuffer<float> Arr[2][2]) {
 // 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)
+// 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 {{.*}} %[[ref_tmp]], ptr 
{{.*}} @_ZL1A)
+// 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 {{.*}} 
%[[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 {{.*}} 
%[[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 {{.*}} 
%[[arrayinit_element9]], ptr {{.*}} %[[ref_tmp7]])
   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: 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

diff  --git a/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
index d1645fdd48e92..9e31f4f150c52 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local1.hlsl
@@ -22,11 +22,11 @@ void main() {
   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: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} %First, ptr 
{{.*}} @_ZL1A)
 // 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: call void @_ZN4hlsl8RWBufferIfEC1ERKS1_(ptr {{.*}} %[[Ptr1]], 
ptr {{.*}} @_ZL1B)
 // 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)
+// 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
@@ -43,7 +43,7 @@ void main() {
 
 // 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)
+// CHECK: call {{.*}} @_ZN4hlsl8RWBufferIfEaSERKS1_(ptr {{.*}} %[[Ptr3]], ptr 
{{.*}} @_ZL1C)
   Second[2] = C;
 
   // NOTE: _ZN4hlsl8RWBufferIfEixEj is the subscript operator for 
RWBuffer<float>

diff  --git a/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl 
b/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
index 8bc3f04d774ca..21ca3f4a98f99 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-local3.hlsl
@@ -20,7 +20,7 @@ RWBuffer<int> Y : register(u1);
 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)
+// CHECK-NEXT: call {{.*}} @_ZN4hlsl8RWBufferIiEaSERKS1_(ptr {{.*}} 
%[[B_0_Ptr]], ptr {{.*}} @_ZL1Y)
   B[0] = Y;
 
 // NOTE: _ZN4hlsl8RWBufferIiEixEj is the subscript operator for RWBuffer<int>
@@ -43,9 +43,9 @@ void main(uint GI : SV_GroupIndex) {
 // 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: 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 @llvm.memcpy.p0.p0.i32(ptr align 4 %[[A_1_Ptr]], ptr 
align 4 @_ZL1Y, i32 4, i1 false)
+// 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

diff  --git a/clang/test/SemaHLSL/Language/InitLists.hlsl 
b/clang/test/SemaHLSL/Language/InitLists.hlsl
index 3607dfd8aedbc..a02b6f9d5a767 100644
--- a/clang/test/SemaHLSL/Language/InitLists.hlsl
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -121,6 +121,5 @@ 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}}


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

Reply via email to