Skip to content

Commit b645894

Browse files
committed
[mir-opt] Lower CopyNonOverlapping(*src, *dst, 1) to *dst = *src
1 parent 50ca3ac commit b645894

File tree

3 files changed

+157
-10
lines changed

3 files changed

+157
-10
lines changed

compiler/rustc_mir/src/transform/lower_intrinsics.rs

+34-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub struct LowerIntrinsics;
1111

1212
impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
1313
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
14+
let param_env = tcx.param_env(body.source.def_id()).with_reveal_all_normalized(tcx);
1415
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
1516
for block in basic_blocks {
1617
let terminator = block.terminator.as_mut().unwrap();
@@ -43,22 +44,36 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
4344
sym::copy_nonoverlapping => {
4445
let target = destination.unwrap().1;
4546
let mut args = args.drain(..);
46-
block.statements.push(Statement {
47-
source_info: terminator.source_info,
48-
kind: StatementKind::CopyNonOverlapping(
49-
box rustc_middle::mir::CopyNonOverlapping {
50-
src: args.next().unwrap(),
51-
dst: args.next().unwrap(),
52-
count: args.next().unwrap(),
53-
},
54-
),
55-
});
47+
let src = args.next().unwrap();
48+
let dst = args.next().unwrap();
49+
let count = args.next().unwrap();
50+
5651
assert_eq!(
5752
args.next(),
5853
None,
5954
"Extra argument for copy_non_overlapping intrinsic"
6055
);
6156
drop(args);
57+
58+
let stmt = if let (Some(1), Some(src), Some(dst)) = (
59+
eval_operand_to_usize(tcx, param_env, &count),
60+
src.place(),
61+
dst.place(),
62+
) {
63+
StatementKind::Assign(box (
64+
tcx.mk_place_deref(dst),
65+
Rvalue::Use(Operand::Copy(tcx.mk_place_deref(src))),
66+
))
67+
} else {
68+
StatementKind::CopyNonOverlapping(
69+
box rustc_middle::mir::CopyNonOverlapping { src, dst, count },
70+
)
71+
};
72+
73+
block
74+
.statements
75+
.push(Statement { source_info: terminator.source_info, kind: stmt });
76+
6277
terminator.kind = TerminatorKind::Goto { target };
6378
}
6479
sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
@@ -126,6 +141,15 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
126141
}
127142
}
128143

