Skip to content

Commit

Permalink
[mir-opt] Lower CopyNonOverlapping(*src, *dst, 1) to *dst = *src
Browse files Browse the repository at this point in the history
  • Loading branch information
wesleywiser committed Apr 29, 2021
1 parent 50ca3ac commit b645894
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 10 deletions.
44 changes: 34 additions & 10 deletions compiler/rustc_mir/src/transform/lower_intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct LowerIntrinsics;

impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let param_env = tcx.param_env(body.source.def_id()).with_reveal_all_normalized(tcx);
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
for block in basic_blocks {
let terminator = block.terminator.as_mut().unwrap();
Expand Down Expand Up @@ -43,22 +44,36 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
sym::copy_nonoverlapping => {
let target = destination.unwrap().1;
let mut args = args.drain(..);
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::CopyNonOverlapping(
box rustc_middle::mir::CopyNonOverlapping {
src: args.next().unwrap(),
dst: args.next().unwrap(),
count: args.next().unwrap(),
},
),
});
let src = args.next().unwrap();
let dst = args.next().unwrap();
let count = args.next().unwrap();

assert_eq!(
args.next(),
None,
"Extra argument for copy_non_overlapping intrinsic"
);
drop(args);

let stmt = if let (Some(1), Some(src), Some(dst)) = (
eval_operand_to_usize(tcx, param_env, &count),
src.place(),
dst.place(),
) {
StatementKind::Assign(box (
tcx.mk_place_deref(dst),
Rvalue::Use(Operand::Copy(tcx.mk_place_deref(src))),
))
} else {
StatementKind::CopyNonOverlapping(
box rustc_middle::mir::CopyNonOverlapping { src, dst, count },
)
};

block
.statements
.push(Statement { source_info: terminator.source_info, kind: stmt });

terminator.kind = TerminatorKind::Goto { target };
}
sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
Expand Down Expand Up @@ -126,6 +141,15 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
}
}

fn eval_operand_to_usize(
tcx: TyCtxt<'tcx>,
param_env: rustc_middle::ty::ParamEnv<'tcx>,
operand: &Operand<'tcx>,
) -> Option<u64> {
let constant = operand.constant()?;
Some(constant.literal.try_eval_usize(tcx, param_env)?)
}

