From 5fc23ad8e6b7a5ef0b5a6936cb043bd85f8bed59 Mon Sep 17 00:00:00 2001 From: Camille GILLOT <gillot.camille@gmail.com> Date: Sat, 25 Mar 2023 22:33:35 +0000 Subject: [PATCH] Simplify unary operations. --- compiler/rustc_mir_transform/src/gvn.rs | 20 +++ .../gvn.fn_pointers.GVN.panic-abort.diff | 18 +-- .../gvn.fn_pointers.GVN.panic-unwind.diff | 18 +-- tests/mir-opt/gvn.rs | 27 ++++ tests/mir-opt/gvn.unary.GVN.panic-abort.diff | 153 ++++++++++++++++++ tests/mir-opt/gvn.unary.GVN.panic-unwind.diff | 153 ++++++++++++++++++ 6 files changed, 371 insertions(+), 18 deletions(-) create mode 100644 tests/mir-opt/gvn.unary.GVN.panic-abort.diff create mode 100644 tests/mir-opt/gvn.unary.GVN.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 3052369c3ca..699b218d46d 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -817,6 +817,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Rvalue::UnaryOp(op, ref mut arg) => { let arg = self.simplify_operand(arg, location)?; + if let Some(value) = self.simplify_unary(op, arg) { + return Some(value); + } Value::UnaryOp(op, arg) } Rvalue::Discriminant(ref mut place) => { @@ -916,6 +919,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(self.insert(Value::Aggregate(ty, variant_index, fields))) } + #[instrument(level = "trace", skip(self), ret)] + fn simplify_unary(&mut self, op: UnOp, value: VnIndex) -> Option<VnIndex> { + let value = match (op, self.get(value)) { + (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(*inner), + (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(*inner), + (UnOp::Not, Value::BinaryOp(BinOp::Eq, lhs, rhs)) => { + Value::BinaryOp(BinOp::Ne, *lhs, *rhs) + } + (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => { + Value::BinaryOp(BinOp::Eq, *lhs, *rhs) + } + _ => return None, + }; + + Some(self.insert(value)) + } + #[instrument(level = "trace", skip(self), ret)] fn simplify_binary( &mut self, diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index 0901896af53..02bf95840da 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21}; + let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21}; + let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:585:19: 585:21}; + let _7: {closure@$DIR/gvn.rs:610:19: 610:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:585:19: 585:21}; +- _7 = {closure@$DIR/gvn.rs:610:19: 610:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index 4b95191ba82..c5dcc8a8ec9 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:585:19: 585:21}; + let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:585:19: 585:21}; + let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:585:19: 585:21}; + let _7: {closure@$DIR/gvn.rs:610:19: 610:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:585:19: 585:21}; +- _7 = {closure@$DIR/gvn.rs:610:19: 610:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:585:19: 585:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 8c06e3a6385..f8f4fdcd732 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -166,6 +166,31 @@ fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) { opaque(a[idx]); } +fn unary(x: i64) { + // CHECK-LABEL: fn unary( + // CHECK: opaque::<i64>(_1) + opaque(--x); // This is `x`. + + // CHECK: [[b:_.*]] = Lt(_1, const 13_i64); + // CHECK: opaque::<bool>([[b]]) + let b = x < 13; + opaque(!!b); // This is `b`. + + // Both lines should test the same thing. + // CHECK: [[c:_.*]] = Ne(_1, const 15_i64); + // CHECK: opaque::<bool>([[c]]) + // CHECK: opaque::<bool>([[c]]) + opaque(x != 15); + opaque(!(x == 15)); + + // Both lines should test the same thing. + // CHECK: [[d:_.*]] = Eq(_1, const 35_i64); + // CHECK: opaque::<bool>([[d]]) + // CHECK: opaque::<bool>([[d]]) + opaque(x == 35); + opaque(!(x != 35)); +} + /// Verify symbolic integer arithmetic simplifications. fn arithmetic(x: u64) { // CHECK-LABEL: fn arithmetic( @@ -623,6 +648,7 @@ fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); repeated_index::<u32, 7>(5, 3); + unary(i64::MIN); arithmetic(5); comparison(5, 6); arithmetic_checked(5); @@ -651,6 +677,7 @@ fn identity<T>(x: T) -> T { // EMIT_MIR gvn.subexpression_elimination.GVN.diff // EMIT_MIR gvn.wrap_unwrap.GVN.diff // EMIT_MIR gvn.repeated_index.GVN.diff +// EMIT_MIR gvn.unary.GVN.diff // EMIT_MIR gvn.arithmetic.GVN.diff // EMIT_MIR gvn.comparison.GVN.diff // EMIT_MIR gvn.arithmetic_checked.GVN.diff diff --git a/tests/mir-opt/gvn.unary.GVN.panic-abort.diff b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff new file mode 100644 index 00000000000..9469032f294 --- /dev/null +++ b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff @@ -0,0 +1,153 @@ +- // MIR for `unary` before GVN ++ // MIR for `unary` after GVN + + fn unary(_1: i64) -> () { + debug x => _1; + let mut _0: (); + let _2: (); + let mut _3: i64; + let mut _4: i64; + let mut _5: i64; + let _6: bool; + let mut _7: i64; + let _8: (); + let mut _9: bool; + let mut _10: bool; + let mut _11: bool; + let _12: (); + let mut _13: bool; + let mut _14: i64; + let _15: (); + let mut _16: bool; + let mut _17: bool; + let mut _18: i64; + let _19: (); + let mut _20: bool; + let mut _21: i64; + let _22: (); + let mut _23: bool; + let mut _24: bool; + let mut _25: i64; + scope 1 { + debug b => _6; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = Neg(move _5); ++ _4 = Neg(_1); + StorageDead(_5); +- _3 = Neg(move _4); ++ _3 = _1; + StorageDead(_4); +- _2 = opaque::<i64>(move _3) -> [return: bb1, unwind unreachable]; ++ _2 = opaque::<i64>(_1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _1; +- _6 = Lt(move _7, const 13_i64); ++ _6 = Lt(_1, const 13_i64); + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = _6; +- _10 = Not(move _11); ++ _10 = Not(_6); + StorageDead(_11); +- _9 = Not(move _10); ++ _9 = _6; + StorageDead(_10); +- _8 = opaque::<bool>(move _9) -> [return: bb2, unwind unreachable]; ++ _8 = opaque::<bool>(_6) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_12); +- StorageLive(_13); ++ nop; + StorageLive(_14); + _14 = _1; +- _13 = Ne(move _14, const 15_i64); ++ _13 = Ne(_1, const 15_i64); + StorageDead(_14); +- _12 = opaque::<bool>(move _13) -> [return: bb3, unwind unreachable]; ++ _12 = opaque::<bool>(_13) -> [return: bb3, unwind unreachable]; + } + + bb3: { +- StorageDead(_13); ++ nop; + StorageDead(_12); + StorageLive(_15); + StorageLive(_16); + StorageLive(_17); + StorageLive(_18); + _18 = _1; +- _17 = Eq(move _18, const 15_i64); ++ _17 = Eq(_1, const 15_i64); + StorageDead(_18); +- _16 = Not(move _17); ++ _16 = _13; + StorageDead(_17); +- _15 = opaque::<bool>(move _16) -> [return: bb4, unwind unreachable]; ++ _15 = opaque::<bool>(_13) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_16); + StorageDead(_15); + StorageLive(_19); +- StorageLive(_20); ++ nop; + StorageLive(_21); + _21 = _1; +- _20 = Eq(move _21, const 35_i64); ++ _20 = Eq(_1, const 35_i64); + StorageDead(_21); +- _19 = opaque::<bool>(move _20) -> [return: bb5, unwind unreachable]; ++ _19 = opaque::<bool>(_20) -> [return: bb5, unwind unreachable]; + } + + bb5: { +- StorageDead(_20); ++ nop; + StorageDead(_19); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); + StorageLive(_25); + _25 = _1; +- _24 = Ne(move _25, const 35_i64); ++ _24 = Ne(_1, const 35_i64); + StorageDead(_25); +- _23 = Not(move _24); ++ _23 = _20; + StorageDead(_24); +- _22 = opaque::<bool>(move _23) -> [return: bb6, unwind unreachable]; ++ _22 = opaque::<bool>(_20) -> [return: bb6, unwind unreachable]; + } + + bb6: { + StorageDead(_23); + StorageDead(_22); + _0 = const (); +- StorageDead(_6); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff new file mode 100644 index 00000000000..e672f6fb6ba --- /dev/null +++ b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff @@ -0,0 +1,153 @@ +- // MIR for `unary` before GVN ++ // MIR for `unary` after GVN + + fn unary(_1: i64) -> () { + debug x => _1; + let mut _0: (); + let _2: (); + let mut _3: i64; + let mut _4: i64; + let mut _5: i64; + let _6: bool; + let mut _7: i64; + let _8: (); + let mut _9: bool; + let mut _10: bool; + let mut _11: bool; + let _12: (); + let mut _13: bool; + let mut _14: i64; + let _15: (); + let mut _16: bool; + let mut _17: bool; + let mut _18: i64; + let _19: (); + let mut _20: bool; + let mut _21: i64; + let _22: (); + let mut _23: bool; + let mut _24: bool; + let mut _25: i64; + scope 1 { + debug b => _6; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = Neg(move _5); ++ _4 = Neg(_1); + StorageDead(_5); +- _3 = Neg(move _4); ++ _3 = _1; + StorageDead(_4); +- _2 = opaque::<i64>(move _3) -> [return: bb1, unwind continue]; ++ _2 = opaque::<i64>(_1) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _1; +- _6 = Lt(move _7, const 13_i64); ++ _6 = Lt(_1, const 13_i64); + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = _6; +- _10 = Not(move _11); ++ _10 = Not(_6); + StorageDead(_11); +- _9 = Not(move _10); ++ _9 = _6; + StorageDead(_10); +- _8 = opaque::<bool>(move _9) -> [return: bb2, unwind continue]; ++ _8 = opaque::<bool>(_6) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_12); +- StorageLive(_13); ++ nop; + StorageLive(_14); + _14 = _1; +- _13 = Ne(move _14, const 15_i64); ++ _13 = Ne(_1, const 15_i64); + StorageDead(_14); +- _12 = opaque::<bool>(move _13) -> [return: bb3, unwind continue]; ++ _12 = opaque::<bool>(_13) -> [return: bb3, unwind continue]; + } + + bb3: { +- StorageDead(_13); ++ nop; + StorageDead(_12); + StorageLive(_15); + StorageLive(_16); + StorageLive(_17); + StorageLive(_18); + _18 = _1; +- _17 = Eq(move _18, const 15_i64); ++ _17 = Eq(_1, const 15_i64); + StorageDead(_18); +- _16 = Not(move _17); ++ _16 = _13; + StorageDead(_17); +- _15 = opaque::<bool>(move _16) -> [return: bb4, unwind continue]; ++ _15 = opaque::<bool>(_13) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_16); + StorageDead(_15); + StorageLive(_19); +- StorageLive(_20); ++ nop; + StorageLive(_21); + _21 = _1; +- _20 = Eq(move _21, const 35_i64); ++ _20 = Eq(_1, const 35_i64); + StorageDead(_21); +- _19 = opaque::<bool>(move _20) -> [return: bb5, unwind continue]; ++ _19 = opaque::<bool>(_20) -> [return: bb5, unwind continue]; + } + + bb5: { +- StorageDead(_20); ++ nop; + StorageDead(_19); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); + StorageLive(_25); + _25 = _1; +- _24 = Ne(move _25, const 35_i64); ++ _24 = Ne(_1, const 35_i64); + StorageDead(_25); +- _23 = Not(move _24); ++ _23 = _20; + StorageDead(_24); +- _22 = opaque::<bool>(move _23) -> [return: bb6, unwind continue]; ++ _22 = opaque::<bool>(_20) -> [return: bb6, unwind continue]; + } + + bb6: { + StorageDead(_23); + StorageDead(_22); + _0 = const (); +- StorageDead(_6); ++ nop; + return; + } + } +