Skip to content

Conversation

@davidben
Copy link
Contributor

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.

@davidben davidben requested a review from a team as a code owner May 10, 2024 20:25
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label May 10, 2024
@llvmbot
Copy link
Member

llvmbot commented May 10, 2024

@llvm/pr-subscribers-libcxx

Author: David Benjamin (davidben)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/91801.diff

1 Files Affected:

  • (modified) libcxx/include/__assert (+31-28)
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

davidben added a commit to davidben/llvm-project that referenced this pull request May 10, 2024
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.
var-const pushed a commit that referenced this pull request Jul 23, 2024
…1804)

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.
Copy link
Member

@ldionne ldionne left a 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.

yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
…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
@ldionne ldionne changed the title Make _LIBCPP_ASSUME usable when it is appropriate [libc++] Make _LIBCPP_ASSUME usable when it is appropriate Sep 13, 2024
@davidben
Copy link
Contributor Author

Friendly ping on this PR. This is a blocker to fixing #101370 which, in turn, is a blocker to making bounded iterators practical.

Copy link
Member

@var-const var-const left a 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.

# define _LIBCPP_ASSUME(expression) ((void)0)
#endif

// Historically, disabled assertions below expanded to `_LIBCPP_ASSUME`, but this both triggers the
Copy link
Member

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.

Copy link
Contributor Author

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.
@ldionne ldionne merged commit adeae92 into llvm:main Sep 17, 2024
@davidben davidben deleted the libcxx-assume branch September 17, 2024 18:08
tmsri pushed a commit to tmsri/llvm-project that referenced this pull request Sep 19, 2024
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)
blueboxd pushed a commit to blueboxd/libcxx that referenced this pull request Apr 19, 2025
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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