about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2024-10-11 14:41:02 -0700
committerJosh Stone <jistone@redhat.com>2024-10-11 16:22:43 -0700
commit5365b3f7be079008d7cac03b821f7c65563ee5ed (patch)
treeb797d50e60b0c4feeabf72027a0a7d25c78839ce
parentf4966590d8edd5f493a1aab04016b94a75494329 (diff)
downloadrust-5365b3f7be079008d7cac03b821f7c65563ee5ed.tar.gz
rust-5365b3f7be079008d7cac03b821f7c65563ee5ed.zip
Avoid superfluous UB checks in `IndexRange`
`IndexRange::len` is justified as an overall invariant, and
`take_prefix` and `take_suffix` are justified by local branch
conditions. A few more UB-checked calls remain in cases that are only
supported locally by `debug_assert!`, which won't do anything in
distributed builds, so those UB checks may still be useful.

We generally expect core's `#![rustc_preserve_ub_checks]` to optimize
away in user's release builds, but the mere presence of that extra code
can sometimes inhibit optimization, as seen in #131563.
-rw-r--r--library/core/src/ops/index_range.rs11
-rw-r--r--tests/codegen/issues/issue-101082.rs5
2 files changed, 12 insertions, 4 deletions
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
index 64214eae377..dce3514a159 100644
--- a/library/core/src/ops/index_range.rs
+++ b/library/core/src/ops/index_range.rs
@@ -45,7 +45,8 @@ impl IndexRange {
     #[inline]
     pub const fn len(&self) -> usize {
         // SAFETY: By invariant, this cannot wrap
-        unsafe { self.end.unchecked_sub(self.start) }
+        // Using the intrinsic because a UB check here impedes LLVM optimization. (#131563)
+        unsafe { crate::intrinsics::unchecked_sub(self.end, self.start) }
     }
 
     /// # Safety
@@ -82,7 +83,8 @@ impl IndexRange {
         let mid = if n <= self.len() {
             // SAFETY: We just checked that this will be between start and end,
             // and thus the addition cannot overflow.
-            unsafe { self.start.unchecked_add(n) }
+            // Using the intrinsic avoids a superfluous UB check.
+            unsafe { crate::intrinsics::unchecked_add(self.start, n) }
         } else {
             self.end
         };
@@ -100,8 +102,9 @@ impl IndexRange {
     pub fn take_suffix(&mut self, n: usize) -> Self {
         let mid = if n <= self.len() {
             // SAFETY: We just checked that this will be between start and end,
-            // and thus the addition cannot overflow.
-            unsafe { self.end.unchecked_sub(n) }
+            // and thus the subtraction cannot overflow.
+            // Using the intrinsic avoids a superfluous UB check.
+            unsafe { crate::intrinsics::unchecked_sub(self.end, n) }
         } else {
             self.start
         };
diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs
index 550d267a98f..4be1b6cb168 100644
--- a/tests/codegen/issues/issue-101082.rs
+++ b/tests/codegen/issues/issue-101082.rs
@@ -1,4 +1,9 @@
 //@ compile-flags: -O
+//@ revisions: host x86-64-v3
+
+// This particular CPU regressed in #131563
+//@[x86-64-v3] only-x86_64
+//@[x86-64-v3] compile-flags: -Ctarget-cpu=x86-64-v3
 
 #![crate_type = "lib"]