Skip to content

Commit

Permalink
Auto merge of rust-lang#116012 - cjgillot:gvn-const, r=oli-obk
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
bors committed Dec 23, 2023
2 parents 495203b + 1293d25 commit a994209
Show file tree
Hide file tree
Showing 208 changed files with 1,084 additions and 1,580 deletions.
526 changes: 11 additions & 515 deletions compiler/rustc_mir_transform/src/const_prop.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ pub struct GVN;

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

#[instrument(level = "trace", skip(self, tcx, body))]
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// destroy the SSA property. It should still happen before const-propagation, so the
// latter pass will leverage the created opportunities.
&separate_const_switch::SeparateConstSwitch,
&const_prop::ConstProp,
&gvn::GVN,
&simplify::SimplifyLocals::AfterGVN,
&dataflow_const_prop::DataflowConstProp,
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen/inherit_overflow.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// compile-flags: -Zmir-enable-passes=+Inline,+ConstProp --crate-type lib
// compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib
// revisions: ASSERT NOASSERT
//[ASSERT] compile-flags: -Coverflow-checks=on
//[NOASSERT] compile-flags: -Coverflow-checks=off
Expand Down
14 changes: 6 additions & 8 deletions tests/coverage/async2.cov-map
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 23)

Function name: async2::async_func::{closure#0}
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]
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]
Number of files: 1
- file 0 => global file 1
Number of expressions: 2
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
Number of expressions: 1
- expression 0 operands: lhs = Counter(1), rhs = Zero
Number of file 0 mappings: 4
- Code(Counter(0)) at (prev + 13, 23) to (start + 3, 9)
- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
= (c0 - c1)
- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
= (c1 + (c0 - c1))
- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
= (c1 + Zero)

Function name: async2::async_func_just_println
Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 24]
Expand Down
8 changes: 4 additions & 4 deletions tests/coverage/partial_eq.cov-map
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ Number of file 0 mappings: 2
- Code(Zero) at (prev + 0, 32) to (start + 0, 33)

Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp
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]
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]
Number of files: 1
- file 0 => global file 1
Number of expressions: 4
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
- expression 1 operands: lhs = Zero, rhs = Counter(2)
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
- expression 3 operands: lhs = Zero, rhs = Counter(4)
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40)
- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49)
= ((c1 + c2) + ((c3 + c4) + c5))
= ((Zero + c2) + ((Zero + c4) + c5))

Function name: <partial_eq::Version as core::fmt::Debug>::fmt
Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16]
Expand Down
4 changes: 2 additions & 2 deletions tests/incremental/hashes/for_loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ pub fn change_iterable() {
}

#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir, optimized_mir")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_iterable() {
let mut _x = 0;
Expand Down
2 changes: 1 addition & 1 deletion tests/incremental/string_constant.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// revisions: cfail1 cfail2
// compile-flags: -Z query-dep-graph
// compile-flags: -Z query-dep-graph -Copt-level=0
// build-pass (FIXME(62277): could be check-pass?)

#![allow(warnings)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// MIR for `main` after ConstProp
// MIR for `main` after GVN

