[libcxx-commits] [libcxx] Add `_LIBCPP_PLACEMENT_NEW_DEFINED` macro to allow for user defined placement new operators (PR #70538)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 27 22:48:24 PDT 2023


https://github.com/MaxEW707 created https://github.com/llvm/llvm-project/pull/70538

https://godbolt.org/z/cT4GK3MbY for reference.

#### Background

I work on a large software project where compile-times and debug performance is a priority.
We also have our own stl equivalent. Usage of `std` is near non-existent except when interfacing with certain vendor or third-party libs.
On the platforms we ship on there are a variety of `std` implementations including `libcxx`.

#### Issue

Clang treats the reserved placement new as an intrinsic as long as it is declared within the TU.
https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/CGExprCXX.cpp#L1587 for reference. 
This avoids generation of a function call and avoids needing to include `<new>` to ensure what effectively should be a language feature in C++.
Since `libc++` adds an `abi_tag` attribute this means if `<new>` is included after our declaration, such as from a vendor or third-party header when interfacing with those APIs, we get a compile-time error.
To cover our bases in these rare cases means we have to forego using the placement-new intrinsic in the majority of cases on platforms where `libcxx` is a potential `std` implementation.

If code includes `<new>` in a TU after our declaration we know we are not getting the compile-time benefits. This case is a small number of cpp files where we have to interface with vendor libraries and need to include vendor headers unlike the majority uses of placement new which is ubiquitous in C++.

Also the removal of a linker symbol and debugging information is an added bonus when using the intrinsic.

MSVC stl does provide a `__PLACEMENT_NEW_INLINE` macro to allow the user to provide their own placement new operators as a point of reference.

#### Answers to potentially common questions

#### Just include `<new>` and stop working around the `std`
Include times. `<new>` is expensive to include on a variety of `std` implementations.

#### Use forceinline on clang with a custom placement new
The debug code generated is worse than the intrinsic as shown in the godbolt above.

#### It's just one function call. Deal with it.
Debug performance is death by 1000 cuts. In isolation one function call isn't a big deal.
Across a large project it can be a major perf hit especially small functions like `std::move`.

Plus what often goes unnoticed is the extra stack usage in debug and extra function calls do not help there when trying to avoid stack overflows.

#### PCH and/or unity builds
We do not use unity builds.

We have to disable PCH for some compilers due to bugs usually around builtin usage within a header.

If you work on the headers in a dev branch included in the PCH then you are just rebuilding every source file.
Depending on the team/engineer it may be common to see PCH builds for a module disabled locally for iteration.
Plus not every source file benefits from PCH depending on the includes within the PCH and what headers that source file actually uses.

#### Alternate Solution

An alternate solution is to internally declare and define the reserve placement new operators within clang itself.
That way they are available in any TU without needing `<new>` from a `std` implementation.
Personally I believe most of the constructs in the `std` should be language level constructs.
If this is a viable alternate solution let me know and I can submit a PR to clang itself.

We could also remove `_LIBCPP_INLINE_VISIBILITY ` if we are compiling under clang since we can assume clang will always treat this reserved operator as an intrinsic and thus never emit a function call.

Let me know what you prefer :).

>From 5f9f232e0e13ea20d71399a57e7bb87b85dc3d06 Mon Sep 17 00:00:00 2001
From: MaxEW707 <82551778+MaxEW707 at users.noreply.github.com>
Date: Sat, 28 Oct 2023 01:37:22 -0400
Subject: [PATCH] Add `_LIBCPP_PLACEMENT_NEW_DEFINED` and
 `_LIBCPP_PLACEMENT_ARRAY_NEW_DEFINED` macro to allow for user defined
 placement new

---
 libcxx/include/new | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/new b/libcxx/include/new
index 0a97c3e37add574..dcfc7515a257f24 100644
--- a/libcxx/include/new
+++ b/libcxx/include/new
@@ -248,10 +248,17 @@ _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE void  operato
 #endif
 #endif
 
+#ifndef _LIBCPP_PLACEMENT_NEW_DEFINED
+#define _LIBCPP_PLACEMENT_NEW_DEFINED
 _LIBCPP_NODISCARD_AFTER_CXX17 inline _LIBCPP_INLINE_VISIBILITY void* operator new  (std::size_t, void* __p) _NOEXCEPT {return __p;}
-_LIBCPP_NODISCARD_AFTER_CXX17 inline _LIBCPP_INLINE_VISIBILITY void* operator new[](std::size_t, void* __p) _NOEXCEPT {return __p;}
 inline _LIBCPP_INLINE_VISIBILITY void  operator delete  (void*, void*) _NOEXCEPT {}
+#endif
+
+#ifndef _LIBCPP_PLACEMENT_ARRAY_NEW_DEFINED
+#define _LIBCPP_PLACEMENT_ARRAY_NEW_DEFINED
+_LIBCPP_NODISCARD_AFTER_CXX17 inline _LIBCPP_INLINE_VISIBILITY void* operator new[](std::size_t, void* __p) _NOEXCEPT {return __p;}
 inline _LIBCPP_INLINE_VISIBILITY void  operator delete[](void*, void*) _NOEXCEPT {}
+#endif
 
 #endif // !_LIBCPP_ABI_VCRUNTIME
 



More information about the libcxx-commits mailing list