about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-17 22:18:24 +0000
committerbors <bors@rust-lang.org>2024-10-17 22:18:24 +0000
commitd9c4b8d475360b52e6debead2cd710e9fe3c7110 (patch)
tree581cfe0d69e1d207d6d693176ee02dc8555c333d
parent3ed6e3cc69857129c1d314daec00119ff47986ed (diff)
parent5365b3f7be079008d7cac03b821f7c65563ee5ed (diff)
downloadrust-d9c4b8d475360b52e6debead2cd710e9fe3c7110.tar.gz
rust-d9c4b8d475360b52e6debead2cd710e9fe3c7110.zip
Auto merge of #131572 - cuviper:ub-index_range, r=thomcc
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"]