Skip to content

Commit 1703a0a

Browse files
committed
add cast evaluation for better MIR
1 parent 86c839f commit 1703a0a

15 files changed

Lines changed: 708 additions & 10 deletions

compiler/rustc_ast_lowering/src/format.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::borrow::Cow;
33
use rustc_ast::*;
44
use rustc_data_structures::fx::FxIndexMap;
55
use rustc_hir as hir;
6+
use rustc_middle::mir::interpret::PointerArithmetic;
67
use rustc_session::config::FmtDebug;
78
use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym};
89

@@ -56,7 +57,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
5657
/// Get the maximum value of int_ty. It is platform-dependent due to the byte size of isize
5758
fn int_ty_max(&self, int_ty: IntTy) -> u128 {
5859
match int_ty {
59-
IntTy::Isize => self.tcx.data_layout.pointer_size().signed_int_max() as u128,
60+
IntTy::Isize => self.tcx.target_isize_max() as u128,
6061
IntTy::I8 => i8::MAX as u128,
6162
IntTy::I16 => i16::MAX as u128,
6263
IntTy::I32 => i32::MAX as u128,
@@ -68,7 +69,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
6869
/// Get the maximum value of uint_ty. It is platform-dependent due to the byte size of usize
6970
fn uint_ty_max(&self, uint_ty: UintTy) -> u128 {
7071
match uint_ty {
71-
UintTy::Usize => self.tcx.data_layout.pointer_size().unsigned_int_max(),
72+
UintTy::Usize => self.tcx.target_usize_max() as u128,
7273
UintTy::U8 => u8::MAX as u128,
7374
UintTy::U16 => u16::MAX as u128,
7475
UintTy::U32 => u32::MAX as u128,

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ use std::hash::{Hash, Hasher};
9191

9292
use either::Either;
9393
use itertools::Itertools as _;
94-
use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx};
94+
use rustc_abi::{
95+
self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Integer, Primitive, Size, VariantIdx,
96+
};
9597
use rustc_arena::DroplessArena;
9698
use rustc_const_eval::const_eval::DummyMachine;
9799
use rustc_const_eval::interpret::{
@@ -108,7 +110,7 @@ use rustc_middle::bug;
108110
use rustc_middle::mir::interpret::{AllocRange, GlobalAlloc};
109111
use rustc_middle::mir::visit::*;
110112
use rustc_middle::mir::*;
111-
use rustc_middle::ty::layout::HasTypingEnv;
113+
use rustc_middle::ty::layout::{HasTypingEnv, IntegerExt};
112114
use rustc_middle::ty::{self, Ty, TyCtxt};
113115
use rustc_span::DUMMY_SP;
114116
use smallvec::SmallVec;
@@ -1482,6 +1484,33 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
14821484
(BinOp::Eq, a, b) if a == b => self.insert_bool(true),
14831485
(BinOp::Ne, Left(a), Left(b)) => self.insert_bool(a != b),
14841486
(BinOp::Ne, a, b) if a == b => self.insert_bool(false),
1487+
// When casting from a value, and comparing with a literal
1488+
// compare the maximum value with this literal
1489+
// to see if it's possible omit the runtime check
1490+
(BinOp::Lt, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a < b) => {
1491+
self.insert_bool(true)
1492+
}
1493+
(BinOp::Lt, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a >= b) => {
1494+
self.insert_bool(false)
1495+
}
1496+
(BinOp::Le, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a <= b) => {
1497+
self.insert_bool(true)
1498+
}
1499+
(BinOp::Le, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a > b) => {
1500+
self.insert_bool(false)
1501+
}
1502+
(BinOp::Gt, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a > b) => {
1503+
self.insert_bool(true)
1504+
}
1505+
(BinOp::Gt, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a <= b) => {
1506+
self.insert_bool(false)
1507+
}
1508+
(BinOp::Ge, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a >= b) => {
1509+
self.insert_bool(true)
1510+
}
1511+
(BinOp::Ge, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a < b) => {
1512+
self.insert_bool(false)
1513+
}
14851514
_ => return None,
14861515
};
14871516

@@ -1494,6 +1523,16 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
14941523
}
14951524
}
14961525

1526+
fn max_value_of_cast(&self, value: VnIndex) -> Option<u128> {
1527+
if let Value::Cast { kind: CastKind::IntToInt, value } = self.get(value) {
1528+
self.max_value_of_cast(value)
1529+
} else if let ty::Uint(uty) = self.ty(value).kind() {
1530+
Some(Integer::from_uint_ty(&self.tcx, *uty).size().unsigned_int_max())
1531+
} else {
1532+
None
1533+
}
1534+
}
1535+
14971536
fn simplify_cast(
14981537
&mut self,
14991538
initial_kind: &mut CastKind,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ test-mir-pass: GVN
2+
// EMIT_MIR_FOR_EACH_BIT_WIDTH
3+
//@ revisions: x86 x86_64
4+
//@[x86] compile-flags: --host i686-unknown-linux-gnu
5+
//@[x86_64] compile-flags: --host x86_64-unknown-linux-gnu
6+
7+
// EMIT_MIR cast_target_usize.target_usize.GVN.diff
8+
fn target_usize() {
9+
// CHECK-LABEL: fn target_usize() -> () {
10+
// x86: const false
11+
// x86_64: const true
12+
13+
assert!(usize::MAX as u64 > 5_000_000_000)
14+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
- // MIR for `array` before GVN
2+
+ // MIR for `array` after GVN
3+
4+
fn array(_1: [i32; 256], _2: u8) -> () {
5+
debug input => _1;
6+
debug lit => _2;
7+
let mut _0: ();
8+
let _3: i32;
9+
let _4: usize;
10+
let mut _5: u8;
11+
let mut _6: bool;
12+
scope 1 {
13+
debug x => _3;
14+
}
15+
16+
bb0: {
17+
StorageLive(_3);
18+
- StorageLive(_4);
19+
+ nop;
20+
StorageLive(_5);
21+
_5 = copy _2;
22+
- _4 = move _5 as usize (IntToInt);
23+
+ _4 = copy _2 as usize (IntToInt);
24+
StorageDead(_5);
25+
- _6 = Lt(copy _4, const 256_usize);
26+
- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 256_usize, copy _4) -> [success: bb1, unwind continue];
27+
+ _6 = const true;
28+
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 256_usize, copy _4) -> [success: bb1, unwind continue];
29+
}
30+
31+
bb1: {
32+
_3 = copy _1[_4];
33+
- StorageDead(_4);
34+
+ nop;
35+
_0 = const ();
36+
StorageDead(_3);
37+
return;
38+
}
39+
}
40+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
- // MIR for `array` before GVN
2+
+ // MIR for `array` after GVN
3+
4+
fn array(_1: [i32; 256], _2: u8) -> () {
5+
debug input => _1;
6+
debug lit => _2;
7+
let mut _0: ();
8+
let _3: i32;
9+
let _4: usize;
10+
let mut _5: u8;
11+
let mut _6: bool;
12+
scope 1 {
13+
debug x => _3;
14+
}
15+
16+
bb0: {
17+
StorageLive(_3);
18+
- StorageLive(_4);
19+
+ nop;
20+
StorageLive(_5);
21+
_5 = copy _2;
22+
- _4 = move _5 as usize (IntToInt);
23+
+ _4 = copy _2 as usize (IntToInt);
24+
StorageDead(_5);
25+
- _6 = Lt(copy _4, const 256_usize);
26+
- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 256_usize, copy _4) -> [success: bb1, unwind continue];
27+
+ _6 = const true;
28+
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 256_usize, copy _4) -> [success: bb1, unwind continue];
29+
}
30+
31+
bb1: {
32+
_3 = copy _1[_4];
33+
- StorageDead(_4);
34+
+ nop;
35+
_0 = const ();
36+
StorageDead(_3);
37+
return;
38+
}
39+
}
40+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
- // MIR for `ge` before GVN
2+
+ // MIR for `ge` after GVN
3+
4+
fn ge(_1: u32) -> () {
5+
debug input => _1;
6+
let mut _0: ();
7+
let _2: bool;
8+
let mut _3: u64;
9+
let mut _4: u32;
10+
let mut _6: u64;
11+
let mut _7: u32;
12+
let mut _8: u64;
13+
let mut _10: u64;
14+
let mut _11: u32;
15+
scope 1 {
16+
debug yes => _2;
17+
let _5: bool;
18+
scope 2 {
19+
debug runtime => _5;
20+
let _9: bool;
21+
scope 3 {
22+
debug no => _9;
23+
}
24+
}
25+
}
26+
27+
bb0: {
28+
StorageLive(_2);
29+
- StorageLive(_3);
30+
+ nop;
31+
StorageLive(_4);
32+
_4 = copy _1;
33+
- _3 = move _4 as u64 (IntToInt);
34+
+ _3 = copy _1 as u64 (IntToInt);
35+
StorageDead(_4);
36+
- _2 = Ge(const U32_MAX_PLUS_ONE, move _3);
37+
- StorageDead(_3);
38+
+ _2 = const true;
39+
+ nop;
40+
StorageLive(_5);
41+
StorageLive(_6);
42+
StorageLive(_7);
43+
_7 = copy _1;
44+
- _6 = move _7 as u64 (IntToInt);
45+
+ _6 = copy _3;
46+
StorageDead(_7);
47+
StorageLive(_8);
48+
- _8 = const core::num::<impl u32>::MAX as u64 (IntToInt);
49+
- _5 = Ge(move _6, move _8);
50+
+ _8 = const 4294967295_u64;
51+
+ _5 = Ge(copy _3, const 4294967295_u64);
52+
StorageDead(_8);
53+
StorageDead(_6);
54+
StorageLive(_9);
55+
StorageLive(_10);
56+
StorageLive(_11);
57+
_11 = copy _1;
58+
- _10 = move _11 as u64 (IntToInt);
59+
+ _10 = copy _3;
60+
StorageDead(_11);
61+
- _9 = Ge(move _10, const U32_MAX_PLUS_ONE);
62+
+ _9 = const false;
63+
StorageDead(_10);
64+
_0 = const ();
65+
StorageDead(_9);
66+
StorageDead(_5);
67+
StorageDead(_2);
68+
return;
69+
}
70+
}
71+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
- // MIR for `ge` before GVN
2+
+ // MIR for `ge` after GVN
3+
4+
fn ge(_1: u32) -> () {
5+
debug input => _1;
6+
let mut _0: ();
7+
let _2: bool;
8+
let mut _3: u64;
9+
let mut _4: u32;
10+
let mut _6: u64;
11+
let mut _7: u32;
12+
let mut _8: u64;
13+
let mut _10: u64;
14+
let mut _11: u32;
15+
scope 1 {
16+
debug yes => _2;
17+
let _5: bool;
18+
scope 2 {
19+
debug runtime => _5;
20+
let _9: bool;
21+
scope 3 {
22+
debug no => _9;
23+
}
24+
}
25+
}
26+
27+
bb0: {
28+
StorageLive(_2);
29+
- StorageLive(_3);
30+
+ nop;
31+
StorageLive(_4);
32+
_4 = copy _1;
33+
- _3 = move _4 as u64 (IntToInt);
34+
+ _3 = copy _1 as u64 (IntToInt);
35+
StorageDead(_4);
36+
- _2 = Ge(const U32_MAX_PLUS_ONE, move _3);
37+
- StorageDead(_3);
38+
+ _2 = const true;
39+
+ nop;
40+
StorageLive(_5);
41+
StorageLive(_6);
42+
StorageLive(_7);
43+
_7 = copy _1;
44+
- _6 = move _7 as u64 (IntToInt);
45+
+ _6 = copy _3;
46+
StorageDead(_7);
47+
StorageLive(_8);
48+
- _8 = const core::num::<impl u32>::MAX as u64 (IntToInt);
49+
- _5 = Ge(move _6, move _8);
50+
+ _8 = const 4294967295_u64;
51+
+ _5 = Ge(copy _3, const 4294967295_u64);
52+
StorageDead(_8);
53+
StorageDead(_6);
54+
StorageLive(_9);
55+
StorageLive(_10);
56+
StorageLive(_11);
57+
_11 = copy _1;
58+
- _10 = move _11 as u64 (IntToInt);
59+
+ _10 = copy _3;
60+
StorageDead(_11);
61+
- _9 = Ge(move _10, const U32_MAX_PLUS_ONE);
62+
+ _9 = const false;
63+
StorageDead(_10);
64+
_0 = const ();
65+
StorageDead(_9);
66+
StorageDead(_5);
67+
StorageDead(_2);
68+
return;
69+
}
70+
}
71+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
- // MIR for `gt` before GVN
2+
+ // MIR for `gt` after GVN
3+
4+
fn gt(_1: u8) -> () {
5+
debug input => _1;
6+
let mut _0: ();
7+
let _2: bool;
8+
let mut _3: u16;
9+
let mut _4: u8;
10+
let mut _6: u16;
11+
let mut _7: u8;
12+
scope 1 {
13+
debug yes => _2;
14+
let _5: bool;
15+
scope 2 {
16+
debug no => _5;
17+
}
18+
}
19+
20+
bb0: {
21+
StorageLive(_2);
22+
- StorageLive(_3);
23+
+ nop;
24+
StorageLive(_4);
25+
_4 = copy _1;
26+
- _3 = move _4 as u16 (IntToInt);
27+
+ _3 = copy _1 as u16 (IntToInt);
28+
StorageDead(_4);
29+
- _2 = Gt(const 256_u16, move _3);
30+
- StorageDead(_3);
31+
+ _2 = const true;
32+
+ nop;
33+
StorageLive(_5);
34+
StorageLive(_6);
35+
StorageLive(_7);
36+
_7 = copy _1;
37+
- _6 = move _7 as u16 (IntToInt);
38+
+ _6 = copy _3;
39+
StorageDead(_7);
40+
- _5 = Gt(move _6, const 256_u16);
41+
+ _5 = const false;
42+
StorageDead(_6);
43+
_0 = const ();
44+
StorageDead(_5);
45+
StorageDead(_2);
46+
return;
47+
}
48+
}
49+

0 commit comments

Comments
 (0)