diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 23124523f17..cf1fff97f2a 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -823,18 +823,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return self.simplify_cast(kind, value, to, location); } Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => { - let ty = lhs.ty(self.local_decls, self.tcx); - let lhs = self.simplify_operand(lhs, location); - let rhs = self.simplify_operand(rhs, location); - // Only short-circuit options after we called `simplify_operand` - // on both operands for side effect. - let lhs = lhs?; - let rhs = rhs?; - - if let Some(value) = self.simplify_binary(op, ty, lhs, rhs) { - return Some(value); - } - Value::BinaryOp(op, lhs, rhs) + return self.simplify_binary(op, lhs, rhs, location); } Rvalue::UnaryOp(op, ref mut arg_op) => { return self.simplify_unary(op, arg_op, location); @@ -1059,6 +1048,52 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { #[instrument(level = "trace", skip(self), ret)] fn simplify_binary( + &mut self, + op: BinOp, + lhs_operand: &mut Operand<'tcx>, + rhs_operand: &mut Operand<'tcx>, + location: Location, + ) -> Option { + + let lhs = self.simplify_operand(lhs_operand, location); + let rhs = self.simplify_operand(rhs_operand, location); + // Only short-circuit options after we called `simplify_operand` + // on both operands for side effect. + let mut lhs = lhs?; + let mut rhs = rhs?; + + let lhs_ty = lhs_operand.ty(self.local_decls, self.tcx); + + // If we're comparing pointers, remove `PtrToPtr` casts if the from + // types of both casts and the metadata all match. + if let BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge = op + && lhs_ty.is_any_ptr() + && let Value::Cast { kind: CastKind::PtrToPtr, value: lhs_value, from: lhs_from, .. } = + self.get(lhs) + && let Value::Cast { kind: CastKind::PtrToPtr, value: rhs_value, from: rhs_from, .. } = + self.get(rhs) + && lhs_from == rhs_from + && lhs_from.pointee_metadata_ty_or_projection(self.tcx) + == lhs_ty.pointee_metadata_ty_or_projection(self.tcx) + { + lhs = *lhs_value; + rhs = *rhs_value; + if let Some(op) = self.try_as_operand(lhs, location) { + *lhs_operand = op; + } + if let Some(op) = self.try_as_operand(rhs, location) { + *rhs_operand = op; + } + } + + if let Some(value) = self.simplify_binary_inner(op, lhs_ty, lhs, rhs) { + return Some(value); + } + let value = Value::BinaryOp(op, lhs, rhs); + Some(self.insert(value)) + } + + fn simplify_binary_inner( &mut self, op: BinOp, lhs_ty: Ty<'tcx>, diff --git a/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-abort.diff b/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-abort.diff new file mode 100644 index 00000000000..757ab959813 --- /dev/null +++ b/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-abort.diff @@ -0,0 +1,134 @@ +- // MIR for `cast_pointer_eq` before GVN ++ // MIR for `cast_pointer_eq` after GVN + + fn cast_pointer_eq(_1: *mut u8, _2: *mut u32, _3: *mut u32, _4: *mut [u32]) -> () { + debug p1 => _1; + debug p2 => _2; + debug p3 => _3; + debug p4 => _4; + let mut _0: (); + let _5: *const u32; + let mut _6: *mut u8; + let mut _8: *const u32; + let mut _9: *mut u32; + let mut _11: *const u32; + let mut _12: *mut u32; + let mut _14: *mut [u32]; + let mut _16: *const u32; + let mut _17: *const u32; + let mut _19: *const u32; + let mut _20: *const u32; + let mut _22: *const u32; + let mut _23: *const u32; + scope 1 { + debug m1 => _5; + let _7: *const u32; + scope 2 { + debug m2 => _7; + let _10: *const u32; + scope 3 { + debug m3 => _10; + let _13: *const u32; + scope 4 { + debug m4 => _13; + let _15: bool; + scope 5 { + debug eq_different_thing => _15; + let _18: bool; + scope 6 { + debug eq_optimize => _18; + let _21: bool; + scope 7 { + debug eq_thin_fat => _21; + } + } + } + } + } + } + } + + bb0: { +- StorageLive(_5); ++ nop; + StorageLive(_6); + _6 = _1; +- _5 = move _6 as *const u32 (PtrToPtr); ++ _5 = _1 as *const u32 (PtrToPtr); + StorageDead(_6); + StorageLive(_7); +- StorageLive(_8); ++ nop; + StorageLive(_9); + _9 = _2; +- _8 = move _9 as *const u32 (PtrToPtr); ++ _8 = _2 as *const u32 (PtrToPtr); + StorageDead(_9); +- _7 = move _8 as *const u32 (PtrToPtr); +- StorageDead(_8); ++ _7 = _8; ++ nop; + StorageLive(_10); +- StorageLive(_11); ++ nop; + StorageLive(_12); + _12 = _3; +- _11 = move _12 as *const u32 (PtrToPtr); ++ _11 = _3 as *const u32 (PtrToPtr); + StorageDead(_12); +- _10 = move _11 as *const u32 (PtrToPtr); +- StorageDead(_11); +- StorageLive(_13); ++ _10 = _11; ++ nop; ++ nop; + StorageLive(_14); + _14 = _4; +- _13 = move _14 as *const u32 (PtrToPtr); ++ _13 = _4 as *const u32 (PtrToPtr); + StorageDead(_14); + StorageLive(_15); + StorageLive(_16); + _16 = _5; + StorageLive(_17); +- _17 = _7; +- _15 = Eq(move _16, move _17); ++ _17 = _8; ++ _15 = Eq(_5, _8); + StorageDead(_17); + StorageDead(_16); + StorageLive(_18); + StorageLive(_19); +- _19 = _7; ++ _19 = _8; + StorageLive(_20); +- _20 = _10; +- _18 = Eq(move _19, move _20); ++ _20 = _11; ++ _18 = Eq(_2, _3); + StorageDead(_20); + StorageDead(_19); + StorageLive(_21); + StorageLive(_22); +- _22 = _10; ++ _22 = _11; + StorageLive(_23); + _23 = _13; +- _21 = Eq(move _22, move _23); ++ _21 = Eq(_11, _13); + StorageDead(_23); + StorageDead(_22); + _0 = const (); + StorageDead(_21); + StorageDead(_18); + StorageDead(_15); +- StorageDead(_13); ++ nop; + StorageDead(_10); + StorageDead(_7); +- StorageDead(_5); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-unwind.diff b/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-unwind.diff new file mode 100644 index 00000000000..757ab959813 --- /dev/null +++ b/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-unwind.diff @@ -0,0 +1,134 @@ +- // MIR for `cast_pointer_eq` before GVN ++ // MIR for `cast_pointer_eq` after GVN + + fn cast_pointer_eq(_1: *mut u8, _2: *mut u32, _3: *mut u32, _4: *mut [u32]) -> () { + debug p1 => _1; + debug p2 => _2; + debug p3 => _3; + debug p4 => _4; + let mut _0: (); + let _5: *const u32; + let mut _6: *mut u8; + let mut _8: *const u32; + let mut _9: *mut u32; + let mut _11: *const u32; + let mut _12: *mut u32; + let mut _14: *mut [u32]; + let mut _16: *const u32; + let mut _17: *const u32; + let mut _19: *const u32; + let mut _20: *const u32; + let mut _22: *const u32; + let mut _23: *const u32; + scope 1 { + debug m1 => _5; + let _7: *const u32; + scope 2 { + debug m2 => _7; + let _10: *const u32; + scope 3 { + debug m3 => _10; + let _13: *const u32; + scope 4 { + debug m4 => _13; + let _15: bool; + scope 5 { + debug eq_different_thing => _15; + let _18: bool; + scope 6 { + debug eq_optimize => _18; + let _21: bool; + scope 7 { + debug eq_thin_fat => _21; + } + } + } + } + } + } + } + + bb0: { +- StorageLive(_5); ++ nop; + StorageLive(_6); + _6 = _1; +- _5 = move _6 as *const u32 (PtrToPtr); ++ _5 = _1 as *const u32 (PtrToPtr); + StorageDead(_6); + StorageLive(_7); +- StorageLive(_8); ++ nop; + StorageLive(_9); + _9 = _2; +- _8 = move _9 as *const u32 (PtrToPtr); ++ _8 = _2 as *const u32 (PtrToPtr); + StorageDead(_9); +- _7 = move _8 as *const u32 (PtrToPtr); +- StorageDead(_8); ++ _7 = _8; ++ nop; + StorageLive(_10); +- StorageLive(_11); ++ nop; + StorageLive(_12); + _12 = _3; +- _11 = move _12 as *const u32 (PtrToPtr); ++ _11 = _3 as *const u32 (PtrToPtr); + StorageDead(_12); +- _10 = move _11 as *const u32 (PtrToPtr); +- StorageDead(_11); +- StorageLive(_13); ++ _10 = _11; ++ nop; ++ nop; + StorageLive(_14); + _14 = _4; +- _13 = move _14 as *const u32 (PtrToPtr); ++ _13 = _4 as *const u32 (PtrToPtr); + StorageDead(_14); + StorageLive(_15); + StorageLive(_16); + _16 = _5; + StorageLive(_17); +- _17 = _7; +- _15 = Eq(move _16, move _17); ++ _17 = _8; ++ _15 = Eq(_5, _8); + StorageDead(_17); + StorageDead(_16); + StorageLive(_18); + StorageLive(_19); +- _19 = _7; ++ _19 = _8; + StorageLive(_20); +- _20 = _10; +- _18 = Eq(move _19, move _20); ++ _20 = _11; ++ _18 = Eq(_2, _3); + StorageDead(_20); + StorageDead(_19); + StorageLive(_21); + StorageLive(_22); +- _22 = _10; ++ _22 = _11; + StorageLive(_23); + _23 = _13; +- _21 = Eq(move _22, move _23); ++ _21 = Eq(_11, _13); + StorageDead(_23); + StorageDead(_22); + _0 = const (); + StorageDead(_21); + StorageDead(_18); + StorageDead(_15); +- StorageDead(_13); ++ nop; + StorageDead(_10); + StorageDead(_7); +- StorageDead(_5); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 8bc2550b8f5..6f1580b49ed 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -883,6 +883,36 @@ fn generic_cast_metadata(ps: *const [T], pa: *const A, } } +fn cast_pointer_eq(p1: *mut u8, p2: *mut u32, p3: *mut u32, p4: *mut [u32]) { + // CHECK-LABEL: fn cast_pointer_eq + // CHECK: debug p1 => [[P1:_1]]; + // CHECK: debug p2 => [[P2:_2]]; + // CHECK: debug p3 => [[P3:_3]]; + // CHECK: debug p4 => [[P4:_4]]; + + // CHECK: [[M1:_.+]] = [[P1]] as *const u32 (PtrToPtr); + // CHECK: [[M2:_.+]] = [[P2]] as *const u32 (PtrToPtr); + // CHECK: [[M3:_.+]] = [[P3]] as *const u32 (PtrToPtr); + // CHECK: [[M4:_.+]] = [[P4]] as *const u32 (PtrToPtr); + let m1 = p1 as *const u32; + let m2 = p2 as *const u32; + let m3 = p3 as *const u32; + let m4 = p4 as *const u32; + + // CHECK-NOT: Eq + // CHECK: Eq([[M1]], [[M2]]) + // CHECK-NOT: Eq + // CHECK: Eq([[P2]], [[P3]]) + // CHECK-NOT: Eq + // CHECK: Eq([[M3]], [[M4]]) + // CHECK-NOT: Eq + let eq_different_thing = m1 == m2; + let eq_optimize = m2 == m3; + let eq_thin_fat = m3 == m4; + + // CHECK: _0 = const (); +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); @@ -950,3 +980,4 @@ fn identity(x: T) -> T { // EMIT_MIR gvn.manual_slice_mut_len.GVN.diff // EMIT_MIR gvn.array_len.GVN.diff // EMIT_MIR gvn.generic_cast_metadata.GVN.diff +// EMIT_MIR gvn.cast_pointer_eq.GVN.diff diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir index 5988a0a03ef..19548beaf2a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir @@ -6,27 +6,25 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { scope 1 (inlined as ExactSizeIterator>::is_empty) { let mut _2: *const *const T; let mut _3: *const std::ptr::NonNull; - let mut _10: *const T; + let mut _8: *const T; scope 2 { let _4: std::ptr::NonNull; - let _12: usize; + let _10: usize; scope 3 { } scope 4 { scope 8 (inlined as PartialEq>::eq) { let mut _5: std::ptr::NonNull; - let mut _7: *mut T; - let mut _9: *mut T; scope 9 (inlined NonNull::::as_ptr) { let mut _6: *const T; } scope 10 (inlined NonNull::::as_ptr) { - let mut _8: *const T; + let mut _7: *const T; } } } scope 5 (inlined std::ptr::const_ptr::::addr) { - let mut _11: *const (); + let mut _9: *const (); scope 6 (inlined std::ptr::const_ptr::::cast::<()>) { } } @@ -36,7 +34,7 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { } bb0: { - StorageLive(_12); + StorageLive(_10); StorageLive(_4); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -49,40 +47,34 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { StorageDead(_2); _4 = (*_3); StorageDead(_3); + StorageLive(_6); StorageLive(_7); StorageLive(_5); _5 = ((*_1).0: std::ptr::NonNull); - StorageLive(_6); _6 = (_5.0: *const T); - _7 = move _6 as *mut T (PtrToPtr); - StorageDead(_6); StorageDead(_5); - StorageLive(_9); - StorageLive(_8); - _8 = (_4.0: *const T); - _9 = move _8 as *mut T (PtrToPtr); - StorageDead(_8); - _0 = Eq(move _7, move _9); - StorageDead(_9); + _7 = (_4.0: *const T); + _0 = Eq(_6, _7); StorageDead(_7); + StorageDead(_6); goto -> bb3; } bb2: { - StorageLive(_10); - _10 = ((*_1).1: *const T); - StorageLive(_11); - _11 = _10 as *const () (PtrToPtr); - _12 = move _11 as usize (Transmute); - StorageDead(_11); - StorageDead(_10); - _0 = Eq(_12, const 0_usize); + StorageLive(_8); + _8 = ((*_1).1: *const T); + StorageLive(_9); + _9 = _8 as *const () (PtrToPtr); + _10 = move _9 as usize (Transmute); + StorageDead(_9); + StorageDead(_8); + _0 = Eq(_10, const 0_usize); goto -> bb3; } bb3: { StorageDead(_4); - StorageDead(_12); + StorageDead(_10); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir index 5988a0a03ef..19548beaf2a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir @@ -6,27 +6,25 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { scope 1 (inlined as ExactSizeIterator>::is_empty) { let mut _2: *const *const T; let mut _3: *const std::ptr::NonNull; - let mut _10: *const T; + let mut _8: *const T; scope 2 { let _4: std::ptr::NonNull; - let _12: usize; + let _10: usize; scope 3 { } scope 4 { scope 8 (inlined as PartialEq>::eq) { let mut _5: std::ptr::NonNull; - let mut _7: *mut T; - let mut _9: *mut T; scope 9 (inlined NonNull::::as_ptr) { let mut _6: *const T; } scope 10 (inlined NonNull::::as_ptr) { - let mut _8: *const T; + let mut _7: *const T; } } } scope 5 (inlined std::ptr::const_ptr::::addr) { - let mut _11: *const (); + let mut _9: *const (); scope 6 (inlined std::ptr::const_ptr::::cast::<()>) { } } @@ -36,7 +34,7 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { } bb0: { - StorageLive(_12); + StorageLive(_10); StorageLive(_4); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -49,40 +47,34 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { StorageDead(_2); _4 = (*_3); StorageDead(_3); + StorageLive(_6); StorageLive(_7); StorageLive(_5); _5 = ((*_1).0: std::ptr::NonNull); - StorageLive(_6); _6 = (_5.0: *const T); - _7 = move _6 as *mut T (PtrToPtr); - StorageDead(_6); StorageDead(_5); - StorageLive(_9); - StorageLive(_8); - _8 = (_4.0: *const T); - _9 = move _8 as *mut T (PtrToPtr); - StorageDead(_8); - _0 = Eq(move _7, move _9); - StorageDead(_9); + _7 = (_4.0: *const T); + _0 = Eq(_6, _7); StorageDead(_7); + StorageDead(_6); goto -> bb3; } bb2: { - StorageLive(_10); - _10 = ((*_1).1: *const T); - StorageLive(_11); - _11 = _10 as *const () (PtrToPtr); - _12 = move _11 as usize (Transmute); - StorageDead(_11); - StorageDead(_10); - _0 = Eq(_12, const 0_usize); + StorageLive(_8); + _8 = ((*_1).1: *const T); + StorageLive(_9); + _9 = _8 as *const () (PtrToPtr); + _10 = move _9 as usize (Transmute); + StorageDead(_9); + StorageDead(_8); + _0 = Eq(_10, const 0_usize); goto -> bb3; } bb3: { StorageDead(_4); - StorageDead(_12); + StorageDead(_10); return; } }