fn main() -> () {
let mut _0: ();
Expand All @@ -7,10 +7,10 @@ fn main() -> () {

bb0: {
StorageLive(_1);
StorageLive(_2);
nop;
_2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
_1 = (*_2);
StorageDead(_2);
nop;
StorageDead(_1);
_0 = const ();
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// MIR for `main` after ConstProp
// MIR for `main` after GVN

fn main() -> () {
let mut _0: ();
Expand All @@ -7,10 +7,10 @@ fn main() -> () {

bb0: {
StorageLive(_1);
StorageLive(_2);
nop;
_2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
_1 = (*_2);
StorageDead(_2);
nop;
StorageDead(_1);
_0 = const ();
return;
Expand Down
4 changes: 2 additions & 2 deletions tests/mir-opt/const_allocation.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// skip-filecheck
// unit-test: ConstProp
// unit-test: GVN
// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
static FOO: &[(Option<i32>, &[&str])] =
&[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])];

// EMIT_MIR const_allocation.main.ConstProp.after.mir
// EMIT_MIR const_allocation.main.GVN.after.mir
fn main() {
FOO;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// MIR for `main` after ConstProp
// MIR for `main` after GVN

fn main() -> () {
let mut _0: ();
Expand All @@ -7,10 +7,10 @@ fn main() -> () {

bb0: {
StorageLive(_1);
StorageLive(_2);
nop;
_2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
_1 = (*_2);
StorageDead(_2);
nop;
StorageDead(_1);
_0 = const ();
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// MIR for `main` after ConstProp
// MIR for `main` after GVN

fn main() -> () {
let mut _0: ();
Expand All @@ -7,10 +7,10 @@ fn main() -> () {

bb0: {
StorageLive(_1);
StorageLive(_2);
nop;
_2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
_1 = (*_2);
StorageDead(_2);
nop;
StorageDead(_1);
_0 = const ();
return;
Expand Down
4 changes: 2 additions & 2 deletions tests/mir-opt/const_allocation2.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// skip-filecheck
// unit-test: ConstProp
// unit-test: GVN
// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR const_allocation2.main.ConstProp.after.mir
// EMIT_MIR const_allocation2.main.GVN.after.mir
fn main() {
FOO;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// MIR for `main` after ConstProp
// MIR for `main` after GVN

fn main() -> () {
let mut _0: ();
Expand All @@ -7,10 +7,10 @@ fn main() -> () {

bb0: {
StorageLive(_1);
StorageLive(_2);
nop;
_2 = const {ALLOC4: &&Packed};
_1 = (*_2);
StorageDead(_2);
nop;
StorageDead(_1);
_0 = const ();
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// MIR for `main` after ConstProp
// MIR for `main` after GVN

fn main() -> () {
let mut _0: ();
Expand All @@ -7,10 +7,10 @@ fn main() -> () {

bb0: {
StorageLive(_1);
StorageLive(_2);
nop;
_2 = const {ALLOC2: &&Packed};
_1 = (*_2);
StorageDead(_2);
nop;
StorageDead(_1);
_0 = const ();
return;
Expand Down
4 changes: 2 additions & 2 deletions tests/mir-opt/const_allocation3.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// skip-filecheck
// unit-test: ConstProp
// unit-test: GVN
// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR const_allocation3.main.ConstProp.after.mir
// EMIT_MIR const_allocation3.main.GVN.after.mir
fn main() {
FOO;
}
Expand Down
25 changes: 15 additions & 10 deletions tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
debug f => _10;
let _11: std::option::Option<u16>;
scope 7 {
debug o => _11;
- debug o => _11;
+ debug o => const Option::<u16>::Some(99_u16);
let _12: Point;
scope 8 {
- debug p => _12;
Expand All @@ -54,11 +55,11 @@
}

bb0: {
StorageLive(_1);
nop;
_1 = const 1_u8;
StorageLive(_2);
nop;
_2 = const 2_u8;
StorageLive(_3);
nop;
_3 = const 3_u8;
StorageLive(_4);
StorageLive(_5);
Expand All @@ -79,27 +80,27 @@
StorageLive(_10);
_10 = (const true, const false, const 123_u32);
StorageLive(_11);
_11 = Option::<u16>::Some(const 99_u16);
_11 = const Option::<u16>::Some(99_u16);
StorageLive(_12);
_12 = const Point {{ x: 32_u32, y: 32_u32 }};
StorageLive(_13);
StorageLive(_14);
nop;
_14 = const 32_u32;
StorageLive(_15);
_15 = const 32_u32;
_13 = const 64_u32;
StorageDead(_15);
StorageDead(_14);
nop;
_0 = const ();
StorageDead(_13);
StorageDead(_12);
StorageDead(_11);
StorageDead(_10);
StorageDead(_9);
StorageDead(_4);
StorageDead(_3);
StorageDead(_2);
StorageDead(_1);
nop;
nop;
nop;
return;
}
}
Expand All @@ -108,3 +109,7 @@
20 00 00 00 20 00 00 00 │ ... ...
}

ALLOC1 (size: 4, align: 2) {
01 00 63 00 │ ..c.
}

4 changes: 2 additions & 2 deletions tests/mir-opt/const_debuginfo.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// unit-test: ConstDebugInfo
// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+ConstProp
// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN

struct Point {
x: u32,
Expand All @@ -15,7 +15,7 @@ fn main() {
// CHECK: debug sum => const 6_u8;
// CHECK: debug s => const "hello, world!";
// CHECK: debug f => {{_.*}};
// CHECK: debug o => {{_.*}};
// CHECK: debug o => const Option::<u16>::Some(99_u16);
// CHECK: debug p => const Point
// CHECK: debug a => const 64_u32;
let x = 1u8;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
- // MIR for `fn0` before ConstProp
+ // MIR for `fn0` after ConstProp
- // MIR for `fn0` before GVN
+ // MIR for `fn0` after GVN

fn fn0() -> bool {
let mut _0: bool;
Expand All @@ -23,24 +23,34 @@

bb0: {
StorageLive(_2);
_2 = (const 1_i32, const false);
StorageLive(_3);
- _2 = (const 1_i32, const false);
- StorageLive(_3);
+ _2 = const (1_i32, false);
+ nop;
_3 = &raw mut (_2.1: bool);
_2 = (const 1_i32, const false);
- _2 = (const 1_i32, const false);
+ _2 = const (1_i32, false);
StorageLive(_4);
(*_3) = const true;
_4 = const ();
StorageDead(_4);
StorageLive(_5);
- StorageLive(_5);
+ nop;
StorageLive(_6);
_6 = (_2.1: bool);
_5 = Not(move _6);
StorageDead(_6);
_0 = _5;
StorageDead(_5);
StorageDead(_3);
- StorageDead(_5);
- StorageDead(_3);
+ nop;
+ nop;
StorageDead(_2);
return;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 01 00 00 00 00 __ __ __ │ .....░░░
}

4 changes: 2 additions & 2 deletions tests/mir-opt/const_prop/address_of_pair.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// unit-test: ConstProp
// unit-test: GVN

// EMIT_MIR address_of_pair.fn0.ConstProp.diff
// EMIT_MIR address_of_pair.fn0.GVN.diff
pub fn fn0() -> bool {
// CHECK-LABEL: fn fn0(
// CHECK: debug pair => [[pair:_.*]];
Expand Down
Loading

0 comments on commit a994209

Please sign in to comment.