8000 Add `_LIBCPP_PLACEMENT_NEW_DEFINED` macro to allow for user defined placement new operators by MaxEW707 · Pull Request #70538 · llvm/llvm-project · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add _LIBCPP_PLACEMENT_NEW_DEFINED macro to allow for user defined placement new operators #70538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

MaxEW707
Copy link
Contributor
@MaxEW707 MaxEW707 commented Oct 28, 2023

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, for the most part, that also implements some of the low-level language bits that are intended to be provided by the std.
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 :).

…DEFINED` macro to allow for user defined placement new
@MaxEW707 MaxEW707 requested a review from a team as a code owner October 28, 2023 05:48
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Oct 28, 2023
@philnik777
Copy link
Contributor

I'm going to go with "just include <new>". If it's actually slow to include, file a bug against the standard library.

@ldionne ldionne added the invalid Resolved as invalid, i.e. not a bug label Oct 31, 2023
@ldionne
Copy link
Member
ldionne commented Oct 31, 2023

Just include <new> and stop working around the std

Include times. <new> is expensive to include on a variety of std implementations.

I just looked and our <new> header should be really cheap to include. Other stdlibs should also make that cheap, otherwise it's arguably a QOI defect against them. Another option is to use #include <version> and then check for #ifdef _LIBCPP_VERSION to check whether libc++ is in use or not -- then you can include <new> only if libc++ is in use cause it's cheap to do so. On other implementations that are more expensive you can use another workaround such as __PLACEMENT_NEW_INLINE.

I am quite reluctant to add any kind of complexity to the library to work around something like this -- I don't think that's the right tradeoff here.

@ldionne ldionne closed this Oct 31, 2023
@ldionne
Copy link
Member
ldionne commented Oct 31, 2023

Reopening, I think there's something I don't understand here.

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 to ensure what effectively should be a language feature in C++.

If you #include <new>, then placement-new is declared inside the TU and so Clang should treat it as an intrinsic, no? Is that not what happens?

I don't think it is worth doing something about the "compilation time issue", however if we do something that pessimizes how Clang handles our stdlib-declared placement new, then it is probably reasonable to do something about that.

@ldionne ldionne reopened this Oct 31, 2023
@philnik777
Copy link
Contributor

Clang always treats placement-new as an intrinsic, so I think we can close this: https://godbolt.org/z/fPjKja3cK

@philnik777 philnik777 closed this Oct 31, 2023
@MaxEW707
Copy link
Contributor Author

Clang always treats placement-new as an intrinsic, so I think we can close this: https://godbolt.org/z/fPjKja3cK

Since clang always treats the reserved placement-new as an intrinsic, even going back to clang 3.x, can we remove _LIBCPP_INLINE_VISIBILITY and thus the abi_tag on clang since the placement-new operator calls will never be generated.
This would allow us to declare the placement-new operator without getting a re-declaration error since a function cannot be re-declared with the abi_tag attribute.

The definition would go from

_LIBCPP_NODISCARD_AFTER_CXX17 inline _LIBCPP_INLINE_VISIBILITY void* operator new  (std::size_t, void* __p) _NOEXCEPT {return __p;}

to this

#if defined(__clang__)
#define _LIBCPP_PLACEMENT_NEW_VIS 
#else
#define _LIBCPP_PLACEMENT_NEW_VIS _LIBCPP_INLINE_VISIBILITY 
#endif

_LIBCPP_NODISCARD_AFTER_CXX17 inline _LIBCPP_PLACEMENT_NEW_VIS void* operator new  (std::size_t, void* __p) _NOEXCEPT {return __p;}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid Resolved as invalid, i.e. not a bug libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0