From 8f42943ff0b821433baade71402b5ece577e5520 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Mon, 16 Mar 2026 15:02:18 +0100 Subject: [PATCH] add cast evaluation for better MIR --- compiler/rustc_ast_lowering/src/format.rs | 5 +- compiler/rustc_mir_transform/src/gvn.rs | 43 +++++++++- .../index_cast.array.GVN.32bit.diff | 40 +++++++++ .../index_cast.array.GVN.64bit.diff | 40 +++++++++ .../const_prop/index_cast.ge.GVN.32bit.diff | 71 ++++++++++++++++ .../const_prop/index_cast.ge.GVN.64bit.diff | 71 ++++++++++++++++ .../const_prop/index_cast.gt.GVN.32bit.diff | 49 +++++++++++ .../const_prop/index_cast.gt.GVN.64bit.diff | 49 +++++++++++ .../const_prop/index_cast.le.GVN.32bit.diff | 71 ++++++++++++++++ .../const_prop/index_cast.le.GVN.64bit.diff | 71 ++++++++++++++++ .../const_prop/index_cast.lt.GVN.32bit.diff | 49 +++++++++++ .../const_prop/index_cast.lt.GVN.64bit.diff | 49 +++++++++++ tests/mir-opt/const_prop/index_cast.rs | 81 +++++++++++++++++++ ...stant_index_overflow.GVN.panic-unwind.diff | 15 ++-- 14 files changed, 694 insertions(+), 10 deletions(-) create mode 100644 tests/mir-opt/const_prop/index_cast.array.GVN.32bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.array.GVN.64bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.ge.GVN.32bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.ge.GVN.64bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.gt.GVN.32bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.gt.GVN.64bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.le.GVN.32bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.le.GVN.64bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.lt.GVN.32bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.lt.GVN.64bit.diff create mode 100644 tests/mir-opt/const_prop/index_cast.rs diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 1f1f86f7edfd7..0e6838530d264 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; +use rustc_middle::mir::interpret::PointerArithmetic; use rustc_session::config::FmtDebug; use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym}; @@ -56,7 +57,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { /// Get the maximum value of int_ty. It is platform-dependent due to the byte size of isize fn int_ty_max(&self, int_ty: IntTy) -> u128 { match int_ty { - IntTy::Isize => self.tcx.data_layout.pointer_size().signed_int_max() as u128, + IntTy::Isize => self.tcx.target_isize_max() as u128, IntTy::I8 => i8::MAX as u128, IntTy::I16 => i16::MAX as u128, IntTy::I32 => i32::MAX as u128, @@ -68,7 +69,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { /// Get the maximum value of uint_ty. It is platform-dependent due to the byte size of usize fn uint_ty_max(&self, uint_ty: UintTy) -> u128 { match uint_ty { - UintTy::Usize => self.tcx.data_layout.pointer_size().unsigned_int_max(), + UintTy::Usize => self.tcx.target_usize_max() as u128, UintTy::U8 => u8::MAX as u128, UintTy::U16 => u16::MAX as u128, UintTy::U32 => u32::MAX as u128, diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 245ee6ec1cb75..38579790aa374 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -91,7 +91,9 @@ use std::hash::{Hash, Hasher}; use either::Either; use itertools::Itertools as _; -use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx}; +use rustc_abi::{ + self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Integer, Primitive, Size, VariantIdx, +}; use rustc_arena::DroplessArena; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ @@ -108,7 +110,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{AllocRange, GlobalAlloc}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::layout::HasTypingEnv; +use rustc_middle::ty::layout::{HasTypingEnv, IntegerExt}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use smallvec::SmallVec; @@ -1482,6 +1484,33 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { (BinOp::Eq, a, b) if a == b => self.insert_bool(true), (BinOp::Ne, Left(a), Left(b)) => self.insert_bool(a != b), (BinOp::Ne, a, b) if a == b => self.insert_bool(false), + // When casting from a value, and comparing with a literal + // compare the maximum value with this literal + // to see if it's possible omit the runtime check + (BinOp::Lt, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a < b) => { + self.insert_bool(true) + } + (BinOp::Lt, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a >= b) => { + self.insert_bool(false) + } + (BinOp::Le, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a <= b) => { + self.insert_bool(true) + } + (BinOp::Le, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a > b) => { + self.insert_bool(false) + } + (BinOp::Gt, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a > b) => { + self.insert_bool(true) + } + (BinOp::Gt, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a <= b) => { + self.insert_bool(false) + } + (BinOp::Ge, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a >= b) => { + self.insert_bool(true) + } + (BinOp::Ge, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a < b) => { + self.insert_bool(false) + } _ => return None, }; @@ -1494,6 +1523,16 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { } } + fn max_value_of_cast(&self, value: VnIndex) -> Option { + if let Value::Cast { kind: CastKind::IntToInt, value } = self.get(value) { + self.max_value_of_cast(value) + } else if let ty::Uint(uty) = self.ty(value).kind() { + Some(Integer::from_uint_ty(&self.tcx, *uty).size().unsigned_int_max()) + } else { + None + } + } + fn simplify_cast( &mut self, initial_kind: &mut CastKind, diff --git a/tests/mir-opt/const_prop/index_cast.array.GVN.32bit.diff b/tests/mir-opt/const_prop/index_cast.array.GVN.32bit.diff new file mode 100644 index 0000000000000..89a17dd11c036 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.array.GVN.32bit.diff @@ -0,0 +1,40 @@ +- // MIR for `array` before GVN ++ // MIR for `array` after GVN + + fn array(_1: [i32; 256], _2: u8) -> () { + debug input => _1; + debug lit => _2; + let mut _0: (); + let _3: i32; + let _4: usize; + let mut _5: u8; + let mut _6: bool; + scope 1 { + debug x => _3; + } + + bb0: { + StorageLive(_3); +- StorageLive(_4); ++ nop; + StorageLive(_5); + _5 = copy _2; +- _4 = move _5 as usize (IntToInt); ++ _4 = copy _2 as usize (IntToInt); + StorageDead(_5); +- _6 = Lt(copy _4, const 256_usize); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 256_usize, copy _4) -> [success: bb1, unwind continue]; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 256_usize, copy _4) -> [success: bb1, unwind continue]; + } + + bb1: { + _3 = copy _1[_4]; +- StorageDead(_4); ++ nop; + _0 = const (); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.array.GVN.64bit.diff b/tests/mir-opt/const_prop/index_cast.array.GVN.64bit.diff new file mode 100644 index 0000000000000..89a17dd11c036 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.array.GVN.64bit.diff @@ -0,0 +1,40 @@ +- // MIR for `array` before GVN ++ // MIR for `array` after GVN + + fn array(_1: [i32; 256], _2: u8) -> () { + debug input => _1; + debug lit => _2; + let mut _0: (); + let _3: i32; + let _4: usize; + let mut _5: u8; + let mut _6: bool; + scope 1 { + debug x => _3; + } + + bb0: { + StorageLive(_3); +- StorageLive(_4); ++ nop; + StorageLive(_5); + _5 = copy _2; +- _4 = move _5 as usize (IntToInt); ++ _4 = copy _2 as usize (IntToInt); + StorageDead(_5); +- _6 = Lt(copy _4, const 256_usize); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 256_usize, copy _4) -> [success: bb1, unwind continue]; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 256_usize, copy _4) -> [success: bb1, unwind continue]; + } + + bb1: { + _3 = copy _1[_4]; +- StorageDead(_4); ++ nop; + _0 = const (); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.ge.GVN.32bit.diff b/tests/mir-opt/const_prop/index_cast.ge.GVN.32bit.diff new file mode 100644 index 0000000000000..7cbc28a8c6b1f --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.ge.GVN.32bit.diff @@ -0,0 +1,71 @@ +- // MIR for `ge` before GVN ++ // MIR for `ge` after GVN + + fn ge(_1: u32) -> () { + debug input => _1; + let mut _0: (); + let _2: bool; + let mut _3: u64; + let mut _4: u32; + let mut _6: u64; + let mut _7: u32; + let mut _8: u64; + let mut _10: u64; + let mut _11: u32; + scope 1 { + debug yes => _2; + let _5: bool; + scope 2 { + debug runtime => _5; + let _9: bool; + scope 3 { + debug no => _9; + } + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as u64 (IntToInt); ++ _3 = copy _1 as u64 (IntToInt); + StorageDead(_4); +- _2 = Ge(const U32_MAX_PLUS_ONE, move _3); +- StorageDead(_3); ++ _2 = const true; ++ nop; + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _1; +- _6 = move _7 as u64 (IntToInt); ++ _6 = copy _3; + StorageDead(_7); + StorageLive(_8); +- _8 = const core::num::::MAX as u64 (IntToInt); +- _5 = Ge(move _6, move _8); ++ _8 = const 4294967295_u64; ++ _5 = Ge(copy _3, const 4294967295_u64); + StorageDead(_8); + StorageDead(_6); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = copy _1; +- _10 = move _11 as u64 (IntToInt); ++ _10 = copy _3; + StorageDead(_11); +- _9 = Ge(move _10, const U32_MAX_PLUS_ONE); ++ _9 = const false; + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.ge.GVN.64bit.diff b/tests/mir-opt/const_prop/index_cast.ge.GVN.64bit.diff new file mode 100644 index 0000000000000..7cbc28a8c6b1f --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.ge.GVN.64bit.diff @@ -0,0 +1,71 @@ +- // MIR for `ge` before GVN ++ // MIR for `ge` after GVN + + fn ge(_1: u32) -> () { + debug input => _1; + let mut _0: (); + let _2: bool; + let mut _3: u64; + let mut _4: u32; + let mut _6: u64; + let mut _7: u32; + let mut _8: u64; + let mut _10: u64; + let mut _11: u32; + scope 1 { + debug yes => _2; + let _5: bool; + scope 2 { + debug runtime => _5; + let _9: bool; + scope 3 { + debug no => _9; + } + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as u64 (IntToInt); ++ _3 = copy _1 as u64 (IntToInt); + StorageDead(_4); +- _2 = Ge(const U32_MAX_PLUS_ONE, move _3); +- StorageDead(_3); ++ _2 = const true; ++ nop; + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _1; +- _6 = move _7 as u64 (IntToInt); ++ _6 = copy _3; + StorageDead(_7); + StorageLive(_8); +- _8 = const core::num::::MAX as u64 (IntToInt); +- _5 = Ge(move _6, move _8); ++ _8 = const 4294967295_u64; ++ _5 = Ge(copy _3, const 4294967295_u64); + StorageDead(_8); + StorageDead(_6); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = copy _1; +- _10 = move _11 as u64 (IntToInt); ++ _10 = copy _3; + StorageDead(_11); +- _9 = Ge(move _10, const U32_MAX_PLUS_ONE); ++ _9 = const false; + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.gt.GVN.32bit.diff b/tests/mir-opt/const_prop/index_cast.gt.GVN.32bit.diff new file mode 100644 index 0000000000000..de855cb17fd33 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.gt.GVN.32bit.diff @@ -0,0 +1,49 @@ +- // MIR for `gt` before GVN ++ // MIR for `gt` after GVN + + fn gt(_1: u8) -> () { + debug input => _1; + let mut _0: (); + let _2: bool; + let mut _3: u16; + let mut _4: u8; + let mut _6: u16; + let mut _7: u8; + scope 1 { + debug yes => _2; + let _5: bool; + scope 2 { + debug no => _5; + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as u16 (IntToInt); ++ _3 = copy _1 as u16 (IntToInt); + StorageDead(_4); +- _2 = Gt(const 256_u16, move _3); +- StorageDead(_3); ++ _2 = const true; ++ nop; + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _1; +- _6 = move _7 as u16 (IntToInt); ++ _6 = copy _3; + StorageDead(_7); +- _5 = Gt(move _6, const 256_u16); ++ _5 = const false; + StorageDead(_6); + _0 = const (); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.gt.GVN.64bit.diff b/tests/mir-opt/const_prop/index_cast.gt.GVN.64bit.diff new file mode 100644 index 0000000000000..de855cb17fd33 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.gt.GVN.64bit.diff @@ -0,0 +1,49 @@ +- // MIR for `gt` before GVN ++ // MIR for `gt` after GVN + + fn gt(_1: u8) -> () { + debug input => _1; + let mut _0: (); + let _2: bool; + let mut _3: u16; + let mut _4: u8; + let mut _6: u16; + let mut _7: u8; + scope 1 { + debug yes => _2; + let _5: bool; + scope 2 { + debug no => _5; + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as u16 (IntToInt); ++ _3 = copy _1 as u16 (IntToInt); + StorageDead(_4); +- _2 = Gt(const 256_u16, move _3); +- StorageDead(_3); ++ _2 = const true; ++ nop; + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _1; +- _6 = move _7 as u16 (IntToInt); ++ _6 = copy _3; + StorageDead(_7); +- _5 = Gt(move _6, const 256_u16); ++ _5 = const false; + StorageDead(_6); + _0 = const (); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.le.GVN.32bit.diff b/tests/mir-opt/const_prop/index_cast.le.GVN.32bit.diff new file mode 100644 index 0000000000000..e26278f8ee4b7 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.le.GVN.32bit.diff @@ -0,0 +1,71 @@ +- // MIR for `le` before GVN ++ // MIR for `le` after GVN + + fn le(_1: u16) -> () { + debug input => _1; + let mut _0: (); + let _2: bool; + let mut _3: u32; + let mut _4: u16; + let mut _6: u32; + let mut _7: u32; + let mut _8: u16; + let mut _10: u32; + let mut _11: u16; + scope 1 { + debug yes => _2; + let _5: bool; + scope 2 { + debug runtime => _5; + let _9: bool; + scope 3 { + debug no => _9; + } + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as u32 (IntToInt); ++ _3 = copy _1 as u32 (IntToInt); + StorageDead(_4); +- _2 = Le(move _3, const U16_MAX_PLUS_ONE); +- StorageDead(_3); ++ _2 = const true; ++ nop; + StorageLive(_5); + StorageLive(_6); +- _6 = const core::num::::MAX as u32 (IntToInt); ++ _6 = const 65535_u32; + StorageLive(_7); + StorageLive(_8); + _8 = copy _1; +- _7 = move _8 as u32 (IntToInt); ++ _7 = copy _3; + StorageDead(_8); +- _5 = Le(move _6, move _7); ++ _5 = Le(const 65535_u32, copy _3); + StorageDead(_7); + StorageDead(_6); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = copy _1; +- _10 = move _11 as u32 (IntToInt); ++ _10 = copy _3; + StorageDead(_11); +- _9 = Le(const U16_MAX_PLUS_ONE, move _10); ++ _9 = const false; + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.le.GVN.64bit.diff b/tests/mir-opt/const_prop/index_cast.le.GVN.64bit.diff new file mode 100644 index 0000000000000..e26278f8ee4b7 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.le.GVN.64bit.diff @@ -0,0 +1,71 @@ +- // MIR for `le` before GVN ++ // MIR for `le` after GVN + + fn le(_1: u16) -> () { + debug input => _1; + let mut _0: (); + let _2: bool; + let mut _3: u32; + let mut _4: u16; + let mut _6: u32; + let mut _7: u32; + let mut _8: u16; + let mut _10: u32; + let mut _11: u16; + scope 1 { + debug yes => _2; + let _5: bool; + scope 2 { + debug runtime => _5; + let _9: bool; + scope 3 { + debug no => _9; + } + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as u32 (IntToInt); ++ _3 = copy _1 as u32 (IntToInt); + StorageDead(_4); +- _2 = Le(move _3, const U16_MAX_PLUS_ONE); +- StorageDead(_3); ++ _2 = const true; ++ nop; + StorageLive(_5); + StorageLive(_6); +- _6 = const core::num::::MAX as u32 (IntToInt); ++ _6 = const 65535_u32; + StorageLive(_7); + StorageLive(_8); + _8 = copy _1; +- _7 = move _8 as u32 (IntToInt); ++ _7 = copy _3; + StorageDead(_8); +- _5 = Le(move _6, move _7); ++ _5 = Le(const 65535_u32, copy _3); + StorageDead(_7); + StorageDead(_6); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = copy _1; +- _10 = move _11 as u32 (IntToInt); ++ _10 = copy _3; + StorageDead(_11); +- _9 = Le(const U16_MAX_PLUS_ONE, move _10); ++ _9 = const false; + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.lt.GVN.32bit.diff b/tests/mir-opt/const_prop/index_cast.lt.GVN.32bit.diff new file mode 100644 index 0000000000000..a9c6860b3dbd2 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.lt.GVN.32bit.diff @@ -0,0 +1,49 @@ +- // MIR for `lt` before GVN ++ // MIR for `lt` after GVN + + fn lt(_1: u8) -> () { + debug input => _1; + let mut _0: (); + let _2: bool; + let mut _3: u64; + let mut _4: u8; + let mut _6: u64; + let mut _7: u8; + scope 1 { + debug yes => _2; + let _5: bool; + scope 2 { + debug no => _5; + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as u64 (IntToInt); ++ _3 = copy _1 as u64 (IntToInt); + StorageDead(_4); +- _2 = Gt(const 256_u64, move _3); +- StorageDead(_3); ++ _2 = const true; ++ nop; + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _1; +- _6 = move _7 as u64 (IntToInt); ++ _6 = copy _3; + StorageDead(_7); +- _5 = Gt(move _6, const 256_u64); ++ _5 = const false; + StorageDead(_6); + _0 = const (); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.lt.GVN.64bit.diff b/tests/mir-opt/const_prop/index_cast.lt.GVN.64bit.diff new file mode 100644 index 0000000000000..a9c6860b3dbd2 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.lt.GVN.64bit.diff @@ -0,0 +1,49 @@ +- // MIR for `lt` before GVN ++ // MIR for `lt` after GVN + + fn lt(_1: u8) -> () { + debug input => _1; + let mut _0: (); + let _2: bool; + let mut _3: u64; + let mut _4: u8; + let mut _6: u64; + let mut _7: u8; + scope 1 { + debug yes => _2; + let _5: bool; + scope 2 { + debug no => _5; + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as u64 (IntToInt); ++ _3 = copy _1 as u64 (IntToInt); + StorageDead(_4); +- _2 = Gt(const 256_u64, move _3); +- StorageDead(_3); ++ _2 = const true; ++ nop; + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _1; +- _6 = move _7 as u64 (IntToInt); ++ _6 = copy _3; + StorageDead(_7); +- _5 = Gt(move _6, const 256_u64); ++ _5 = const false; + StorageDead(_6); + _0 = const (); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/const_prop/index_cast.rs b/tests/mir-opt/const_prop/index_cast.rs new file mode 100644 index 0000000000000..1ae60208daa10 --- /dev/null +++ b/tests/mir-opt/const_prop/index_cast.rs @@ -0,0 +1,81 @@ +//@ test-mir-pass: GVN +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +fn main() {} + +// EMIT_MIR index_cast.array.GVN.diff +fn array(input: [i32; 256], lit: u8) { + // CHECK-LABEL: fn array(_1: [i32; 256], _2: u8) -> () { + // CHECK: debug x => _3; + + // CHECK: assert(const true + // CHECK: _3 = copy _1[_4]; + let x = input[lit as usize]; +} + +// EMIT_MIR index_cast.lt.GVN.diff +fn lt(input: u8) { + // CHECK-LABEL: fn lt(_1: u8) -> () { + + // CHECK: debug yes => _2; + // CHECK: debug no => _5; + + // CHECK: _2 = const true; + let yes = 256u64 > (input as u64); + + // CHECK: _5 = const false; + let no = (input as u64) > 256u64; +} + +// EMIT_MIR index_cast.le.GVN.diff +fn le(input: u16) { + // CHECK-LABEL: fn le(_1: u16) -> () { + + // CHECK: debug yes => _2; + // CHECK: debug runtime => _5; + // CHECK: debug no => _9; + + // CHECK: _2 = const true; + let yes = (input as u32) <= U16_MAX_PLUS_ONE; + + // CHECK: _5 = Le(const 65535_u32, copy _3); + let runtime = u16::MAX as u32 <= (input as u32); + + // CHECK: _9 = const false; + let no = U16_MAX_PLUS_ONE <= (input as u32); +} + +// EMIT_MIR index_cast.gt.GVN.diff +fn gt(input: u8) { + // CHECK-LABEL: fn gt(_1: u8) -> () { + + // CHECK: debug yes => _2; + // CHECK: debug no => _5; + + // CHECK: _2 = const true; + let yes = 256u16 > (input as u16); + + // CHECK: _5 = const false; + let no = (input as u16) > 256u16; +} + +// EMIT_MIR index_cast.ge.GVN.diff +fn ge(input: u32) { + // CHECK-LABEL: fn ge(_1: u32) -> () { + + // CHECK: debug yes => _2; + // CHECK: debug runtime => _5; + // CHECK: debug no => _9; + + // CHECK: _2 = const true; + let yes = U32_MAX_PLUS_ONE >= (input as u64); + + // CHECK: _5 = Ge(copy _3 + let runtime = (input as u64) >= u32::MAX as u64; + + // CHECK: _9 = const false; + let no = (input as u64) >= U32_MAX_PLUS_ONE; +} + +const U16_MAX_PLUS_ONE: u32 = (u16::MAX as u32) + 1u32; +const U32_MAX_PLUS_ONE: u64 = (u32::MAX as u64) + 1u64; diff --git a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff index 03e8aa3bd9b98..c8ff1eb02df66 100644 --- a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff @@ -30,7 +30,8 @@ + nop; + _2 = const usize::MAX; StorageLive(_3); - StorageLive(_4); +- StorageLive(_4); ++ nop; StorageLive(_5); - _5 = copy _2; + _5 = const usize::MAX; @@ -43,8 +44,9 @@ bb1: { StorageDead(_7); - _4 = Lt(move _5, move _6); -+ _4 = Lt(const usize::MAX, move _6); - switchInt(move _4) -> [0: bb4, otherwise: bb2]; +- switchInt(move _4) -> [0: bb4, otherwise: bb2]; ++ _4 = const false; ++ switchInt(const false) -> [0: bb4, otherwise: bb2]; } bb2: { @@ -56,8 +58,8 @@ _9 = PtrMetadata(copy _1); - _10 = Lt(copy _8, copy _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue]; -+ _10 = Lt(const usize::MAX, copy _9); -+ assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const usize::MAX) -> [success: bb3, unwind continue]; ++ _10 = const false; ++ assert(const false, "index out of bounds: the length is {} but the index is {}", move _9, const usize::MAX) -> [success: bb3, unwind continue]; } bb3: { @@ -87,7 +89,8 @@ } bb6: { - StorageDead(_4); +- StorageDead(_4); ++ nop; StorageLive(_14); _14 = copy _3; _0 = opaque::(move _14) -> [return: bb7, unwind continue];