about summary refs log tree commit diff
path: root/tests/codegen
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-01-22 04:18:30 +0000
committerbors <bors@rust-lang.org>2025-01-22 04:18:30 +0000
commitb2728d5426bab1d8c39709768c7e22b7f66dde5d (patch)
tree87bf763b2ee84e7cb3c243efa7a43aa4595a024c /tests/codegen
parentc234b839d1681a7aa3abb1bda6f6f350714eacfe (diff)
parent6fe82006a4edf2d244f436aa7d14d985d0b1f39a (diff)
downloadrust-b2728d5426bab1d8c39709768c7e22b7f66dde5d.tar.gz
rust-b2728d5426bab1d8c39709768c7e22b7f66dde5d.zip
Auto merge of #135674 - scottmcm:assume-better, r=estebank
Update our range `assume`s to the format that LLVM prefers

I found out in https://github.com/llvm/llvm-project/issues/123278#issuecomment-2597440158 that the way I started emitting the `assume`s in #109993 was suboptimal, and as seen in that LLVM issue the way we're doing it -- with two `assume`s sometimes -- can at times lead to CVP/SCCP not realize what's happening because one of them turns into a `ne` instead of conveying a range.

So this updates how it's emitted from
```
assume( x >= LOW );
assume( x <= HIGH );
```
or
```
// (for ranges that wrap the range)
assume( (x <= LOW) | (x >= HIGH) );
```
to
```
assume( (x - LOW) <= (HIGH - LOW) );
```
so that we don't need multiple `icmp`s nor multiple `assume`s for a single value, and both wrappping and non-wrapping ranges emit the same shape.

(And we don't bother emitting the subtraction if `LOW` is zero, since that's trivial for us to check too.)
Diffstat (limited to 'tests/codegen')
-rw-r--r--tests/codegen/intrinsics/transmute-niched.rs122
-rw-r--r--tests/codegen/transmute-optimized.rs8
2 files changed, 75 insertions, 55 deletions
diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs
index f5b7bd2efea..88119ccb8b2 100644
--- a/tests/codegen/intrinsics/transmute-niched.rs
+++ b/tests/codegen/intrinsics/transmute-niched.rs
@@ -17,12 +17,13 @@ pub enum SmallEnum {
 // CHECK-LABEL: @check_to_enum(
 #[no_mangle]
 pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
-    // OPT: %0 = icmp uge i8 %x, 10
-    // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp ule i8 %x, 12
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, 10
+    // OPT: %1 = icmp ule i8 %0, 2
     // OPT: call void @llvm.assume(i1 %1)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -31,12 +32,13 @@ pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
 // CHECK-LABEL: @check_from_enum(
 #[no_mangle]
 pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
-    // OPT: %0 = icmp uge i8 %x, 10
-    // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp ule i8 %x, 12
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, 10
+    // OPT: %1 = icmp ule i8 %0, 2
     // OPT: call void @llvm.assume(i1 %1)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -45,12 +47,13 @@ pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
 // CHECK-LABEL: @check_to_ordering(
 #[no_mangle]
 pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
-    // OPT: call void @llvm.assume(i1 %2)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -59,12 +62,13 @@ pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
 // CHECK-LABEL: @check_from_ordering(
 #[no_mangle]
 pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
-    // OPT: call void @llvm.assume(i1 %2)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -98,14 +102,15 @@ pub enum Minus100ToPlus100 {
 // CHECK-LABEL: @check_enum_from_char(
 #[no_mangle]
 pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i32 %x, 1114111
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i32 %x, -100
-    // OPT: %2 = icmp ule i32 %x, 100
-    // OPT: %3 = or i1 %1, %2
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %1 = sub i32 %x, -100
+    // OPT: %2 = icmp ule i32 %1, 200
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i32 %x
 
     transmute(x)
@@ -114,14 +119,15 @@ pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
 // CHECK-LABEL: @check_enum_to_char(
 #[no_mangle]
 pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
-    // OPT: %0 = icmp uge i32 %x, -100
-    // OPT: %1 = icmp ule i32 %x, 100
-    // OPT: %2 = or i1 %0, %1
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i32 %x, -100
+    // OPT: %1 = icmp ule i32 %0, 200
+    // OPT: call void @llvm.assume(i1 %1)
+    // OPT: %2 = icmp ule i32 %x, 1114111
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i32 %x, 1114111
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i32 %x
 
     transmute(x)
@@ -130,16 +136,20 @@ pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
 // CHECK-LABEL: @check_swap_pair(
 #[no_mangle]
 pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i32 %x.0, 1114111
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i32 %x.0, 1
-    // OPT: call void @llvm.assume(i1 %1)
-    // OPT: %2 = icmp uge i32 %x.1, 1
+    // OPT: %1 = sub i32 %x.0, 1
+    // OPT: %2 = icmp ule i32 %1, -2
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i32 %x.1, 1114111
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %3 = sub i32 %x.1, 1
+    // OPT: %4 = icmp ule i32 %3, -2
+    // OPT: call void @llvm.assume(i1 %4)
+    // OPT: %5 = icmp ule i32 %x.1, 1114111
+    // OPT: call void @llvm.assume(i1 %5)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0
     // CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1
     // CHECK: ret { i32, i32 } %[[P2]]
@@ -150,14 +160,15 @@ pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
 // CHECK-LABEL: @check_bool_from_ordering(
 #[no_mangle]
 pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // OPT: %2 = icmp ule i8 %x, 1
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i8 %x, 1
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: %[[R:.+]] = trunc i8 %x to i1
     // CHECK: ret i1 %[[R]]
 
@@ -168,14 +179,15 @@ pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
 #[no_mangle]
 pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
     // CHECK: %_0 = zext i1 %x to i8
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i8 %_0, 1
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i8 %_0, -1
-    // OPT: %2 = icmp ule i8 %_0, 1
-    // OPT: %3 = or i1 %1, %2
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %1 = sub i8 %_0, -1
+    // OPT: %2 = icmp ule i8 %1, 2
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %_0
 
     transmute(x)
diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs
index 11bd0523788..de54eecf0c0 100644
--- a/tests/codegen/transmute-optimized.rs
+++ b/tests/codegen/transmute-optimized.rs
@@ -110,3 +110,11 @@ pub fn char_is_negative(c: char) -> bool {
     let x: i32 = unsafe { std::mem::transmute(c) };
     x < 0
 }
+
+// CHECK-LABEL: i1 @transmute_to_char_is_negative(i32
+#[no_mangle]
+pub fn transmute_to_char_is_negative(x: i32) -> bool {
+    // CHECK: ret i1 false
+    let _c: char = unsafe { std::mem::transmute(x) };
+    x < 0
+}