forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of rust-lang#124114 - scottmcm:better-checked, r=workingju…
…bilee Make `checked` ops emit *unchecked* LLVM operations where feasible For things with easily pre-checked overflow conditions -- shifts and unsigned subtraction -- write the checked methods in such a way that we stop emitting wrapping versions of them. For example, today <https://rust.godbolt.org/z/qM9YK8Txb> neither ```rust a.checked_sub(b).unwrap() ``` nor ```rust a.checked_sub(b).unwrap_unchecked() ``` actually optimizes to `sub nuw`. After this PR they do. cc rust-lang#103299
- Loading branch information
Showing
6 changed files
with
160 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
//@ compile-flags: -O -Z merge-functions=disabled | ||
|
||
#![crate_type = "lib"] | ||
#![feature(unchecked_shifts)] | ||
|
||
// Because the result of something like `u32::checked_sub` can only be used if it | ||
// didn't overflow, make sure that LLVM actually knows that in optimized builds. | ||
// Thanks to poison semantics, this doesn't even need branches. | ||
|
||
// CHECK-LABEL: @checked_sub_unsigned | ||
// CHECK-SAME: (i16 noundef %a, i16 noundef %b) | ||
#[no_mangle] | ||
pub fn checked_sub_unsigned(a: u16, b: u16) -> Option<u16> { | ||
// CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b | ||
// CHECK-DAG: %[[DIFF_P:.+]] = sub nuw i16 %a, %b | ||
// CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i16 | ||
// CHECK-DAG: %[[DIFF_U:.+]] = select i1 %[[IS_SOME]], i16 %[[DIFF_P]], i16 undef | ||
|
||
// CHECK: %[[R0:.+]] = insertvalue { i16, i16 } poison, i16 %[[DISCR]], 0 | ||
// CHECK: %[[R1:.+]] = insertvalue { i16, i16 } %[[R0]], i16 %[[DIFF_U]], 1 | ||
// CHECK: ret { i16, i16 } %[[R1]] | ||
a.checked_sub(b) | ||
} | ||
|
||
// Note that `shl` and `shr` in LLVM are already unchecked. So rather than | ||
// looking for no-wrap flags, we just need there to not be any masking. | ||
|
||
// CHECK-LABEL: @checked_shl_unsigned | ||
// CHECK-SAME: (i32 noundef %a, i32 noundef %b) | ||
#[no_mangle] | ||
pub fn checked_shl_unsigned(a: u32, b: u32) -> Option<u32> { | ||
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 | ||
// CHECK-DAG: %[[SHIFTED_P:.+]] = shl i32 %a, %b | ||
// CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 | ||
// CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef | ||
|
||
// CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 | ||
// CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 | ||
// CHECK: ret { i32, i32 } %[[R1]] | ||
a.checked_shl(b) | ||
} | ||
|
||
// CHECK-LABEL: @checked_shr_unsigned | ||
// CHECK-SAME: (i32 noundef %a, i32 noundef %b) | ||
#[no_mangle] | ||
pub fn checked_shr_unsigned(a: u32, b: u32) -> Option<u32> { | ||
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 | ||
// CHECK-DAG: %[[SHIFTED_P:.+]] = lshr i32 %a, %b | ||
// CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 | ||
// CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef | ||
|
||
// CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 | ||
// CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 | ||
// CHECK: ret { i32, i32 } %[[R1]] | ||
a.checked_shr(b) | ||
} | ||
|
||
// CHECK-LABEL: @checked_shl_signed | ||
// CHECK-SAME: (i32 noundef %a, i32 noundef %b) | ||
#[no_mangle] | ||
pub fn checked_shl_signed(a: i32, b: u32) -> Option<i32> { | ||
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 | ||
// CHECK-DAG: %[[SHIFTED_P:.+]] = shl i32 %a, %b | ||
// CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 | ||
// CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef | ||
|
||
// CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 | ||
// CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 | ||
// CHECK: ret { i32, i32 } %[[R1]] | ||
a.checked_shl(b) | ||
} | ||
|
||
// CHECK-LABEL: @checked_shr_signed | ||
// CHECK-SAME: (i32 noundef %a, i32 noundef %b) | ||
#[no_mangle] | ||
pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> { | ||
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 | ||
// CHECK-DAG: %[[SHIFTED_P:.+]] = ashr i32 %a, %b | ||
// CHECK-DAG: %[[DISCR:.+]] = zext i1 %[[IS_SOME]] to i32 | ||
// CHECK-DAG: %[[SHIFTED_U:.+]] = select i1 %[[IS_SOME]], i32 %[[SHIFTED_P]], i32 undef | ||
|
||
// CHECK: %[[R0:.+]] = insertvalue { i32, i32 } poison, i32 %[[DISCR]], 0 | ||
// CHECK: %[[R1:.+]] = insertvalue { i32, i32 } %[[R0]], i32 %[[SHIFTED_U]], 1 | ||
// CHECK: ret { i32, i32 } %[[R1]] | ||
a.checked_shr(b) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters