-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[libc++] Make _LIBCPP_ASSUME usable when it is appropriate #91801
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
Conversation
@llvm/pr-subscribers-libcxx Author: David Benjamin (davidben) Changeslibc++ turned off _LIBCPP_ASSUME because turning every debug assert into __builtin_assume tripped However, this means we can't use _LIBCPP_ASSUME when there is a clear optimization intent. See #78929 (comment) for discussion of a place where _LIBCPP_ASSUME would be valuable. Go ahead and fix this now, and adjust the comments. I don't think we want _LIBCPP_ASSUME in disabled asserts anyway, at least not in any of the hardened modes. This PR should have no impact on libc++ right now, since _LIBCPP_ASSUME is currently never called standalone, but I figure I can do this as a standalone PR since it's pretty straightforward. Full diff: https://github.com/llvm/llvm-project/pull/91801.diff 1 Files Affected:
diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index 49769fb4d4497..3847a47558a72 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -23,10 +23,10 @@
: _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING( \
expression) " failed: " message "\n"))
-// TODO: __builtin_assume can currently inhibit optimizations. Until this has been fixed and we can add
-// assumptions without a clear optimization intent, disable that to avoid worsening the code generation.
-// See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a discussion.
-#if 0 && __has_builtin(__builtin_assume)
+// WARNING: __builtin_assume can currently inhibit optimizations. Only add assumptions with a clear
+// optimization intent. See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a
+// discussion.
+#if __has_builtin(__builtin_assume)
# define _LIBCPP_ASSUME(expression) \
(_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wassume") \
__builtin_assume(static_cast<bool>(expression)) _LIBCPP_DIAGNOSTIC_POP)
@@ -34,6 +34,9 @@
# define _LIBCPP_ASSUME(expression) ((void)0)
#endif
+// Historically, disabled assertions below expanded to `_LIBCPP_ASSUME`, but this both triggers the
+// issue described above, and also causes every debug assertion to be a safety risk.
+
// clang-format off
// Fast hardening mode checks.
@@ -44,18 +47,18 @@
# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message)
// Disabled checks.
// On most modern platforms, dereferencing a null pointer does not lead to an actual memory access.
-# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_NON_NULL(expression, message) ((void)0)
// Overlapping ranges will make algorithms produce incorrect results but don't directly lead to a security
// vulnerability.
-# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) ((void)0)
// Extensive hardening mode checks.
@@ -73,8 +76,8 @@
# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
// Disabled checks.
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) ((void)0)
// Debug hardening mode checks.
@@ -99,18 +102,18 @@
#else
// All checks disabled.
-# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_NON_NULL(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) ((void)0)
+# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) ((void)0)
#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST
// clang-format on
|
Fixes llvm#91634. This could alternatively be done with an _LIBCPP_ASSUME, after llvm#91801 lands, but would also require llvm#91619 be fixed first. Given the dependencies, it seemed simplest to just make a private ctor.
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.
This makes sense to me. Deferring to @var-const for final approval, but at first glance I like this.
…1804) Summary: Fixes #91634. This could alternatively be done with an _LIBCPP_ASSUME, after #91801 lands, but would also require #91619 be fixed first. Given the dependencies, it seemed simplest to just make a private ctor. Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251551
fe88aab
to
f0eabdc
Compare
Friendly ping on this PR. This is a blocker to fixing #101370 which, in turn, is a blocker to making bounded iterators practical. |
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.
So sorry about the very slow review! LGTM.
libcxx/include/__assert
Outdated
# define _LIBCPP_ASSUME(expression) \ | ||
(_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wassume") \ | ||
__builtin_assume(static_cast<bool>(expression)) _LIBCPP_DIAGNOSTIC_POP) | ||
#else | ||
# define _LIBCPP_ASSUME(expression) ((void)0) | ||
#endif | ||
|
||
// Historically, disabled assertions below expanded to `_LIBCPP_ASSUME`, but this both triggers the |
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.
Nit: I'd remove this comment -- I understand the desire to make sure somebody doesn't reintroduce the previous state (which seems to make a lot of sense in theory but doesn't work in practice), but IMO the comment we have on _LIBCPP_ASSUME
should be enough of a deterrence.
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.
Removed and rebased.
libc++ turned off _LIBCPP_ASSUME because turning every debug assert into __builtin_assume tripped https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 However, this means we can't use _LIBCPP_ASSUME when there is a clear optimization intent. See llvm#78929 (comment) for discussion of a place where _LIBCPP_ASSUME would be valuable. Go ahead and fix this now, and adjust the comments. I don't think we want _LIBCPP_ASSUME in disabled asserts anyway, at least not in any of the hardened modes. This PR should have no impact on libc++ right now, since _LIBCPP_ASSUME is currently never called standalone, but I figure I can do this as a standalone PR since it's pretty straightforward.
f0eabdc
to
a01582a
Compare
libc++ turned off _LIBCPP_ASSUME because turning every debug assert into __builtin_assume tripped [1]. However, this means we can't use _LIBCPP_ASSUME when there is a clear optimization intent. See [2] for discussion of a place where _LIBCPP_ASSUME would be valuable. This patch fixes this by not undefining the definition of _LIBCPP_ASSUME and making sure that we don't attempt to `_LIBCPP_ASSSUME` every assertion in the library. [1]: https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 [2]: llvm#78929 (comment)
…1804) Fixes #91634. This could alternatively be done with an _LIBCPP_ASSUME, after llvm/llvm-project#91801 lands, but would also require llvm/llvm-project#91619 be fixed first. Given the dependencies, it seemed simplest to just make a private ctor. NOKEYCHECK=True GitOrigin-RevId: 795a47fb66b7479f6da4f8cdfc9f83ea5d654a55
libc++ turned off _LIBCPP_ASSUME because turning every debug assert into __builtin_assume tripped
https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609
However, this means we can't use _LIBCPP_ASSUME when there is a clear optimization intent. See #78929 (comment) for discussion of a place where _LIBCPP_ASSUME would be valuable.
Go ahead and fix this now, and adjust the comments. I don't think we want _LIBCPP_ASSUME in disabled asserts anyway, at least not in any of the hardened modes. This PR should have no impact on libc++ right now, since _LIBCPP_ASSUME is currently never called standalone, but I figure I can do this as a standalone PR since it's pretty straightforward.