diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index 74dadb2572565..25c0bcc5b73ab 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -3,10 +3,13 @@ use crate::transform::MirPass; use rustc_hir::Mutability; use rustc_middle::mir::{ - BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, - StatementKind, + BasicBlock, LocalDecls, PlaceElem, SourceInfo, Statement, StatementKind, Terminator, + TerminatorKind, }; +use rustc_middle::mir::{BinOp, Body, Constant, Local, Operand, Place, ProjectionElem, Rvalue}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{sym, Symbol}; +use rustc_target::spec::abi::Abi; pub struct InstCombine; @@ -25,6 +28,10 @@ impl<'tcx> MirPass<'tcx> for InstCombine { _ => {} } } + + if let Some(terminator) = &mut block.terminator { + ctx.combine_copy_nonoverlapping(terminator, local_decls, &mut block.statements); + } } } } @@ -120,4 +127,78 @@ impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { } } } + + fn func_as_intrinsic( + &self, + operand: &Operand<'tcx>, + locals: &LocalDecls<'tcx>, + ) -> Option { + let func_ty = operand.ty(locals, self.tcx); + + if let ty::FnDef(def_id, _) = *func_ty.kind() { + let fn_sig = func_ty.fn_sig(self.tcx); + + if fn_sig.abi() == Abi::RustIntrinsic { + return Some(self.tcx.item_name(def_id)); + } + } + + None + } + + fn find_copy_nonoverlapping( + &self, + terminator: &Terminator<'tcx>, + locals: &LocalDecls<'tcx>, + ) -> Option<(Local, Local, BasicBlock)> { + if let TerminatorKind::Call { func, args, destination: Some((_, next_bb)), .. } = + &terminator.kind + { + let intrinsic = self.func_as_intrinsic(func, locals)?; + + if intrinsic == sym::copy_nonoverlapping && args.len() == 3 { + let src = args[0].place()?.as_local()?; + let dest = args[1].place()?.as_local()?; + let constant = args[2].constant()?; + + if constant.literal.ty == self.tcx.types.usize { + let val = constant + .literal + .val + .try_to_value()? + .try_to_scalar()? + .to_machine_usize(&self.tcx) + .ok()?; + + if val == 1 { + return Some((src, dest, *next_bb)); + } + } + } + } + + None + } + + fn combine_copy_nonoverlapping( + &self, + terminator: &mut Terminator<'tcx>, + locals: &LocalDecls<'tcx>, + statements: &mut Vec>, + ) { + if let Some((src, dest, next_bb)) = self.find_copy_nonoverlapping(terminator, locals) { + trace!("replacing call to copy_nonoverlapping({:?}, {:?}, 1) intrinsic", src, dest); + let deref_projection = self.tcx._intern_place_elems(&[PlaceElem::Deref]); + + statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + Place { local: dest, projection: deref_projection }, + Rvalue::Use(Operand::Copy(Place { local: src, projection: deref_projection })), + ))), + }); + + terminator.kind = TerminatorKind::Goto { target: next_bb }; + } + } } diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index e509c35de40b8..842c9db334b11 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -482,6 +482,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &multiple_return_terminators::MultipleReturnTerminators, &instcombine::InstCombine, + &simplify::SimplifyCfg::new("after-instcombine"), &const_prop::ConstProp, &simplify_branches::SimplifyBranches::new("after-const-prop"), &early_otherwise_branch::EarlyOtherwiseBranch, diff --git a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index 04a8c94e003c4..0f718a720f4cc 100644 --- a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -3,47 +3,45 @@ fn num_to_digit(_1: char) -> u32 { debug num => _1; // in scope 0 at $DIR/issue-59352.rs:12:21: 12:24 let mut _0: u32; // return place in scope 0 at $DIR/issue-59352.rs:12:35: 12:38 - let mut _2: bool; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - let mut _3: std::option::Option; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:41 - let mut _4: char; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:29 - let mut _5: u32; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - let mut _10: isize; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:41 + let mut _3: char; // in scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + let mut _4: u32; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + let mut _9: isize; // in scope 0 at $DIR/issue-59352.rs:14:8: 14:23 scope 1 (inlined char::methods::::is_digit) { // at $DIR/issue-59352.rs:14:8: 14:23 - debug self => _8; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - debug radix => _5; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - let mut _6: &std::option::Option; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - let _7: std::option::Option; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - let mut _8: char; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + debug self => _7; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + debug radix => _4; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + let mut _5: &std::option::Option; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + let _6: std::option::Option; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + let mut _7: char; // in scope 1 at $DIR/issue-59352.rs:14:8: 14:23 scope 2 (inlined Option::::is_some) { // at $DIR/issue-59352.rs:14:8: 14:23 - debug self => _6; // in scope 2 at $DIR/issue-59352.rs:14:8: 14:23 + debug self => _5; // in scope 2 at $DIR/issue-59352.rs:14:8: 14:23 } } scope 3 (inlined #[track_caller] Option::::unwrap) { // at $DIR/issue-59352.rs:14:26: 14:50 - debug self => _3; // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50 - let mut _9: isize; // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + debug self => _2; // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + let mut _8: isize; // in scope 3 at $DIR/issue-59352.rs:14:26: 14:50 scope 4 { debug val => _0; // in scope 4 at $DIR/issue-59352.rs:14:26: 14:50 } } bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - _8 = _1; // scope 0 at $DIR/issue-59352.rs:14:8: 14:11 - StorageLive(_5); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - _5 = const 8_u32; // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + _7 = _1; // scope 0 at $DIR/issue-59352.rs:14:8: 14:11 + StorageLive(_4); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + _4 = const 8_u32; // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + StorageLive(_5); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 StorageLive(_6); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - StorageLive(_7); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - _7 = char::methods::::to_digit(move _8, const 8_u32) -> bb5; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + _6 = char::methods::::to_digit(move _7, const 8_u32) -> bb5; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 // mir::Constant // + span: $DIR/issue-59352.rs:14:8: 14:23 // + literal: Const { ty: fn(char, u32) -> std::option::Option {std::char::methods::::to_digit}, val: Value(Scalar()) } } bb1: { - StorageLive(_3); // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 - StorageLive(_4); // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 - _4 = _1; // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 - _3 = char::methods::::to_digit(move _4, const 8_u32) -> bb3; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 + StorageLive(_2); // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 + StorageLive(_3); // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + _3 = _1; // scope 0 at $DIR/issue-59352.rs:14:26: 14:29 + _2 = char::methods::::to_digit(move _3, const 8_u32) -> bb3; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 // mir::Constant // + span: $DIR/issue-59352.rs:14:30: 14:38 // + literal: Const { ty: fn(char, u32) -> std::option::Option {std::char::methods::::to_digit}, val: Value(Scalar()) } @@ -55,25 +53,23 @@ fn num_to_digit(_1: char) -> u32 { } bb3: { - StorageDead(_4); // scope 0 at $DIR/issue-59352.rs:14:40: 14:41 - StorageLive(_9); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 - _9 = discriminant(_3); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 - switchInt(move _9) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + StorageDead(_3); // scope 0 at $DIR/issue-59352.rs:14:40: 14:41 + StorageLive(_8); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 + _8 = discriminant(_2); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + switchInt(move _8) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 } bb4: { - StorageDead(_2); // scope 0 at $DIR/issue-59352.rs:14:62: 14:63 return; // scope 0 at $DIR/issue-59352.rs:15:2: 15:2 } bb5: { - _6 = &_7; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - _10 = discriminant((*_6)); // scope 2 at $DIR/issue-59352.rs:14:8: 14:23 - _2 = Eq(_10, const 1_isize); // scope 2 at $DIR/issue-59352.rs:14:8: 14:23 + _5 = &_6; // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 + _9 = discriminant((*_5)); // scope 2 at $DIR/issue-59352.rs:14:8: 14:23 + StorageDead(_5); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 StorageDead(_6); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - StorageDead(_7); // scope 1 at $DIR/issue-59352.rs:14:8: 14:23 - StorageDead(_5); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63 + StorageDead(_4); // scope 0 at $DIR/issue-59352.rs:14:8: 14:23 + switchInt(move _9) -> [1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63 } bb6: { @@ -94,9 +90,9 @@ fn num_to_digit(_1: char) -> u32 { } bb8: { - _0 = move ((_3 as Some).0: u32); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 - StorageDead(_9); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 - StorageDead(_3); // scope 0 at $DIR/issue-59352.rs:14:49: 14:50 + _0 = move ((_2 as Some).0: u32); // scope 3 at $DIR/issue-59352.rs:14:26: 14:50 + StorageDead(_8); // scope 0 at $DIR/issue-59352.rs:14:26: 14:50 + StorageDead(_2); // scope 0 at $DIR/issue-59352.rs:14:49: 14:50 goto -> bb4; // scope 0 at $DIR/issue-59352.rs:14:5: 14:63 } }