Skip to content

Commit f348fd6

Browse files
committed
add cast evaluation for better MIR
1 parent 5b61449 commit f348fd6

12 files changed

Lines changed: 684 additions & 0 deletions

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,33 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
14821482
(BinOp::Eq, a, b) if a == b => self.insert_bool(true),
14831483
(BinOp::Ne, Left(a), Left(b)) => self.insert_bool(a != b),
14841484
(BinOp::Ne, a, b) if a == b => self.insert_bool(false),
1485+
// When casting from a value, and comparing with a literal
1486+
// compare the maximum value with this literal
1487+
// to see if it's possible omit the runtime check
1488+
(BinOp::Lt, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a < b) => {
1489+
self.insert_bool(true)
1490+
}
1491+
(BinOp::Lt, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| b >= a) => {
1492+
self.insert_bool(false)
1493+
}
1494+
(BinOp::Le, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a <= b) => {
1495+
self.insert_bool(true)
1496+
}
1497+
(BinOp::Le, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a > b) => {
1498+
self.insert_bool(false)
1499+
}
1500+
(BinOp::Gt, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a > b) => {
1501+
self.insert_bool(true)
1502+
}
1503+
(BinOp::Gt, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a <= b) => {
1504+
self.insert_bool(false)
1505+
}
1506+
(BinOp::Ge, Left(a), Right(b)) if self.max_value_of_cast(b).is_some_and(|b| a >= b) => {
1507+
self.insert_bool(true)
1508+
}
1509+
(BinOp::Ge, Right(a), Left(b)) if self.max_value_of_cast(a).is_some_and(|a| a < b) => {
1510+
self.insert_bool(false)
1511+
}
14851512
_ => return None,
14861513
};
14871514

@@ -1494,6 +1521,22 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
14941521
}
14951522
}
14961523

1524+
fn max_value_of_cast(&self, value: VnIndex) -> Option<u128> {
1525+
let Value::Cast { kind: CastKind::IntToInt, value } = self.get(value) else {
1526+
return None;
1527+
};
1528+
let max_value = match self.ty(value).kind() {
1529+
ty::Uint(ty::UintTy::U8) => u8::MAX as u128,
1530+
ty::Uint(ty::UintTy::U16) => u16::MAX as u128,
1531+
ty::Uint(ty::UintTy::U32) => u32::MAX as u128,
1532+
ty::Uint(ty::UintTy::U64) => u64::MAX as u128,
1533+
ty::Uint(ty::UintTy::Usize) => usize::MAX as u128,
1534+
// u128::MAX intentionally omitted
1535+
_ => return None,
1536+
};
1537+
Some(max_value)
1538+
}
1539+
14971540
fn simplify_cast(
14981541
&mut self,
14991542
initial_kind: &mut CastKind,
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 _9: u64;
13+
let mut _10: u32;
14+
let mut _11: u64;
15+
scope 1 {
16+
debug yes => _2;
17+
let _5: bool;
18+
scope 2 {
19+
debug no => _5;
20+
let _8: bool;
21+
scope 3 {
22+
debug runtime => _8;
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+
- _5 = Ge(move _6, const U32_MAX_PLUS_ONE);
48+
+ _5 = const false;
49+
StorageDead(_6);
50+
StorageLive(_8);
51+
StorageLive(_9);
52+
StorageLive(_10);
53+
_10 = copy _1;
54+
- _9 = move _10 as u64 (IntToInt);
55+
+ _9 = copy _3;
56+
StorageDead(_10);
57+
StorageLive(_11);
58+
- _11 = const core::num::<impl u32>::MAX as u64 (IntToInt);
59+
- _8 = Ge(move _9, move _11);
60+
+ _11 = const 4294967295_u64;
61+
+ _8 = Ge(copy _3, const 4294967295_u64);
62+
StorageDead(_11);
63+
StorageDead(_9);
64+
_0 = const ();
65+
StorageDead(_8);
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+
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)