fn resolve_rust_intrinsic(
tcx: TyCtxt<'tcx>,
func_ty: Ty<'tcx>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
- // MIR for `copy_nonoverlapping` before LowerIntrinsics
+ // MIR for `copy_nonoverlapping` after LowerIntrinsics

fn copy_nonoverlapping() -> () {
let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:76:30: 76:30
let _1: i32; // in scope 0 at $DIR/lower_intrinsics.rs:77:9: 77:12
let _4: (); // in scope 0 at $DIR/lower_intrinsics.rs:82:9: 82:88
let mut _5: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:46: 82:62
let mut _6: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:46: 82:62
let _7: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:46: 82:50
let mut _8: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:64: 82:84
let mut _9: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:64: 82:84
let mut _10: &mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:64: 82:74
let _11: (); // in scope 0 at $DIR/lower_intrinsics.rs:83:9: 83:88
let mut _12: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:46: 83:62
let mut _13: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:46: 83:62
let _14: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:46: 83:50
let mut _15: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:64: 83:84
let mut _16: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:64: 83:84
let mut _17: &mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:64: 83:74
scope 1 {
debug src => _1; // in scope 1 at $DIR/lower_intrinsics.rs:77:9: 77:12
let mut _2: i32; // in scope 1 at $DIR/lower_intrinsics.rs:78:9: 78:18
scope 2 {
debug dst_1 => _2; // in scope 2 at $DIR/lower_intrinsics.rs:78:9: 78:18
let mut _3: i32; // in scope 2 at $DIR/lower_intrinsics.rs:79:9: 79:18
scope 3 {
debug dst_2 => _3; // in scope 3 at $DIR/lower_intrinsics.rs:79:9: 79:18
scope 4 {
}
}
}
}

bb0: {
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:77:9: 77:12
_1 = const 42_i32; // scope 0 at $DIR/lower_intrinsics.rs:77:15: 77:17
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:78:9: 78:18
_2 = const 1_i32; // scope 1 at $DIR/lower_intrinsics.rs:78:21: 78:22
StorageLive(_3); // scope 2 at $DIR/lower_intrinsics.rs:79:9: 79:18
_3 = const 2_i32; // scope 2 at $DIR/lower_intrinsics.rs:79:21: 79:22
StorageLive(_4); // scope 4 at $DIR/lower_intrinsics.rs:82:9: 82:88
StorageLive(_5); // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:62
StorageLive(_6); // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:62
StorageLive(_7); // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:50
_7 = &_1; // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:50
_6 = &raw const (*_7); // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:50
_5 = _6; // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:62
StorageLive(_8); // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:84
StorageLive(_9); // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:84
StorageLive(_10); // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:74
_10 = &mut _2; // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:74
_9 = &raw mut (*_10); // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:74
_8 = _9; // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:84
- _4 = std::intrinsics::copy_nonoverlapping::<i32>(move _5, move _8, const 1_usize) -> bb1; // scope 4 at $DIR/lower_intrinsics.rs:82:9: 82:88
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:82:9: 82:45
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {std::intrinsics::copy_nonoverlapping::<i32>}, val: Value(Scalar(<ZST>)) }
+ (*_8) = (*_5); // scope 4 at $DIR/lower_intrinsics.rs:82:9: 82:88
+ goto -> bb1; // scope 4 at $DIR/lower_intrinsics.rs:82:9: 82:88
}

bb1: {
StorageDead(_8); // scope 4 at $DIR/lower_intrinsics.rs:82:87: 82:88
StorageDead(_5); // scope 4 at $DIR/lower_intrinsics.rs:82:87: 82:88
StorageDead(_10); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
StorageDead(_9); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
StorageDead(_7); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
StorageDead(_6); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
StorageDead(_4); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
StorageLive(_11); // scope 4 at $DIR/lower_intrinsics.rs:83:9: 83:88
StorageLive(_12); // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:62
StorageLive(_13); // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:62
StorageLive(_14); // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:50
_14 = &_1; // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:50
_13 = &raw const (*_14); // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:50
_12 = _13; // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:62
StorageLive(_15); // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:84
StorageLive(_16); // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:84
StorageLive(_17); // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:74
_17 = &mut _3; // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:74
_16 = &raw mut (*_17); // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:74
_15 = _16; // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:84
- _11 = std::intrinsics::copy_nonoverlapping::<i32>(move _12, move _15, const 1_usize) -> bb2; // scope 4 at $DIR/lower_intrinsics.rs:83:9: 83:88
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:83:9: 83:45
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {std::intrinsics::copy_nonoverlapping::<i32>}, val: Value(Scalar(<ZST>)) }
+ (*_15) = (*_12); // scope 4 at $DIR/lower_intrinsics.rs:83:9: 83:88
+ goto -> bb2; // scope 4 at $DIR/lower_intrinsics.rs:83:9: 83:88
}

bb2: {
StorageDead(_15); // scope 4 at $DIR/lower_intrinsics.rs:83:87: 83:88
StorageDead(_12); // scope 4 at $DIR/lower_intrinsics.rs:83:87: 83:88
StorageDead(_17); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
StorageDead(_16); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
StorageDead(_14); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
StorageDead(_13); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
StorageDead(_11); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
_0 = const (); // scope 4 at $DIR/lower_intrinsics.rs:81:5: 84:6
StorageDead(_3); // scope 2 at $DIR/lower_intrinsics.rs:85:1: 85:2
StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:85:1: 85:2
StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:85:1: 85:2
return; // scope 0 at $DIR/lower_intrinsics.rs:85:2: 85:2
}

bb3 (cleanup): {
resume; // scope 0 at $DIR/lower_intrinsics.rs:76:1: 85:2
}
}

12 changes: 12 additions & 0 deletions src/test/mir-opt/lower_intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,15 @@ pub fn discriminant<T>(t: T) {
core::intrinsics::discriminant_value(&());
core::intrinsics::discriminant_value(&E::B);
}

// EMIT_MIR lower_intrinsics.copy_nonoverlapping.LowerIntrinsics.diff
pub fn copy_nonoverlapping() {
let src = 42;
let mut dst_1 = 1;
let mut dst_2 = 2;

unsafe {
std::intrinsics::copy_nonoverlapping(&src as *const _, &mut dst_1 as *mut _, 1);
std::intrinsics::copy_nonoverlapping(&src as *const _, &mut dst_2 as *mut _, 1);
}
}

0 comments on commit b645894

Please sign in to comment.