https://github.com/spall updated 
https://github.com/llvm/llvm-project/pull/229939

>From 83235680a7d359f216091f848c9a478d2c761906 Mon Sep 17 00:00:00 2001
From: Sarah Spall <[email protected]>
Date: Wed, 7 Oct 2026 15:40:26 -0700
Subject: [PATCH 1/2] implicit struct passing for groupshared struct

---
 clang/lib/Sema/SemaOverload.cpp               | 13 ++++----
 clang/test/AST/HLSL/StructPassing-AST.hlsl    | 18 +++++++++++
 .../BasicFeatures/StructPassing.hlsl          | 30 +++++++++++++++++++
 3 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index e5049d11480ac..44b397d2a47b9 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6344,12 +6344,15 @@ ExprResult 
Sema::PerformImplicitObjectArgumentInitialization(
   QualType FromRecordType, DestType;
   QualType ImplicitParamRecordType = Method->getFunctionObjectParameterType();
 
+  LangAS FromAS = From->getType().getAddressSpace();
   if (getLangOpts().HLSL &&
-      From->getType().getAddressSpace() == LangAS::hlsl_constant) {
-    QualType CastType = From->getType().getLocalUnqualifiedType().withConst();
-    From = ImplicitCastExpr::Create(Context, CastType, CK_LValueToRValue, From,
-                                    /*BasePath=*/nullptr, VK_PRValue,
-                                    FPOptionsOverride());
+      (FromAS == LangAS::hlsl_constant || FromAS == LangAS::hlsl_groupshared)) 
{
+    QualType CastType = From->getType().getLocalUnqualifiedType();
+    From = ImplicitCastExpr::Create(
+        Context,
+        FromAS == LangAS::hlsl_constant ? CastType.withConst() : CastType,
+        CK_LValueToRValue, From,
+        /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride());
   }
 
   Expr::Classification FromClassification;
diff --git a/clang/test/AST/HLSL/StructPassing-AST.hlsl 
b/clang/test/AST/HLSL/StructPassing-AST.hlsl
index 8ae83fa89b390..745187514bd43 100644
--- a/clang/test/AST/HLSL/StructPassing-AST.hlsl
+++ b/clang/test/AST/HLSL/StructPassing-AST.hlsl
@@ -118,5 +118,23 @@ void case6(S s) {
   useP(s);
 }
 
+struct G {
+  void f() {}
+};
+
+groupshared G g;
+  
+// CHECK: FunctionDecl {{.*}} case7 'void ()'
+// CHECK-NEXT: CompoundStmt {{.*}}
+// CHECK-NEXT: ExprWithCleanups {{.*}} 'void'
+// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'void'
+// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .f {{.*}}
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'G' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'G' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 
'groupshared G'
+void case7() {
+  g.f();
+}
+
 // CHECK-NOT: CXXConstructExpr
 // CHECK-NOT: CXXOperatorCallExpr
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl 
b/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl
index c80c7c9466afc..a846f682493fa 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl
@@ -133,3 +133,33 @@ void case6(S s) {
   // derived to base conversion in argument passing
   useP(s);
 }
+
+// CHECK-LABEL: define hidden void @_Z5case7v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call token 
@llvm.experimental.convergence.entry()
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_G:%.*]], align 1
+// CHECK-NEXT:    call void @_ZN1G1fEv(ptr noundef nonnull align 1 
dereferenceable(1) [[REF_TMP]]) #[[ATTR3]] [ "convergencectrl"(token [[TMP0]]) ]
+// CHECK-NEXT:    ret void
+//
+void case7();
+
+struct G {
+// CHECK-LABEL: define linkonce_odr hidden void @_ZN1G1fEv(
+// CHECK-SAME: ptr noundef nonnull align 1 dereferenceable(1) [[THIS:%.*]]) 
#[[ATTR0]] align 2 {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call token 
@llvm.experimental.convergence.entry()
+// CHECK-NEXT:    [[THIS_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
+// CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
+// CHECK-NEXT:    ret void
+//
+  void f() {}
+};
+
+groupshared G g;
+
+void case7() {
+  // implicit argument passing of a groupshared struct
+  g.f();
+}

