-
Notifications
You must be signed in to change notification settings - Fork 445
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
Make -DCMAKE_INTERPROCEDURAL_OPTIMIZATION Enable LTO #4908
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO it would be a good idea to check this against more OS versions than we do with just CI, but I'm not sure how easy it is to do that. Adding more builds to CI might be getting excessive.
lib/gc.cpp
Outdated
@@ -81,6 +81,33 @@ static void maybe_initialize_gc() { | |||
} | |||
} | |||
|
|||
#ifdef __GLIBC__ | |||
#define GNOEXCEPT __THROW | |||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that this should depend on the version of glibc you're linking against as different version have different exception specifications?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ChrisDodd the __THROW
specifier is defined as a macro in cdefs.h
and appears to be whatever glibc wants to use. With any remotely modern compiler, it will always decay noexcept
, but it will decay to throw()
for C++03 and earlier. I don't believe p4c supports C++03, so we could just use noexcept
, but perhaps __THROW
is slightly more future-proof in case glibc changes its mind about what exception specification it wants to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ChrisDodd and that __THROW
macro has been in glibc since at least 1999, so it should work: https://github.com/bminor/glibc/blob/c1422e5b7cdb4400f934c91bcefa3a1a96d789fb/misc/sys/cdefs.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would stick to noexcept
to keep things simple? If the semantics of __THROW
changed we can revisit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fruffy I originally had it as noexcept
, and I don't like __THROW
because we're reaching using internal glibc macros, which I'm pretty sure we're not supposed to do. So, I'm happy to change it back.
@ChrisDodd The If we had one additional platform to test, I'd recommend GCC compiled against glibc on MacOS. However, I can't personally test that. |
The sanitizer failure is very plausible since the constructor for |
To save CI resources that check is optional, I am guessing #4909 was merged without enabling the sanitizer for it. |
lib/gc.cpp
Outdated
#else | ||
#define GNOEXCEPT | ||
#endif | ||
void *operator new(std::size_t size) __attribute__((used)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment why these prototypes are necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void *operator new(std::size_t size) __attribute__((used)); | |
[[gnu::used]] void *operator new(std::size_t size); |
Would this work? This syntax is safer as other compilers will just ignore it, unlike the __attribute__
syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, the exception declarations don't still don't match those in <new>
which could be a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be that we don't need to be messing with new
and friends at all. Let me check to see. I'm going to try to reproduce the original issue with p4c
master since the problem originally presented in an internal branch.
CMakeLists.txt
Outdated
@@ -56,7 +56,7 @@ STATIC_BUILD_WITH_DYNAMIC_STDLIB." OFF) | |||
OPTION (STATIC_BUILD_WITH_DYNAMIC_STDLIB "Build a (mostly) statically linked release binary. \ | |||
Glibc and C++ standard library is linked dynamically." OFF) | |||
|
|||
if (STATIC_BUILD_WITH_DYNAMIC_GLIBC OR STATIC_BUILD_WITH_DYNAMIC_STDLIB) | |||
if (STATIC_BUILD_WITH_DYNAMIC_GLIBC OR STATIC_BUILD_WITH_DYNAMIC_STDLIB OR CMAKE_INTERPROCEDURAL_OPTIMIZATION) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should replace ENABLE_LTO
with CMAKE_INTERPROCEDURAL_OPTIMIZATION
.
lib/gc.cpp
Outdated
@@ -81,6 +81,33 @@ static void maybe_initialize_gc() { | |||
} | |||
} | |||
|
|||
#ifdef __GLIBC__ | |||
#define GNOEXCEPT __THROW | |||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would stick to noexcept
to keep things simple? If the semantics of __THROW
changed we can revisit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the __extrarnally_visible__
attribute and _GLIBCXX_NODISCARD
used in <new>
not enough? This seems hightly suspicious to me. Also, you may be hiding that attribute by the new declarations, I'm not sure how the double declaration gets resolved.
lib/gc.cpp
Outdated
#else | ||
#define GNOEXCEPT | ||
#endif | ||
void *operator new(std::size_t size) __attribute__((used)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void *operator new(std::size_t size) __attribute__((used)); | |
[[gnu::used]] void *operator new(std::size_t size); |
Would this work? This syntax is safer as other compilers will just ignore it, unlike the __attribute__
syntax.
lib/gc.cpp
Outdated
#else | ||
#define GNOEXCEPT | ||
#endif | ||
void *operator new(std::size_t size) __attribute__((used)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, the exception declarations don't still don't match those in <new>
which could be a problem.
I'm off today and Monday and so will make changes to the PR to address reviewer comments on Tuesday. For now, I have no objections to replacing |
We had issues in the past at least with unity builds as things might got redeclared multiple times due to sources / headers combined. This is why we had this gcc is currently quite lax in terms of checking (invalid) redeclaration w/o The unity scenario was as follows:
|
@asl-AMD, glibc has never claimed to restrict its implementing code to anything other than the GNU standards of C and C++. clang can't even compile glibc because clang only has partial support for the GNU standards. The only guarantee glibc makes about the ISO standards is that ISO-compliant code should build and run when compiled and linked against glibc using gcc with an ISO dialect flag. Whether So, I don't think we need to reach into glibc's internals and use |
I really do not want to debate about things like this. But do you happen to have a link to this specification? Is would be very useful to insert reference to this specification in the comments so whoever will change the code in the future would be aware about these restrictions. There are C and C++ standards. And the standard library is expected to follow these standard before everything else. The standard specifies that these functions are declared without |
@asl well, sure, I don't want to debate this either :) That's why I originally changed it for you without discussion. But, I do think it's somewhat better with noexcept since the alternative uses an internal glibc macro that I don't think we have glibc's permission to be relying on. Here's the link I was referring to: https://www.gnu.org/software/libc/manual/html_node/ISO-C.html |
Great, thanks. Could you please refer me to |
@asl I don't think the
Re what glibc is "expected" to do, the GNU Project has the same rights as anyone to publish whatever code it wants to. ISO standards have no legal or moral authority; they merely exist to help implementations and users when they happen to be helpful. If glibc feels its users are better served by putting |
This is certainly fine and understood. However, p4c as a project is expected to be compiled with different compilers (e.g.
My point is that these cases should be supported as well. We know that in the past that not accounting for glibc differences caused issues. At least in unity builds IIRC. So when introducing changes into functions that are supposed to override whatever standard library provides we need to be very careful and certainly not to prefer one configurations to others. I believe one plausible breakage scenario in the past was mentioned above. Maybe there are others. |
@asl yes, we shouldn't push code to
Either of these works, and I don't think it's a huge deal which one we use. I think the better way is to I've said all I care to say about this issue now and will defer to the consensus of the reviewers on which way to go. |
I'm having difficulty reproducing the link error with p4c master. If I can't, I'm not sure if there is sufficient motivation to have the |
The only place I can reproduce this error is inside a docker with a locally-compiled GCC 9.5 running on CentOS 7. So, the link problem is almost certainly a host compiler bug. That's probably a very unusual build environment, so I don't think we should add prototypes to work around that issue. |
It looks like the only change here now is to add |
Hi @fruffy, yes I do think |
If so, could you replace ENABLE_LTO with it? And for backward compatibility use |
28d94ad
to
febf96b
Compare
Signed-off-by: Patrick Simmons <[email protected]>
Signed-off-by: Patrick Simmons <[email protected]>
@fruffy okay, done. |
else() | ||
set (_ENABLE_LTO_DEFAULT OFF) | ||
set (CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this mess with the setting of CMAKE_INTERPROCEDRAL_OPTIMIZATION
done on the commandline? Actually probably both branches would mess with it. The idea behind _ENABLE_LTO_DEFAULT
was that it is still possible to do STATIC_*
with LTO explicitly disabled, I'm worried this would no longer work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vlstill command-line arguments take precedence over anything in CMakeLists.txt
Turning on
CMAKE_INTERPROCEDURAL_OPTIMIZATION
is CMake's standard way of enabling LTO. This PR makes that option enable LTO for p4c. It also fixes linker errors which occur due to p4c's garbage-collected implementations of the C standard memory allocation functions being discarded when LTO is enabled. This is avoided by prototyping these functions with__attribute__((used))
. Exception specifications are included for these prototypes when compiling on glibc since Clang requires the prototypes to exactly match those from whatever C standard library it is being compiled against.