From 22986b72e5a94768aec538bf3ccc0b834f9d7da2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 15 Apr 2023 17:00:43 +0000 Subject: [PATCH] Implement algebraic simplifications. --- .../src/dataflow_const_prop.rs | 36 ++++++++++++++++--- .../dataflow-const-prop/boolean_identities.rs | 10 ++++++ ...ean_identities.test.DataflowConstProp.diff | 33 +++++++++++++++++ .../dataflow-const-prop/mult_by_zero.rs | 10 ++++++ .../mult_by_zero.test.DataflowConstProp.diff | 18 ++++++++++ 5 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 tests/mir-opt/dataflow-const-prop/boolean_identities.rs create mode 100644 tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff create mode 100644 tests/mir-opt/dataflow-const-prop/mult_by_zero.rs create mode 100644 tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 91bed82a634..e5e419cdae9 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -309,7 +309,10 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { ) -> (FlatSet, FlatSet) { let left = self.eval_operand(left, state); let right = self.eval_operand(right, state); + match (left, right) { + (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), + // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { match self.ecx.overflowing_binary_op(op, &left, &right) { Ok((Scalar::Int(val), overflow, _)) => { @@ -318,11 +321,36 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { _ => (FlatSet::Top, FlatSet::Top), } } - (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), - (_, _) => { - // Could attempt some algebraic simplifications here. - (FlatSet::Top, FlatSet::Top) + // Exactly one side is known, attempt some algebraic simplifications. + (FlatSet::Elem(const_arg), _) | (_, FlatSet::Elem(const_arg)) => { + let layout = const_arg.layout; + if !matches!(layout.abi, rustc_target::abi::Abi::Scalar(..)) { + return (FlatSet::Top, FlatSet::Top); + } + + let arg_scalar = const_arg.to_scalar(); + let Ok(arg_scalar) = arg_scalar.try_to_int() else { + return (FlatSet::Top, FlatSet::Top); + }; + let Ok(arg_value) = arg_scalar.to_bits(layout.size) else { + return (FlatSet::Top, FlatSet::Top); + }; + + match op { + BinOp::BitAnd if arg_value == 0 => (FlatSet::Elem(arg_scalar), FlatSet::Bottom), + BinOp::BitOr + if arg_value == layout.size.truncate(u128::MAX) + || (layout.ty.is_bool() && arg_value == 1) => + { + (FlatSet::Elem(arg_scalar), FlatSet::Bottom) + } + BinOp::Mul if layout.ty.is_integral() && arg_value == 0 => { + (FlatSet::Elem(arg_scalar), FlatSet::Elem(false)) + } + _ => (FlatSet::Top, FlatSet::Top), + } } + (FlatSet::Top, FlatSet::Top) => (FlatSet::Top, FlatSet::Top), } } diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.rs b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs new file mode 100644 index 00000000000..9e911e85b88 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs @@ -0,0 +1,10 @@ +// unit-test: DataflowConstProp + +// EMIT_MIR boolean_identities.test.DataflowConstProp.diff +pub fn test(x: bool, y: bool) -> bool { + (y | true) & (x & false) +} + +fn main() { + test(true, false); +} diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff new file mode 100644 index 00000000000..5440c38ce4b --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff @@ -0,0 +1,33 @@ +- // MIR for `test` before DataflowConstProp ++ // MIR for `test` after DataflowConstProp + + fn test(_1: bool, _2: bool) -> bool { + debug x => _1; + debug y => _2; + let mut _0: bool; + let mut _3: bool; + let mut _4: bool; + let mut _5: bool; + let mut _6: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = _2; +- _3 = BitOr(move _4, const true); ++ _3 = const true; + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = _1; +- _5 = BitAnd(move _6, const false); ++ _5 = const false; + StorageDead(_6); +- _0 = BitAnd(move _3, move _5); ++ _0 = const false; + StorageDead(_5); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs new file mode 100644 index 00000000000..dbea1480445 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs @@ -0,0 +1,10 @@ +// unit-test: DataflowConstProp + +// EMIT_MIR mult_by_zero.test.DataflowConstProp.diff +fn test(x : i32) -> i32 { + x * 0 +} + +fn main() { + test(10); +} diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff new file mode 100644 index 00000000000..91bc10a562f --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff @@ -0,0 +1,18 @@ +- // MIR for `test` before DataflowConstProp ++ // MIR for `test` after DataflowConstProp + + fn test(_1: i32) -> i32 { + debug x => _1; + let mut _0: i32; + let mut _2: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = Mul(move _2, const 0_i32); ++ _0 = const 0_i32; + StorageDead(_2); + return; + } + } +