>From 4437bff2ca71e485c76f4bdb8ebaa58aac64cbfc Mon Sep 17 00:00:00 2001
From: Sarah Spall <[email protected]>
Date: Wed, 7 Oct 2026 16:47:10 -0700
Subject: [PATCH 2/2] add new test. change test file so update script won't
 break new tests

---
 .../BasicFeatures/StructPassing.hlsl          | 59 +++++++++++++++----
 1 file changed, 48 insertions(+), 11 deletions(-)

diff --git a/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl 
b/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl
index a846f682493fa..07455027a1ac7 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl
@@ -134,19 +134,33 @@ void case6(S s) {
   useP(s);
 }
 
+// disabled otherwise the IR will be generated in the wrong order.
+// UTC_ARGS: --disable
+
+struct G {
+  int X;
+  void f() {}
+  void setX(int val) { this.X = val; }
+};
+
+groupshared G g;
+
 // CHECK-LABEL: define hidden void @_Z5case7v(
 // CHECK-SAME: ) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[TMP0:%.*]] = call token 
@llvm.experimental.convergence.entry()
 // CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_G:%.*]], align 1
-// CHECK-NEXT:    call void @_ZN1G1fEv(ptr noundef nonnull align 1 
dereferenceable(1) [[REF_TMP]]) #[[ATTR3]] [ "convergencectrl"(token [[TMP0]]) ]
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p3.i32(ptr align 1 [[REF_TMP]], 
ptr addrspace(3) align 1 @g, i32 4, i1 false)
+// CHECK-NEXT:    call void @_ZN1G1fEv(ptr noundef nonnull align 1 
dereferenceable(4) [[REF_TMP]]) #[[ATTR3]] [ "convergencectrl"(token [[TMP0]]) ]
 // CHECK-NEXT:    ret void
 //
-void case7();
+void case7() {
+  // implicit argument passing of a groupshared struct
+  g.f();
+}
 
-struct G {
 // CHECK-LABEL: define linkonce_odr hidden void @_ZN1G1fEv(
-// CHECK-SAME: ptr noundef nonnull align 1 dereferenceable(1) [[THIS:%.*]]) 
#[[ATTR0]] align 2 {
+// CHECK-SAME: ptr noundef nonnull align 1 dereferenceable(4) [[THIS:%.*]]) 
#[[ATTR0]] align 2 {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[TMP0:%.*]] = call token 
@llvm.experimental.convergence.entry()
 // CHECK-NEXT:    [[THIS_ADDR:%.*]] = alloca ptr, align 4
@@ -154,12 +168,35 @@ struct G {
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
 // CHECK-NEXT:    ret void
 //
-  void f() {}
-};
-
-groupshared G g;
 
-void case7() {
-  // implicit argument passing of a groupshared struct
-  g.f();
+// CHECK-LABEL: define hidden void @_Z5case8i(
+// CHECK-SAME: i32 noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call token 
@llvm.experimental.convergence.entry()
+// CHECK-NEXT:    [[VAL_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_G:%.*]], align 1
+// CHECK-NEXT:    store i32 [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p3.i32(ptr align 1 [[REF_TMP]], 
ptr addrspace(3) align 1 @g, i32 4, i1 false)
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    call void @_ZN1G4setXEi(ptr noundef nonnull align 1 
dereferenceable(4) [[REF_TMP]], i32 noundef [[TMP1]]) #[[ATTR3]] [ 
"convergencectrl"(token [[TMP0]]) ]
+// CHECK-NEXT:    ret void
+//
+void case8(int val) {
+  // implicit argument passing of a groupshared struct where the implicit 
object is modified
+  g.setX(val);
 }
+
+// CHECK-LABEL: define linkonce_odr hidden void @_ZN1G4setXEi(
+// CHECK-SAME: ptr noundef nonnull align 1 dereferenceable(4) [[THIS:%.*]], 
i32 noundef [[VAL:%.*]]) #[[ATTR0]] align 2 {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call token 
@llvm.experimental.convergence.entry()
+// CHECK-NEXT:    [[THIS_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[VAL_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_G:%.*]], ptr 
[[THIS1]], i32 0, i32 0
+// CHECK-NEXT:    store i32 [[TMP1]], ptr [[X]], align 1
+// CHECK-NEXT:    ret void
+//

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

Reply via email to