[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
ilya-biryukov wrote: I second @cor3ntin's concern here. We are adding a builtin that is named very similarly to the one from C++23 standard, but not actually having the semantics that is desired. I believe we do need the effect that __builtin_launder provides to allow memcpy for types that have vtables, which was original motivation for this change and #86512. However, we could get those guarantees by using __builtin_launder directly. Looking at the code, the __builtin_launder currently has a sole effect of preventing optimizations that would load an incorrect vtable when -fstrict-vtable-pointers is passed and same storage is reused for different types. I feel it's better to just go with std::launder on our end at this point and instead focus on preventing misoptimizations from TBAA to get a proper implementation of start_lifetime_as. It carries a risk of hitting a misoptimization in the future on our end, but seems very unlikely unless we start using TBAA or LLVM starts optimizing much more aggressively based on C++ notion of object lifetimes, neither of which should go unnoticed. @hokein WDYT? https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
cor3ntin wrote: @sam-mccall Are you referring to https://reviews.llvm.org/D147020 or something more recent? https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
hokein wrote: Friendly ping. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
https://github.com/hokein updated https://github.com/llvm/llvm-project/pull/82776 >From 3ab1a074592f85715c061007c56c69c24794a556 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 23 Feb 2024 10:03:16 +0100 Subject: [PATCH 1/2] [clang] Add __builtin_start_object_lifetime builtin. This patch implements a clang built `__builtin_start_object_lifetime`, it has the same semantics as C++23's `std::start_lifetime_as`, but without the implicit-lifetime type restriction, it can be used for implementing `std::start_lifetime_as` in the future. Due to the current clang lowering, the builtin reuses the existing `__builtin_launder` implementation: - it is a no-op for the most part; - with `-fstrict-vtable-pointers` flag, we update the vtpr assumption correctly (mark the load/store vptr with appropriate invariant group intrinsics) to prevent incorrect vptr load folding; - for now, the builtin is non-constant, cannot be executed in constant evaluation; CAVEAT: - this builtin may cause TBAA miscomplies without the `-fno-strict-alias` flag. These TBAA miscompiles are known issues and may need more LLVM IR support for the fix, fixing them is orthogonal to the implementaton of the builtin. Context: https://discourse.llvm.org/t/extension-for-creating-objects-via-memcpy/76961 --- clang/include/clang/Basic/Builtins.td | 6 +++ clang/lib/CodeGen/CGBuiltin.cpp | 1 + clang/lib/Sema/SemaChecking.cpp | 2 + clang/test/CodeGen/builtins.c | 10 .../builtin-start-object-life-time.cpp| 49 +++ clang/test/SemaCXX/builtins.cpp | 33 - 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/builtin-start-object-life-time.cpp diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index de721a87b3341d..399fabe53d9fa0 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -926,6 +926,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { + let Spellings = ["__builtin_start_object_lifetime"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void*(void*)"; +} + def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> { let Spellings = ["__builtin_is_constant_evaluated"]; let Attributes = [NoThrow, Constexpr]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 7e5f2edfc732cc..e81f39149bfbc9 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4521,6 +4521,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: { const Expr *Arg = E->getArg(0); QualType ArgTy = Arg->getType()->getPointeeType(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 51757f4cf727d6..f16a9a53857154 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -38,6 +38,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" @@ -2641,6 +2642,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: return BuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 407e0857d22311..00c81c23d0ed02 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -143,6 +143,7 @@ int main(void) { P(signbit, (1.0)); R(launder, ()); + R(start_object_lifetime, ()); return 0; } @@ -511,6 +512,15 @@ void test_builtin_launder(int *p) { int *d = __builtin_launder(p); } +/// It should be a NOP in C since there are no vtables. +// CHECK-LABEL: define{{.*}} void @test_builtin_start_object_lifetime +void test_builtin_start_object_lifetime(int *p) { + // CHECK: [[TMP:%.*]] = load ptr, + // CHECK-NOT: @llvm.launder + // CHECK: store ptr [[TMP]], + int *d = __builtin_start_object_lifetime(p); +} + // __warn_memset_zero_len should be NOP, see https://sourceware.org/bugzilla/show_bug.cgi?id=25399 // CHECK-LABEL: define{{.*}} void @test___warn_memset_zero_len void test___warn_memset_zero_len(void) { diff --git a/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp b/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp new file mode 100644 index 00..58012f52cc0ef5 --- /dev/null +++ b/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp @@ -0,0
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
https://github.com/hokein updated https://github.com/llvm/llvm-project/pull/82776 >From 7fcd58b750872221aa754e81e17ab9068e144a44 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 23 Feb 2024 10:03:16 +0100 Subject: [PATCH 1/2] [clang] Add __builtin_start_object_lifetime builtin. This patch implements a clang built `__builtin_start_object_lifetime`, it has the same semantics as C++23's `std::start_lifetime_as`, but without the implicit-lifetime type restriction, it can be used for implementing `std::start_lifetime_as` in the future. Due to the current clang lowering, the builtin reuses the existing `__builtin_launder` implementation: - it is a no-op for the most part; - with `-fstrict-vtable-pointers` flag, we update the vtpr assumption correctly (mark the load/store vptr with appropriate invariant group intrinsics) to prevent incorrect vptr load folding; - for now, the builtin is non-constant, cannot be executed in constant evaluation; CAVEAT: - this builtin may cause TBAA miscomplies without the `-fno-strict-alias` flag. These TBAA miscompiles are known issues and may need more LLVM IR support for the fix, fixing them is orthogonal to the implementaton of the builtin. Context: https://discourse.llvm.org/t/extension-for-creating-objects-via-memcpy/76961 --- clang/include/clang/Basic/Builtins.td | 6 +++ clang/lib/CodeGen/CGBuiltin.cpp | 1 + clang/lib/Sema/SemaChecking.cpp | 2 + clang/test/CodeGen/builtins.c | 10 .../builtin-start-object-life-time.cpp| 49 +++ clang/test/SemaCXX/builtins.cpp | 33 - 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/builtin-start-object-life-time.cpp diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index f421223ff087de..2c2e0eb58b15a1 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -926,6 +926,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { + let Spellings = ["__builtin_start_object_lifetime"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void*(void*)"; +} + def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> { let Spellings = ["__builtin_is_constant_evaluated"]; let Attributes = [NoThrow, Constexpr]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 483f9c26859923..6cdb602f8bb07d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4509,6 +4509,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: { const Expr *Arg = E->getArg(0); QualType ArgTy = Arg->getType()->getPointeeType(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 11401b6f56c0ea..356765609f694b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -37,6 +37,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" @@ -2642,6 +2643,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: return SemaBuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 407e0857d22311..00c81c23d0ed02 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -143,6 +143,7 @@ int main(void) { P(signbit, (1.0)); R(launder, ()); + R(start_object_lifetime, ()); return 0; } @@ -511,6 +512,15 @@ void test_builtin_launder(int *p) { int *d = __builtin_launder(p); } +/// It should be a NOP in C since there are no vtables. +// CHECK-LABEL: define{{.*}} void @test_builtin_start_object_lifetime +void test_builtin_start_object_lifetime(int *p) { + // CHECK: [[TMP:%.*]] = load ptr, + // CHECK-NOT: @llvm.launder + // CHECK: store ptr [[TMP]], + int *d = __builtin_start_object_lifetime(p); +} + // __warn_memset_zero_len should be NOP, see https://sourceware.org/bugzilla/show_bug.cgi?id=25399 // CHECK-LABEL: define{{.*}} void @test___warn_memset_zero_len void test___warn_memset_zero_len(void) { diff --git a/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp b/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp new file mode 100644 index 00..58012f52cc0ef5 --- /dev/null +++ b/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp @@ -0,0
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -156,6 +156,37 @@ void test_noexcept(int *i) { #undef TEST_TYPE } // end namespace test_launder +namespace test_start_object_lifetime { +// The builtin is non-constant. +constexpr int test_non_constexpr(int i) { // expected-error {{constexpr function never produces a constant expression}} + __builtin_start_object_lifetime(); // expected-note {{subexpression not valid in a constant expression}} +#ifdef CXX11 + // expected-warning@-2 {{use of this statement in a constexpr function is a C++14 extension}} +#endif + return 0; +} + +struct Incomplete; // expected-note {{forward declaration}} +void test_incomplete(Incomplete *i) { + // Requires a complete type + __builtin_start_object_lifetime(i); // expected-error {{incomplete type 'Incomplete' where a complete type is required}} +} + +// The builtin is type-generic. +#define TEST_TYPE(Ptr, Type) \ + static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type") hokein wrote: oops, yeah, it should be `__builtin_start_object_lifetime `. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { + let Spellings = ["__builtin_start_object_lifetime"]; hokein wrote: I don't have strong opinion on the name. Since this builtin doesn't strictly align with std::start_lifetime_as, I think it's better to have some divergence in the name. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -4386,6 +4386,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: hokein wrote: Added a comment for it, please take a look. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { hokein wrote: Done. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -4386,6 +4386,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: { hokein wrote: I think the name is fine, we're in the CodeGen, and the BuiltinLaunder in `TypeRequiresBuiltinLaunder` means the LLVM IR `llvm.launder` [intrinsics](https://llvm.org/docs/LangRef.html#llvm-launder-invariant-group-intrinsic). https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
https://github.com/hokein updated https://github.com/llvm/llvm-project/pull/82776 >From 7fcd58b750872221aa754e81e17ab9068e144a44 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 23 Feb 2024 10:03:16 +0100 Subject: [PATCH 1/2] [clang] Add __builtin_start_object_lifetime builtin. This patch implements a clang built `__builtin_start_object_lifetime`, it has the same semantics as C++23's `std::start_lifetime_as`, but without the implicit-lifetime type restriction, it can be used for implementing `std::start_lifetime_as` in the future. Due to the current clang lowering, the builtin reuses the existing `__builtin_launder` implementation: - it is a no-op for the most part; - with `-fstrict-vtable-pointers` flag, we update the vtpr assumption correctly (mark the load/store vptr with appropriate invariant group intrinsics) to prevent incorrect vptr load folding; - for now, the builtin is non-constant, cannot be executed in constant evaluation; CAVEAT: - this builtin may cause TBAA miscomplies without the `-fno-strict-alias` flag. These TBAA miscompiles are known issues and may need more LLVM IR support for the fix, fixing them is orthogonal to the implementaton of the builtin. Context: https://discourse.llvm.org/t/extension-for-creating-objects-via-memcpy/76961 --- clang/include/clang/Basic/Builtins.td | 6 +++ clang/lib/CodeGen/CGBuiltin.cpp | 1 + clang/lib/Sema/SemaChecking.cpp | 2 + clang/test/CodeGen/builtins.c | 10 .../builtin-start-object-life-time.cpp| 49 +++ clang/test/SemaCXX/builtins.cpp | 33 - 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/builtin-start-object-life-time.cpp diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index f421223ff087de..2c2e0eb58b15a1 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -926,6 +926,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { + let Spellings = ["__builtin_start_object_lifetime"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void*(void*)"; +} + def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> { let Spellings = ["__builtin_is_constant_evaluated"]; let Attributes = [NoThrow, Constexpr]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 483f9c26859923..6cdb602f8bb07d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4509,6 +4509,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: { const Expr *Arg = E->getArg(0); QualType ArgTy = Arg->getType()->getPointeeType(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 11401b6f56c0ea..356765609f694b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -37,6 +37,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" @@ -2642,6 +2643,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: return SemaBuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 407e0857d22311..00c81c23d0ed02 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -143,6 +143,7 @@ int main(void) { P(signbit, (1.0)); R(launder, ()); + R(start_object_lifetime, ()); return 0; } @@ -511,6 +512,15 @@ void test_builtin_launder(int *p) { int *d = __builtin_launder(p); } +/// It should be a NOP in C since there are no vtables. +// CHECK-LABEL: define{{.*}} void @test_builtin_start_object_lifetime +void test_builtin_start_object_lifetime(int *p) { + // CHECK: [[TMP:%.*]] = load ptr, + // CHECK-NOT: @llvm.launder + // CHECK: store ptr [[TMP]], + int *d = __builtin_start_object_lifetime(p); +} + // __warn_memset_zero_len should be NOP, see https://sourceware.org/bugzilla/show_bug.cgi?id=25399 // CHECK-LABEL: define{{.*}} void @test___warn_memset_zero_len void test___warn_memset_zero_len(void) { diff --git a/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp b/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp new file mode 100644 index 00..58012f52cc0ef5 --- /dev/null +++ b/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp @@ -0,0
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
frederick-vs-ja wrote: > This does something both useful and correct with `-fno-strict-aliasing`. I'm not sure whether an instrinsic is even needed with `-fno-strict-aliasing`. IIUC `std::start_lifetime_as` mainly tells the compiler that the types of data in the storage can be changed (indeterminately) with the object representations unchanged. This behaves like some fence for TBAA. > we can now observe them and use them to validate e.g. the `llvm.tbaa.fence` > proposal. Yeah. I guess we need to implement `std::start_lifetime_as(_array)` with `llvm.tbaa.fence`. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -156,6 +156,37 @@ void test_noexcept(int *i) { #undef TEST_TYPE } // end namespace test_launder +namespace test_start_object_lifetime { +// The builtin is non-constant. +constexpr int test_non_constexpr(int i) { // expected-error {{constexpr function never produces a constant expression}} + __builtin_start_object_lifetime(); // expected-note {{subexpression not valid in a constant expression}} +#ifdef CXX11 + // expected-warning@-2 {{use of this statement in a constexpr function is a C++14 extension}} +#endif + return 0; +} + +struct Incomplete; // expected-note {{forward declaration}} +void test_incomplete(Incomplete *i) { + // Requires a complete type + __builtin_start_object_lifetime(i); // expected-error {{incomplete type 'Incomplete' where a complete type is required}} +} + +// The builtin is type-generic. +#define TEST_TYPE(Ptr, Type) \ + static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type") sam-mccall wrote: should this be `__builtin_start_object_lifetime`? https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { sam-mccall wrote: https://github.com/llvm/llvm-project/pull/86512 is the answer here, I think. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
sam-mccall wrote: This has been dormant in part while thinking about the memcpy half, I think. Something like https://github.com/llvm/llvm-project/pull/86512 solves that well but likely needs this change too. > I am a bit concerned that this does not actually have the desired semantics > at all, but @zygoloid seemed to be "happy" with it. I will admit I struggle > understanding the motivation of adding a builtin that does...less than it > should. This does something both useful and correct with `-fno-strict-aliasing`. I think we're far from alone in building in this mode (in part precisely because of existing TBAA soundness questions!)[1]. I think it gets us incrementally closer to fully supporting std::start_lifetime_as: if there are specific miscompiles this would produce with strict-aliasing enabled, we can now observe them and use them to validate e.g. the `llvm.tbaa.fence` proposal. (It looks like what we need here but I also don't understand the LLVM change deeply). > Similarly, do you have plans for the array version of start_lifetime_as? I think we need a similar parallel version of this, e.g.: `__start_dynamic_array_lifetime(T*, size_t) -> T*`. This seems like a purely mechanical extension that could be done in this patch or subsequently. Preferences? [1] I hope this is the year we can put some work into strict-aliasing and turn it on. By coincidence, our best estimate of the overall performance win is roughly the same as applying this optimization to one widely-used library... https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
cor3ntin wrote: I am a bit concerned that this does not actually have the desired semantics at all, but @zygoloid seemed to be "happy" with it. I will admit I struggle understanding the motivation of adding a builtin that does...less than it should (when it should do something). Similarly, do you have plans for the array version of start_lifetime_as? https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { + let Spellings = ["__builtin_start_object_lifetime"]; frederick-vs-ja wrote: IMO if the intent of this intrinsic is to handle polymorphic classes (which is not covered by `std::start_lifetime_as`), its name should diverge from "plain" `start_lifetime`. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { zygoloid wrote: Nit: lifetime is one word not two, so the `T` should not be capitalized. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { sam-mccall wrote: For creating-objects-via-memcpy, what are we planning to do about the memcpy part being UB and the start_lifetime part being correspondingly hard to specify (what's the relationship between the bytes and the new objects?) I thought a combined memcpy + start_object_lifetime intrinsic would solve this neatly (values of new objects are the values of the old objects), but certainly we want the start-lifetime-only part to support start_lifetime_as. I don't see a great way out for non-implicit-lifetime types though... https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { + let Spellings = ["__builtin_start_object_lifetime"]; sam-mccall wrote: nit, I'd consider `__builtin_start_lifetime` both for brevity and to parallel `std::start_lifetime_as`. I don't think it's really ambiguous what we're starting the lifetime of. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -4386,6 +4386,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: sam-mccall wrote: is there something to be commented here about why what we do here is sufficient? It seems surprising to my very-untrained eye that start_lifetime is the same as launder, and we don't need any extra TBAA metadata or so... https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
https://github.com/sam-mccall edited https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
https://github.com/sam-mccall commented: Thanks for working on this! I'm far from an expert on the LLVM side so we'll need someone to weigh in. We need to specify specify the behavior somewhere. I think we should add a description to `docs/LanguageExtensions.html`, which describes various other `__builtin_*`. I'm not sure defining this in terms of "like start_lifetime_as but..." is ideal because: - implicit object creation recurses into only implicit-lifetimes subobjects, where this will recurse into everything. (Whether this is the same or different depends on your persepctive. - Unlike start_lifetime_as, it's clearly more useful to say "this starts an object's lifetime" than "this may start an object's lifetime as needed to avoid UB", I think this clarifies when you can/must call destructors. In this sense it's more like placement-new than start-lifetime-as. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
frederick-vs-ja wrote: > * with `-fstrict-vtable-pointers` flag, we update the vtpr assumption > correctly (mark the load/store vptr with appropriate invariant group > intrinsics) to prevent incorrect vptr load folding; I _guess_ we want a variant of this intrinsic which doesn't affect analyzation for devirtualization. Such an intrinsic should be sufficient for **C++23** `std::start_lifetime_as(_array)`. > * for now, it is non-constant, thus cannot be executed in constant evaluation; It seems intended that `std::start_lifetime_as(_array)` is not usable in constant evaluation, as the indeterminism of implicit object creation doesn't seem compatible with constant evaluation. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
@@ -4386,6 +4386,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: { erichkeane wrote: Should the `TypeRequiresBuiltinLaunder` function be generalized, at least in name? https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
https://github.com/erichkeane commented: This would also need a release note I believe. I don't have the codegen expertise to review this with high confidence, but it looks right to me. https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
https://github.com/erichkeane edited https://github.com/llvm/llvm-project/pull/82776 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Haojian Wu (hokein) Changes This patch implements a clang builtin `__builtin_start_object_lifetime`, it has the same semantics as C++23's `std::start_lifetime_as`, but without the implicit-lifetime type restriction, it could be used for implementing `std::start_lifetime_as` in the future. Due to the current clang lowering, the builtin reuses the existing `__builtin_launder` implementation: - it is a no-op for the most part; - with `-fstrict-vtable-pointers` flag, we update the vtpr assumption correctly (mark the load/store vptr with appropriate invariant group intrinsics) to prevent incorrect vptr load folding; - for now, it is non-constant, thus cannot be executed in constant evaluation; CAVEAT: - this builtin may cause TBAA miscomplies without the `-fno-strict-aliasing` flag. These TBAA miscompiles are known issues and may need more LLVM IR support for the fix, fixing them is orthogonal to the implementation of the builtin. Context: https://discourse.llvm.org/t/extension-for-creating-objects-via-memcpy --- Full diff: https://github.com/llvm/llvm-project/pull/82776.diff 6 Files Affected: - (modified) clang/include/clang/Basic/Builtins.td (+6) - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+1) - (modified) clang/lib/Sema/SemaChecking.cpp (+2) - (modified) clang/test/CodeGen/builtins.c (+10) - (added) clang/test/CodeGenCXX/builtin-start-object-life-time.cpp (+49) - (modified) clang/test/SemaCXX/builtins.cpp (+32-1) ``diff diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index df74026c5d2d50..70361afe69a980 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { + let Spellings = ["__builtin_start_object_lifetime"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void*(void*)"; +} + def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> { let Spellings = ["__builtin_is_constant_evaluated"]; let Attributes = [NoThrow, Constexpr]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d454ccc1dd8613..7a98f734f32ada 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4386,6 +4386,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: { const Expr *Arg = E->getArg(0); QualType ArgTy = Arg->getType()->getPointeeType(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8e76338477..f79cb7e0445260 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -37,6 +37,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" @@ -2386,6 +2387,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: return SemaBuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 88282120283b8a..f46d6eb7632afc 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -143,6 +143,7 @@ int main(void) { P(signbit, (1.0)); R(launder, ()); + R(start_object_lifetime, ()); return 0; } @@ -511,6 +512,15 @@ void test_builtin_launder(int *p) { int *d = __builtin_launder(p); } +/// It should be a NOP in C since there are no vtables. +// CHECK-LABEL: define{{.*}} void @test_builtin_start_object_lifetime +void test_builtin_start_object_lifetime(int *p) { + // CHECK: [[TMP:%.*]] = load ptr, + // CHECK-NOT: @llvm.launder + // CHECK: store ptr [[TMP]], + int *d = __builtin_start_object_lifetime(p); +} + // __warn_memset_zero_len should be NOP, see https://sourceware.org/bugzilla/show_bug.cgi?id=25399 // CHECK-LABEL: define{{.*}} void @test___warn_memset_zero_len void test___warn_memset_zero_len(void) { diff --git a/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp b/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp new file mode 100644 index 00..58012f52cc0ef5 --- /dev/null +++ b/clang/test/CodeGenCXX/builtin-start-object-life-time.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fstrict-vtable-pointers -o - %s \ +// RUN: | FileCheck --check-prefixes=CHECK,CHECK-STRICT %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck
[clang] [clang] Add __builtin_start_object_lifetime builtin. (PR #82776)
https://github.com/hokein created https://github.com/llvm/llvm-project/pull/82776 This patch implements a clang builtin `__builtin_start_object_lifetime`, it has the same semantics as C++23's `std::start_lifetime_as`, but without the implicit-lifetime type restriction, it could be used for implementing `std::start_lifetime_as` in the future. Due to the current clang lowering, the builtin reuses the existing `__builtin_launder` implementation: - it is a no-op for the most part; - with `-fstrict-vtable-pointers` flag, we update the vtpr assumption correctly (mark the load/store vptr with appropriate invariant group intrinsics) to prevent incorrect vptr load folding; - for now, it is non-constant, thus cannot be executed in constant evaluation; CAVEAT: - this builtin may cause TBAA miscomplies without the `-fno-strict-aliasing` flag. These TBAA miscompiles are known issues and may need more LLVM IR support for the fix, fixing them is orthogonal to the implementation of the builtin. Context: https://discourse.llvm.org/t/extension-for-creating-objects-via-memcpy >From baf6f2eeda35182fcc1e04adf7334b513160419c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 23 Feb 2024 10:03:16 +0100 Subject: [PATCH] [clang] Add __builtin_start_object_lifetime builtin. This patch implements a clang built `__builtin_start_object_lifetime`, it has the same semantics as C++23's `std::start_lifetime_as`, but without the implicit-lifetime type restriction, it can be used for implementing `std::start_lifetime_as` in the future. Due to the current clang lowering, the builtin reuses the existing `__builtin_launder` implementation: - it is a no-op for the most part; - with `-fstrict-vtable-pointers` flag, we update the vtpr assumption correctly (mark the load/store vptr with appropriate invariant group intrinsics) to prevent incorrect vptr load folding; - for now, the builtin is non-constant, cannot be executed in constant evaluation; CAVEAT: - this builtin may cause TBAA miscomplies without the `-fno-strict-alias` flag. These TBAA miscompiles are known issues and may need more LLVM IR support for the fix, fixing them is orthogonal to the implementaton of the builtin. Context: https://discourse.llvm.org/t/extension-for-creating-objects-via-memcpy/76961 --- clang/include/clang/Basic/Builtins.td | 6 +++ clang/lib/CodeGen/CGBuiltin.cpp | 1 + clang/lib/Sema/SemaChecking.cpp | 2 + clang/test/CodeGen/builtins.c | 10 .../builtin-start-object-life-time.cpp| 49 +++ clang/test/SemaCXX/builtins.cpp | 33 - 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/builtin-start-object-life-time.cpp diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index df74026c5d2d50..70361afe69a980 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -896,6 +896,12 @@ def Launder : Builtin { let Prototype = "void*(void*)"; } +def StartObjectLifeTime : Builtin { + let Spellings = ["__builtin_start_object_lifetime"]; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void*(void*)"; +} + def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> { let Spellings = ["__builtin_is_constant_evaluated"]; let Attributes = [NoThrow, Constexpr]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d454ccc1dd8613..7a98f734f32ada 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4386,6 +4386,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: { const Expr *Arg = E->getArg(0); QualType ArgTy = Arg->getType()->getPointeeType(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8e76338477..f79cb7e0445260 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -37,6 +37,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" @@ -2386,6 +2387,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; } + case Builtin::BI__builtin_start_object_lifetime: case Builtin::BI__builtin_launder: return SemaBuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 88282120283b8a..f46d6eb7632afc 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -143,6 +143,7 @@ int main(void) {