144+
fn eval_operand_to_usize(
145+
tcx: TyCtxt<'tcx>,
146+
param_env: rustc_middle::ty::ParamEnv<'tcx>,
147+
operand: &Operand<'tcx>,
148+
) -> Option<u64> {
149+
let constant = operand.constant()?;
150+
Some(constant.literal.try_eval_usize(tcx, param_env)?)
151+
}
152+
129153
fn resolve_rust_intrinsic(
130154
tcx: TyCtxt<'tcx>,
131155
func_ty: Ty<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
- // MIR for `copy_nonoverlapping` before LowerIntrinsics
2+
+ // MIR for `copy_nonoverlapping` after LowerIntrinsics
3+
4+
fn copy_nonoverlapping() -> () {
5+
let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:76:30: 76:30
6+
let _1: i32; // in scope 0 at $DIR/lower_intrinsics.rs:77:9: 77:12
7+
let _4: (); // in scope 0 at $DIR/lower_intrinsics.rs:82:9: 82:88
8+
let mut _5: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:46: 82:62
9+
let mut _6: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:46: 82:62
10+
let _7: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:46: 82:50
11+
let mut _8: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:64: 82:84
12+
let mut _9: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:64: 82:84
13+
let mut _10: &mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:82:64: 82:74
14+
let _11: (); // in scope 0 at $DIR/lower_intrinsics.rs:83:9: 83:88
15+
let mut _12: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:46: 83:62
16+
let mut _13: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:46: 83:62
17+
let _14: &i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:46: 83:50
18+
let mut _15: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:64: 83:84
19+
let mut _16: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:64: 83:84
20+
let mut _17: &mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:83:64: 83:74
21+
scope 1 {
22+
debug src => _1; // in scope 1 at $DIR/lower_intrinsics.rs:77:9: 77:12
23+
let mut _2: i32; // in scope 1 at $DIR/lower_intrinsics.rs:78:9: 78:18
24+
scope 2 {
25+
debug dst_1 => _2; // in scope 2 at $DIR/lower_intrinsics.rs:78:9: 78:18
26+
let mut _3: i32; // in scope 2 at $DIR/lower_intrinsics.rs:79:9: 79:18
27+
scope 3 {
28+
debug dst_2 => _3; // in scope 3 at $DIR/lower_intrinsics.rs:79:9: 79:18
29+
scope 4 {
30+
}
31+
}
32+
}
33+
}
34+
35+
bb0: {
36+
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:77:9: 77:12
37+
_1 = const 42_i32; // scope 0 at $DIR/lower_intrinsics.rs:77:15: 77:17
38+
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:78:9: 78:18
39+
_2 = const 1_i32; // scope 1 at $DIR/lower_intrinsics.rs:78:21: 78:22
40+
StorageLive(_3); // scope 2 at $DIR/lower_intrinsics.rs:79:9: 79:18
41+
_3 = const 2_i32; // scope 2 at $DIR/lower_intrinsics.rs:79:21: 79:22
42+
StorageLive(_4); // scope 4 at $DIR/lower_intrinsics.rs:82:9: 82:88
43+
StorageLive(_5); // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:62
44+
StorageLive(_6); // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:62
45+
StorageLive(_7); // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:50
46+
_7 = &_1; // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:50
47+
_6 = &raw const (*_7); // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:50
48+
_5 = _6; // scope 4 at $DIR/lower_intrinsics.rs:82:46: 82:62
49+
StorageLive(_8); // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:84
50+
StorageLive(_9); // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:84
51+
StorageLive(_10); // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:74
52+
_10 = &mut _2; // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:74
53+
_9 = &raw mut (*_10); // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:74
54+
_8 = _9; // scope 4 at $DIR/lower_intrinsics.rs:82:64: 82:84
55+
- _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
56+
- // mir::Constant
57+
- // + span: $DIR/lower_intrinsics.rs:82:9: 82:45
58+
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {std::intrinsics::copy_nonoverlapping::<i32>}, val: Value(Scalar(<ZST>)) }
59+
+ (*_8) = (*_5); // scope 4 at $DIR/lower_intrinsics.rs:82:9: 82:88
60+
+ goto -> bb1; // scope 4 at $DIR/lower_intrinsics.rs:82:9: 82:88
61+
}
62+
63+
bb1: {
64+
StorageDead(_8); // scope 4 at $DIR/lower_intrinsics.rs:82:87: 82:88
65+
StorageDead(_5); // scope 4 at $DIR/lower_intrinsics.rs:82:87: 82:88
66+
StorageDead(_10); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
67+
StorageDead(_9); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
68+
StorageDead(_7); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
69+
StorageDead(_6); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
70+
StorageDead(_4); // scope 4 at $DIR/lower_intrinsics.rs:82:88: 82:89
71+
StorageLive(_11); // scope 4 at $DIR/lower_intrinsics.rs:83:9: 83:88
72+
StorageLive(_12); // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:62
73+
StorageLive(_13); // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:62
74+
StorageLive(_14); // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:50
75+
_14 = &_1; // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:50
76+
_13 = &raw const (*_14); // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:50
77+
_12 = _13; // scope 4 at $DIR/lower_intrinsics.rs:83:46: 83:62
78+
StorageLive(_15); // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:84
79+
StorageLive(_16); // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:84
80+
StorageLive(_17); // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:74
81+
_17 = &mut _3; // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:74
82+
_16 = &raw mut (*_17); // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:74
83+
_15 = _16; // scope 4 at $DIR/lower_intrinsics.rs:83:64: 83:84
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
85+
- // mir::Constant
86+
- // + span: $DIR/lower_intrinsics.rs:83:9: 83:45
87+
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {std::intrinsics::copy_nonoverlapping::<i32>}, val: Value(Scalar(<ZST>)) }
88+
+ (*_15) = (*_12); // scope 4 at $DIR/lower_intrinsics.rs:83:9: 83:88
89+
+ goto -> bb2; // scope 4 at $DIR/lower_intrinsics.rs:83:9: 83:88
90+
}
91+
92+
bb2: {
93+
StorageDead(_15); // scope 4 at $DIR/lower_intrinsics.rs:83:87: 83:88
94+
StorageDead(_12); // scope 4 at $DIR/lower_intrinsics.rs:83:87: 83:88
95+
StorageDead(_17); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
96+
StorageDead(_16); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
97+
StorageDead(_14); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
98+
StorageDead(_13); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
99+
StorageDead(_11); // scope 4 at $DIR/lower_intrinsics.rs:83:88: 83:89
100+
_0 = const (); // scope 4 at $DIR/lower_intrinsics.rs:81:5: 84:6
101+
StorageDead(_3); // scope 2 at $DIR/lower_intrinsics.rs:85:1: 85:2
102+
StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:85:1: 85:2
103+
StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:85:1: 85:2
104+
return; // scope 0 at $DIR/lower_intrinsics.rs:85:2: 85:2
105+
}
106+
107+
bb3 (cleanup): {
108+
resume; // scope 0 at $DIR/lower_intrinsics.rs:76:1: 85:2
109+
}
110+
}
111+

src/test/mir-opt/lower_intrinsics.rs

+12
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,15 @@ pub fn discriminant<T>(t: T) {
7171
core::intrinsics::discriminant_value(&());
7272
core::intrinsics::discriminant_value(&E::B);
7373
}
74+
75+
// EMIT_MIR lower_intrinsics.copy_nonoverlapping.LowerIntrinsics.diff
76+
pub fn copy_nonoverlapping() {
77+
let src = 42;
78+
let mut dst_1 = 1;
79+
let mut dst_2 = 2;
80+
81+
unsafe {
82+
std::intrinsics::copy_nonoverlapping(&src as *const _, &mut dst_1 as *mut _, 1);
83+
std::intrinsics::copy_nonoverlapping(&src as *const _, &mut dst_2 as *mut _, 1);
84+
}
85+
}

0 commit comments

Comments
 (0)