Skip to content

Commit 529a8c2

Browse files
committed
Auto merge of rust-lang#116012 - cjgillot:gvn-const, r=oli-obk
Implement constant propagation on top of MIR SSA analysis This implements the idea I proposed in rust-lang#110719 (comment) Based on rust-lang#109597 The value numbering "GVN" pass formulates each rvalue that appears in MIR with an abstract form (the `Value` enum), and assigns an integer `VnIndex` to each. This abstract form can be used to deduplicate values, reusing an earlier local that holds the same value instead of recomputing. This part is proposed in rust-lang#109597. From this abstract representation, we can perform more involved simplifications, for example in rust-lang#111344. With the abstract representation `Value`, we can also attempt to evaluate each to a constant using the interpreter. This builds a `VnIndex -> OpTy` map. From this map, we can opportunistically replace an operand or a rvalue with a constant if their value has an associated `OpTy`. The most relevant commit is [Evaluated computed values to constants.](rust-lang@2767c49)" r? `@oli-obk`
2 parents ef1b78e + a3dd640 commit 529a8c2

File tree

208 files changed

+1084
-1580
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

208 files changed

+1084
-1580
lines changed

compiler/rustc_mir_transform/src/const_prop.rs

+11-515
Large diffs are not rendered by default.

compiler/rustc_mir_transform/src/gvn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ pub struct GVN;
109109

110110
impl<'tcx> MirPass<'tcx> for GVN {
111111
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
112-
sess.mir_opt_level() >= 4
112+
sess.mir_opt_level() >= 2
113113
}
114114

115115
#[instrument(level = "trace", skip(self, tcx, body))]

compiler/rustc_mir_transform/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
587587
// destroy the SSA property. It should still happen before const-propagation, so the
588588
// latter pass will leverage the created opportunities.
589589
&separate_const_switch::SeparateConstSwitch,
590-
&const_prop::ConstProp,
591590
&gvn::GVN,
592591
&simplify::SimplifyLocals::AfterGVN,
593592
&dataflow_const_prop::DataflowConstProp,

tests/codegen/inherit_overflow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// compile-flags: -Zmir-enable-passes=+Inline,+ConstProp --crate-type lib
1+
// compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib
22
// revisions: ASSERT NOASSERT
33
//[ASSERT] compile-flags: -Coverflow-checks=on
44
//[NOASSERT] compile-flags: -Coverflow-checks=off

tests/coverage/async2.cov-map

+6-8
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,17 @@ Number of file 0 mappings: 1
77
- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 23)
88

99
Function name: async2::async_func::{closure#0}
10-
Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
10+
Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
1111
Number of files: 1
1212
- file 0 => global file 1
13-
Number of expressions: 2
14-
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
15-
- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
13+
Number of expressions: 1
14+
- expression 0 operands: lhs = Counter(1), rhs = Zero
1615
Number of file 0 mappings: 4
1716
- Code(Counter(0)) at (prev + 13, 23) to (start + 3, 9)
1817
- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
19-
- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
20-
= (c0 - c1)
21-
- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
22-
= (c1 + (c0 - c1))
18+
- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
19+
- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
20+
= (c1 + Zero)
2321

2422
Function name: async2::async_func_just_println
2523
Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 24]

tests/coverage/partial_eq.cov-map

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,18 @@ Number of file 0 mappings: 2
2525
- Code(Zero) at (prev + 0, 32) to (start + 0, 33)
2626

2727
Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp
28-
Raw bytes (22): 0x[01, 01, 04, 07, 0b, 05, 09, 0f, 15, 0d, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
28+
Raw bytes (22): 0x[01, 01, 04, 07, 0b, 00, 09, 0f, 15, 00, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
2929
Number of files: 1
3030
- file 0 => global file 1
3131
Number of expressions: 4
3232
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
33-
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
33+
- expression 1 operands: lhs = Zero, rhs = Counter(2)
3434
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
35-
- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
35+
- expression 3 operands: lhs = Zero, rhs = Counter(4)
3636
Number of file 0 mappings: 2
3737
- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40)
3838
- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49)
39-
= ((c1 + c2) + ((c3 + c4) + c5))
39+
= ((Zero + c2) + ((Zero + c4) + c5))
4040

4141
Function name: <partial_eq::Version as core::fmt::Debug>::fmt
4242
Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16]

tests/incremental/hashes/for_loops.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ pub fn change_iterable() {
103103
}
104104

