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/5] 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 e5049d11480ac4..44b397d2a47b93 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 8ae83fa89b3905..745187514bd432 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 c80c7c9466afcf..a846f682493fa6 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/5] 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 a846f682493fa6..07455027a1ac71 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 +// >From 641eb2fbb5864421d21c99b5dc813131e6ff2fbe Mon Sep 17 00:00:00 2001 From: Sarah Spall <[email protected]> Date: Thu, 8 Oct 2026 08:31:52 -0700 Subject: [PATCH 3/5] respond to pr comment --- clang/lib/Sema/SemaOverload.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 44b397d2a47b93..d90ef3a2a49bb3 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6348,10 +6348,10 @@ ExprResult Sema::PerformImplicitObjectArgumentInitialization( if (getLangOpts().HLSL && (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, + if (FromAS == LangAS::hlsl_constant) + CastType = CastType.withConst(); + + From = ImplicitCastExpr::Create(Context, CastType, CK_LValueToRValue, From, /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride()); } >From 961e9d6e4e0acb162f081eaf8064715d14f50a2c Mon Sep 17 00:00:00 2001 From: Sarah Spall <[email protected]> Date: Thu, 8 Oct 2026 10:20:59 -0700 Subject: [PATCH 4/5] format --- clang/lib/Sema/SemaOverload.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index d90ef3a2a49bb3..1876f547db836e 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6350,9 +6350,10 @@ ExprResult Sema::PerformImplicitObjectArgumentInitialization( QualType CastType = From->getType().getLocalUnqualifiedType(); if (FromAS == LangAS::hlsl_constant) CastType = CastType.withConst(); - + From = ImplicitCastExpr::Create(Context, CastType, CK_LValueToRValue, From, - /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride()); + /*BasePath=*/nullptr, VK_PRValue, + FPOptionsOverride()); } Expr::Classification FromClassification; >From cec374d943d58ba0df937381f1e06eab6c870834 Mon Sep 17 00:00:00 2001 From: Sarah Spall <[email protected]> Date: Wed, 14 Oct 2026 09:13:35 -0700 Subject: [PATCH 5/5] update so we use hlsl in out expr for implicit object param --- clang/lib/CodeGen/CGExpr.cpp | 6 +- clang/lib/CodeGen/CGExprCXX.cpp | 16 ++++- clang/lib/CodeGen/CodeGenFunction.h | 2 +- clang/lib/Sema/SemaOverload.cpp | 31 ++++++++-- clang/test/AST/HLSL/StructPassing-AST.hlsl | 60 +++++++++++++++++-- .../BasicFeatures/StructPassing.hlsl | 49 ++++++++++++--- 6 files changed, 142 insertions(+), 22 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 8323a170a1dbbc..4fc208550f2710 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -6585,7 +6585,8 @@ CodeGenFunction::EmitHLSLOutArgLValues(const HLSLOutArgExpr *E, QualType Ty) { } LValue CodeGenFunction::EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, - CallArgList &Args, QualType Ty) { + CallArgList &Args, QualType Ty, + bool IsImplicitObject) { auto [BaseLV, TempLV] = EmitHLSLOutArgLValues(E, Ty); @@ -6594,7 +6595,8 @@ LValue CodeGenFunction::EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, Address TmpAddr(Addr, ElTy, TempLV.getAlignment()); Args.addWriteback(BaseLV, TmpAddr, nullptr, E->getWritebackCast()); - Args.add(RValue::get(TmpAddr, *this), Ty); + if (!IsImplicitObject) + Args.add(RValue::get(TmpAddr, *this), Ty); return TempLV; } diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 8279611accba33..46d50e26533ac6 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -278,8 +278,18 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( } } - auto getLValueForThis = [this, IsArrow, - Base](bool EmitCheckedForStore = false) { + LValue HLSLThisLValue; + if (auto *HLSLOutArg = dyn_cast<HLSLOutArgExpr>(Base)) { + if (!RtlArgs) + RtlArgs = &RtlArgStorage; + HLSLThisLValue = EmitHLSLOutArgExpr( + HLSLOutArg, *RtlArgs, HLSLOutArg->getType(), /*IsImplicitObject=*/true); + EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(), + drop_begin(CE->arguments(), 0), CE->getDirectCallee()); + } + + auto getLValueForThis = [this, IsArrow, Base, + HLSLThisLValue](bool EmitCheckedForStore = false) { // FIXME: Respect EmitCheckedForStore for the IsArrow case. if (IsArrow) { LValueBaseInfo BaseInfo; @@ -288,6 +298,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( return MakeAddrLValue(ThisValue, Base->getType()->getPointeeType(), BaseInfo, TBAAInfo); } + if (isa<HLSLOutArgExpr>(Base)) + return HLSLThisLValue; if (EmitCheckedForStore) return EmitCheckedLValue(Base, TCK_Store); return EmitLValue(Base); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 00294ad547d5ec..28fef2193b5164 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4586,7 +4586,7 @@ class CodeGenFunction : public CodeGenTypeCache { std::pair<LValue, LValue> EmitHLSLOutArgLValues(const HLSLOutArgExpr *E, QualType Ty); LValue EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, CallArgList &Args, - QualType Ty); + QualType Ty, bool IsImplicitObject = false); Address EmitExtVectorElementLValue(LValue V); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 1876f547db836e..0746d28378ece3 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6346,14 +6346,35 @@ ExprResult Sema::PerformImplicitObjectArgumentInitialization( LangAS FromAS = From->getType().getAddressSpace(); if (getLangOpts().HLSL && - (FromAS == LangAS::hlsl_constant || FromAS == LangAS::hlsl_groupshared)) { - QualType CastType = From->getType().getLocalUnqualifiedType(); - if (FromAS == LangAS::hlsl_constant) - CastType = CastType.withConst(); - + (FromAS == LangAS::hlsl_constant || + (FromAS == LangAS::hlsl_groupshared && Method->isConst()))) { + QualType CastType = From->getType().getLocalUnqualifiedType().withConst(); From = ImplicitCastExpr::Create(Context, CastType, CK_LValueToRValue, From, /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride()); + } else if (getLangOpts().HLSL && FromAS == LangAS::hlsl_groupshared) { + ASTContext &Ctx = SemaRef.getASTContext(); + QualType Ty = + From->getType().getLocalUnqualifiedType().getNonLValueExprType(Ctx); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty); + auto *FromOpV = new (Ctx) OpaqueValueExpr( + From->getBeginLoc(), From->getType().getLocalUnqualifiedType(), + VK_LValue, OK_Ordinary, From); + ExprResult Res = + SemaRef.PerformCopyInitialization(Entity, From->getBeginLoc(), From); + if (Res.isInvalid()) + return ExprError(); + Expr *Base = Res.get(); + auto *OpV = new (Ctx) + OpaqueValueExpr(From->getBeginLoc(), Ty, VK_LValue, OK_Ordinary, Base); + + Res = SemaRef.ActOnBinOp(SemaRef.getCurScope(), From->getBeginLoc(), + tok::equal, FromOpV, OpV); + if (Res.isInvalid()) + return ExprError(); + Expr *Writeback = Res.get(); + From = HLSLOutArgExpr::Create(Ctx, Ty, FromOpV, OpV, Writeback, + /*IsInOut=*/true); } Expr::Classification FromClassification; diff --git a/clang/test/AST/HLSL/StructPassing-AST.hlsl b/clang/test/AST/HLSL/StructPassing-AST.hlsl index 745187514bd432..c8c87b46b9e0a7 100644 --- a/clang/test/AST/HLSL/StructPassing-AST.hlsl +++ b/clang/test/AST/HLSL/StructPassing-AST.hlsl @@ -119,22 +119,72 @@ void case6(S s) { } struct G { + int X; void f() {} + void setX(int val) { X = val; } + int getX() const { return X; } }; groupshared G g; -// CHECK: FunctionDecl {{.*}} case7 'void ()' -// CHECK-NEXT: CompoundStmt {{.*}} -// CHECK-NEXT: ExprWithCleanups {{.*}} 'void' +// CHECK: FunctionDecl {{.*}} case7 'void ()' external-linkage +// CHECK-NEXT: CompoundStmt // CHECK-NEXT: CXXMemberCallExpr {{.*}} 'void' -// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .f {{.*}} -// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'G' lvalue +// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .f +// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'G' lvalue inout +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'G' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'G' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'G' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' +// CHECK-NEXT: BinaryOperator {{.*}} 'G' lvalue '=' +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'G' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'G' <LValueToRValue> +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'G' lvalue // CHECK-NEXT: ImplicitCastExpr {{.*}} 'G' <LValueToRValue> // CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' void case7() { g.f(); } +// CHECK: FunctionDecl {{.*}} case8 'void (int)' external-linkage +// CHECK-NEXT: ParmVarDecl {{.*}} used V 'int' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'void' +// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .setX +// CHECK-NEXT: HLSLOutArgExpr {{.*}} 'G' lvalue inout +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'G' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'G' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'G' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' +// CHECK-NEXT: BinaryOperator {{.*}} 'G' lvalue '=' +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'G' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'G' <LValueToRValue> +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'G' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'G' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'V' 'int' +void case8(int V) { + g.setX(V); +} + +// CHECK: FunctionDecl {{.*}} case9 'void ()' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: DeclStmt +// CHECK-NEXT: VarDecl {{.*}} Y 'int' cinit +// CHECK-NEXT: ExprWithCleanups {{.*}} 'int' +// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'int' +// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .getX +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'const G' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const G' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'groupshared G' lvalue Var {{.*}} 'g' 'groupshared G' +void case9() { + int Y = g.getX(); +} + // CHECK-NOT: CXXConstructExpr // CHECK-NOT: CXXOperatorCallExpr diff --git a/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl index 07455027a1ac71..382bf0cf860442 100644 --- a/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl +++ b/clang/test/CodeGenHLSL/BasicFeatures/StructPassing.hlsl @@ -141,6 +141,7 @@ struct G { int X; void f() {} void setX(int val) { this.X = val; } + int getX() const { return X; } }; groupshared G g; @@ -149,9 +150,12 @@ groupshared G g; // 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 @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: [[TMP:%.*]] = alloca [[STRUCT_G:%.*]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = alloca [[STRUCT_G]], align 1 +// CHECK-NEXT: call void @llvm.memcpy.p0.p3.i32(ptr align 1 [[TMP]], ptr addrspace(3) align 1 @g, i32 4, i1 false) +// CHECK-NEXT: call void @_ZN1G1fEv(ptr noundef nonnull align 1 dereferenceable(4) [[TMP]]) #[[ATTR3]] [ "convergencectrl"(token [[TMP0]]) ] +// CHECK-NEXT: call void @llvm.memcpy.p3.p0.i32(ptr addrspace(3) align 1 @g, ptr align 1 [[TMP]], i32 4, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p3.i32(ptr align 1 [[TMP1]], ptr addrspace(3) align 1 @g, i32 4, i1 false) // CHECK-NEXT: ret void // void case7() { @@ -174,11 +178,14 @@ void case7() { // 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: [[TMP:%.*]] = alloca [[STRUCT_G:%.*]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = 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: call void @llvm.memcpy.p0.p3.i32(ptr align 1 [[TMP]], ptr addrspace(3) align 1 @g, i32 4, i1 false) +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[VAL_ADDR]], align 4 +// CHECK-NEXT: call void @_ZN1G4setXEi(ptr noundef nonnull align 1 dereferenceable(4) [[TMP]], i32 noundef [[TMP2]]) #[[ATTR3]] [ "convergencectrl"(token [[TMP0]]) ] +// CHECK-NEXT: call void @llvm.memcpy.p3.p0.i32(ptr addrspace(3) align 1 @g, ptr align 1 [[TMP]], i32 4, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p3.i32(ptr align 1 [[TMP1]], ptr addrspace(3) align 1 @g, i32 4, i1 false) // CHECK-NEXT: ret void // void case8(int val) { @@ -200,3 +207,31 @@ void case8(int val) { // CHECK-NEXT: store i32 [[TMP1]], ptr [[X]], align 1 // CHECK-NEXT: ret void // + +// CHECK-LABEL: define hidden void @_Z5case9v( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_G:%.*]], align 1 +// 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: [[CALL1:%.*]] = call noundef i32 @_ZNK1G4getXEv(ptr noundef nonnull align 1 dereferenceable(4) [[REF_TMP]]) #[[ATTR3]] [ "convergencectrl"(token [[TMP0]]) ] +// CHECK-NEXT: store i32 [[CALL1]], ptr [[Y]], align 4 +// CHECK-NEXT: ret void +// +void case9() { + // implicit argument passing of a groupshared struct where the function is const + int Y = g.getX(); +} + +// CHECK-LABEL: define linkonce_odr hidden noundef i32 @_ZNK1G4getXEv( +// 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 +// CHECK-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4 +// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_G:%.*]], ptr [[THIS1]], i32 0, i32 0 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[X]], align 1 +// CHECK-NEXT: ret i32 [[TMP1]] +// _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
