Skip to content

Commit af75f58

Browse files
committed
Compute binary ops between pointers in GVN.
1 parent b2dbe4e commit af75f58

File tree

3 files changed

+120
-68
lines changed

3 files changed

+120
-68
lines changed

compiler/rustc_mir_transform/src/dataflow_const_prop.rs

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
//!
33
//! Currently, this pass only propagates scalar values.
44
5-
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
5+
use rustc_const_eval::interpret::{
6+
ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Pointer, PointerArithmetic, Projectable,
7+
};
68
use rustc_data_structures::fx::FxHashMap;
79
use rustc_hir::def::DefKind;
810
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
@@ -935,12 +937,64 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
935937
}
936938

937939
fn binary_ptr_op(
938-
_ecx: &InterpCx<'mir, 'tcx, Self>,
939-
_bin_op: BinOp,
940-
_left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
941-
_right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
940+
ecx: &InterpCx<'mir, 'tcx, Self>,
941+
bin_op: BinOp,
942+
left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
943+
right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
942944
) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
943-
throw_machine_stop_str!("can't do pointer arithmetic");
945+
use rustc_middle::mir::BinOp::*;
946+
Ok(match bin_op {
947+
Eq | Ne | Lt | Le | Gt | Ge => {
948+
assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for`
949+
let size = ecx.pointer_size();
950+
// Just compare the bits. ScalarPairs are compared lexicographically.
951+
// We thus always compare pairs and simply fill scalars up with 0.
952+
let left = match **left {
953+
Immediate::Scalar(l) => (l.to_bits(size)?, 0),
954+
Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
955+
Immediate::Uninit => panic!("we should never see uninit data here"),
956+
};
957+
let right = match **right {
958+
Immediate::Scalar(r) => (r.to_bits(size)?, 0),
959+
Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
960+
Immediate::Uninit => panic!("we should never see uninit data here"),
961+
};
962+
let res = match bin_op {
963+
Eq => left == right,
964+
Ne => left != right,
965+
Lt => left < right,
966+
Le => left <= right,
967+
Gt => left > right,
968+
Ge => left >= right,
969+
_ => bug!(),
970+
};
971+
(ImmTy::from_bool(res, *ecx.tcx), false)
972+
}
973+
974+
// Some more operations are possible with atomics.
975+
// The return value always has the provenance of the *left* operand.
976+
Add | Sub | BitOr | BitAnd | BitXor => {
977+
assert!(left.layout.ty.is_unsafe_ptr());
978+
assert!(right.layout.ty.is_unsafe_ptr());
979+
let ptr = left.to_scalar().to_pointer(ecx)?;
980+
// We do the actual operation with usize-typed scalars.
981+
let usize_layout = ecx.layout_of(ecx.tcx.types.usize).unwrap();
982+
let left = ImmTy::from_uint(ptr.addr().bytes(), usize_layout);
983+
let right = ImmTy::from_uint(right.to_scalar().to_target_usize(ecx)?, usize_layout);
984+
let (result, overflowing) = ecx.overflowing_binary_op(bin_op, &left, &right)?;
985+
// Construct a new pointer with the provenance of `ptr` (the LHS).
986+
let result_ptr = Pointer::new(
987+
ptr.provenance,
988+
Size::from_bytes(result.to_scalar().to_target_usize(ecx)?),
989+
);
990+
(
991+
ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, ecx), left.layout),
992+
overflowing,
993+
)
994+
}
995+
996+
_ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
997+
})
944998
}
945999

9461000
fn expose_ptr(

tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,9 @@
111111
- StorageLive(_1);
112112
+ nop;
113113
StorageLive(_2);
114-
- StorageLive(_3);
115-
+ nop;
114+
StorageLive(_3);
116115
StorageLive(_4);
117-
- StorageLive(_5);
118-
+ nop;
116+
StorageLive(_5);
119117
_69 = const _;
120118
_5 = &(*_69);
121119
_4 = &(*_5);
@@ -124,18 +122,14 @@
124122
_2 = &raw const (*_3);
125123
_1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize));
126124
StorageDead(_2);
127-
- StorageDead(_5);
128-
- StorageDead(_3);
125+
StorageDead(_5);
126+
StorageDead(_3);
129127
- StorageLive(_7);
130-
+ nop;
131-
+ nop;
132128
+ nop;
133129
StorageLive(_8);
134-
- StorageLive(_9);
135-
+ nop;
130+
StorageLive(_9);
136131
StorageLive(_10);
137-
- StorageLive(_11);
138-
+ nop;
132+
StorageLive(_11);
139133
_68 = const _;
140134
_11 = &(*_68);
141135
_10 = &(*_11);
@@ -144,10 +138,8 @@
144138
_8 = &raw const (*_9);
145139
_7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize));
146140
StorageDead(_8);
147-
- StorageDead(_11);
148-
- StorageDead(_9);
149-
+ nop;
150-
+ nop;
141+
StorageDead(_11);
142+
StorageDead(_9);
151143
StorageLive(_13);
152144
StorageLive(_14);
153145
_14 = _1;
@@ -255,13 +247,14 @@
255247
- _45 = _39;
256248
- _43 = Eq(move _44, move _45);
257249
+ _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
258-
+ _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
250+
+ _43 = const false;
259251
StorageDead(_45);
260252
StorageDead(_44);
261-
_42 = Not(move _43);
253+
- _42 = Not(move _43);
254+
+ _42 = const true;
262255
StorageDead(_43);
263256
- _41 = opaque::<bool>(move _42) -> [return: bb1, unwind unreachable];
264-
+ _41 = opaque::<bool>(_42) -> [return: bb1, unwind unreachable];
257+
+ _41 = opaque::<bool>(const true) -> [return: bb1, unwind unreachable];
265258
}
266259

267260
bb1: {
@@ -277,11 +270,11 @@
277270
- _49 = _39;
278271
- _47 = Ne(move _48, move _49);
279272
+ _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
280-
+ _47 = Ne(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
273+
+ _47 = const true;
281274
StorageDead(_49);
282275
StorageDead(_48);
283276
- _46 = opaque::<bool>(move _47) -> [return: bb2, unwind unreachable];
284-
+ _46 = opaque::<bool>(_42) -> [return: bb2, unwind unreachable];
277+
+ _46 = opaque::<bool>(const true) -> [return: bb2, unwind unreachable];
285278
}
286279

287280
bb2: {
@@ -296,10 +289,11 @@
296289
- _53 = _39;
297290
- _51 = Le(move _52, move _53);
298291
+ _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
299-
+ _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
292+
+ _51 = const true;
300293
StorageDead(_53);
301294
StorageDead(_52);
302-
_50 = opaque::<bool>(move _51) -> [return: bb3, unwind unreachable];
295+
- _50 = opaque::<bool>(move _51) -> [return: bb3, unwind unreachable];
296+
+ _50 = opaque::<bool>(const true) -> [return: bb3, unwind unreachable];
303297
}
304298

305299
bb3: {
@@ -314,10 +308,11 @@
314308
- _57 = _39;
315309
- _55 = Lt(move _56, move _57);
316310
+ _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
317-
+ _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
311+
+ _55 = const true;
318312
StorageDead(_57);
319313
StorageDead(_56);
320-
_54 = opaque::<bool>(move _55) -> [return: bb4, unwind unreachable];
314+
- _54 = opaque::<bool>(move _55) -> [return: bb4, unwind unreachable];
315+
+ _54 = opaque::<bool>(const true) -> [return: bb4, unwind unreachable];
321316
}
322317

323318
bb4: {
@@ -333,12 +328,14 @@
333328
- _62 = _39;
334329
- _60 = Ge(move _61, move _62);
335330
+ _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
336-
+ _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
331+
+ _60 = const false;
337332
StorageDead(_62);
338333
StorageDead(_61);
339-
_59 = Not(move _60);
334+
- _59 = Not(move _60);
335+
+ _59 = const true;
340336
StorageDead(_60);
341-
_58 = opaque::<bool>(move _59) -> [return: bb5, unwind unreachable];
337+
- _58 = opaque::<bool>(move _59) -> [return: bb5, unwind unreachable];
338+
+ _58 = opaque::<bool>(const true) -> [return: bb5, unwind unreachable];
342339
}
343340

344341
bb5: {
@@ -354,12 +351,14 @@
354351
- _67 = _39;
355352
- _65 = Gt(move _66, move _67);
356353
+ _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
357-
+ _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
354+
+ _65 = const false;
358355
StorageDead(_67);
359356
StorageDead(_66);
360-
_64 = Not(move _65);
357+
- _64 = Not(move _65);
358+
+ _64 = const true;
361359
StorageDead(_65);
362-
_63 = opaque::<bool>(move _64) -> [return: bb6, unwind unreachable];
360+
- _63 = opaque::<bool>(move _64) -> [return: bb6, unwind unreachable];
361+
+ _63 = opaque::<bool>(const true) -> [return: bb6, unwind unreachable];
363362
}
364363

365364
bb6: {

tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,9 @@
111111
- StorageLive(_1);
112112
+ nop;
113113
StorageLive(_2);
114-
- StorageLive(_3);
115-
+ nop;
114+
StorageLive(_3);
116115
StorageLive(_4);
117-
- StorageLive(_5);
118-
+ nop;
116+
StorageLive(_5);
119117
_69 = const _;
120118
_5 = &(*_69);
121119
_4 = &(*_5);
@@ -124,18 +122,14 @@
124122
_2 = &raw const (*_3);
125123
_1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize));
126124
StorageDead(_2);
127-
- StorageDead(_5);
128-
- StorageDead(_3);
125+
StorageDead(_5);
126+
StorageDead(_3);
129127
- StorageLive(_7);
130-
+ nop;
131-
+ nop;
132128
+ nop;
133129
StorageLive(_8);
134-
- StorageLive(_9);
135-
+ nop;
130+
StorageLive(_9);
136131
StorageLive(_10);
137-
- StorageLive(_11);
138-
+ nop;
132+
StorageLive(_11);
139133
_68 = const _;
140134
_11 = &(*_68);
141135
_10 = &(*_11);
@@ -144,10 +138,8 @@
144138
_8 = &raw const (*_9);
145139
_7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize));
146140
StorageDead(_8);
147-
- StorageDead(_11);
148-
- StorageDead(_9);
149-
+ nop;
150-
+ nop;
141+
StorageDead(_11);
142+
StorageDead(_9);
151143
StorageLive(_13);
152144
StorageLive(_14);
153145
_14 = _1;
@@ -255,13 +247,14 @@
255247
- _45 = _39;
256248
- _43 = Eq(move _44, move _45);
257249
+ _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
258-
+ _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
250+
+ _43 = const false;
259251
StorageDead(_45);
260252
StorageDead(_44);
261-
_42 = Not(move _43);
253+
- _42 = Not(move _43);
254+
+ _42 = const true;
262255
StorageDead(_43);
263256
- _41 = opaque::<bool>(move _42) -> [return: bb1, unwind continue];
264-
+ _41 = opaque::<bool>(_42) -> [return: bb1, unwind continue];
257+
+ _41 = opaque::<bool>(const true) -> [return: bb1, unwind continue];
265258
}
266259

267260
bb1: {
@@ -277,11 +270,11 @@
277270
- _49 = _39;
278271
- _47 = Ne(move _48, move _49);
279272
+ _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
280-
+ _47 = Ne(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
273+
+ _47 = const true;
281274
StorageDead(_49);
282275
StorageDead(_48);
283276
- _46 = opaque::<bool>(move _47) -> [return: bb2, unwind continue];
284-
+ _46 = opaque::<bool>(_42) -> [return: bb2, unwind continue];
277+
+ _46 = opaque::<bool>(const true) -> [return: bb2, unwind continue];
285278
}
286279

287280
bb2: {
@@ -296,10 +289,11 @@
296289
- _53 = _39;
297290
- _51 = Le(move _52, move _53);
298291
+ _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
299-
+ _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
292+
+ _51 = const true;
300293
StorageDead(_53);
301294
StorageDead(_52);
302-
_50 = opaque::<bool>(move _51) -> [return: bb3, unwind continue];
295+
- _50 = opaque::<bool>(move _51) -> [return: bb3, unwind continue];
296+
+ _50 = opaque::<bool>(const true) -> [return: bb3, unwind continue];
303297
}
304298

305299
bb3: {
@@ -314,10 +308,11 @@
314308
- _57 = _39;
315309
- _55 = Lt(move _56, move _57);
316310
+ _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
317-
+ _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
311+
+ _55 = const true;
318312
StorageDead(_57);
319313
StorageDead(_56);
320-
_54 = opaque::<bool>(move _55) -> [return: bb4, unwind continue];
314+
- _54 = opaque::<bool>(move _55) -> [return: bb4, unwind continue];
315+
+ _54 = opaque::<bool>(const true) -> [return: bb4, unwind continue];
321316
}
322317

323318
bb4: {
@@ -333,12 +328,14 @@
333328
- _62 = _39;
334329
- _60 = Ge(move _61, move _62);
335330
+ _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
336-
+ _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
331+
+ _60 = const false;
337332
StorageDead(_62);
338333
StorageDead(_61);
339-
_59 = Not(move _60);
334+
- _59 = Not(move _60);
335+
+ _59 = const true;
340336
StorageDead(_60);
341-
_58 = opaque::<bool>(move _59) -> [return: bb5, unwind continue];
337+
- _58 = opaque::<bool>(move _59) -> [return: bb5, unwind continue];
338+
+ _58 = opaque::<bool>(const true) -> [return: bb5, unwind continue];
342339
}
343340

344341
bb5: {
@@ -354,12 +351,14 @@
354351
- _67 = _39;
355352
- _65 = Gt(move _66, move _67);
356353
+ _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
357-
+ _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
354+
+ _65 = const false;
358355
StorageDead(_67);
359356
StorageDead(_66);
360-
_64 = Not(move _65);
357+
- _64 = Not(move _65);
358+
+ _64 = const true;
361359
StorageDead(_65);
362-
_63 = opaque::<bool>(move _64) -> [return: bb6, unwind continue];
360+
- _63 = opaque::<bool>(move _64) -> [return: bb6, unwind continue];
361+
+ _63 = opaque::<bool>(const true) -> [return: bb6, unwind continue];
363362
}
364363

365364
bb6: {

0 commit comments

Comments
 (0)