105105
#[cfg(not(any(cfail1,cfail4)))]
106-
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
106+
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir, optimized_mir")]
107107
#[rustc_clean(cfg="cfail3")]
108-
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir")]
108+
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")]
109109
#[rustc_clean(cfg="cfail6")]
110110
pub fn change_iterable() {
111111
let mut _x = 0;

tests/incremental/string_constant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub mod x {
1717
}
1818

1919
#[cfg(cfail2)]
20-
#[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail2")]
20+
#[rustc_clean(except = "hir_owner_nodes,promoted_mir,optimized_mir", cfg = "cfail2")]
2121
pub fn x() {
2222
println!("{}", "2");
2323
}

tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir tests/mir-opt/const_allocation.main.GVN.after.32bit.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// MIR for `main` after ConstProp
1+
// MIR for `main` after GVN
22

33
fn main() -> () {
44
let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
77

88
bb0: {
99
StorageLive(_1);
10-
StorageLive(_2);
10+
nop;
1111
_2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
1212
_1 = (*_2);
13-
StorageDead(_2);
13+
nop;
1414
StorageDead(_1);
1515
_0 = const ();
1616
return;

tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir tests/mir-opt/const_allocation.main.GVN.after.64bit.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// MIR for `main` after ConstProp
1+
// MIR for `main` after GVN
22

33
fn main() -> () {
44
let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
77

88
bb0: {
99
StorageLive(_1);
10-
StorageLive(_2);
10+
nop;
1111
_2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
1212
_1 = (*_2);
13-
StorageDead(_2);
13+
nop;
1414
StorageDead(_1);
1515
_0 = const ();
1616
return;

tests/mir-opt/const_allocation.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// skip-filecheck
2-
// unit-test: ConstProp
2+
// unit-test: GVN
33
// ignore-endian-big
44
// EMIT_MIR_FOR_EACH_BIT_WIDTH
55
static FOO: &[(Option<i32>, &[&str])] =
66
&[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])];
77

8-
// EMIT_MIR const_allocation.main.ConstProp.after.mir
8+
// EMIT_MIR const_allocation.main.GVN.after.mir
99
fn main() {
1010
FOO;
1111
}

tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir tests/mir-opt/const_allocation2.main.GVN.after.32bit.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// MIR for `main` after ConstProp
1+
// MIR for `main` after GVN
22

33
fn main() -> () {
44
let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
77

88
bb0: {
99
StorageLive(_1);
10-
StorageLive(_2);
10+
nop;
1111
_2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
1212
_1 = (*_2);
13-
StorageDead(_2);
13+
nop;
1414
StorageDead(_1);
1515
_0 = const ();
1616
return;

tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir tests/mir-opt/const_allocation2.main.GVN.after.64bit.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// MIR for `main` after ConstProp
1+
// MIR for `main` after GVN
22

33
fn main() -> () {
44
let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
77

88
bb0: {
99
StorageLive(_1);
10-
StorageLive(_2);
10+
nop;
1111
_2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
1212
_1 = (*_2);
13-
StorageDead(_2);
13+
nop;
1414
StorageDead(_1);
1515
_0 = const ();
1616
return;

tests/mir-opt/const_allocation2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// skip-filecheck
2-
// unit-test: ConstProp
2+
// unit-test: GVN
33
// ignore-endian-big
44
// EMIT_MIR_FOR_EACH_BIT_WIDTH
5-
// EMIT_MIR const_allocation2.main.ConstProp.after.mir
5+
// EMIT_MIR const_allocation2.main.GVN.after.mir
66
fn main() {
77
FOO;
88
}

tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir tests/mir-opt/const_allocation3.main.GVN.after.32bit.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// MIR for `main` after ConstProp
1+
// MIR for `main` after GVN
22

33
fn main() -> () {
44
let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
77

88
bb0: {
99
StorageLive(_1);
10-
StorageLive(_2);
10+
nop;
1111
_2 = const {ALLOC4: &&Packed};
1212
_1 = (*_2);
13-
StorageDead(_2);
13+
nop;
1414
StorageDead(_1);
1515
_0 = const ();
1616
return;

tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir tests/mir-opt/const_allocation3.main.GVN.after.64bit.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// MIR for `main` after ConstProp
1+
// MIR for `main` after GVN
22

33
fn main() -> () {
44
let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
77

88
bb0: {
99
StorageLive(_1);
10-
StorageLive(_2);
10+
nop;
1111
_2 = const {ALLOC2: &&Packed};
1212
_1 = (*_2);
13-
StorageDead(_2);
13+
nop;
1414
StorageDead(_1);
1515
_0 = const ();
1616
return;

tests/mir-opt/const_allocation3.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// skip-filecheck
2-
// unit-test: ConstProp
2+
// unit-test: GVN
33
// ignore-endian-big
44
// EMIT_MIR_FOR_EACH_BIT_WIDTH
5-
// EMIT_MIR const_allocation3.main.ConstProp.after.mir
5+
// EMIT_MIR const_allocation3.main.GVN.after.mir
66
fn main() {
77
FOO;
88
}

tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff

+15-10
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
debug f => _10;
3535
let _11: std::option::Option<u16>;
3636
scope 7 {
37-
debug o => _11;
37+
- debug o => _11;
38+
+ debug o => const Option::<u16>::Some(99_u16);
3839
let _12: Point;
3940
scope 8 {
4041
- debug p => _12;
@@ -54,11 +55,11 @@
5455
}
5556

5657
bb0: {
57-
StorageLive(_1);
58+
nop;
5859
_1 = const 1_u8;
59-
StorageLive(_2);
60+
nop;
6061
_2 = const 2_u8;
61-
StorageLive(_3);
62+
nop;
6263
_3 = const 3_u8;
6364
StorageLive(_4);
6465
StorageLive(_5);
@@ -79,27 +80,27 @@
7980
StorageLive(_10);
8081
_10 = (const true, const false, const 123_u32);
8182
StorageLive(_11);
82-
_11 = Option::<u16>::Some(const 99_u16);
83+
_11 = const Option::<u16>::Some(99_u16);
8384
StorageLive(_12);
8485
_12 = const Point {{ x: 32_u32, y: 32_u32 }};
8586
StorageLive(_13);
86-
StorageLive(_14);
87+
nop;
8788
_14 = const 32_u32;
8889
StorageLive(_15);
8990
_15 = const 32_u32;
9091
_13 = const 64_u32;
9192
StorageDead(_15);
92-
StorageDead(_14);
93+
nop;
9394
_0 = const ();
9495
StorageDead(_13);
9596
StorageDead(_12);
9697
StorageDead(_11);
9798
StorageDead(_10);
9899
StorageDead(_9);
99100
StorageDead(_4);
100-
StorageDead(_3);
101-
StorageDead(_2);
102-
StorageDead(_1);
101+
nop;
102+
nop;
103+
nop;
103104
return;
104105
}
105106
}
@@ -108,3 +109,7 @@
108109
20 00 00 00 20 00 00 00 │ ... ...
109110
}
110111

112+
ALLOC1 (size: 4, align: 2) {
113+
01 00 63 00 │ ..c.
114+
}
115+

tests/mir-opt/const_debuginfo.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// unit-test: ConstDebugInfo
2-
// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+ConstProp
2+
// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN
33

44
struct Point {
55
x: u32,
@@ -15,7 +15,7 @@ fn main() {
1515
// CHECK: debug sum => const 6_u8;
1616
// CHECK: debug s => const "hello, world!";
1717
// CHECK: debug f => {{_.*}};
18-
// CHECK: debug o => {{_.*}};
18+
// CHECK: debug o => const Option::<u16>::Some(99_u16);
1919
// CHECK: debug p => const Point
2020
// CHECK: debug a => const 64_u32;
2121
let x = 1u8;

tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff

+18-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
- // MIR for `fn0` before ConstProp
2-
+ // MIR for `fn0` after ConstProp
1+
- // MIR for `fn0` before GVN
2+
+ // MIR for `fn0` after GVN
33

44
fn fn0() -> bool {
55
let mut _0: bool;
@@ -23,24 +23,34 @@
2323

2424
bb0: {
2525
StorageLive(_2);
26-
_2 = (const 1_i32, const false);
27-
StorageLive(_3);
26+
- _2 = (const 1_i32, const false);
27+
- StorageLive(_3);
28+
+ _2 = const (1_i32, false);
29+
+ nop;
2830
_3 = &raw mut (_2.1: bool);
29-
_2 = (const 1_i32, const false);
31+
- _2 = (const 1_i32, const false);
32+
+ _2 = const (1_i32, false);
3033
StorageLive(_4);
3134
(*_3) = const true;
3235
_4 = const ();
3336
StorageDead(_4);
34-
StorageLive(_5);
37+
- StorageLive(_5);
38+
+ nop;
3539
StorageLive(_6);
3640
_6 = (_2.1: bool);
3741
_5 = Not(move _6);
3842
StorageDead(_6);
3943
_0 = _5;
40-
StorageDead(_5);
41-
StorageDead(_3);
44+
- StorageDead(_5);
45+
- StorageDead(_3);
46+
+ nop;
47+
+ nop;
4248
StorageDead(_2);
4349
return;
4450
}
51+
+ }
52+
+
53+
+ ALLOC0 (size: 8, align: 4) {
54+
+ 01 00 00 00 00 __ __ __ │ .....░░░
4555
}
4656

tests/mir-opt/const_prop/address_of_pair.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// unit-test: ConstProp
1+
// unit-test: GVN
22

3-
// EMIT_MIR address_of_pair.fn0.ConstProp.diff
3+
// EMIT_MIR address_of_pair.fn0.GVN.diff
44
pub fn fn0() -> bool {
55
// CHECK-LABEL: fn fn0(
66
// CHECK: debug pair => [[pair:_.*]];

0 commit comments

Comments
 (0)