llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Helena Kotas (hekota) <details> <summary>Changes</summary> Structs in constant buffers are in the `hlsl_constant` address space and in a specific constant buffer layout. In order to invoke a method on such struct, it first needs to be copied out into temporary variable in a standard layout. This change adds `Lvalue_to_Rvalue` cast to the method `this` argument which takes care of that. Fixes #<!-- -->190299 --- Full diff: https://github.com/llvm/llvm-project/pull/206596.diff 5 Files Affected: - (modified) clang/lib/Sema/SemaOverload.cpp (+8) - (modified) clang/test/AST/HLSL/ConstantBuffers-AST.hlsl (+14-1) - (added) clang/test/AST/HLSL/resources-in-structs-method-call.hlsl (+36) - (added) clang/test/CodeGenHLSL/resources/resources-in-structs-method-call.hlsl (+85) - (modified) clang/test/SemaHLSL/BuiltIns/ConstantBuffer-member-funcs.hlsl (+1-5) ``````````diff diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index c663765573612..c8b05a9f94bd0 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6271,6 +6271,14 @@ ExprResult Sema::PerformImplicitObjectArgumentInitialization( QualType FromRecordType, DestType; QualType ImplicitParamRecordType = Method->getFunctionObjectParameterType(); + 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()); + } + Expr::Classification FromClassification; if (const PointerType *PT = From->getType()->getAs<PointerType>()) { FromRecordType = PT->getPointeeType(); diff --git a/clang/test/AST/HLSL/ConstantBuffers-AST.hlsl b/clang/test/AST/HLSL/ConstantBuffers-AST.hlsl index 6a880c437db8f..327d39a225b0b 100644 --- a/clang/test/AST/HLSL/ConstantBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/ConstantBuffers-AST.hlsl @@ -71,6 +71,7 @@ ConstantBuffer<S> cb; struct Nested { S s; float b; + float getA() const { return s.a; } }; ConstantBuffer<Nested> cb_nested; @@ -116,5 +117,17 @@ float main() { // CHECK-NEXT: HLSLOutArgExpr {{.*}} 'ConstantBuffer<S>':'hlsl::ConstantBuffer<S>' lvalue inout takes_inout_cb(cb); - return f1 + f2 + f3; + // CHECK: VarDecl {{.*}} a 'float' + // CHECK-NEXT: ExprWithCleanups {{.*}} 'float' + // CHECK-NEXT: CXXMemberCallExpr {{.*}} 'float' + // CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .getA + // CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'const Nested' lvalue + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'const Nested' <LValueToRValue> + // CHECK-NEXT: CXXMemberCallExpr {{.*}} 'const hlsl_constant Nested' lvalue + // CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator const hlsl_constant Nested & + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'const hlsl::ConstantBuffer<Nested>' lvalue <NoOp> + // CHECK-NEXT: DeclRefExpr {{.*}} 'ConstantBuffer<Nested>':'hlsl::ConstantBuffer<Nested>' lvalue Var {{.*}} 'cb_nested' 'ConstantBuffer<Nested>':'hlsl::ConstantBuffer<Nested>' + float a = cb_nested.getA(); + + return f1 + f2 + f3 + a; } diff --git a/clang/test/AST/HLSL/resources-in-structs-method-call.hlsl b/clang/test/AST/HLSL/resources-in-structs-method-call.hlsl new file mode 100644 index 0000000000000..ef8be74671533 --- /dev/null +++ b/clang/test/AST/HLSL/resources-in-structs-method-call.hlsl @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -ast-dump %s | FileCheck %s + +struct MyStruct { + float f; + RWBuffer<float> Buf; + + void Store() const { + Buf[0] = f; + } +}; + +cbuffer CB { + MyStruct one; +} + +MyStruct two; + +// CHECK: FunctionDecl {{.*}} main 'void ()' +[numthreads(1, 1, 1)] +void main() { +// CHECK: ExprWithCleanups {{.*}} 'void' +// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'void' +// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .Store +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'const MyStruct' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const MyStruct' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl_constant MyStruct' lvalue Var {{.*}} 'one' 'hlsl_constant MyStruct' + one.Store(); + +// CHECK: ExprWithCleanups {{.*}} 'void' +// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'void' +// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .Store {{.*}} +// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'const MyStruct' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const MyStruct' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl_constant MyStruct' lvalue Var {{.*}} 'two' 'hlsl_constant MyStruct' + two.Store(); +} diff --git a/clang/test/CodeGenHLSL/resources/resources-in-structs-method-call.hlsl b/clang/test/CodeGenHLSL/resources/resources-in-structs-method-call.hlsl new file mode 100644 index 0000000000000..29019dd6f99c3 --- /dev/null +++ b/clang/test/CodeGenHLSL/resources/resources-in-structs-method-call.hlsl @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s + +struct MyStruct { + float f; + RWBuffer<float> Buf; + + void Store() const { + Buf[0] = f; + } +}; + +// CHECK-DAG: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 0, 0) } +// CHECK-DAG: %__cblayout_CB = type <{ %__cblayout_MyStruct }> +// CHECK-DAG: %__cblayout_MyStruct = type <{ float }> +// CHECK-DAG: %struct.MyStruct = type { float, %"class.hlsl::RWBuffer" } +cbuffer CB { + MyStruct one; +} + +// CHECK-DAG: @one.Buf = internal global %"class.hlsl::RWBuffer" poison, align 4 +// CHECK-DAG: @CB.cb = internal global target("dx.CBuffer", %__cblayout_CB) poison +// CHECK-DAG: @one = external hidden addrspace(2) global %__cblayout_MyStruct, align 4 + +// $Globals constant buffer +// CHECK-DAG: @"$Globals.cb" = internal global target("dx.CBuffer", %"__cblayout_$Globals") poison +// CHECK-DAG: %"__cblayout_$Globals" = type <{ %__cblayout_MyStruct }> +// CHECK-DAG: @two.Buf = internal global %"class.hlsl::RWBuffer" poison, align 4 +// CHECK-DAG: @two = external hidden addrspace(2) global %struct.MyStruct, align 4 +MyStruct two; + +// CHECK-DAG: @Constants = internal global %"class.hlsl::ConstantBuffer" poison, align 4 +// CHECK-DAG: %MyConstants = type <{ <4 x float>, <3 x i32> }> +// CHECK-DAG: %struct.MyConstants = type { <4 x float>, <3 x i32> } + +struct MyConstants { + float4 vec; + int3 pos; + int3 getPosition() const { return pos; } +}; + +ConstantBuffer<MyConstants> Constants; + +// CHECK-LABEL: main +[numthreads(4,1,1)] +void main() { +// CHECK: [[TMP1:%.*]] = alloca %struct.MyStruct, align 4 +// CHECK-NEXT: [[TMP2:%.*]] = alloca %struct.MyStruct, align 4 +// CHECK-NEXT: %pos = alloca <3 x i32>, align 4 +// CHECK-NEXT: [[TMP3:%.*]] = alloca %struct.MyConstants, align 1 + +// Make sure we copy the struct from the constant buffer element by element to a temporary +// variable and then call the method on that. + +// CHECK-NEXT: [[TMP1_F_PTR:%.*]] = getelementptr inbounds %struct.MyStruct, ptr [[TMP1]], i32 0, i32 0 +// CHECK-NEXT: [[CBUFLOAD0:%.*]] = load float, ptr addrspace(2) @one, align 4 +// CHECK-NEXT: store float [[CBUFLOAD0]], ptr [[TMP1_F_PTR]], align 4 +// CHECK-NEXT: [[TMP1_BUF_PTR:%.*]] = getelementptr inbounds %struct.MyStruct, ptr [[TMP1]], i32 0, i32 1 +// CHECK-NEXT: store ptr @one.Buf, ptr [[TMP1_BUF_PTR]], align 4 +// CHECK-NEXT: call void @MyStruct::Store() const(ptr {{.*}} [[TMP1]]) + one.Store(); + +// CHECK-NEXT: [[TMP2_F_PTR:%.*]] = getelementptr inbounds %struct.MyStruct, ptr [[TMP2]], i32 0, i32 0 +// CHECK-NEXT: [[CBUFLOAD2:%.*]] = load float, ptr addrspace(2) @two, align 4 +// CHECK-NEXT: store float [[CBUFLOAD2]], ptr [[TMP2_F_PTR]], align 4 +// CHECK-NEXT: [[TMP2_BUF_PTR:%.*]] = getelementptr inbounds %struct.MyStruct, ptr [[TMP2]], i32 0, i32 1 +// CHECK-NEXT: store ptr @two.Buf, ptr [[TMP2_BUF_PTR]], align 4 +// CHECK-NEXT: call void @MyStruct::Store() const(ptr {{.*}} [[TMP2]]) + two.Store(); + +// CHECK-NEXT: [[CB_PTR:%.*]] = call {{.*}} ptr addrspace(2) @hlsl::ConstantBuffer<MyConstants>::operator MyConstants const AS2&() const(ptr {{.*}} @Constants) + +// CHECK-NEXT: [[CB_PTR_VEC:%.*]] = getelementptr inbounds %MyConstants, ptr addrspace(2) [[CB_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[TMP3_VEC_PTR:%.*]] = getelementptr inbounds %struct.MyConstants, ptr [[TMP3]], i32 0, i32 0 +// CHECK-NEXT: [[CBUFLOAD3:%.*]] = load <4 x float>, ptr addrspace(2) [[CB_PTR_VEC]], align 4 +// CHECK-NEXT: store <4 x float> [[CBUFLOAD3]], ptr [[TMP3_VEC_PTR]], align 4 + +// CHECK-NEXT: [[CB_POS_PTR:%.*]] = getelementptr inbounds %MyConstants, ptr addrspace(2) [[CB_PTR]], i32 0, i32 1 +// CHECK-NEXT: [[TMP3_POS_PTR:%.*]] = getelementptr inbounds %struct.MyConstants, ptr [[TMP3]], i32 0, i32 1 +// CHECK-NEXT: [[CBUFLOAD4:%.*]] = load <3 x i32>, ptr addrspace(2) [[CB_POS_PTR]], align 4 +// CHECK-NEXT: store <3 x i32> [[CBUFLOAD4]], ptr [[TMP3_POS_PTR]], align 4 + +// CHECK-NEXT: [[POS:%.*]] = call noundef <3 x i32> @MyConstants::getPosition() const(ptr {{.*}} [[TMP3]]) +// CHECK-NEXT: store <3 x i32> [[POS]], ptr %pos, align 4 + int3 pos = Constants.getPosition(); +} diff --git a/clang/test/SemaHLSL/BuiltIns/ConstantBuffer-member-funcs.hlsl b/clang/test/SemaHLSL/BuiltIns/ConstantBuffer-member-funcs.hlsl index 179a4e1fec101..a5d8862294cf6 100644 --- a/clang/test/SemaHLSL/BuiltIns/ConstantBuffer-member-funcs.hlsl +++ b/clang/test/SemaHLSL/BuiltIns/ConstantBuffer-member-funcs.hlsl @@ -16,13 +16,9 @@ ConstantBuffer<S> CB; [numthreads(4,1,1)] void main() { - // Bug: https://github.com/llvm/llvm-project/issues/153055 - // Calling non-const member function is allowed, but not implemented yet. - // We should remove the expected error when done. - // expected-error@+1 {{cannot initialize object parameter of type 'const S' with an expression of type 'const hlsl_constant S'}} float tmp = CB.foo(); // Calling non-const member function is not allowed. - // expected-error@+1 {{'this' argument to member function 'bar' has type 'const hlsl_constant S', but function is not marked const}} + // expected-error@+1 {{'this' argument to member function 'bar' has type 'const S', but function is not marked const}} CB.bar(); } `````````` </details> https://github.com/llvm/llvm-project/pull/206596 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
