diff options
| author | Scott McMurray <scottmcm@users.noreply.github.com> | 2025-02-14 20:25:43 -0800 |
|---|---|---|
| committer | Scott McMurray <scottmcm@users.noreply.github.com> | 2025-02-19 11:36:52 -0800 |
| commit | 511bf307f03d7045f54a376d389ebdf9786e7a24 (patch) | |
| tree | 3a9452d197ec7dd77d01de89cffa35dc39b7e230 /tests/codegen | |
| parent | ed49386d3aa3a445a9889707fd405df01723eced (diff) | |
| download | rust-511bf307f03d7045f54a376d389ebdf9786e7a24.tar.gz rust-511bf307f03d7045f54a376d389ebdf9786e7a24.zip | |
Emit `trunc nuw` for unchecked shifts and `to_immediate_scalar`
- For shifts this shrinks the IR by no longer needing an `assume` while still providing the UB information - Having this on the `i8`→`i1` truncations will hopefully help with some places that have to load `i8`s or pass those in LLVM structs without range information
Diffstat (limited to 'tests/codegen')
| -rw-r--r-- | tests/codegen/intrinsics/transmute-niched.rs | 2 | ||||
| -rw-r--r-- | tests/codegen/intrinsics/transmute.rs | 11 | ||||
| -rw-r--r-- | tests/codegen/transmute-scalar.rs | 2 | ||||
| -rw-r--r-- | tests/codegen/unchecked_shifts.rs | 58 | ||||
| -rw-r--r-- | tests/codegen/union-abi.rs | 2 |
5 files changed, 36 insertions, 39 deletions
diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs index 5ded0e192fa..8ff5cc8ee4f 100644 --- a/tests/codegen/intrinsics/transmute-niched.rs +++ b/tests/codegen/intrinsics/transmute-niched.rs @@ -170,7 +170,7 @@ pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool { // OPT: call void @llvm.assume(i1 %2) // CHECK-NOT: icmp // CHECK-NOT: assume - // CHECK: %[[R:.+]] = trunc i8 %x to i1 + // CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1 // CHECK: ret i1 %[[R]] transmute(x) diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 5b40a6a12c0..ff297b27065 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -11,6 +11,9 @@ use std::intrinsics::mir::*; use std::intrinsics::{transmute, transmute_unchecked}; use std::mem::MaybeUninit; +// FIXME(LLVM18REMOVED): `trunc nuw` doesn't exist in LLVM 18, so once we no +// longer support it the optional flag checks can be changed to required. + pub enum ZstNever {} #[repr(align(2))] @@ -153,7 +156,7 @@ pub unsafe fn check_from_newtype(x: Scalar64) -> u64 { pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool { // CHECK: %x = alloca [1 x i8], align 1 // CHECK: %[[BYTE:.+]] = load i8, ptr %x, align 1 - // CHECK: %[[BOOL:.+]] = trunc i8 %[[BYTE]] to i1 + // CHECK: %[[BOOL:.+]] = trunc{{( nuw)?}} i8 %[[BYTE]] to i1 // CHECK: ret i1 %[[BOOL]] transmute(x) } @@ -171,7 +174,7 @@ pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 { #[no_mangle] pub unsafe fn check_byte_to_bool(x: u8) -> bool { // CHECK-NOT: alloca - // CHECK: %[[R:.+]] = trunc i8 %x to i1 + // CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1 // CHECK: ret i1 %[[R]] transmute(x) } @@ -284,7 +287,7 @@ pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] { #[no_mangle] pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) { // CHECK-NOT: alloca - // CHECK: trunc i8 %x.0 to i1 + // CHECK: trunc{{( nuw)?}} i8 %x.0 to i1 // CHECK: zext i1 %x.1 to i8 transmute(x) } @@ -338,7 +341,7 @@ pub unsafe fn check_heterogeneous_integer_pair(x: (i32, bool)) -> (bool, u32) { // CHECK: store i8 %[[WIDER]] // CHECK: %[[BYTE:.+]] = load i8 - // CHECK: trunc i8 %[[BYTE:.+]] to i1 + // CHECK: trunc{{( nuw)?}} i8 %[[BYTE:.+]] to i1 // CHECK: load i32 transmute(x) } diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index 43da7c1781e..c080259a917 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -26,7 +26,7 @@ pub fn bool_to_byte(b: bool) -> u8 { } // CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) -// CHECK: %_0 = trunc i8 %byte to i1 +// CHECK: %_0 = trunc{{( nuw)?}} i8 %byte to i1 // CHECK-NEXT: ret i1 %_0 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs index b27eb73c0cc..a0d8990d29f 100644 --- a/tests/codegen/unchecked_shifts.rs +++ b/tests/codegen/unchecked_shifts.rs @@ -1,4 +1,10 @@ -//@ compile-flags: -Copt-level=3 +//@ revisions: LLVM18 LLVM19PLUS +//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes +//@[LLVM18] exact-llvm-major-version: 18 +//@[LLVM19PLUS] min-llvm-version: 19 + +// This runs mir-opts to inline the standard library call, but doesn't run LLVM +// optimizations so it doesn't need to worry about them adding more flags. #![crate_type = "lib"] #![feature(unchecked_shifts)] @@ -17,12 +23,9 @@ pub unsafe fn unchecked_shl_unsigned_same(a: u32, b: u32) -> u32 { // CHECK-LABEL: @unchecked_shl_unsigned_smaller #[no_mangle] pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { - // This uses -DAG to avoid failing on irrelevant reorderings, - // like emitting the truncation earlier. - - // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16 - // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i32 %b to i16 + // CHECK-NOT: assume + // LLVM18-DAG: %[[TRUNC:.+]] = trunc i32 %b to i16 + // LLVM19PLUS-DAG: %[[TRUNC:.+]] = trunc nuw i32 %b to i16 // CHECK-DAG: shl i16 %a, %[[TRUNC]] a.unchecked_shl(b) } @@ -31,7 +34,7 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { #[no_mangle] pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i32 %b to i64 + // CHECK: %[[EXT:.+]] = zext i32 %b to i64 // CHECK: shl i64 %a, %[[EXT]] a.unchecked_shl(b) } @@ -49,13 +52,10 @@ pub unsafe fn unchecked_shr_signed_same(a: i32, b: u32) -> i32 { // CHECK-LABEL: @unchecked_shr_signed_smaller #[no_mangle] pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { - // This uses -DAG to avoid failing on irrelevant reorderings, - // like emitting the truncation earlier. - - // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i32 %b, 16 - // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i32 %b to i16 - // CHECK-DAG: ashr i16 %a, %[[TRUNC]] + // CHECK-NOT: assume + // LLVM18: %[[TRUNC:.+]] = trunc i32 %b to i16 + // LLVM19PLUS: %[[TRUNC:.+]] = trunc nuw i32 %b to i16 + // CHECK: ashr i16 %a, %[[TRUNC]] a.unchecked_shr(b) } @@ -63,7 +63,7 @@ pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { #[no_mangle] pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i32 %b to i64 + // CHECK: %[[EXT:.+]] = zext i32 %b to i64 // CHECK: ashr i64 %a, %[[EXT]] a.unchecked_shr(b) } @@ -72,7 +72,7 @@ pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { #[no_mangle] pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 { // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i8 %b to i128 + // CHECK: %[[EXT:.+]] = zext i8 %b to i128 // CHECK: lshr i128 %a, %[[EXT]] std::intrinsics::unchecked_shr(a, b) } @@ -81,7 +81,7 @@ pub unsafe fn unchecked_shr_u128_i8(a: u128, b: i8) -> u128 { #[no_mangle] pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 { // CHECK-NOT: assume - // CHECK: %[[EXT:.+]] = zext{{( nneg)?}} i8 %b to i128 + // CHECK: %[[EXT:.+]] = zext i8 %b to i128 // CHECK: shl i128 %a, %[[EXT]] std::intrinsics::unchecked_shl(a, b) } @@ -89,25 +89,19 @@ pub unsafe fn unchecked_shl_i128_u8(a: i128, b: u8) -> i128 { // CHECK-LABEL: @unchecked_shl_u8_i128 #[no_mangle] pub unsafe fn unchecked_shl_u8_i128(a: u8, b: i128) -> u8 { - // This uses -DAG to avoid failing on irrelevant reorderings, - // like emitting the truncation earlier. - - // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8 - // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i128 %b to i8 - // CHECK-DAG: shl i8 %a, %[[TRUNC]] + // CHECK-NOT: assume + // LLVM18: %[[TRUNC:.+]] = trunc i128 %b to i8 + // LLVM19PLUS: %[[TRUNC:.+]] = trunc nuw i128 %b to i8 + // CHECK: shl i8 %a, %[[TRUNC]] std::intrinsics::unchecked_shl(a, b) } // CHECK-LABEL: @unchecked_shr_i8_u128 #[no_mangle] pub unsafe fn unchecked_shr_i8_u128(a: i8, b: u128) -> i8 { - // This uses -DAG to avoid failing on irrelevant reorderings, - // like emitting the truncation earlier. - - // CHECK-DAG: %[[INRANGE:.+]] = icmp ult i128 %b, 8 - // CHECK-DAG: tail call void @llvm.assume(i1 %[[INRANGE]]) - // CHECK-DAG: %[[TRUNC:.+]] = trunc{{( nuw)?( nsw)?}} i128 %b to i8 - // CHECK-DAG: ashr i8 %a, %[[TRUNC]] + // CHECK-NOT: assume + // LLVM18: %[[TRUNC:.+]] = trunc i128 %b to i8 + // LLVM19PLUS: %[[TRUNC:.+]] = trunc nuw i128 %b to i8 + // CHECK: ashr i8 %a, %[[TRUNC]] std::intrinsics::unchecked_shr(a, b) } diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs index 16022fad8af..28acc4de2f3 100644 --- a/tests/codegen/union-abi.rs +++ b/tests/codegen/union-abi.rs @@ -142,4 +142,4 @@ pub union UnionBool { pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } } -// CHECK: %_0 = trunc i8 %b to i1 +// CHECK: %_0 = trunc{{( nuw)?}} i8 %b to i1 |
